Ë
    +Pkjí  ã            
       óº  — U 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	m
Z
mZmZmZmZmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZmZmZ d dlmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6  e ee«      g¬	«      Z7 e«       Z8i Z9d
Z:i Z;e<e=e<f   e>d<   i Z?e<e=e<f   e>d<   i Z@e<e=e<f   e>d<   dZAi ZBe<e=e<f   e>d<   dZCdeDde	fd„ZEdede=fd„ZFd¹d„ZGde=de2ddfd„ZHde<de=de<dz  fd„ZIde<de=de<ddfd„ZJd¹d„ZKe7j™                  d «      d!„ «       ZMe7j™                  d"«      	 	 dºd#e=dz  d$eNfd%„«       ZOe7j¡                  d&«      d'„ «       ZQe7j¡                  d(«      d)„ «       ZRe7j¡                  d*«      d+„ «       ZSe7j™                  d,«      d-„ «       ZTe7j¡                  d.«       e«       fdefd/„«       ZUe7j™                  d0«      d1„ «       ZVe7j¡                  d2«      de5fd3„«       ZWe7j¡                  d4«      d»de6dz  fd5„«       ZXe7j™                  d6«      d»d#e=dz  fd7„«       ZYe7j™                  d8«      d¼d9eNd#e=dz  fd:„«       ZZe7j¡                  d;«      de(fd<„«       Z[e7j¡                  d=«      d>„ «       Z\e7j¡                  d?«      de)fd@„«       Z]e7j¡                  dA«      defdB„«       Z^e7j™                  dC«      dD„ «       Z_e7j¡                  dE«      defdF„«       Z`e7j™                  dG«      dH„ «       Zae7j¡                  dI«      de fdJ„«       Zbe7j¡                  dK«      de!fdL„«       Zce7j™                  dM«      dN„ «       Zde7j¡                  dM«      de"fdO„«       Zee7j¡                  dP«      de#fdQ„«       Zfe7j™                  dR«      dS„ «       Zge7j¡                  dR«      dT„ «       Zhe7j¡                  dU«      de&fdV„«       Zie7j¡                  dW«      de'fdX„«       Zje7j¡                  dY«      dZ„ «       Zke7j™                  d[«      d\„ «       Zle7j¡                  d]«      d^„ «       Zme7j™                  d_«      d`„ «       Zndae=fdb„Zoe7j¡                  dc«       ed«       edd«      fdeedfepdz  dge
fdh„«       Zqe7j™                  di«      dj„ «       Zre7j¡                  dk«      de$fdl„«       Zse7j¡                  dm«      dn„ «       Zte7j™                  do«      dp„ «       Zue7j¡                  dq«      dr„ «       Zve7j™                  ds«      dt„ «       Zwe7j¡                  du«      de%fdv„«       Zxe7j¡                  dw«      dx„ «       Zye7j™                  dy«      d»d#e=dz  fdz„«       Zze7j™                  d{«      d½d#e=dz  d$eNfd|„«       Z{e7j™                  d}«      	 d¾d#e=dz  d~e=d$eNfd„«       Z|e7j™                  d€«      	 	 	 	 d¿d#e=dz  d~e=dae=d$eNfd�„«       Z}e7j¡                  d‚ejü                  ¬ƒ«       ee«      fde2deedefd„„«       Ze7j¡                  d…«       ee«      fde3defd†„«       Z€e7j¡                  d‡«       ee«      fde4defdˆ„«       Z�e7j™                  d‰«      d  ee«      fde=dŠe‚defd‹„«       Zƒe7j¡                  dŒ«      de*fd�„«       Z„e7j¡                  dŽ«      d�„ «       Z…e7j¡                  d�«      de+fd‘„«       Z†e7j¡                  d’«      de,fd“„«       Z‡e7j¡                  d”«      de+fd•„«       Zˆe7j¡                  d–«      de-fd—„«       Z‰e7j¡                  d˜«      d™„ «       ZŠe7j¡                  dš«      de.fd›„«       Z‹e7j¡                  dœ«      de/fd�„«       ZŒe7j¡                  dž«      de+fdŸ„«       Z�e7j¡                  d «      de1fd¡„«       ZŽe7j¡                  d¢«      de0fd£„«       Z�e7j™                  d¤«      d¥„ «       Z�e7j™                  d¦«      d§e=fd¨„«       Z‘e7j¡                  d©«      de+fdª„«       Z’e8j™                  d««      d»d¬e=d­ed®e=fd¯„«       Z“e8j™                  d°«      d»d¬e=d­ed®e=fd±„«       Z”e8j™                  d²«      dÀd³epd®e=deefd´„«       Z•e8j™                  dµ«      	 	 dºd¶e=d­ed®e=d·eNfd¸„«       Z–y)Áé    N)	Ú	APIRouterÚDependsÚHTTPExceptionÚ
UploadFileÚFileÚFormÚBackgroundTasksÚRequestÚstatus)Úbrowser_manager)Úrun_task)Úsession_store)ÚHudlForbiddenError)ÚAuthContextÚrequire_authÚresolve_auth_from_token)ÚExchangeSearchSchemaÚExchangeTypeSchemaÚLoginSchemaÚVideoSelectSchemaÚPlaylistSelectSchemaÚStatsSchemaÚNotesSchemaÚDeleteFileSchemaÚVideoDetailsSchemaÚCancelSchemaÚ
BackSchemaÚActiveExchangeDetailsSchemaÚActiveExchangeActionSchemaÚVideoStreamSchemaÚLibraryActionBaseSchemaÚLibraryUpdateTypeSchemaÚLibraryUpdateEventSchemaÚLibraryRenameSchemaÚLibraryEmailDownloadSchemaÚLibraryDownloadToMediaSchemaÚLibraryDownloadByRefSchemaÚManageLibraryDownloadSchemaÚManageLibrarySelectSchemaÚManageLibraryClipMetaSchemaÚSwitchHudlTeamSchemaÚOpenExchangeSchema)Údependenciesé´   ÚMANAGE_LIBRARY_CACHEÚMANAGE_LIBRARY_SEASON_CACHEÚMANAGE_LIBRARY_FOLDER_CACHEi  ÚMANAGE_LIBRARY_DOWNLOAD_JOBSi€Q ÚexcÚreturnc                 ó¨   — t        | t        «      r| S t        | t        «      rt        d| j                  «       ¬«      S t        dt	        | «      ¬«      S )uE   Map automation errors to HTTP â€” preserve Hudl 403 permission pages.i“  ©Ústatus_codeÚdetailéô  )Ú
isinstancer   r   Úas_dictÚstr©r3   s    ú=/var/www/html/sergio/sergio-backend/app/routes/hudl_routes.pyÚ_hudl_http_errorr?   A   s@   € ä�#”}Ô%Øˆ
Ü�#Ô)Ô*Ü¨°S·[±[³]ÔCÐCÜ S´°S³Ô:Ð:ó    Úauthc                 ó®   — | j                   �d| j                   j                  › �S | j                  �d| j                  j                  › �S t        dd«      ‚)Nzuser:zaccount:é‘  zAuthentication required)ÚuserÚidÚaccountr   )rA   s    r>   Ú_download_job_ownerrG   J   sO   € Ø‡y�yÐØ�t—y‘y—|‘|�nÐ%Ð%Ø‡|�|ÐØ˜$Ÿ,™,Ÿ/™/Ð*Ð+Ð+Ü
˜Ð6Ó
7Ð7r@   c                  óÜ   — t        j                   «       t        z
  } t        j                  «       D ��cg c]  \  }}|d   | k  r|‘Œ }}}|D ]  }t        j	                  |d «       Œ y c c}}w )NÚ
created_at)ÚtimeÚMANAGE_LIBRARY_DOWNLOAD_JOB_TTLr2   ÚitemsÚpop)ÚcutoffÚjob_idÚjobÚexpired_idss       r>   Ú_prune_download_jobsrR   R   sp   € Ü�Y‰Y‹[Ô:Ñ:€Fô 8×=Ñ=Ô?ôá?‰KˆF�CØˆ|Ñ˜vÒ%ò 	Ø?ð ñ ó
 ˆÜ$×(Ñ(¨°Õ6ñ ùós   ³A(rO   Úbodyc           
   ƒ   ób  K  — t         j                  | «      }|sy |j                  dd¬«       	 t        d|j                  |j
                  |j                  D �cg c]  }|j                  «       ‘Œ c}|j                  |j                  ¬«      ƒ d {  –—† }|j                  d|j                  dd«      |t        j                  «       ¬	«       y c c}w 7 ŒA# t        $ rN}t        d
| › d|› �«       |j                  dt        |«      xs dt        j                  «       ¬«       Y d }~y d }~ww xY w­w)NÚ
processingz2Selecting items and starting the download on Hudl.©r   ÚmessageÚdownload_manage_library_items)Úteam_idÚseason_labelrL   Údownload_formatÚinclude_breakdownÚ	completedrW   z<We'll email you a link when your video is ready to download.)r   rW   ÚresultÚcompleted_atz*Manage Library background download error (z): Úfailedz%Failed to start the download on Hudl.)r   rW   r_   )r2   ÚgetÚupdater   rY   ÚseasonrL   Ú
model_dumpÚformatr\   rJ   Ú	ExceptionÚprintr<   )rO   rS   rP   Úitemr^   r3   s         r>   Ú _run_manage_library_download_jobri   ]   s  è ø€ Ü
&×
*Ñ
*¨6Ó
2€CÙØà‡J�J�lÐ,`€JÔað
ÜØ+Ø—L‘LØŸ™Ø15·²Ó<±¨�4—?‘?Õ$°Ñ<Ø ŸK™KØ"×4Ñ4ô
÷ 
ˆð 	�
‰
ØØ—J‘JØØNóð ÜŸ™›ð 	õ 	
ùò	 =ð	
ùô" ò 
ÜÐ:¸6¸(À#ÀcÀUÐKÔLØ�
‰
ØÜ˜“HÒGÐ GÜŸ™›ð 	÷ 	
ñ 	
ûð
üsM   ‚,D/¯*C ÁCÁ0!C ÂCÂ;C ÃD/ÃC Ã	D,ÃAD'Ä"D/Ä'D,Ä,D/ÚcacheÚkeyc                 óž   — | j                  |«      }|sy dd l} |j                  «       |d   z
  t        kD  r| j                  |d «       y |d   S )Nr   Ú	timestampÚdata)ra   rJ   ÚMANAGE_LIBRARY_CACHE_TTLrM   )rj   rk   ÚentryrJ   s       r>   Ú
_cache_getrq   ~   sN   € Ø�I‰I�c‹N€EÙØÛØ€t‡y�yƒ{�U˜;Ñ'Ñ'Ô*BÒBØ�	‰	�#�tÔØØ�‰=Ðr@   rn   c                 ó:   — dd l } |j                   «       |dœ| |<   y )Nr   )rm   rn   )rJ   )rj   rk   rn   rJ   s       r>   Ú
_cache_setrs   ‰   s   € ÛØ(˜tŸy™y›{°DÑ9€Eˆ#‚Jr@   c               ƒ   óô  K  — ddl m} m}m} d}t	        j
                  |«      4 ƒd{  –—†  t	        j                  |d«       	 t	        j                  |¬«      ƒ d{  –—† } | |«      ƒ d{  –—† rL ||«      ƒ d{  –—† s<	 t	        j                  |d«       t	        j                  «        ddd«      ƒd{  –—†  y ||«      ƒ d{  –—† rt        d«        ||«      ƒ d{  –—†  t	        j                  |d«       t	        j                  «        ddd«      ƒd{  –—†  y7 Œû7 ŒÈ7 Œº7 Œ¬7 Œs7 Œd7 ŒK# t	        j                  |d«       t	        j                  «        w xY w7 ŒB# 1 ƒd{  –—†7  sw Y   yxY w­w)	u  Start the Manage Library lane. Login only if Hudl shows the identity form.

    Blank lane tabs share cookies with the rest of the browser context, so we do
    NOT treat about:blank as logged-out â€” that forced a full re-login on every
    download after a lane tab was created.
    r   )Úis_hudl_logged_inÚis_login_pageÚrunÚmanage_libraryNT)ÚlaneFu1   Manage Library: session expired â€” logging in...)
Úapp.automation.tasks.loginru   rv   rw   r   Ú	lane_lockÚset_lane_busyÚstartÚrecord_activityrg   )ru   rv   Ú	login_runry   Úpages        r>   Ú_ensure_hudl_browser_readyr�   Ž   s,  è ø€ ÷ ^Ñ]à€DÜ×(Ñ(¨×.Õ.Ü×%Ñ% d¨DÔ1ð	.Ü(×.Ñ.°DÔ9×9ˆDá& tÓ,×,Ð,¹=ÈÓ;N×5NÐ5NØô ×)Ñ)¨$°Ô6Ü×+Ñ+Ô-÷ /×.Ð.ñ # 4Ó(×(Ð(ÜÐIÔJÙ “o×%Ð%ä×)Ñ)¨$°Ô6Ü×+Ñ+Ô-÷ /×.Ñ.øð :øà,øÐ5Nøð /øð )øà%ùä×)Ñ)¨$°Ô6Ü×+Ñ+Õ-úð /ø×.×.Ñ.üsÚ   ‚&E8¨D$©E8¬E#ÁD2ÁD&ÁD2Á-D(Á.D2Á=D*Á>D2Â*E#Â-E8Â8D,Â9E8Â>D2Ã	D.Ã
D2Ã$D0Ã%D2Ã)*E#ÄE8ÄE!ÄE8Ä&D2Ä(D2Ä*D2Ä,E8Ä.D2Ä0D2Ä2,EÅE#Å!E8Å#E5Å)E,Å*E5Å1E8z/statusc            
   ƒ   óœ  K  — t        j                  «       } t        j                  }t        j                  «       }t        j
                  | j                  dd«      |r|j                  «       s|j                  nd | j                  d«      |t        j                  d«      t        j                  d«      t        j                  d«      dœdœS ­w)	NÚ	logged_inFÚlast_urlÚdefaultÚexchangerx   )r…   r†   rx   )Úbrowser_runningrƒ   Úcurrent_urlr„   Ústorage_warningÚ
lanes_busy)
r   Úreadr   r€   Úget_storage_warning_cachedÚ
is_runningra   Ú	is_closedÚurlÚis_lane_busy)Ústater€   r‰   s      r>   Úhudl_statusr’   ©   s¡   è ø€ ä×ÑÓ €EÜ×Ñ€DÜ#×>Ñ>Ó@€Oä*×5Ñ5Ø—Y‘Y˜{¨EÓ2Ù#'°·±Ô0@�t—x’xÀdØ—I‘I˜jÓ)Ø*ä&×3Ñ3°IÓ>Ü'×4Ñ4°ZÓ@Ü-×:Ñ:Ð;KÓLñ
ñð ùs   ‚C
Cz/storagerY   Úrefreshc              ƒ   ó  K  — t        | xs d«      j                  «       xs d}|r|j                  «       sd}|st        j                  |¬«      }|rd|dœS 	 ddlm} ddlm} t        j                  «       ƒ d{  –—† }t        j                  «       s ||«      ƒ d{  –—†   |||¬«      ƒ d{  –—† }t        j                  ||¬«       d|dœS 7 ŒV7 Œ47 Œ$# t        $ r}d	t        |«      d
didœcY d}~S d}~ww xY w­w)uN   Return Hudl storage usage for the sidebar â€” team-scoped when team_id is set.Ú N©rY   Úok)r   r‰   r   ©rw   )Úfetch_hudl_storage_usageÚerrorÚ	availableF)r   rW   r‰   )r<   ÚstripÚisdigitr   rŒ   rz   rw   Úapp.automation.tasks.libraryr™   r   r}   Úis_marked_logged_inÚset_storage_warningrf   )rY   r“   Útidr‰   r   r™   r€   r3   s           r>   Úget_hudl_storager¢   ¼   sî   è ø€ ô ˆgŠm˜Ó
×
"Ñ
"Ó
$Ò
,¨€CÙ
�3—;‘;”=ØˆáÜ'×BÑBÈ3ÔOˆÙØ"°ÑGÐGð
Ý?ÝIä$×*Ñ*Ó,×,ˆÜ×0Ñ0Ô2Ù˜D“/×!Ð!Ù 8¸ÀsÔ K×KˆÜ×)Ñ)¨/À3ÕGØ°?ÑCÐCð -øà!øØKùô ò 
àÜ˜3“xØ +¨UÐ3ñ
õ 	
ûð
üsl   ‚AC?Á#C Á;CÁ<#C ÂCÂ C Â1CÂ2C ÃC?ÃC ÃC ÃC Ã	C<Ã!C7Ã1C<Ã2C?Ã7C<Ã<C?z/browser/startc               ƒ   ó    K  — 	 t        j                  «       ƒ d {  –—† } d| j                  dœS 7 Œ# t        $ r}t	        |«      |‚d }~ww xY w­w)Nr—   )r   r�   )r   r}   r�   rf   r?   )r€   r3   s     r>   Ústart_browserr¤   Ý   sL   è ø€ ð-Ü$×*Ñ*Ó,×,ˆØ t§x¡xÑ0Ð0ð -ùäò -Ü˜sÓ#¨Ð,ûð-üs0   ‚A„1 ›/œ1 ®A¯1 ±	AºAÁAÁAz/browser/clear-sessionc               ƒ   ó  K  — d} d}t        d| dz   «      D ]W  }	 t        j                  «       ƒ d{  –—†  t        j                  «       ƒ d{  –—† }ddlm}  ||«      ƒ d{  –—†  dddœc S  t        dd| › d|› �«      ‚7 ŒP7 Œ67 Œ"# t        $ rn}|}t        d	|› d
|› �«       	 t        j                  «       ƒ d{  –—†7   n# t        $ r Y nw xY w|| k  rddl	}|j                  d«      ƒ d{  –—†7   Y d}~Œäd}~ww xY w­w)zdClear the persistent browser session data completely and force a fresh login with automatic retries.é   Né   r   r˜   r—   z2Browser session cleared and fresh login completed.rV   zClear session attempt z	 failed: é   r9   zFailed to reset session after z attempts. Error: )Úranger   Úclear_sessionr}   rz   rw   rf   rg   ÚcloseÚasyncioÚsleepr   )Úmax_retriesÚlast_excÚattemptr€   r   r3   r¬   s          r>   Úclear_browser_sessionr±   æ   s	  è ø€ ð €KØ€HÜ˜˜K¨!™OÖ,ˆð	'Ü!×/Ñ/Ó1×1Ð1Ü(×.Ñ.Ó0×0ˆDÝCÙ˜D“/×!Ð!Ø"Ð/cÑdÒdð -ô$ ˜Ð=¸k¸]ÐJ\Ð]eÐ\fÐgÓ
hÐhð! 2øØ0øà!ùäò 		'ØˆHÜÐ*¨7¨)°9¸S¸EÐBÔCðÜ%×+Ñ+Ó-×-Ò-øÜò Ùðúà˜Ò$ÛØ—m‘m AÓ&×&Ñ&ÿøð		'üsž   ‚DšB±B²BÁBÁBÁ#BÁ$BÁ,DÂBÂBÂBÂ	C?ÂC:Â%CÂ<B?Â=CÃC:Ã	CÃC:ÃCÃ C:Ã/C2Ã0C:Ã5DÃ:C?Ã?Dz/logoutc               ƒ   óè   K  — 	 t        j                  «       ƒ d{  –—†  t        j                  «       } d| d<   t        j                  | «       dddœS 7 Œ7# t
        $ r}t        |«      |‚d}~ww xY w­w)z<Close the browser session and reset status upon user logout.NFrƒ   r—   z$Browser session closed successfully.rV   )r   r«   r   r‹   Úwriterf   r?   )r‘   r3   s     r>   Úhudl_logoutr´      sr   è ø€ ð-Ü×#Ñ#Ó%×%Ð%Ü×"Ñ"Ó$ˆØ"ˆˆkÑÜ×Ñ˜EÔ"ØÐ+QÑRÐRð	 	&ùô
 ò -Ü˜sÓ#¨Ð,ûð-üs8   ‚A2„A ›Aœ6A ÁA2ÁA Á	A/ÁA*Á*A/Á/A2z/account-namec               ƒ   óø   K  — t        j                  «       } | sE	 ddlm}m} t        j                  «       ƒ d{  –—† } ||«      ƒ d{  –—†   ||«      ƒ d{  –—† } d| dœS 7 Œ)7 Œ7 Œ# t        $ r d} Y Œw xY w­w)zKReturns the cached Hudl account holder's name or fetches it if not present.r   )Úfetch_hudl_account_namerw   Nr•   r—   )r   Úname)r   Úget_account_holder_namerz   r¶   rw   r   r}   rf   )r·   r¶   r   r€   s       r>   Úget_hudl_account_namer¹     sy   è ø€ ô ×0Ñ0Ó2€DÙð	ß\Ü(×.Ñ.Ó0×0ˆDÙ˜D“/×!Ð!Ù0°Ó6×6ˆDð  DÑ)Ð)ð 1øØ!øØ6ùÜò 	ØŠDð	üs\   ‚A:šA) ¹A#ºA) Á	A%Á
A) ÁA'ÁA) ÁA:Á#A) Á%A) Á'A) Á)A7Á4A:Á6A7Á7A:z/loginc              ƒ   óÜ   K  — ddl m} 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        |f$ r}t        dt        |«      «      |‚d}~wt        $ r}t        |«      |‚d}~ww xY w­w)zMHudl website login (JWT already checked). App login = POST /api/v1/auth/loginr   )ÚLoginVerificationErrorÚlogin)ÚforceNé�  )	rz   r»   r   r½   Ú
ValueErrorr   r<   rf   r?   )rS   r»   r3   s      r>   Úhudl_site_loginrÀ     sf   è ø€ õ Bð-Ü˜g¨T¯Z©ZÔ8×8Ð8Ð8ùÜÐ.Ð/ò 4Ü˜C¤ S£Ó*°Ð3ûÜò -Ü˜sÓ#¨Ð,ûð-üs<   ‚A,Š+ ¤)¥+ ¨A,©+ «A)¶AÁA)ÁA$Á$A)Á)A,z/organizationsc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zPList every school/team from the Hudl team switcher (full Organizations sidebar).Úlist_hudl_organizationsN©r   rf   r?   r=   s    r>   Úlist_hudl_organizations_apirÄ   )  s9   è ø€ ð-ÜÐ7Ó8×8Ð8Ð8ùÜò -Ü˜sÓ#¨Ð,ûð-üó(   ‚6„ ’“ –6— ™	3¢.®3³6z/team/switchc              ƒ   óÀ  K  — 	 t        j                  «        t        d| j                  | j                  | j
                  ¬«      ƒ d{  –—† }t        |j                  d«      xs d«      j                  «       }|j                  «       r|j                  dd«       |S 7 ŒT# t        $ r}t        dt        |«      «      |‚d}~wt        $ r}t        |«      |‚d}~ww xY w­w)	uÒ   Click a Hudl team by id/name and return its team_id.

    Intentionally does NOT open Exchange here â€” that was blocking the switch
    modal for 30â€“90s. The Exchange page warms itself after navigation.
    Úswitch_hudl_team_by_name)Ú	team_nameÚorg_namerY   NrY   r•   Úhas_exchangeTr¾   )r   Úclear_storage_warningr   rÈ   rÉ   rY   r<   ra   rœ   r�   Ú
setdefaultr¿   r   rf   r?   )rS   r^   rY   r3   s       r>   Úswitch_hudl_teamrÍ   2  s¿   è ø€ ð-ä×+Ñ+Ô-ÜØ&Ø—n‘nØ—]‘]Ø—L‘Lô	
÷ 
ˆô �f—j‘j Ó+Ò1¨rÓ2×8Ñ8Ó:ˆØ�?‰?ÔØ×Ñ˜n¨dÔ3Øˆð
ùô ò 4Ü˜C¤ S£Ó*°Ð3ûÜò -Ü˜sÓ#¨Ð,ûð-üsH   ‚C„AB ÁBÁ	AB ÂCÂB Â	CÂ(B>Â>CÃ
CÃCÃCz/exchange/openc              ƒ   ó”   K  — 	 | r| j                   nd }t        d|¬«      ƒ d {  –—† S 7 Œ# t        $ r}t        |«      |‚d }~ww xY w­w)NÚopen_exchanger–   )rY   r   rf   r?   )rS   rY   r3   s      r>   rÏ   rÏ   M  sG   è ø€ ð-Ù"&�$—,’,¨DˆÜ˜o°wÔ?×?Ð?Ð?ùÜò -Ü˜sÓ#¨Ð,ûð-üs0   ‚A„ + ¤)¥+ ¨A©+ «	A´A Á AÁAz/exchange/datac              ƒ   ót   K  — 	 t        d| ¬«      ƒ d {  –—† S 7 Œ# t        $ r}t        |«      |‚d }~ww xY w­w)NÚget_exchange_datar–   rÃ   ©rY   r3   s     r>   rÑ   rÑ   V  s;   è ø€ ð-ÜÐ1¸7ÔC×CÐCÐCùÜò -Ü˜sÓ#¨Ð,ûð-üó(   ‚8„ ”• ˜8™ ›	5¤0°5µ8z/exchange/activeÚfull_scrollc              ƒ   óv   K  — 	 t        d| |¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)zEGET: Fetch list of active exchanges directly from page list elements.Úget_active_exchanges)rÔ   rY   NrÃ   )rÔ   rY   r3   s      r>   Úget_active_exchanges_apir×   ^  sI   è ø€ ð-ÜØ"Ø#Øô
÷ 
ð 	
ð 
ùô
 ò -Ü˜sÓ#¨Ð,ûð-üs(   ‚9„ •– ™9š œ	6¥1±6¶9z/exchange/active/detailsc              ƒ   óä   K  — 	 t        d| j                  | j                  | j                  | j                  | j
                  ¬«      ƒ d{  –—† }|S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)zYPOST: Fetch specific active exchange's dynamic ex-details by team name (live Playwright).Úget_active_exchange_details)Úexchange_nameÚexchange_indexÚexchange_idÚhrefrY   N)r   r·   ÚindexrÜ   rÝ   rY   rf   r?   ©rS   Úresr3   s      r>   Úget_active_exchange_details_apirá   k  sl   è ø€ ð-ÜØ)ØŸ)™)ØŸ:™:Ø×(Ñ(Ø—‘Ø—L‘Lô
÷ 
ˆð ˆ
ð
ùô ò -Ü˜sÓ#¨Ð,ûð-üs;   ‚A0„AA Á
AÁA ÁA0ÁA Á	A-ÁA(Á(A-Á-A0z!/exchange/incoming-videos/processc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zHPOST: Auto-add all 'They sent you video' exchanges to the video library.Ú process_incoming_video_exchangesNrÃ   r=   s    r>   Ú$process_incoming_video_exchanges_apirä   |  s9   è ø€ ð-ÜÐ@ÓA×AÐAÐAùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/exchange/active/actionc              ƒ   ó  K  — 	 t        d| j                  | j                  | j                  | j                  | j
                  ¬«      ƒ d{  –—† }|r‘|j                  d«      dk(  r}t        D �cg c]R  }| j                  r|d   | j                  k(  s0| j
                  r|d   | j
                  k(  s|d   | j                  k(  r|‘ŒT c}D ]  }t        j                  |d«       Œ |S 7 Œ™c c}w # t        $ r}t        |«      |‚d}~ww xY w­w)	zMPOST: Click a header action button (delete/cancel/etc) on an active exchange.Úclick_active_exchange_button)Úaction_typerÚ   rÛ   rÜ   rÝ   Nr   r—   r   r§   r¨   )r   rç   r·   rÞ   rÜ   rÝ   ra   ÚDETAILS_CACHErM   rf   r?   )rS   rà   Úkr3   s       r>   Úactive_exchange_action_apirê   …  sû   è ø€ ð-ÜØ*Ø×(Ñ(ØŸ)™)ØŸ:™:Ø×(Ñ(Ø—‘ô
÷ 
ˆñ �3—7‘7˜8Ó$¨Ò,å(óÙ(�aØ×$Ò$¨¨1©°×1AÑ1AÒ)AØ—I’I ! A¡$¨$¯)©)Ò"3Ø�Q‘4˜4Ÿ9™9Ò$ò ˜=ô�ô ×!Ñ! ! TÕ*ðð ˆ
ð#
úòøô ò -Ü˜sÓ#¨Ð,ûð-üsN   ‚D„AC+ Á
C$Á"C+ Á-AC&ÃC+ Ã#DÃ$C+ Ã&C+ Ã+	DÃ4D Ä DÄDz/exchange/searchc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)uŠ   
    3rd API (POST): search box me keyword â†’ loader wait â†’ header text.
    File: app/automation/tasks/search.py â†’ run_search()
    Ú
run_search)ÚqueryN)r   rí   rf   r?   ©rS   r3   s     r>   Úexchange_searchrï   Ÿ  s>   è ø€ ð-Ü˜l°$·*±*Ô=×=Ð=Ð=ùÜò -Ü˜sÓ#¨Ð,ûð-üó+   ‚A„% ž#Ÿ% ¢A£% ¥	?®:º?¿Az/exchange/search/teamsc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)u°   
    3rd API (GET): search results ki team list (2nd API jaisa format).
    File: app/automation/tasks/search.py â†’ get_search_teams()
  Call POST /exchange/search first.
    Úget_search_teamsNrÃ   r=   s    r>   Úexchange_search_teamsró   «  s9   è ø€ ð-ÜÐ0Ó1×1Ð1Ð1ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/exchange/typesc              ƒ   óÊ   K  — 	 t        d| j                  | j                  | j                  | j                  ¬«      ƒ d{  –—† S 7 Œ# t
        $ r}t        |«      |‚d}~ww xY w­w)un  
    4th API: team id click â†’ exchange type â†’ Next.

    Code: app/automation/tasks/exchange_types.py

    Example body:
      {
        "team_id": "<opponent from GET /exchange/data suggested_teams>",
        "owner_team_id": "<Football/Basketball Hudl id from Organizations>",
        "team_source": "suggested",
        "exchange_type": "two-way"
      }
    Úselect_exchange_type)rY   Úteam_sourceÚexchange_typeÚowner_team_idN)r   rY   rö   r÷   rø   rf   r?   rî   s     r>   Úexchange_typesrù   ¸  se   è ø€ ð	-ÜØ"Ø—L‘LØ×(Ñ(Ø×,Ñ,Ø×,Ñ,ô
÷ 
ð 	
ð 
ùô ò -Ü˜sÓ#¨Ð,ûð-üó9   ‚A#„;A ¿AÁ A ÁA#ÁA Á	A ÁAÁA Á A#z/exchange/videosc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)uP  
    5th API (GET): get video list from events-container.

    Reads all <li> from //section[@id="events-container"]/div/ul.
    Skips li[@class="bad-status"] items (video still processing).

    Call after POST /exchange/types (when the video selection page is open).

    File: app/automation/tasks/videos.py â†’ get_video_list()
    Úget_video_listNrÃ   r=   s    r>   rü   rü   Ó  s9   è ø€ ð-ÜÐ.Ó/×/Ð/Ð/ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/exchange/videos/selectc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z‘
    6th API (POST): Select videos/games from the list.
    Football multi-step may return wizard_step=playlists (incl. empty No Playlists).
    Úselect_videos)Úvideo_indicesN)r   rÿ   rf   r?   rî   s     r>   rþ   rþ   å  s@   è ø€ ð-Ü˜o¸T×=OÑ=OÔP×PÐPÐPùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/exchange/playlists/selectc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)zCSelect playlists on Choose Playlist(s) and click Next when enabled.Úselect_playlists)Úplaylist_indicesN)r   r  rf   r?   rî   s     r>   r  r  ñ  sK   è ø€ ð-ÜØ°×1FÑ1Fô
÷ 
ð 	
ð 
ùô ò -Ü˜sÓ#¨Ð,ûð-ürð   z/exchange/statsc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zR
    7th API (GET): Get available options on the stats page before selecting.
    Úget_stats_optionsNrÃ   r=   s    r>   r  r  ü  s9   è ø€ ð
-ÜÐ1Ó2×2Ð2Ð2ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   c              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)zm
    7th API (POST): Optionally include stats and click next.
    Example body: {"include_stats": false}
    Úselect_stats)Úinclude_statsN)r   r  rf   r?   rî   s     r>   r  r    s@   è ø€ ð-Ü˜n¸D×<NÑ<NÔO×OÐOÐOùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/exchange/notesc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z 
    8th API (POST): Add an optional message in the notes section and click next.
    Example body: {"message": "Here are the videos!"} (or omit/send null)
    Ú	add_notes)rW   N)r   rW   rf   r?   rî   s     r>   r	  r	    s>   è ø€ ð-Ü˜k°4·<±<Ô@×@Ð@Ð@ùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/exchange/confirmc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)z£
    9th API (GET): Read the confirmation screen details before submitting.
    Returns exchange_name, school_name, school_image, video_names, stats, message.
    Úget_confirm_detailsNrÃ   r=   s    r>   r  r    ó9   è ø€ ð-ÜÐ3Ó4×4Ð4Ð4ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   c               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zP
    9th API (POST): Click the Send Exchange button to finalize everything.
    Úsubmit_exchangeNrÃ   r=   s    r>   r  r  +  s9   è ø€ ð
-ÜÐ/Ó0×0Ð0Ð0ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/exchange/cancelc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)zA
    POST API: Cancel exchange wizard at current step index.
    Úcancel_exchange)Ú
step_indexN)r   r  rf   r?   rî   s     r>   r  r  6  s?   è ø€ ð
-ÜÐ/¸D¿O¹OÔL×LÐLÐLùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/exchange/backc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)zC
    POST API: Click the physical back button at active index.
    Úgo_back_exchange)Ú
back_indexN)r   r  rf   r?   rî   s     r>   r  r  A  s?   è ø€ ð
-ÜÐ0¸T¿_¹_ÔM×MÐMÐMùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/upload/openc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)z910th API (POST): Click the global upload navigation link.Úopen_uploadNrÃ   r=   s    r>   r  r  L  s8   è ø€ ð-Ü˜mÓ,×,Ð,Ð,ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/upload/teamc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zC11th API (GET): Read the currently selected team from the combobox.Úget_upload_teamNrÃ   r=   s    r>   r  r  U  s9   è ø€ ð-ÜÐ/Ó0×0Ð0Ð0ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/upload/team/dropdownc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zB11th API (POST): Click the dropdown arrow to reveal the team list.Úopen_team_dropdownNrÃ   r=   s    r>   r  r  ^  ó9   è ø€ ð-ÜÐ2Ó3×3Ð3Ð3ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/upload/teams-listc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zJ12th API (GET): Read the list of available teams after dropdown is opened.Úget_upload_teams_listNrÃ   r=   s    r>   r  r  g  ó9   è ø€ ð-ÜÐ5Ó6×6Ð6Ð6ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   Úpathc                 ón   — t         j                  j                  | «      rt        j                  | «       yy)z6Background task to delete temporary file after upload.N)Úosr  ÚexistsÚremove)r  s    r>   Údelete_temp_filer$  p  s"   € ä	‡w�w‡~�~�dÔÜ
�	‰	�$�ð r@   z/upload/select-files.Úbackground_tasksÚ
team_indexÚfilec              ƒ   ó  K  — 	 t         j                  j                  t        j                  «       t        t        j                  «       «      «      }t        j                  |d¬«       t         j                  j                  ||j                  «      }t        |d«      5 }t        j                  |j                  |«       ddd«       t        d||¬«      ƒ d{  –—† S # 1 sw Y   ŒxY w7 Œ# t        $ r}t!        |«      |‚d}~ww xY w­w)zŸ
    12th API (POST): Optionally select a team from the list by index, 
    and upload a file. The server will pass this file to Playwright automatically.
    T)Úexist_okÚwbNÚselect_files)r&  Ú	file_path)r!  r  ÚjoinÚtempfileÚ
gettempdirr<   ÚuuidÚuuid4ÚmakedirsÚfilenameÚopenÚshutilÚcopyfileobjr'  r   rf   r?   )r%  r&  r'  Ú
unique_dirÚtmp_pathÚbufferr3   s          r>   Úselect_files_apir:  v  s½   è ø€ ð-ä—W‘W—\‘\¤(×"5Ñ"5Ó"7¼¼T¿Z¹Z»\Ó9JÓKˆ
Ü
�‰�J¨Õ.Ü—7‘7—<‘< 
¨D¯M©MÓ:ˆä�(˜DÔ! VÜ×Ñ˜tŸy™y¨&Ô1÷ "ô ˜n¸ÈxÔX×XÐX÷ "Ð!úð YùÜò -Ü˜sÓ#¨Ð,ûð-üsM   ‚D„BC+ Â!CÂ?C+ ÃC)ÃC+ ÃDÃC&Ã"C+ Ã+	DÃ4D Ä DÄDz/upload/filesc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)z013th API (GET): Read the list of uploaded files.Úget_uploaded_filesNrÃ   r=   s    r>   r<  r<  ’  r  rÅ   z/upload/files/deletec              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z613th API (POST): Delete an uploaded file by its index.Údelete_uploaded_file)Ú
file_indexN)r   r?  rf   r?   rî   s     r>   r>  r>  ›  s?   è ø€ ð-ÜÐ4ÀÇÁÔQ×QÐQÐQùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/upload/triggerc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)z114th API (POST): Click the trigger upload button.Útrigger_uploadNrÃ   r=   s    r>   rA  rA  ¤  s9   è ø€ ð-ÜÐ.Ó/×/Ð/Ð/ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/upload/progressc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zA14.5 API (GET): Fetch live upload progress (total and completed).Úget_upload_progressNrÃ   r=   s    r>   rC  rC  ­  ó9   è ø€ ð-ÜÐ3Ó4×4Ð4Ð4ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/upload/schedule-event/openc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zF15th API (POST): Click the Select-placeholder to open schedule events.Úopen_schedule_eventNrÃ   r=   s    r>   rF  rF  ·  rD  rÅ   z/upload/schedule-eventsc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)z¨
    15th API (GET): Fetch all parsed events from the Select-menu-outer dropdown.
    MUST be called after POST /upload/schedule-event/open so the menu is visible.
    Úget_schedule_eventsNrÃ   r=   s    r>   rH  rH  À  r  rÅ   z/upload/detailsc              ƒ   óÊ   K  — 	 t        d| j                  | j                  | j                  | j                  ¬«      ƒ d{  –—† S 7 Œ# t
        $ r}t        |«      |‚d}~ww xY w­w)zZ
    16th API (POST): Fill out the details (video type, schedule event, title, save).
    Úfill_video_details)Úschedule_event_indexÚ
video_typeÚtitleÚcheck_eventN)r   rK  rL  rM  rN  rf   r?   rî   s     r>   rJ  rJ  Ì  sc   è ø€ ð
	-ÜØ Ø!%×!:Ñ!:Ø—‘Ø—*‘*Ø×(Ñ(ô
÷ 
ð 	
ð 
ùô ò -Ü˜sÓ#¨Ð,ûð-ürú   z/upload/cancelc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zb
    17th API (POST): Cancel the current upload by clicking the cancel button and confirming.
    Úcancel_uploadNrÃ   r=   s    r>   rP  rP  Ý  s8   è ø€ ð
-Ü˜oÓ.×.Ð.Ð.ùÜò -Ü˜sÓ#¨Ð,ûð-ürÅ   z/library/videosc              ƒ   ót   K  — 	 t        d| ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z/Fetch parsed video items from the Hudl library.Úget_library_videosr–   NrÃ   rÒ   s     r>   rR  rR  è  s;   è ø€ ð-ÜÐ2¸GÔD×DÐDÐDùÜò -Ü˜sÓ#¨Ð,ûð-ürÓ   z/manage-libraryc              ƒ   ó    K  — 	 t        «       ƒ d{  –—†  t        d| ¬«      ƒ d{  –—† }|S 7 Œ7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)zAFetch Manage Library seasons from Hudl via Playwright (no cache).NÚget_manage_libraryr–   )r�   r   rf   r?   )rY   r“   r^   r3   s       r>   rT  rT  ñ  sQ   è ø€ ð-Ü(Ó*×*Ð*ÜÐ 4¸gÔF×FˆØˆð 	+øØFùäò -Ü˜sÓ#¨Ð,ûð-üs<   ‚A„1 ‘-’1 ¦/§1 ¬A­1 ¯1 ±	AºAÁAÁAz/manage-library/seasonrc   c              ƒ   ó$  K  — |j                  «       st        dd«      ‚	 t        «       ƒ d{  –—†  t        d| |¬«      ƒ d{  –—† }|S 7 Œ7 Œ# t        $ r6}ddl}t        d|›d|› �«       |j                  «        t        |«      |‚d}~ww xY w­w)	z:Expand a season on Hudl Library via Playwright (no cache).r¾   úseason query param is requiredNÚexpand_manage_library_season)rY   rZ   r   zmanage-library/season 500 for z: )	rœ   r   r�   r   rf   Ú	tracebackrg   Ú	print_excr?   )rY   rc   r“   r^   r3   rX  s         r>   rW  rW  ü  s�   è ø€ ð
 �<‰<Œ>Ü˜CÐ!AÓBÐBð-Ü(Ó*×*Ð*ÜØ*ØØô
÷ 
ˆð
 ˆð 	+øð
ùô ò -ÛäÐ.¨v¨j¸¸3¸%Ð@ÔAØ×ÑÔÜ˜sÓ#¨Ð,ûð-üsJ   ‚B A ­A
®A ÁAÁA Á	BÁ
A ÁA Á	BÁ1BÂBÂBz/manage-library/folderc           
   ƒ   óf  K  — |j                  «       st        dd«      ‚ddl}|j                  d|j                  «      }|j                  d«      }|j                  d«      D �cg c]P  }|j                  «       r>|j                  d|j                  d|«      j                  «       «      j                  «       ‘ŒR }}|D �cg c]  }|sŒ|‘Œ	 }}|st        dd	«      ‚	 t        «       ƒ d{  –—†  t        d
| ||¬«      ƒ d{  –—† }	|	S c c}w c c}w 7 Œ'7 Œ# t        $ r}
t        |
«      |
‚d}
~
ww xY w­w)zFExpand a folder path on Hudl Manage Library via Playwright (no cache).r¾   rV  r   Nz?(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+\d{1,2}\bz\s*\(\d+\)\s*$Ú,r•   z<path query param is required (comma-separated folder labels)Úexpand_manage_library_folder)rY   rZ   Úfolder_path)rœ   r   ÚreÚcompileÚ
IGNORECASEÚsplitÚsubr�   r   rf   r?   )rY   rc   r  r“   Ú_reÚ_MONTH_STRIPÚ_COUNT_STRIPÚpr]  r^   r3   s              r>   r\  r\    s9  è ø€ ð �<‰<Œ>Ü˜CÐ!AÓBÐBÛØ—;‘;ØJØ�‰ó€Lð —;‘;Ð0Ó1€Lð —‘˜C”óá ˆAØ�7‰7Œ9ð 	×Ñ˜˜\×-Ñ-¨b°!Ó4×:Ñ:Ó<Ó=×CÑCÕEØ ð ð ñ
 *Ó/™k˜ªQ’1˜k€KÐ/ÙÜ˜CÐ!_Ó`Ð`ð
-Ü(Ó*×*Ð*ÜØ*ØØØ#ô	
÷ 
ˆð ˆùò!ùò
 0ð 	+øð
ùô ò -Ü˜sÓ#¨Ð,ûð-üsm   ‚A!D1Á#ADÂ8D1Â>DÃDÃ
D1ÃD Ã(DÃ)D Ã?DÄ D ÄD1ÄD ÄD Ä	D.ÄD)Ä)D.Ä.D1z/manage-library/download)r7   c           
   ƒ   óò  K  — | j                   st        dd«      ‚t        «        t        t	        j
                  «       «      }|t        |«      ddt        | j                   «      | j                   D �cg c]  }|j                  ‘Œ c}t        j                  «       dddœ	t        |<   |j                  t        || «       t        |   j                  «       D ��ci c]  \  }}|dk7  r||“Œ c}}S c c}w c c}}w ­w)zMQueue a background job that selects clips and triggers Hudl's email download.r¾   zitems is requiredÚqueuedzGDownload queued. Sergio will complete the Hudl steps in the background.N)	rO   Úownerr   rW   Ú
item_countrL   rI   r_   r^   ri  )rL   r   rR   r<   r0  r1  rG   ÚlenÚlabelrJ   r2   Úadd_taskri   )rS   r%  rA   rO   rh   rk   Úvalues          r>   rX   rX   8  sã   è ø€ ð �:Š:Ü˜CÐ!4Ó5Ð5äÔÜ”—‘“Ó€FàÜ$ TÓ*ØØ\Ü˜$Ÿ*™*“oØ)-¯ªÓ4© �$—*“*¨Ñ4Ü—i‘i“kØØñ
,Ô  Ñ(ð ×ÑÔ>ÀÈÔMô 7°vÑ>×DÑDÔFôáF‰JˆC�Ø�'Š>ð 	ˆU‰
ØFòð ùò 5ùóùs   ‚A/C7Á1C,ÂAC7ÃC1Ã(C7z/manage-library/selectc              ƒ   óü  ‡K  — t        |«      Št        ˆfd„t        j                  «       D «       «      }|rdd| j                  | j
                  dœS 	 t        «       ƒ d{  –—†  t        d| j                  | j                  | j                  | j                  | j
                  ¬«      ƒ d{  –—† S 7 ŒO7 Œ# t        $ r<}t        d|› �«       d	t        |«      | j                  | j
                  dœcY d}~S d}~ww xY w­w)
aa  Mirror a frontend clip selection onto the open Hudl Manage Library page.

    Best-effort: the download flow re-selects clips itself, so a failure here
    must never surface as a 500 or block the UI. It also skips while a download
    is in progress, since running a select on the same page would fight the
    download's own selection/navigation.
    c              3   óp   •K  — | ]-  }|j                  d «      ‰k(  xr |j                  d«      dv –— Œ/ y­w©ri  r   ©rh  rU   N©ra   ©Ú.0rP   ri  s     €r>   Ú	<genexpr>z-select_manage_library_clip.<locals>.<genexpr>d  ó>   øè ø€ ð á8ˆCð 	�‰�Ó˜EÑ!ÒS c§g¡g¨hÓ&7Ð;SÐ&SÓSÙ8ùó   ƒ36ÚskippedÚdownload_in_progress)r   Úreasonrl  ÚselectedNÚ!set_manage_library_clip_selection)rY   rZ   r  rl  r|  z1Manage Library select mirror failed (non-fatal): rš   )rG   Úanyr2   Úvaluesrl  r|  r�   r   rY   rc   r  rf   rg   r<   ©rS   rA   Údownload_activer3   ri  s       @r>   Úselect_manage_library_clipr‚  W  sí   øè ø€ ô   Ó%€EÜó ä/×6Ñ6Ô8óó €Oñ àØ,Ø—Z‘ZØŸ™ñ	
ð 	
ð
Ü(Ó*×*Ð*ÜØ/Ø—L‘LØŸ™Ø—‘Ø—*‘*Ø—]‘]ô
÷ 
ð 	
ð 	+øð
ùô ò 
äÐAÀ#ÀÐGÔHàÜ˜#“hØ—Z‘ZØŸ™ñ	
õ 	
ûð
üs[   ƒAC<ÁB4 Á B0Á!A
B4 Â+B2Â,B4 Â/C<Â0B4 Â2B4 Â4	C9Â=1C4Ã.C9Ã/C<Ã4C9Ã9C<z/manage-library/clip-metac              ƒ   óî  ‡K  — t        |«      Št        ˆfd„t        j                  «       D «       «      }|rdd| j                  d| j                  idœS 	 t        «       ƒ d{  –—†  t        d| j                  | j                  | j                  | j                  ¬«      ƒ d{  –—† S 7 ŒD7 Œ# t        $ r>}t        d	|› �«       d
t        |«      | j                  d| j                  idœcY d}~S d}~ww xY w­w)uQ   Read Hudl hover tooltip fields (Created by, Shared with, Date, â€¦) for one clip.c              3   óp   •K  — | ]-  }|j                  d «      ‰k(  xr |j                  d«      dv –— Œ/ y­wrq  rs  rt  s     €r>   rv  z/get_manage_library_clip_meta.<locals>.<genexpr>Œ  rw  rx  ry  rz  r·   )r   r{  rl  ÚmetaNÚget_manage_library_clip_meta)rY   rZ   r]  rl  z-Manage Library clip meta failed (non-fatal): rš   )rG   r~  r2   r  rl  r�   r   rY   rc   r  rf   rg   r<   r€  s       @r>   r†  r†  …  sð   øè ø€ ô   Ó%€EÜó ä/×6Ñ6Ô8óó €Oñ àØ,Ø—Z‘ZØ˜TŸZ™ZÐ(ñ	
ð 	
ð
Ü(Ó*×*Ð*ÜØ*Ø—L‘LØŸ™ØŸ	™	Ø—*‘*ô
÷ 
ð 	
ð 	+øð
ùô ò 
ÜÐ=¸c¸UÐCÔDàÜ˜#“hØ—Z‘ZØ˜TŸZ™ZÐ(ñ	
õ 	
ûð
üsZ   ƒAC5ÁB+ Á"B'Á#?B+ Â"B)Â#B+ Â&C5Â'B+ Â)B+ Â+	C2Â43C-Ã'C2Ã(C5Ã-C2Ã2C5z!/manage-library/download/{job_id}Úwaitc              ƒ   óL  K  — ddl }t        «        t        |«      }t        j	                  | «      }|r|d   |k7  rt        dd«      ‚|r©|dkD  r¤t        j                  «       t        |d«      z   }|j	                  d«      dv rpt        j                  «       |k\  rnX|j                  d	«      ƒ d{  –—†  t        j	                  | «      }|r|d   |k7  rt        dd«      ‚|j	                  d«      dv rŒp|j                  «       D ��ci c]  \  }}|dk7  sŒ||“Œ c}}S 7 Œmc c}}w ­w)
a^  Return the current state of a queued Manage Library download.

    Supports long-polling: pass ?wait=<seconds> and the request will block until
    the job reaches a terminal state (completed/failed) or the wait window
    elapses. This lets the frontend keep one slow request open instead of
    hammering this endpoint every couple of seconds.
    r   Nri  é”  zDownload job not foundg      9@r   rr  g      à?)r¬   rR   rG   r2   ra   r   rJ   Ú	monotonicÚminr­   rL   )	rO   r‡  rA   r¬   ri  rP   Údeadlinerk   rn  s	            r>   Úget_manage_library_download_jobr�  «  s  è ø€ ó äÔÜ Ó%€EÜ
&×
*Ñ
*¨6Ó
2€CÙ�#�g‘, %Ò'Ü˜CÐ!9Ó:Ð:á��q’ä—>‘>Ó#¤c¨$°£oÑ5ˆØ�g‰g�hÓÐ#;Ñ;Ü�~‰~Ó 8Ò+ØØ—-‘- Ó$×$Ð$Ü.×2Ñ2°6Ó:ˆCÙ˜#˜g™,¨%Ò/Ü# CÐ)AÓBÐBð �g‰g�hÓÐ#;Ò;ð *-¯©¬ÔG©™:˜3 ¸¸w»ˆC�‰J¨ÒGÐGð %úó
 Hùs1   ‚B,D$Â.DÂ/AD$Ã2D$ÄDÄDÄD$ÄD$z/library/video-streamc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z;Fetch the intercepted HLS stream URL for a given watch URL.Úget_video_stream_url)Ú	watch_urlN)r   r�  rf   r?   rî   s     r>   r�  r�  Î  s?   è ø€ ð-ÜÐ4ÀÇÁÔO×OÐOÐOùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/library/close-videoc               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)z>Trigger clicking the close/back button on Hudl's watch screen.Úclose_video_playerNrÃ   r=   s    r>   r’  r’  ×  r  rÅ   z/library/video/details/openc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z:Open details panel for a video and return its information.Úopen_library_details©Úvideo_indexN©r   r–  rf   r?   rî   s     r>   Úopen_video_detailsr˜  à  óA   è ø€ ð-ÜÐ4À$×BRÑBRÔS×SÐSÐSùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/library/video/details/typec              ƒ   óž   K  — 	 t        d| j                  | j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t	        |«      |‚d}~ww xY w­w)zHUpdate video type (Game, Scout, Practice) inside the open details panel.Úupdate_library_type)r–  rL  N)r   r–  rL  rf   r?   rî   s     r>   Úupdate_video_typerœ  é  sJ   è ø€ ð-ÜÐ3À×AQÑAQÐ^b×^mÑ^mÔn×nÐnÐnùÜò -Ü˜sÓ#¨Ð,ûð-üó0   ‚A„%0 ©.ª0 ­A®0 °	A
¹AÁA
Á
Az$/library/video/details/event/optionsc              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z1Retrieve event dropdown options in details panel.Úget_library_event_optionsr•  Nr—  rî   s     r>   Úget_video_event_optionsr   ò  sA   è ø€ ð-ÜÐ9Àt×GWÑGWÔX×XÐXÐXùÜò -Ü˜sÓ#¨Ð,ûð-ürð   z/library/video/details/eventc              ƒ   óž   K  — 	 t        d| j                  | j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t	        |«      |‚d}~ww xY w­w)z6Select a specific event in the details panel dropdown.Úupdate_library_event)r–  Ú
event_nameN)r   r–  r£  rf   r?   rî   s     r>   Úupdate_video_eventr¤  û  sJ   è ø€ ð-ÜÐ4À$×BRÑBRÐ_c×_nÑ_nÔo×oÐoÐoùÜò -Ü˜sÓ#¨Ð,ûð-ür�  z/library/video/details/closec               ƒ   óp   K  — 	 t        d«      ƒ d{  –—† S 7 Œ# t        $ r} t        | «      | ‚d} ~ ww xY w­w)zClose details panel.Úclose_library_detailsNrÃ   r=   s    r>   Úclose_video_detailsr§    r  rÅ   z/library/video/renamec              ƒ   ó´   K  — 	 t        d| j                  | j                  | j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z3Rename video tile (either save new_name or cancel).Úrename_library_video)r–  Únew_nameÚcancelN)r   r–  rª  r«  rf   r?   rî   s     r>   Úrename_videor¬    sS   è ø€ ð-ÜÐ4À$×BRÑBRÐ]a×]jÑ]jÐsw×s~Ñs~Ô×ÐÐùÜò -Ü˜sÓ#¨Ð,ûð-üó1   ‚A„0; ´9µ; ¸A¹; »	AÁAÁAÁAz/library/video/email-downloadc              ƒ   ó´   K  — 	 t        d| j                  | j                  | j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z>Trigger Email Download Link popup with stats option or cancel.Úemail_download_link)r–  Úoptionr«  N)r   r–  r°  r«  rf   r?   rî   s     r>   Úemail_downloadr±    sS   è ø€ ð-ÜÐ3À×AQÑAQÐZ^×ZeÑZeÐnr×nyÑnyÔz×zÐzÐzùÜò -Ü˜sÓ#¨Ð,ûð-ür­  z/library/video/downloadc           	   ƒ   óš  K  — 	 t        d| j                  ¬«      ƒ d{  –—† }|j                  d«      dk(  rYd|v rUdd|j                  d«      |j                  d	«      |j                  d«      |j                  d
«      |j                  d«      dœS t        d|j                  dd«      «      ‚7 Œ�# t        $ r}t        |«      |‚d}~ww xY w­w)zdDownload video from Hudl and save under media/{id}/ (server). Local browser download kept commented.Údownload_library_videor•  Nr   r—   Ú
local_pathúVideo saved to media folder.Úmedia_idr  r3  Ú	file_size©r   rW   r¶  r  r´  r3  r·  r9   rW   úDownload failed)r   r–  ra   r   rf   r?   rß   s      r>   Údownload_videorº    sÅ   è ø€ ð-ÜÐ5À4×CSÑCSÔT×TˆØ�7‰7�8Ó Ò$¨¸Ñ)<ð Ø9ØŸG™G JÓ/ØŸ™ ›Ø!Ÿg™g lÓ3ØŸG™G JÓ/Ø ŸW™W [Ó1ñð ô"    S§W¡W¨YÐ8IÓ%JÓKÐKð) Uùô* ò -Ü˜sÓ#¨Ð,ûð-üs9   ‚C„B. žB,ŸA0B. ÂCÂB. Â.	CÂ7CÃCÃCz/library/video/download-by-refc              ƒ   ó  ‡‡K  — ddl m} ddlm} ddlm} ddlm} ddlm	Šm
}m}mŠm}m}m}	 | j                   xs dj#                  «       xs d}
d}|
rdd	lm}m}  ||
«      xs  ||
«      }d
t*        dt,        dz  dt.        fˆˆfd„}|r7 |«       5 } |||«      }|r ||«      r ||d|¬«      cddd«       S ddd«       	 t1        d| j2                  |
¬«      ƒ d{  –—† }|j9                  d«      dk7  sd|vrIt;        dt-        |j9                  dd«      «      j=                  «       v rdnd|j9                  dd«      «      ‚|d   } ||«      j?                  «       st;        dd«      ‚|j9                  d«      xs |xs dj#                  «       xs d}|j9                  d«      xs dj#                  «       }|s|rd ||d¬«      › �}|sd | j2                  › �}|r ||«      n ||«      }	  |«       5 }|r |||«      }|r|j@                  } |	|||j9                  d!«      xs |j9                  d"«      xs d#||j9                  d"«      xs d$|j9                  d%«      ||j9                  d&«      ¬'«      } ||d(|¬«      cddd«       S # 1 sw Y   �ŒÒxY w7 �Œ¹# t4        $ r}t7        |«      |‚d}~ww xY w# 1 sw Y   yxY w# t4        $ r:}	  ||«      jC                  d¬)«       n# t4        $ r Y nw xY wt7        |«      |‚d}~ww xY w­w)*u¯   
    Download a Hudl library video by `video_index` or `v` and save it under media/{id}/
    on the server only. Returns JSON locations â€” never a browser file download.
    r   ©ÚPath©Úquote©ÚSessionLocal©Ú
MediaVideo)ÚBACKEND_ROOTÚfind_media_by_hudl_vÚmedia_file_existsÚserialize_mediaÚsource_key_from_hudl_vÚsource_key_from_watch_urlÚstore_downloaded_videor•   N)Ú_canonical_hudl_vÚ_extract_hudl_vÚalready_savedÚv_valuer4   c                ó   •—  ‰| «      }|j                  d«      xs d}|rt        ‰|z  «      nd }d|rdnd||| j                  |j                  d«      |j                  d«      |j                  d«      ||||j                  d«      rt        ‰d	z  |d   z  «      nd |j                  d
«      |j                  d«      |j                  d«      dœS )Nr,  r•   r—   ú$Video already saved in media folder.rµ  rM  r�  rE   ÚmediaÚ
access_urlÚoriginal_filenamer·  )r   rW   rÍ  Úvr–  rM  r�  r¶  r  r,  r´  Úmedia_folder_pathrÒ  r3  r·  )ra   r<   r–  )ÚrowrÍ  rÎ  rÑ  ÚrelÚabs_pathrÄ  rÇ  s         €€r>   Ú_media_payloadz-download_video_by_ref.<locals>._media_payloadZ  sÏ   ø€ Ù Ó$ˆØ�i‰i˜Ó$Ò*¨ˆÙ.1”3�| cÑ)Ô*°tˆàñ !ñ 7à3à*ØØŸ?™?Ø—Y‘Y˜wÓ'ØŸ™ ;Ó/ØŸ	™	 $›ØØØ"ØNSÏiÉiÐX\Ìo¤ \°GÑ%;¸eÀD¹kÑ%IÔ!JÐcgØŸ)™) LÓ1ØŸ	™	Ð"5Ó6ØŸ™ ;Ó/ñ'
ð 	
r@   T)rÍ  rÎ  Údownload_library_video_by_ref)r–  rÔ  r   r—   r´  z	not foundrW   r‰  r9   r¹  úDownloaded file missing on diskrÔ  r�  z*https://app.hudl.com/watch/team/analyze?v=z=+/)Úsafezhudl://library/index/rM  r3  ÚVideoú	video.mp4r–  r¶  )Ú	temp_pathrM  r�  rÓ  r–  Ú
source_keyr¶  F©Ú
missing_ok)"Úpathlibr½  Úurllib.parser¿  Úapp.core.databaserÁ  Úapp.models.media_modelrÃ  Úapp.services.media_servicerÄ  rÅ  rÆ  rÇ  rÈ  rÉ  rÊ  rÔ  rœ   rž   rË  rÌ  Úboolr<   Údictr   r–  rf   r?   ra   r   ÚlowerÚis_filerà  Úunlink)rS   r½  r¿  rÁ  rÃ  rÅ  rÆ  rÈ  rÉ  rÊ  Úv_rawÚv_canonrË  rÌ  rÙ  ÚdbÚexistingrà   r3   rß  rÎ  r�  rà  rÖ  rÄ  rÇ  s                           @@r>   Údownload_video_by_refrñ  =  s   ùè ø€ õ Ý"å.Ý1÷÷ ñ ð �V‰VŠ\�r× Ñ Ó"Ò* d€EØ€GÙçSá! %Ó(ÒDÑ,=¸eÓ,Dˆð
¬dð 
¼SÀ4¹Zð 
ÌDö 
ñ6 ÙŒ^˜rÙ+¨B°Ó8ˆHÙÑ-¨hÔ7Ù% h¸dÈGÔT÷ �^‰^ð
-ÜØ+Ø×(Ñ(Øô
÷ 
ˆð ‡w�wˆxÓ˜DÒ  L¸Ñ$;ÜØ¤# c§g¡g¨i¸Ó&<Ó"=×"CÑ"CÓ"EÑE‰CÈ3Ø�G‰G�IÐ0Ó1ó
ð 	
ð
 �LÑ!€IÙ�	‹?×"Ñ"Ô$Ü˜CÐ!BÓCÐCà�w‰w�s‹|Ò,˜wÒ,¨"×3Ñ3Ó5Ò=¸€GØ—‘˜Ó%Ò+¨×2Ñ2Ó4€IÙ™Ø@ÁÀwÐUZÔA[Ð@\Ð]ˆ	Ùà+¨D×,<Ñ,<Ð+=Ð>ˆ	á4;Ñ'¨Ô0ÑAZÐ[dÓAe€Jð-ÙŒ^˜ráÙ/°°GÓ<�ÙØ!)×!4Ñ!4�JÙ(ØØ#Ø—g‘g˜gÓ&ÒH¨#¯'©'°*Ó*=ÒHÀØ#Ø"%§'¡'¨*Ó"5Ò"D¸ØŸG™G MÓ2Ø%ØŸ™ Ó,ô	ˆCñ " #°UÀGÔL÷! ‰^÷G ‰^úð
úô
 ò -Ü˜sÓ#¨Ð,ûð-ú÷0 ˆ^ûô" ò -ð	Ù�‹O×"Ñ"¨dÐ"Õ3øÜò 	Ùð	úä˜sÓ#¨Ð,ûð-üs¼   „BLÂJÂ2LÃJ Ã JÃ!J Ã%D
LÇ0K Ç7BJ9Ê	K ÊLÊJÊLÊJ Ê	J6Ê%J1Ê1J6Ê6LÊ9KÊ>K ËLËK Ë	LËK(Ë'LË(	K4Ë1LË3K4Ë4LÌLÌLz /library/video/download-to-mediac           
   ƒ   óÂ  K  — ddl m} ddlm} ddlm} ddlm}m}m	}m
} | j                  xs dj                  «       }|st        dd«      ‚dd	lm}	  |«       5 }
 ||«      }|
j                  |«      j!                  |j"                  |k(  «      j%                  «       }|r ||«      rd
dddœ ||«      ¥cddd«       S 	 ddlm}  ||«      }|r* |	|
|«      }|r ||«      rd
dddœ ||«      ¥cddd«       S ddd«       	 t-        d| j.                  ¬«      ƒ d{  –—† }|j3                  d«      d
k7  sd|vrt        d|j3                  dd«      «      ‚|d   } ||«      j5                  «       st        dd«      ‚	  |«       5 }
 ||
|| j6                  ||j3                  d«      xs d| j.                  ¬«      } ||«      }ddd«       d
dddœ¥S # t*        $ r Y Œäw xY w# 1 sw Y   ŒéxY w7 ŒÐ# t*        $ r}t1        |«      |‚d}~ww xY w# 1 sw Y   ŒKxY w# t*        $ r:}	  ||«      j9                  d¬«       n# t*        $ r Y nw xY wt1        |«      |‚d}~ww xY w­w)z�
    Download a Hudl library video via Playwright, save under media/{id}/,
    and store id + path in the database for later direct access.
    r   r¼  rÀ  rÂ  )rÆ  rÇ  rÉ  rÊ  r•   r¾   zwatch_url is required)rÅ  r—   TrÐ  )r   rÍ  rW   N©rÌ  r³  r•  r   r´  r9   rW   r¹  rÛ  r3  rÞ  )rß  rM  r�  rÓ  r–  rá  Frµ  )rã  r½  rå  rÁ  ræ  rÃ  rç  rÆ  rÇ  rÉ  rÊ  r�  rœ   r   rÅ  rí   Úfilterrà  Úfirstrž   rÌ  rf   r   r–  r?   ra   rë  rM  rì  )rS   r½  rÁ  rÃ  rÆ  rÇ  rÉ  rÊ  r�  rÅ  rï  rk   rð  rÌ  rÔ  Úby_vrà   r3   rß  rÖ  Úpayloads                        r>   Údownload_video_to_mediarø  ³  s~  è ø€ õ å.Ý1÷ó ð —‘Ò% 2×,Ñ,Ó.€IÙÜ˜CÐ!8Ó9Ð9å?á	Œ˜2Ù'¨	Ó2ˆØ—8‘8˜JÓ'×.Ñ.¨z×/DÑ/DÈÑ/KÓL×RÑRÓTˆÙÑ)¨(Ô3àØ!%ØAññ " (Ó+ð	÷	 
‰ð	ÝDá 	Ó*ˆAÙÙ+¨B°Ó2�ÙÑ-¨dÔ3à"&Ø)-Ø#Iññ *¨$Ó/ð	÷% 
�‰ð6-ÜÐ5À4×CSÑCSÔT×Tˆð ‡w�wˆxÓ˜DÒ  L¸Ñ$;Ü˜C §¡¨Ð4EÓ!FÓGÐGà�LÑ!€IÙ�	‹?×"Ñ"Ô$Ü˜CÐ!BÓCÐCð-ÙŒ^˜rÙ(ØØ#Ø—j‘jØ#Ø"%§'¡'¨*Ó"5Ò"D¸Ø ×,Ñ,ôˆCñ & cÓ*ˆG÷ ð$ ØØ1ñð ð	ð øôC ò 	Ùð	ú÷1 
ˆúð8 UùÜò -Ü˜sÓ#¨Ð,ûð-ú÷ ˆ^ûô ò -ð	Ù�‹O×"Ñ"¨dÐ"Õ3øÜò 	Ùð	úä˜sÓ#¨Ð,ûð-üsÔ   ‚AIÁAG"Â5
IÃ 0GÃ0IÄG0 ÄG.ÄG0 Ä"AIÅ>H Æ>HÇH ÇIÇ	GÇG"ÇGÇG"Ç"G+Ç'IÇ.G0 Ç0	H
Ç9HÈH
È
IÈHÈH È	IÈ#H<È;IÈ<	IÉIÉIÉIÉIÉIz/mediac            	   ƒ   óD  K  — ddl m}  ddlm} ddlm}  | «       5 }|j                  |«      j                  |j                  j                  «       «      j                  «       }dt        |«      |D �cg c]
  } ||«      ‘Œ c}dœcddd«       S c c}w # 1 sw Y   yxY w­w)z-List all videos saved under the media folder.r   rÀ  rÂ  )rÇ  r—   )r   ÚcountÚvideosN)rå  rÁ  ræ  rÃ  rç  rÇ  rí   Úorder_byrI   ÚdescÚallrk  )rÁ  rÃ  rÇ  rï  ÚrowsÚrs         r>   Úlist_media_videosr    s„   è ø€ õ /Ý1Ý:á	Œ˜2à�H‰H�ZÓ ß‰X�j×+Ñ+×0Ñ0Ó2Ó3ß‰S‹Uð 	ð Ü˜“YÙ37Ó8±4¨a‘ qÕ)°4Ñ8ñ
÷ 
‰ùò 9÷ 
ˆüs/   ‚B œABÁ2B
ÂBÂ
B ÂBÂBÂB z/media/lookupr�  c              ƒ   óf  K  — ddl m} ddlm} ddlm} ddlm}m}m	}m
}  | || xs d«      «      j                  «       } |«       5 }	| xs d|fD ]j  }
|
sŒ ||
«      }|	j                  |«      j                  |j                  |k(  «      j                  «       }|sŒL ||«      sŒUdd ||«      d	œc cd
d
d
«       S  	 ddlm}  ||«      xs  || xs d«      }|r( ||	|«      }|r ||«      rdd ||«      d	œcd
d
d
«       S ddd
d	œcd
d
d
«       S # t$        $ r d
}Y ŒFw xY w# 1 sw Y   y
xY w­w)z?Find a saved media video by Hudl watch_url or by `v` inside it.r   )ÚunquoterÀ  rÂ  )rÅ  rÆ  rÇ  rÉ  r•   r—   T)r   ÚfoundÚvideoNró  F)rä  r  rå  rÁ  ræ  rÃ  rç  rÅ  rÆ  rÇ  rÉ  rœ   rí   rô  rà  rõ  rž   rÌ  rf   )r�  r  rÁ  rÃ  rÅ  rÆ  rÇ  rÉ  Úrawrï  Ú	candidaterk   rÖ  rÌ  rÔ  s                  r>   Úlookup_media_by_watch_urlr    s>  è ø€ õ %å.Ý1÷ó ñ ‘'˜)š/ rÓ*Ó
+×
1Ñ
1Ó
3€CÙ	Œ˜2à#š/ r¨3Ó/ˆIÙØÙ+¨IÓ6ˆCØ—(‘(˜:Ó&×-Ñ-¨j×.CÑ.CÀsÑ.JÓK×QÑQÓSˆCÚÑ(¨Õ-à"Ø!Ù,¨SÓ1ññ ÷ 
‰à/ð	ÝDá Ó$ÒH©¸	ºÀRÓ(HˆAñ Ù& r¨1Ó-ˆCÙÑ(¨Ô-à"Ø!Ù,¨SÓ1ñ÷1 
‰ð< ¨¸Ñ>÷= 
‰øô& ò 	ØŠAð	ú÷' 
ˆüsg   ‚AD1ÁAD%ÂD%Â&D%Â3
D1Â=D%Â?DÃ D%Ã;
D1ÄD%Ä

D1ÄD"ÄD%Ä!D"Ä"D%Ä%D.Ä*D1z/library/video/deletec              ƒ   óˆ   K  — 	 t        d| j                  ¬«      ƒ d{  –—† S 7 Œ# t        $ r}t        |«      |‚d}~ww xY w­w)z&Delete a video item from Hudl Library.Údelete_library_videor•  Nr—  rî   s     r>   Údelete_videor  O  r™  rð   z/library/stream-proxyr�   ÚrequestÚtokenc           	   ƒ   óˆ  ‡(‡)‡*‡+K  — ddl }ddl}ddlŠ+ddlŠ+ddl}ddlm}m}m}m	}	 |Š*‰*sD|rB|j                  j                  d«      }
|
r%|
j                  d«      r|
j                  d«      d   Š*‰*s	 ‰*s ||j                  d¬	«      ‚	 dd
lm}  |«       5 }t#        ‰*|«       ddd«       t&        j(                  j+                  «       ƒ d{  –—† }dj-                  |D �cg c]  }|d   › d|d   › �‘Œ c}«      }‰+j.                  j                  | «      Š)‰)j1                  dd«       ‰)j1                  d|«       	 |j3                  «       }ˆ)ˆ+fd„}|j5                  d|«      ƒ d{  –—† \  }}}|j                  d«      dk(  xs |j                  d«      }|r	 |j7                  |«      }|j                  dd«      }d|j9                  «       v s$| j                  d«      d   j;                  d«      �rx	 |j=                  d«      }‰+j>                  jA                  | «      }tB        jD                  jG                  |jD                  «      }|j;                  d«      s|dz  }|jH                  › d|jJ                  › |› �Š(|jM                  «       }g }|D ]¶  }|jO                  «       }|s|jQ                  |«       Œ'|j                  d«      r1d |v rˆ(ˆ*ˆ+fd!„} |jR                  d"||«      }|jQ                  |«       Œi‰+j>                  jU                  ‰(|«      } d#‰+j>                  jW                  | «      › d$‰*› �}!|jQ                  |!«       Œ¸ d%j-                  |«      jY                  d«      }d&}d(d)i}#|j]                  «       D ]  \  }$}%|$j9                  «       }&|&d*vsŒ|%|#|$<   Œ!  |||||#¬+«      S # 1 sw Y   �ŒxY w# |$ r ‚ t$        $ r} ||j                  d|› �¬	«      ‚d}~ww xY w7 �Œc c}w 7 �Œˆ# t$        $ r Y �ŒSw xY w# t$        $ r}"t[        d'|"› �«       Y d}"~"Œ³d}"~"ww xY w# t$        $ r}' |d,d-|'› �«      ‚d}'~'ww xY w­w).zV
    Proxy HLS stream requests and inject Hudl session cookies for authorization.
    r   N)ÚResponser   r   r
   ÚAuthorizationúBearer Ú r§   úAuthentication token requiredr6   rÀ  úAuthentication failed: ú; r·   Ú=rn  ú
User-AgentúeMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36ÚCookiec                  óÎ  •— 	 ‰j                   j                  ‰«      5 } | j                  t        | j                  «      | j                  «       fcd d d «       S # 1 sw Y   y xY w# ‰j                  j                  $ r:}|j                  t        |j                  «      |j                  «       fcY d }~S d }~wt        $ r&}di t        |«      j                  «       fcY d }~S d }~ww xY w)Nr9   ©r  Úurlopenr   ré  Úheadersr‹   rš   Ú	HTTPErrorÚcoderf   r<   Úencode©ÚresponseÚheÚeÚreqÚurllibs      €€r>   Úfetch_remotez'hudl_stream_proxy.<locals>.fetch_remote‡  s    ø€ ð0Ø—^‘^×+Ñ+¨CÔ0°HØ#Ÿ?™?¬D°×1AÑ1AÓ,BÀHÇMÁMÃOÐS÷ 1×0Ò0ûà—<‘<×)Ñ)ò <Ø—w‘w¤ R§Z¡ZÓ 0°"·'±'³)Ð;Õ;ûÜò 0Ø˜B¤ A£§¡£Ð/Õ/ûð0úsL   ƒA$ ž0AÁ	A$ ÁA!ÁA$ Á!A$ Á$C$Á=/B2Â,C$Â2C$Â>CÃC$ÃC$zContent-EncodingÚgzips   ‹úContent-Typeúapplication/octet-streamÚmpegurlÚ?z.m3u8zutf-8Ú/z://Ú#úURI="c                 ó¬   •— | j                  d«      }‰j                  j                  ‰|«      }d‰j                  j                  |«      › d‰› �}d|› d�S )Nr§   ú&/api/v1/hudl/library/stream-proxy?url=ú&token=r/  Ú")ÚgroupÚparseÚurljoinr¿  )ÚmatchÚtag_uriÚabs_uriÚproxied_uriÚbase_urlÚ	token_valr&  s       €€€r>   Úreplace_uriz&hudl_stream_proxy.<locals>.replace_uri²  si   ø€ Ø*/¯+©+°a«. Ø*0¯,©,×*>Ñ*>¸xÈÓ*Q Ø0VÐW]×WcÑWc×WiÑWiÐjqÓWrÐVsÐszð  |Eð  {Fð  /G Ø).¨{¨m¸1Ð'=Ð =r@   zURI="([^"]+)"r1  r2  Ú
zapplication/vnd.apple.mpegurlzError rewriting manifest: úAccess-Control-Allow-OriginÚ*)zcontent-encodingzcontent-lengthztransfer-encodingÚserverÚ
connection©Úcontentr7   Ú
media_typer  r9   zStreaming proxy failed: )/r¬   r(  Úurllib.requesträ  r^  Úfastapir  r   r   r
   r  ra   Ú
startswithra  ÚHTTP_401_UNAUTHORIZEDrå  rÁ  r   rf   r   ÚcontextÚcookiesr-  r  Ú
add_headerÚget_running_loopÚrun_in_executorÚ
decompressrê  ÚendswithÚdecoder5  Úurlparser!  r  ÚdirnameÚschemeÚnetlocÚ
splitlinesrœ   Úappendrb  r6  r¿  r   rg   rL   ),r�   r  r  r¬   r(  r^  r  r   r   r
   Úauth_headerrÁ  rï  Úauth_errrK  ÚcÚ
cookie_strÚloopr'  r7   r  rS   Ú
is_gzippedÚcontent_typeÚmanifest_textÚ
parsed_urlÚ	base_pathÚlinesÚ	new_linesÚlineÚ
line_stripr=  Ú
abs_targetÚproxied_targetÚrewrite_errÚresponse_headersré   rÔ  Úk_lowr3   r;  r%  r<  r&  s,                                           @@@@r>   Úhudl_stream_proxyrk  X  sL  ûè ø€ ó
 ÛÛÛÛß@Ó@ð €IÙ™Ø—o‘o×)Ñ)¨/Ó:ˆÙ˜;×1Ñ1°)Ô<Ø#×)Ñ)¨#Ó.¨qÑ1ˆIáàáÙ¨×(DÑ(DÐMlÔmÐmðsÝ2áŒ^˜rÜ# I¨rÔ2÷ ô $×+Ñ+×3Ñ3Ó5×5€GØ—‘ÁÓIÁ¸A˜q ™y˜k¨¨1¨W©:¨,Ò7ÀÑIÓJ€Jð �.‰.×
 Ñ
  Ó
%€CØ‡N�N�<ð  "Iô  JØ‡N�N�8˜ZÔ(ðKCØ×'Ñ'Ó)ˆõ	0ð ,0×+?Ñ+?ÀÀlÓ+S×%SÑ"ˆ�W˜dð —[‘[Ð!3Ó4¸Ñ>Ò^À$Ç/Á/ÐR]ÓB^ˆ
ÙðØ—‘ tÓ,�ð —{‘{ >Ð3MÓNˆð ˜×*Ñ*Ó,Ñ,°·	±	¸#³¸qÑ0A×0JÑ0JÈ7Õ0Sð$BØ $§¡¨GÓ 4�ð $Ÿ\™\×2Ñ2°3Ó7�
ÜŸG™GŸO™O¨J¯O©OÓ<�	Ø ×)Ñ)¨#Ô.Ø Ñ$�IØ(×/Ñ/Ð0°°J×4EÑ4EÐ3FÀyÀkÐR�ð &×0Ñ0Ó2�Ø�	Û!�DØ!%§¡£�JÙ%Ø!×(Ñ(¨Õ.Ø#×.Ñ.¨sÔ3à" d™?ö>ð
 $* 2§6¡6Ð*:¸KÈÓ#N˜DØ!×(Ñ(¨Õ.ð &,§\¡\×%9Ñ%9¸(ÀJÓ%O˜
Ø+QÐRX×R^ÑR^×RdÑRdÐeoÓRpÐQqÐqxð  zCð  yDð  *E˜Ø!×(Ñ(¨Õ8ð% "ð( —y‘y Ó+×2Ñ2°7Ó;�Ø>�ð *¨3ð
Ðð —M‘M–O‰DˆAˆqØ—G‘G“IˆEØÐoÒoØ&'Ð  Ò#ð $ñ
  °+È,Ð`pÔqÐq÷q ‰^ûàò ØÜò sÙ¨×(DÑ(DÐOfÐgoÐfpÐMqÔrÐrûðsúð 6ûÚIð$ &Túô ò ÚðûôT ò BÜÐ2°;°-Ð@×AÑAûðBûô ò CÙ˜CÐ#;¸C¸5Ð!AÓBÐBûðCüsí   †BQÂ	N9 ÂN,Â#N9 Â+!QÃO&ÃQÃ O)Ã4AQÄ;+P% Å&O.Å'1P% ÆO1 Æ*AP% Ç3E7P Í*.P% ÎP% Î+QÎ,N6Î1N9 Î9O#ÏOÏO#Ï#QÏ)QÏ.P% Ï1	O>Ï:P% Ï=O>Ï>P% Ð	P"Ð
PÐP% ÐP"Ð"P% Ð%	P?Ð.P:Ð:P?Ð?Qz/library/thumb-proxyc           	   ƒ   ó  ‡‡K  — ddl }ddlŠddlŠddlm}m}m} |}|sD|rB|j                  j                  d«      }|r%|j                  d«      r|j                  d«      d   }|s ||j                  d¬	«      ‚	 dd
lm}	  |	«       5 }
t        ||
«       ddd«       | xs dj!                  «       }|j                  d«      s	 |dd«      ‚t#        j$                  d|t"        j&                  «      r	 |dd«      ‚t(        j*                  j-                  «       ƒ d{  –—† }dj/                  |D �cg c]  }|d   › d|d   › �‘Œ c}«      }‰j0                  j3                  |«      Š‰j5                  dd«       ‰j5                  d|«       ‰j5                  dd«       	 |j7                  «       }ˆˆfd„}|j9                  d|«      ƒ d{  –—† \  }}}|j                  dd«      }|dk\  s|s |dd|› d �«      ‚ ||d!|j                  d"«      d   j!                  «       xs dd#d$d%œ¬&«      S # 1 sw Y   �Œ•xY w# |$ r ‚ t        $ r} ||j                  d|› �¬	«      ‚d}~ww xY w7 �ŒHc c}w 7 Œ£# |$ r ‚ t        $ r} |d'd(|› �«      ‚d}~ww xY w­w))zš
    Proxy Hudl library thumbnail images with the Playwright session cookies
    so the frontend can show original film stills (not profile avatars).
    r   N)r  r   r   r  r  r  r§   r  r6   rÀ  r  r•   Úhttpr¾   zInvalid thumbnail urlz avatar|profile|headshot|/users?/zNot a video thumbnailr  r·   r  rn  r  r  r  ÚRefererzhttps://www.hudl.com/c                  óÒ  •— 	 ‰j                   j                  ‰d¬«      5 } | j                  t        | j                  «      | j                  «       fcd d d «       S # 1 sw Y   y xY w# ‰j                  j                  $ r:}|j                  t        |j                  «      |j                  «       fcY d }~S d }~wt        $ r&}di t        |«      j                  «       fcY d }~S d }~ww xY w)Né   )Útimeoutr9   r  r!  s      €€r>   r'  z&hudl_thumb_proxy.<locals>.fetch_remote  s¥   ø€ ð0Ø—^‘^×+Ñ+¨C¸Ð+Ô<ÀØ#Ÿ?™?¬D°×1AÑ1AÓ,BÀHÇMÁMÃOÐS÷ =×<Ò<ûà—<‘<×)Ñ)ò <Ø—w‘w¤ R§Z¡ZÓ 0°"·'±'³)Ð;Õ;ûÜò 0Ø˜B¤ A£§¡£Ð/Õ/ûð0úsL   ƒA&  0AÁ	A& ÁA#ÁA& Á#A& Á&C&Á?/B4Â.C&Â4C&Ã C!ÃC&Ã!C&r)  z
image/jpegiö  zThumbnail fetch failed (Ú)éÈ   Ú;zprivate, max-age=3600r@  )zCache-Controlr?  rC  r9   zThumbnail proxy failed: )r¬   rF  rä  rG  r  r   r   r  ra   rH  ra  rI  rå  rÁ  r   rf   rœ   r^  ÚsearchÚIr   rJ  rK  r-  r  r
   rL  rM  rN  )r�   r  r  r¬   r  r   r   r<  rX  rÁ  rï  rY  r  rK  rZ  r[  r\  r'  r7   r  rS   r^  r3   r%  r&  s                          @@r>   Úhudl_thumb_proxyrw  Ó  s˜  ùè ø€ ó ÛÛß7Ñ7à€IÙ™Ø—o‘o×)Ñ)¨/Ó:ˆÙ˜;×1Ñ1°)Ô<Ø#×)Ñ)¨#Ó.¨qÑ1ˆIÙÙ¨×(DÑ(DÐMlÔmÐmð
Ý2áŒ^˜rÜ# I¨rÔ2÷ ð Š9�"×
Ñ
Ó
€CØ�>‰>˜&Ô!Ù˜CÐ!8Ó9Ð9ä	‡y�yÐ4°c¼2¿4¹4Ô@Ù˜CÐ!8Ó9Ð9ä#×+Ñ+×3Ñ3Ó5×5€GØ—‘ÁÓIÁ¸A˜q ™y˜k¨¨1¨W©:¨,Ò7ÀÑIÓJ€JØ
�.‰.×
 Ñ
  Ó
%€CØ‡N�NØØoôð ‡N�N�8˜ZÔ(Ø‡N�N�9Ð5Ô6ðCØ×'Ñ'Ó)ˆõ	0ð ,0×+?Ñ+?ÀÀlÓ+S×%SÑ"ˆ�W˜dØ—{‘{ >°<Ó@ˆØ˜#Ò¡TÙ Ð'?À¸}ÈAÐ%NÓOÐOÙØØØ#×)Ñ)¨#Ó.¨qÑ1×7Ñ7Ó9ÒI¸\à!8Ø/2ñô	
ð 	
÷W ‰^ûàò ØÜò 
ÙØ×4Ñ4Ø,¨X¨JÐ7ô
ð 	
ûð
úð 6ûÚIð* &Tùð ò ØÜò CÙ˜CÐ#;¸C¸5Ð!AÓBÐBûðCüs™   „A5JÁ:H4 ÂH'ÂH4 ÂA=JÄI!ÄJÄ-I$ÅAJÆ+I+ ÇI)ÇA I+ È&JÈ'H1È,H4 È4IÉIÉIÉJÉ$JÉ)I+ É+J
É9JÊJ
Ê
Jz/library/video/download-directr–  c           	   ƒ   óZ  K  — |}|st        dd¬«      ‚	 ddlm}  |«       5 }t        ||«       ddd«       	 t        d| ¬	«      ƒ d{  –—† }|j                  d
«      dk(  rYd|v rUdd|j                  d«      |j                  d«      |j                  d«      |j                  d«      |j                  d«      dœS t        d|j                  dd«      «      ‚# 1 sw Y   Œ¨xY w# t         $ r ‚ t        $ r}t        dd|› �¬«      ‚d}~ww xY w7 ŒÃ# t        $ r}t        |«      |‚d}~ww xY w­w)z�
    Download video from Hudl and save under media/{id}/ on the server.
    Local browser FileResponse download is kept commented below.
    rC   r  r6   r   rÀ  Nr  r³  r•  r   r—   r´  rµ  r¶  r  r3  r·  r¸  r9   rW   r¹  )r   rå  rÁ  r   rf   r   ra   r?   )	r–  r  r%  r<  rÁ  rï  rY  rà   r3   s	            r>   Údownload_video_directry  #  s2  è ø€ ð €IÙÜ¨Ð4SÔTÐTðZÝ2áŒ^˜rÜ# I¨rÔ2÷ ð&-ÜÐ5À;ÔO×OˆØ�7‰7�8Ó Ò$¨¸Ñ)<ð Ø9ØŸG™G JÓ/ØŸ™ ›Ø!Ÿg™g lÓ3ØŸG™G JÓ/Ø ŸW™W [Ó1ñð ô@    S§W¡W¨YÐ8IÓ%JÓKÐK÷W ˆ^ûäò ØÜò ZÜ¨Ð6MÈhÈZÐ4XÔYÐYûðZúð PùôH ò -Ü˜sÓ#¨Ð,ûð-üst   ‚D+•C" ¢C¯C" ¸D ÁDÁ	A0D Â9D+Â:D ÃCÃC" Ã"D	Ã4DÄD	Ä	D+ÄD Ä	D(ÄD#Ä#D(Ä(D+z/media/{media_id}r¶  Údownloadc              ƒ   óŽ  K  — ddl m} ddlm} ddlm} ddlm} ddlm	}m
}	 |}
|
sD|rB|j                  j                  d«      }|r%|j                  d«      r|j                  d	«      d
   }
|
st        dd¬«      ‚	  |«       5 }t!        |
|«       |j#                  |«      j%                  |j&                  | k(  «      j)                  «       }|st        dd«      ‚ |	|«      st        dd«      ‚ ||j*                  «      }|j,                  xs |j.                  }t1        |«      }|}ddd«       ddi}|r/j5                  dd«      }d|› d ||«      › �|d<    ||d|¬«      S dj5                  t7        d«      d«      › d�|d<    |d|¬«      S # 1 sw Y   ŒkxY w# t        $ r ‚ t2        $ r}t        dd|› �¬«      ‚d}~ww xY w­w) z 
    Direct access to a video saved under media/{id}/.
    - Default: inline playback for <video src>
    - ?download=1: browser file download (attachment)
    r   )ÚFileResponser¾  rÀ  rÂ  )Úabsolute_media_pathrÆ  r  r  r  r§   rC   r  r6   r‰  zMedia video not foundzMedia file missing on diskNr  r?  r@  r3  r•   zattachment; filename="z"; filename*=UTF-8''zContent-Dispositionr*  )r  r3  rE  r  zinline; filename="é"   z	video/mp4)r  rE  r  )Úfastapi.responsesr|  rä  r¿  rå  rÁ  ræ  rÃ  rç  r}  rÆ  r  ra   rH  ra  r   r   rí   rô  rE   rõ  r,  rÓ  r·   r<   rf   ÚreplaceÚchr)r¶  r  r  rz  r|  r¿  rÁ  rÃ  r}  rÆ  r<  rX  rï  rÖ  rØ  r3  Úpath_strr·   rY  r  Ú	safe_names                        r>   Úserve_media_videor„  e  sã  è ø€ õ /Ý"å.Ý1ßQà€IÙ™Ø—o‘o×)Ñ)¨/Ó:ˆÙ˜;×1Ñ1°)Ô<Ø#×)Ñ)¨#Ó.¨qÑ1ˆIÙÜ¨Ð4SÔTÐTðZÙŒ^˜rÜ# I¨rÔ2Ø—(‘(˜:Ó&×-Ñ-¨j¯m©m¸xÑ.GÓH×NÑNÓPˆCÙÜ# CÐ)@ÓAÐAÙ$ SÔ)Ü# CÐ)EÓFÐFÙ*¨3¯=©=Ó9ˆHØ×,Ñ,Ò=°·±ˆHÜ˜8“}ˆHØˆD÷ ð  -¨cÐ2€GáØ—L‘L  bÓ)ˆ	à$ Y Kð 0 Ù % iÓ 0Ð1ð3ð 	Ð%Ñ&ñ ØØØ1Øô	
ð 	
ð (:¸$¿,¹,ÄsÈ2ÃwÐPRÓ:SÐ9TÐTUÐ%V€GÐ!Ñ"ÙØØØôð ÷A ˆ^ûô ò ØÜò ZÜ¨Ð6MÈhÈZÐ4XÔYÐYûðZüsD   ‚A8GÁ;F ÂB#FÄ%F Ä-A"GÆFÆF ÆGÆ-F=Æ=GÇG)r4   N)NF)N)FN)NT)Nr•   T)Nr•   r•   T)NN)—r!  r^  r5  r.  rJ   r0  rG  r   r   r   r   r   r   r	   r
   r   Úapp.automation.browser_managerr   Úapp.automation.runnerr   Úapp.automation.session_storer   Ú app.automation.tasks.permissionsr   Úapp.core.auth_depsr   r   r   Úapp.schemas.hudl_schemar   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   ÚrouterÚstream_routerrè   Ú	CACHE_TTLr/   ré  r<   Ú__annotations__r0   r1   ro   r2   rK   rf   r?   rG   rR   ri   rq   rs   r�   ra   r’   rè  r¢   Úpostr¤   r±   r´   r¹   rÀ   rÄ   rÍ   rÏ   rÑ   r×   rá   rä   rê   rï   ró   rù   rü   rþ   r  r  r  r	  r  r  r  r  r  r  r  r  r$  Úintr:  r<  r>  rA  rC  rF  rH  rJ  rP  rR  rT  rW  r\  ÚHTTP_202_ACCEPTEDrX   r‚  r†  Úfloatr�  r�  r’  r˜  rœ  r   r¤  r§  r¬  r±  rº  rñ  rø  r  r  r  rk  rw  ry  r„  © r@   r>   Ú<module>r”     s8  ðÜ 	Û 	Û Û Û Û ß o× oÕ oå :Ý *Ý 6Ý ?ß QÑ Q÷÷ ÷ ÷ ÷ ÷ ÷ ñ< 
¡¨Ó!6Ð 7Ô	8€Ù“€ð
 €Ø€	ð )+Ð �d˜3 ˜9‘oÓ *Ø/1Ð ˜T # t )™_Ó 1Ø/1Ð ˜T # t )™_Ó 1ØÐ ð 13Ð ˜d 3¨ 9™oÓ 2Ø"'Ð ð;˜)ð ;¨ó ;ð8˜kð 8¨có 8ó7ð
°3ð 
Ð>Yð 
Ð^bó 
ðB�dð  ð ¨°©ó ð:�dð : ð :¨Dð :°Tó :ó
.ð6 ‡�ˆIÓñó ðð$ ‡�ˆJÓàØñ
Ø�4‰Zð
àò
ó ð
ð@ ‡�ÐÓñ-ó ð-ð ‡�Ð%Ó&ñió 'ðið2 ‡�ˆYÓñ	-ó ð	-ð ‡�ˆOÓñ*ó ð*ð ‡�ˆXÓÙ.9«mñ 	- ò 	-ó ð	-ð ‡�ÐÓñ-ó ð-ð ‡�ˆ^Óð-Ð!5ò -ó ð-ð4 ‡�ÐÓñ-Ð0°4Ñ7ò -ó ð-ð ‡�ÐÓñ- S¨4¡Zò -ó ð-ð ‡�ÐÓñ	-°ð 	-ÀsÈTÁzò 	-ó  ð	-ð ‡�Ð'Ó(ð-Ð0Kò -ó )ð-ð  ‡�Ð0Ó1ñ-ó 2ð-ð ‡�Ð&Ó'ð-Ð+Eò -ó (ð-ð2 ‡�ÐÓ ð-Ð 4ò -ó !ð-ð ‡�Ð$Ó%ñ	-ó &ð	-ð ‡�ÐÓð-Ð1ò -ó  ð-ð4 ‡�ÐÓñ-ó  ð-ð" ‡�Ð&Ó'ð-Ð/ò -ó (ð-ð ‡�Ð)Ó*ð-Ð!5ò -ó +ð-ð ‡�ÐÓñ-ó ð-ð ‡�ÐÓð-˜[ò -ó  ð-ð ‡�ÐÓð-˜+ò -ó  ð-ð ‡�ÐÓ ñ-ó !ð-ð ‡�Ð Ó!ñ-ó "ð-ð ‡�ÐÓ ð- ò -ó !ð-ð ‡�ÐÓð- ò -ó ð-ð ‡�ˆ^Óñ-ó ð-ð ‡�ˆNÓñ-ó ð-ð ‡�Ð$Ó%ñ-ó &ð-ð ‡�Ð Ó!ñ-ó "ð-ð˜3ó ð ‡�Ð#Ó$ñ " $›ZÙ˜C“yñ-Ø%ð-à�d‘
ð-ð ò-ó %ð-ð6 ‡�ˆOÓñ-ó ð-ð ‡�Ð#Ó$ð-Ð%5ò -ó %ð-ð ‡�ÐÓñ-ó  ð-ð ‡�ÐÓñ-ó  ð-ð ‡�Ð*Ó+ñ-ó ,ð-ð ‡�Ð%Ó&ñ-ó 'ð-ð ‡�ÐÓð-Ð#5ò -ó  ð-ð  ‡�ÐÓñ-ó ð-ð ‡�ÐÓñ- c¨D¡jò -ó ð-ð ‡�ÐÓñ- c¨D¡jð -À$ò -ó ð-ð ‡�Ð$Ó%àBFñ-Ø�4‰Zð-Ø(+ð-Ø;?ò-ó &ð-ð, ‡�Ð$Ó%àØØØñ	!-Ø�4‰Zð!-àð!-ð ð!-ð ò	!-ó &ð!-ðH ‡�Ð'°V×5MÑ5M€ÓNñ   Ó-ñØ
%ðà%ðð òó Oðð< ‡�Ð%Ó&ñ   Ó-ñ*
Ø
#ð*
à
ò*
ó 'ð*
ðZ ‡�Ð(Ó)ñ   Ó-ñ"
Ø
%ð"
à
ò"
ó *ð"
ðJ ‡�Ð/Ó0ð Ù Ó-ñHØðHà
ðHð òHó 1ðHðD ‡�Ð$Ó%ð-Ð%6ò -ó &ð-ð ‡�Ð#Ó$ñ-ó %ð-ð ‡�Ð*Ó+ð-Ð#:ò -ó ,ð-ð ‡�Ð*Ó+ð-Ð"9ò -ó ,ð-ð ‡�Ð3Ó4ð-Ð(?ò -ó 5ð-ð ‡�Ð+Ó,ð-Ð#;ò -ó -ð-ð ‡�Ð+Ó,ñ-ó -ð-ð ‡�Ð$Ó%ð-Ð0ò -ó &ð-ð ‡�Ð,Ó-ð-Ð9ò -ó .ð-ð ‡�Ð&Ó'ð-Ð6ò -ó (ð-ð: ‡�Ð-Ó.ðr-Ð&@ò r-ó /ðr-ðj ‡�Ð/Ó0ðTÐ(Dò Tó 1ðTðn ‡�ˆHÓñ
ó ð
ð& ‡�ˆOÓð,?¨sò ,?ó ð,?ð^ ‡�Ð$Ó%ð-Ð4ò -ó &ð-ð ×ÑÐ*Ó+ñwC ð wC¨wð wC¸sò wCó ,ðwCðt ×ÑÐ)Ó*ñLC ð LC¨gð LC¸cò LCó +ðLCð^ ×ÑÐ3Ó4ñ>-¨Sð >-¸ð >-ÐWfò >-ó 5ð>-ðB ×ÑÐ&Ó'ð Øñ	?Øð?àð?ð ð?ð ò	?ó (ñ?r@   