
    $Ki2                     x   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m	Z	 ddl
Z
ej                  j                  dej                  j                  ej                  j                  e                   ddlmZ dZdZddiZd	d
dddddddd	dddZd Zd Zd Zd Zd ZddZd Zedk(  r e        yy)z
Ingest Play-by-Play Data from ESPN
Captures game flow events for pace analysis, foul tracking, turnover impact, etc.

ESPN endpoint: /sports/{sport}/{league}/playbyplay?event={id}

Run: Daily after games complete
    N)datetimetimezone	timedelta)normalize_to_fullz-https://site.api.espn.com/apis/site/v2/sportsg      ?z
User-Agentz<Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
basketballnba)sportespn_leaguefootballnflhockeynhlmens-college-basketball)r   r   r   ncaabc                  ~   d} 	 t        | d      5 }|D ]S  }|j                  d      s|j                  dd      d   j                         j                  d      d   c cd d d        S  	 d d d        t
        j                  j                  dd	      j                  d      d   S # 1 sw Y   ;xY w# t        $ r Y Iw xY w)
Nz/var/www/html/eventheodds/.envrzSPORTS_DATABASE_URL==   ?r   SPORTS_DATABASE_URL )open
startswithsplitstripFileNotFoundErrorosenvironget)env_pathflines      scripts/ingest_play_by_play.pyload_db_urlr$   !   s    /H(C  	GA G??#9:::c1-a0668>>sCAFF	G 	GG	G ::>>/4::3?BB	G 	G  s9   B0 B$6B$	B0 (B$*B0 $B-)B0 0	B<;B<c                     | j                  d       | j                  d       | j                  d       | j                  d       y)z!Create PlayByPlay table if neededa  
        CREATE TABLE IF NOT EXISTS "PlayByPlay" (
            id BIGSERIAL PRIMARY KEY,
            league VARCHAR(50) NOT NULL,
            "gameId" BIGINT,
            "espnEventId" VARCHAR(50),
            "gameDate" TIMESTAMP,
            period INT,
            "gameClock" VARCHAR(20),
            "sequenceNumber" INT,
            "playType" VARCHAR(100),
            "playText" TEXT,
            "homeScore" INT,
            "awayScore" INT,
            "scoringPlay" BOOLEAN DEFAULT FALSE,
            "teamId" VARCHAR(50),
            "team" VARCHAR(20),
            "playerId" VARCHAR(50),
            "playerName" VARCHAR(200),
            "turnover" BOOLEAN DEFAULT FALSE,
            "foul" BOOLEAN DEFAULT FALSE,
            "timeout" BOOLEAN DEFAULT FALSE,
            raw JSONB,
            "createdAt" TIMESTAMP DEFAULT NOW(),
            UNIQUE(league, "espnEventId", "sequenceNumber")
        )
    zZCREATE INDEX IF NOT EXISTS "PlayByPlay_league_game_idx" ON "PlayByPlay" (league, "gameId")zQCREATE INDEX IF NOT EXISTS "PlayByPlay_playType_idx" ON "PlayByPlay" ("playType")z]CREATE INDEX IF NOT EXISTS "PlayByPlay_period_idx" ON "PlayByPlay" (league, "gameId", period)N)execute)curs    r#   ensure_pbp_tabler(   -   s<    KK  	6 KKlmKKcdKKop    c           	         t          d|  d| d| }|dv r|dz  }	 t        j                  |t        d      }|j                  dk7  rg S |j                         }g }|j                  dg       D ]  }|j                  d	      }|j                  d
i       j                  di       j                  d      }	|	dk7  rK|j                  dg       }
|
s`|
d   }|j                  dg       }d}d}|D ]M  }|j                  di       }|j                  dd      j                         }|j                  d      dk(  r|}L|}O |s|j                  ||||j                  d      d        |S # t        $ r}g cY d}~S d}~ww xY w)zGet ESPN event IDs for a date/z/scoreboard?dates=)r   zcollege-footballz&groups=50&limit=300   headerstimeout   eventsidstatustypestatepostcompetitionsr   competitorsNteamabbreviationr   homeAwayhomedate)r2   r<   awayr=   )		ESPN_BASErequestsr   HEADERSstatus_codejsonupperappend	Exception)r	   r
   date_strurlrespdatar1   eventevent_idr3   r7   compr8   	home_team	away_team
competitorr9   abbreves                      r#   get_espn_events_for_daterS   O   s   Kqq-?z
JCEE%%+||C"=s"Iyy{XXh+ 	EyyHYYx,00<@@IF  99^R8L?D((="5KII) '
!~~fb1."5;;=>>*-7 &I &I' "%%!IIf-	 5	B  	s*   ,E& 	C3E& =(E& &	E;/E60E;6E;c                     t          d|  d| d| }	 t        j                  |t        d      }|j                  dk7  ry|j                         S #  Y yxY w)z-Fetch play-by-play data from summary endpointr+   z/summary?event=   r-   r0   N)r?   r@   r   rA   rB   rC   )r	   r
   rL   rH   rI   s        r#   fetch_play_by_playrV      s^     Kqq_XJ
GC||C"=s"yy{s   +A A Ac           	         g }| s|S i }| j                  di       j                  dg       D ]R  }|j                  di       }t        |j                  dd            }|j                  dd      j                         ||<   T | j                  dg       }|s| j                  di       }t        |t              ri|j                  d	g       }	|j                  d
i       }
|	|
r|
gng z   }|D ]6  }t        |t              s|j                  dg       }|j                  |       8 d}|D ]$  }|dz  }|j                  di       }t        |t              r|j                  dd      n
t        |      }|j                  dd      j                         }d|v xs
 d|v xs d|v }d|v }d|v }|j                  dd      }|j                  dd      }|j                  di       }t        |t              r|j                  dd      nd}|j                  di       }t        |t              r|j                  dd      n
t        |      }|j                  di       }t        |t              rt        |j                  dd            nd}|j                  |d      }|j                  dg       }d}d} |rB|d   j                  di       }!t        |!j                  dd            }|!j                  dd      } |j                  i d|d|d|d |d!|j                  dd      d"|d#|d$|j                  d%d&      d'|d|d(|d)| d|d|d|d*|       ' |S )+z/Parse play-by-play data into structured recordsboxscoreteamsr9   r2   r   r:   playsdrivespreviouscurrentr   r   r4   textturnoverstealinterceptionfoulr/   	homeScore	awayScoreperiodnumberclockdisplayValueparticipantsNathletedisplayName
game_clocksequence	play_type	play_text
home_score
away_scorescoring_playscoringPlayFteam_id	player_idplayer_nameraw)r   strrD   
isinstancedictextendlowerrE   )"pbp_dataleaguerZ   	teams_mapr9   	team_infort   	all_playsr[   previous_drivescurrent_drive
drive_listdrivedrive_playsseqplayrn   play_type_text
text_loweris_turnoveris_foul
is_timeoutrp   rq   re   
period_numrg   rl   	team_datateam_abbrevri   ru   rv   rj   s"                                     r#   parse_playsr      s   E IZ,00"= GHHVR(	immD"-.&]]>2>DDF	'G Wb)I h+fd#$jjR8O"JJy"5M(}]ORTUJ# 2eT*"'))GR"8K$$[12
 C 5qHHVR(	6@D6Qvr2WZ[dWe XXfb)//1
 J.g'Z2Gg>]gKgJ&*,
 XXk1-
XXk1-
 (B'0:640HVZZ!,a
"%6@6MUYY~r2SVW\S]
 HHVR(	2<Y2M#immD"-.SUmmGR0 xx3	"1o)))R8GGKKb12I!++mR8K 
j
*
 
 	

 &"-
 *
 *
 DHH]E:
 w
 K
 
 ;
 
 G
 z
  4!
 	I5n Lr)   c                    | t         vrt        d|         dddS t         |    }t               }t        j                  |      }|j                         }t        |       |j                          t        j                  t        j                        j                         }|t        |      z
  }t        d| j                          d| d|        d}	d}
d}|}||k  r||k  r|j                  d      }t!        |d	   |d
   |      }|D ]  }||k\  r n{|j#                  d| |d   f       |j%                         d   dkD  r:t'        j(                  t*               t-        |d	   |d
   |d         }|slt/        ||       }|s{t1        |d   |       }t1        |d   |       }|j#                  d| ||||f       |j%                         }|r|d   nd}|r|d   n|}|D ]t  }	 |j#                  d| ||d   ||d   |d   |d   |d   |d   |d   |d   |d   |d   |d   |d   |d   |d   |d    |d!   t3        j4                  |d"         f       |
dz  }
v |	dz  }	|dz  }|d#z  dk(  s_t        d$|  d%| d&|
 d'       |j                           |t        d      z  }||k  r||k  r|j                          |j9                          |j9                          t        d$|  d(|	 d&|
 d'       |	|
dS # t6        $ r}Y d}~'d}~ww xY w))z Ingest play-by-play for a leaguezUnknown league: r   )gamesrZ   )days
z: Fetching PBP from z to z%Y%m%dr	   r
   zx
                SELECT COUNT(*) FROM "PlayByPlay"
                WHERE league = %s AND "espnEventId" = %s
            r2   r<   r>   a  
                SELECT id, "gameDate" FROM "SportsGame"
                WHERE league = %s
                  AND "homeTeam" = %s AND "awayTeam" = %s
                  AND "gameDate"::date BETWEEN %s AND %s + INTERVAL '1 day'
                LIMIT 1
            Nr   a  
                        INSERT INTO "PlayByPlay" (
                            league, "gameId", "espnEventId", "gameDate",
                            period, "gameClock", "sequenceNumber", "playType", "playText",
                            "homeScore", "awayScore", "scoringPlay",
                            "teamId", team, "playerId", "playerName",
                            turnover, foul, timeout, raw
                        )
                        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                        ON CONFLICT (league, "espnEventId", "sequenceNumber") DO NOTHING
                    re   rl   rm   rn   ro   rp   rq   rr   rt   r9   ru   rv   r_   rb   r/   rw   
   z  z: Processed  games,  playsz: Total )LEAGUE_CONFIGprintr$   psycopg2connectcursorr(   commitr   nowr   utcr=   r   rD   strftimerS   r&   fetchonetimesleepREQUEST_DELAYrV   r   r   rC   dumpsrF   close)r~   	days_backlimitconfigdb_urlconnr'   end_date
start_datetotal_gamestotal_playsgames_processedcurrent_daterG   r1   rK   r}   rZ   	home_full	away_fullgamegame_id	game_dater   rR   s                            r#   ingest_pbp_for_leaguer      s   ]" )*Q''6"F]FF#D
++-CSKKM||HLL)..0HI955J	Bv||~2:,d8*
MNKKOL
(
"'>((2)&/6-;PRZ[ F	E%' KK  %+&(
 ||~a 1$JJ}%)&/6-;PRWX\R]^H&1E)%-@I)%-@I KK  )YlKM <<>D!%d1g4G#'Q\I  KK 
! tiX\(:D<L[)4+<\*D,>^@TYftK7H$}J]Z($v,Y

4;/&  1$K+2 1Kq O#q(6(,.?x}TZ[\MF	P 		q))Y (
"'>\ 	KKMIIKJJL	Bvhh{m8K=
GH ;77# ! s   #A1K77	LLc                     t        j                  d      } | j                  dt        dd       | j                  dt        dd	       | j                  d
t        dd       | j                         }t        d       t        d       t        dt        j                  t        j                        j                                 t        d       |j                  j                  d      D cg c]   }|j                         j                         " }}d}d}|D ]4  }t!        ||j"                  |j$                        }||d   z  }||d   z  }6 t        dd        t        d| d| d       t        d       y c c}w )NzIngest play-by-play from ESPN)descriptionz	--leaguesznba,nflzComma-separated leagues)r4   defaulthelpz--days   zDays to look backz--limitd   zMax games per leaguez<============================================================zINGEST PLAY-BY-PLAY FROM ESPNzTime: ,r   )r   r   r   rZ   r   zTOTAL: r   r   )argparseArgumentParseradd_argumentrx   int
parse_argsr   r   r   r   r   	isoformatleaguesr   r   r|   r   r   r   )parserargslr   r   r   r~   results           r#   mainr   Y  s`   $$1PQF
#y6  8
sA0  2
	S3  5D	(O	
)*	F8<<-779:
;<	(O*.,,*<*<S*ABQqwwy BGBKK '&v$**Uvg&vg&'
 
Bvh-	GK=V
<=	(O Cs   -%E=__main__)r   2   )__doc__r@   r   r   sysr   r   r   r   r   rC   pathinsertdirnameabspath__file__
team_namesr   r?   r   rA   r   r$   r(   rS   rV   r   r   r   __name__ r)   r#   <module>r      s      	 
   2 2  277??277??8#<= > (;	W
X "%86e4#4MN		CqD1hVrk8\< zF r)   