
    }^i?H                        d Z ddlZddlZddlZddlZddlZddlZddlmZmZ ddl	m
Z
 ddlmZmZmZmZ 	 ddlZej(                  j+                  ej(                  j-                  ej(                  j/                  e                   	 ddlZd	Zej6                  j9                  d
d      ZdeiZ e
d      ZdZ  ejB                  ejD                  d ejF                  ej(                  j-                  e       ejH                        r ejJ                  e       n ejL                          ejL                         g        ejN                  e(      Z)ddddddddddddddddddddddddd dddddd!d"ddd#ddddddd$d%dd&dddddd'd%dd(dd)ddd*dd+d%dd,dd)ddd*d-dd.ddd/dddddd0ddd1dddddd0ddd2dddddd0ddd3dddddd0ddd4dddddd0ddd5dddddd0ddd6d7d8d9d:d*dd;d%dd<Z* G d= d>      Z+d? Z,e(d@k(  r e,        yy# e$ r  ed        ej&                  d       Y w xY w# e$ r  ed       dZY w xY w)Aa  
Comprehensive Sports Data Updater for BallDontLie API.

This script fetches and caches ALL available sports data to reduce API calls.
Designed to run daily via systemd service.

Sports supported (per BallDontLie API):
- NBA, NFL, NHL, MLB
- WNBA, NCAAF, NCAAB
- EPL, La Liga, Serie A, Bundesliga, Ligue 1
- UEFA Champions League
- MMA

Usage:
    python sports_data_updater.py [--sport SPORT] [--force]
    
    --sport: Specific sport to update (default: all)
    --force: Force update even if recent data exists
    N)datetime	timedelta)Path)DictListOptionalAnyz7Error: requests required. Install: pip install requests   z!Warning: fetch_odds_api not foundzhttps://api.balldontlie.ioBALLDONTLIE_API_KEYz$db60bdff-30db-4e3c-999a-9ce31d0a6c6cAuthorizationz/var/www/html/eventheodds/dataz /var/log/sports_data_updater.logz)%(asctime)s - %(levelname)s - %(message)s)levelformathandlersz/v1z/teamsz/players/gamesz
/standingsz/player_injuries/oddsz/statsz/season_averages)teamsplayersgames	standingsinjuriesoddsstatsseason_averagesi  )prefix	endpointsseasonz/nfl/v1z/season_stats)r   r   r   r   r   r   r   season_statsz/nhl/v1z/box_scores)r   r   r   r   r   
box_scoresz/mlb/v1)r   r   r   r   r   r   i  z/wnba/v1)r   r   r   r   r   z	/ncaaf/v1z/conferencesz	/rankings)r   conferencesr   r   rankingsr   z	/ncaab/v1z	/brackets)r   r   r   r   r    bracketsr   z/epl/v1)r   r   r   r   r   z/bundesliga/v1z
/laliga/v1z
/ligue1/v1z
/seriea/v1z/ucl/v1z/mma/v1z/leaguesz/eventsz	/fightersz/fights)leagueseventsfightersfightsr    r   )nbanflnhlmlbwnbancaafncaabepl
bundesligalaligaligue1serieauclmmac            
           e Zd ZdZefdefdZddedede	e   fdZ
ddeded	edee   fd
ZdededefdZddededefdZdedefdZdedefdZd Zddee   defdZy)SportsDataUpdaterz)Handles fetching and caching sports data.data_dirc                 (    || _         dddd| _        y )Nr   )fetchederrorsskipped)r6   r   )selfr6   s     8/var/www/html/eventheodds/scripts/sports_data_updater.py__init__zSportsDataUpdater.__init__   s     !"aA>
    Nurlparamsreturnc                    t        d      D ]  }	 t        j                  |t        |d      }|j                  dk(  r+t
        j                  d       t        j                  d       [|j                  dk(  rt
        j                  d        y	|j                  d
k(  rt
        j                  d|         y	|j                  dk(  rt
        j                  d|         y	|j                          |j                         c S  y	# t        j                  j                  $ rA}t
        j                  d|dz    d|        t        j                  d|z         Y d	}~Pd	}~ww xY w)z"Make API request with retry logic.      )headersr@   timeouti  zRate limited, waiting 60s...<   i  z%Authentication failed - check API keyNi  z"Access denied (tier restriction): i  zEndpoint not found: zRequest failed (attempt r
   z):    )rangerequestsgetHEADERSstatus_codeloggerwarningtimesleeperrordebugraise_for_statusjson
exceptionsRequestException)r;   r?   r@   attemptresponsees         r<   make_requestzSportsDataUpdater.make_request   s,   Qx 	)G)#<<WVUWX''3.NN%ACJJrN''3.LL!HI''3.LL#EcU!KL''3.LL#7u!=>))+}}&-	)8 	 &&77 )!9'A+c!MN

1<(()s0   AD'$D'D6'DDE! 6EE!	max_pagesc                 F   g }|xs i }d|d<   d}t        |      D ]  }|r||d<   | j                  ||      }|s |S |j                  dg       }|s |S |j                  |       |j                  di       j                  d      }|s |S t	        j
                  d        |S )	z(Fetch all pages of a paginated endpoint.d   per_pageNcursordatametanext_cursor333333?)rI   r[   rK   extendrP   rQ   )	r;   r?   r@   r\   all_datar`   pagera   itemss	            r<   fetch_paginatedz!SportsDataUpdater.fetch_paginated  s    2 z)$ 	D#)x $$S&1D  HHVR(E  OOE"XXfb)--m<F  JJsO%	( r>   sport	data_typera   c                 v   | j                   |z  }|j                  dd       || dz  }t        |d      5 }t        j                  ||dt
               ddd       t        j                  d| d	| d
t        |t              rt        |      nd d       | j                  dxx   dz  cc<   y# 1 sw Y   [xY w)zSave data to JSON file.T)parentsexist_okz.jsonwrH   )indentdefaultNzSaved /: configz entriesr8   r
   )r6   mkdiropenrU   dumpstrrN   info
isinstancelistlenr   )r;   rj   rk   ra   	sport_dirfilepathfs          r<   	save_datazSportsDataUpdater.save_data/  s    MME)	t4)E22(C  	6AIIdAa5	6 	fUG1YKrz$PT?U#d)[c1ddlmn

9"		6 	6s   B//B8rt   forcec                 d   t         j                  d        t         j                  d|j                                 t         j                  d        |d   }|d   }|d   j                         D ]  \  }}	 t         | | }i }	|dv r(|dv r||	d<   n|d	v r||	d<   n|d
v r||	d<   n
|dk(  r||	d<   |dk(  r| j                  ||       Yt         j                  d| d       |dv r| j                  ||	      }
n(| j                  ||	      }|r|j                  dg       ng }
|
r| j                  |||
       n/t         j                  d|        | j                  dxx   dz  cc<    y# t        $ r=}t         j                  d| d|        | j                  dxx   dz  cc<   Y d}~:d}~ww xY w)z%Update all data for a specific sport.z2==================================================z	Updating r   r   r   )r   r   r   r   r   r    r!   )r&   r*   z	seasons[])r'   r,   )r+   r(   r   z  Fetching z...)r   r   r   r   r%   r$   r#   ra   z  No data for r:   r
   z  Error fetching rs   r9   N)rN   ry   upperrh   API_BASE_fetch_oddsri   r[   rK   r   rS   r   	ExceptionrR   )r;   rj   rt   r   r   r   endpoint_nameendpoint_pathr?   r@   ra   rY   rZ   s                r<   update_sportzSportsDataUpdater.update_sport;  s   xj"i/0xj"!!,2;,?,E,E,G &	*(M=%*!
6(=/: !$~~/.4{+"22+1x()+.4{+%.4{+ !F*$$UF3k-<= !$mm//V<D#00f=H7?8<<3RDNN5->LL>-!ABJJy)Q.)E&	*H  *0r!EF

8$)$$*s    7AE)	BE))	F/22F**F/c                 D   |d   }|d   }g }t         j                  d       |dk(  rt        dd      D ]p  }t         | d}||dd	}| j	                  ||      }	|	r4|	j                  d
      r#|	d
   D ]  }
||
d<   	 |j                  |	d
          t        j                  d       r nc|dv rt        j                         }t        d      D ]  }|t        |      z
  j                  d      }t         | d}|dk(  r|dd}n|dd}| j	                  ||      }	|	r4|	j                  d
      r#|	d
   D ]  }
||
d<   	 |j                  |	d
          t        j                  d        n|dv rt        j                         }t        d      D ]~  }|t        |      z
  j                  d      }t         | d}|dd}| j	                  ||      }	|	r%|	j                  d
      r|j                  |	d
          t        j                  d        |r| j                  |d|       yy)z+Fetch betting odds with date/week handling.r   r   z  Fetching odds...r'   r
      r   r^   )r   weekr_   ra   r   rd   )r&   r(   rG   days%Y-%m-%dr&   )dater_   zdates[]r_   r   )r+   r,   r-   rD   r   N)rN   ry   rI   r   r[   rK   re   rP   rQ   r   nowr   strftimer   )r;   rj   rt   r   r   all_oddsr   r?   r@   ra   itemtodayir   s                 r<   r   zSportsDataUpdater._fetch_oddsl  s-   !!(*E>a  !
6(%0$*DcJ((f5DHHV, $V ,'+V,OODL1

3  n$LLNE2Y  	q 11;;JG!
6(%0E>&*<F)-3?F((f5DHHV, $V ,'+V,OODL1

3   //LLNE2Y  	q 11;;JG!
6(%0%)s;((f5DHHV,OODL1

3  NN5&(3 r>   c                    |d   }t         j                  d       t        j                         }g }t	        dd      D ]|  }|t        |      z   j                  d      }t         | d}|dd	}	| j                  ||	      }
|
sF|
j                  d
      sX|j                  |
d
   D cg c]  }|d   	 c}       ~ g }|dd D ]_  }t         | d}d|i}	| j                  ||	      }
|
r%|
j                  d
      r|j                  |
d
          t        j                  d       a |r| j                  |d|       yyc c}w )z+Fetch live player props for upcoming games.r   z  Fetching player props...rC   r   r   r   2   r   ra   idN   z/odds/player_propsgame_idrd   player_props)rN   ry   r   r   rI   r   r   r   r[   rK   re   rP   rQ   r   )r;   rj   rt   r   r   game_idsr   r   r?   r@   ra   g	all_propsr   s                 r<   fetch_player_propsz$SportsDataUpdater.fetch_player_props  sI   !02 r1 	AAI1--77
CDJvhf-C!%26F$$S&1D($v, ?Q4 ?@	A 	} 	GJvh&89C)F$$S&1D(  f.JJsO	 NN5.)<  !@s   'D<
c                    t        j                         j                         i dddd}| j                  j	                         D ]  }|j                         s|j                  j                  d      r0i }|j                  d      D ]  }	 t        |      5 }t        j                  |      }t        |t              rt        |      nd}|t        |      |j!                         j"                  dz  d||j$                  <   |d	   d
xx   |z  cc<   |d	   dxx   dz  cc<   ddd        |s||d   |j                  <    t        | j                  dz  d      5 }t        j&                  ||d       ddd       t(        j+                  d|d	   d
    d|d	   d    d       y# 1 sw Y   xY w#  Y .xY w# 1 sw Y   FxY w)z'Create master index of all cached data.r   )entriesfiles)
updated_atsportstotals.z*.jsonr
   i   )countfilesize_kbr   r   r   Nr   zmaster_index.jsonro   rH   )rp   zMaster index: z entries in z files)r   r   	isoformatr6   iterdiris_dirname
startswithglobrv   rU   loadrz   r{   r|   rx   statst_sizestemrw   rN   ry   )r;   indexr}   
sport_data	json_filer   ra   r   s           r<   create_master_indexz%SportsDataUpdater.create_master_index  s    #,,.224"#a0
 ..0 	AI!)..*C*CC*H
!*!9 I!)_ 	:#'99Q<D1;D$1GCIQE).(+I+4>>+;+C+Cd+J:Jy~~6
 "(OI6%?6!(OG494	: 6@E(OINN3'	A* $--"55s; 	*qIIeQq)	* 	nU8_Y%?$@US[_]dMeLfflmn'	: 	:
	* 	*s1   F0B
F$ F0F8$F-)F00F58Gr   c                    t        j                         }t        j                  d       t        j                  d|        t        j                  d       |xs t	        t
        j                               }|D ]\  }|t
        v r:| j                  |t
        |   |       |dv s*	 | j                  |t
        |          Et        j                  d|        ^ t        r*	 t        j                  d       t        j                          | j                          t        j                         |z
  j!                         }t        j                  d       t        j                  d
       t        j                  d|dd       t        j                  d| j"                  d           t        j                  d| j"                  d           t        j                  d| j"                  d           t        j                  d       y# t        $ r&}t        j                  d| d|        Y d}~d}~ww xY w# t        $ r#}t        j                  d	|        Y d}~Wd}~ww xY w)zRun the update process.zF======================================================================z!Sports Data Updater - Started at )r&   r'   r(   r-   zPlayer props not available for rs   NzUnknown sport: zRunning The Odds API fetcher...z Error running Odds API fetcher: zUPDATE COMPLETEz
Duration: z.1fsz	Fetched: r8   z	Skipped: r:   zErrors: r9   )r   r   rN   ry   r{   SPORTS_CONFIGkeysr   r   r   rS   rO   fetch_odds_apifetch_all_mapped_sportsrR   r   total_secondsr   )r;   r   r   
start_timesports_to_updaterj   rZ   durations           r<   runzSportsDataUpdater.run  s   \\^
H7
|DEH!?T-*<*<*>%?% 	:E%!!%u)=uE 88U//}U7KL 89	: E=>668 	  " LLNZ/>>@H%&j#a01i

9 5678i

9 5678htzz(3456H1 % U'FugRPQs%STTU  E?sCDDEs0   %H )H9 	H6H11H69	I%I  I%)N)Nr   )F)NF)__name__
__module____qualname____doc__DATA_DIRr   r=   rx   dictr   r[   intr   ri   r	   r   boolr   r   r   r   r    r>   r<   r5   r5      s    3(0 ? ? T Xd^ @3   UYZ^U_ :
#s 
#s 
## 
#/*# /*t /*D /*b44 44d 44l= =T =< oD)$s) )4 )r>   r5   c                     t        j                  d      } | j                  dt        d       | j                  ddd	       | j                  d
dd	       | j	                         }|j
                  r%t        d       t        D ]  }t        d|         y t               }|j                  r|j                  gnd }|j                  ||j                         y )Nz'Update sports data from BallDontLie API)descriptionz--sportzSpecific sport to update)typehelpz--force
store_truezForce update)actionr   z--listzList available sportszAvailable sports:z  - )r   r   )argparseArgumentParseradd_argumentrx   
parse_argsr{   printr   r5   rj   r   r   )parserargsrj   updaterr   s        r<   mainr     s    $$1Z[F
	2LM
	,^L
<STDyy!"" 	"ED.!	"!G!ZZdjj\TFKKvTZZK0r>   __main__)-r   ossysrU   rP   r   loggingr   r   pathlibr   typingr   r   r   r	   rJ   ImportErrorr   exitpathappenddirnameabspath__file__r   r   environrK   API_KEYrL   r   LOG_FILEbasicConfigINFOaccessW_OKFileHandlerStreamHandler	getLoggerr   rN   r   r5   r   r   r>   r<   <module>r      s  ( 
 
     (  , ,  9: ; (
**...0V
WG
$01-   
,,6)2277??83Lbgg)VH%\q\c\q\q\s 
		8	$
 !%*1	
  !%*+	
  !%'
  !%*
  !%*
 
 )%#
  )%##
  !%
 
 #!%
 
 !%
 
 !%
 
 !%
 
 !%
 
 !##
 wgT` `F	1$ zF }  	
CDCHHQK  	
-.Ns#   H H; H87H8;II