
    V|hT                         S SK rS SKrS SKrS SKrS SKrS SKrS SKrSSKJ	r	  SSK
Jr  SSKJrJr  SSKJr  SSKJrJr  SS	KJrJrJr  SS
KJr  SSKJr   " S S\5      r " S S\	5      rg)    N   )FileDownloader)HttpFD   )aes_cbc_decrypt_bytesunpad_pkcs7)Request)	HTTPErrorIncompleteRead)DownloadErrorRetryManagertraverse_obj)HTTPHeaderDict)ProgressCalculatorc                       \ rS rSrS r\rSrg)HttpQuietDownloader   c                     g N )selfargskargss      T/home/james-whalen/.local/lib/python3.13/site-packages/yt_dlp/downloader/fragment.py	to_screenHttpQuietDownloader.to_screen   s        r   N)__name__
__module____qualname____firstlineno__r   to_console_title__static_attributes__r   r   r   r   r      s     !r   r   c                       \ rS rSrSrS rSS jrS rS rS r	S	 r
S
 rSS jrS rS rS rS rS rS rS rS rS S SSSS.S jrSrg)
FragmentFD   a  
A base file downloader class for fragmented media (e.g. f4m/m3u8 manifests).

Available options:

fragment_retries:   Number of times to retry a fragment for HTTP error
                    (DASH and hlsnative only). Default is 0 for API, but 10 for CLI
skip_unavailable_fragments:
                    Skip unavailable fragments (DASH and hlsnative only)
keep_fragments:     Keep downloaded fragments on disk after downloading is
                    finished
concurrent_fragment_downloads:  The number of threads to use for native hls and dash downloads
_no_ytdl_file:      Don't use .ytdl file

For each incomplete fragment download yt-dlp keeps on disk a special
bookkeeping file with download state and metadata (in future such files will
be used for any incomplete download handled by yt-dlp). This file is
used to properly handle resuming, check download file consistency and detect
potential errors. The file has a .ytdl extension and represents a standard
JSON file of the following format:

extractor:
    Dictionary of extractor related data. TBD.

downloader:
    Dictionary of downloader related data. May contain following data:
        current_fragment:
            Dictionary with current (being downloaded) fragment data:
            index:  0-based index of current fragment among all fragments
        fragment_count:
            Total count of fragments

This feature is experimental and file format may change in future.
c                 H    U R                  S5        U R                  XXB5      $ )Nz{yt_dlp.downloader.FragmentFD.report_retry_fragment is deprecated. Use yt_dlp.downloader.FileDownloader.report_retry instead)deprecation_warningreport_retry)r   err
frag_indexcountretriess        r   report_retry_fragment FragmentFD.report_retry_fragment>   s*       "] 	^  WAAr   Nc                 T    U(       a  SU S3OSnU R                  SU SUS S35        g )N ; z
[download]z Skipping fragment dz ...)r   )r   r+   r*   s      r   report_skip_fragmentFragmentFD.report_skip_fragmentC   s1    #ajRC5(;Jq>NOr   c                 P    UR                  S5      nU(       a  [        US U5      $ U$ )Nhttp_headers)getr	   )r   	info_dicturlheaderss       r   _prepare_urlFragmentFD._prepare_urlG   s&    --/.5wsD'*>3>r   c                 H    U R                  U5        U R                  X5        g r   )_prepare_frag_download_start_frag_download)r   ctxr:   s      r    _prepare_and_start_frag_download+FragmentFD._prepare_and_start_frag_downloadK   s    ##C(!!#1r   c                 |    US   SL=(       a/    US   S:g  =(       a     U R                   R                  S5      (       + $ )NliveTtmpfilename-_no_ytdl_file)paramsr9   )r   rB   s     r   __do_ytdl_fileFragmentFD.__do_ytdl_fileO   s6    6{$&m3}+=+DmT[[__]lMmImmr   c                 b   SU;  d   eU R                  U R                  US   5      S5      u  p# [        R                  " UR	                  5       5      nUS   S   S   US'   SUS   ;   a  US   S   US'   UR                  5         g ! [
         a    S	US'    N"f = f! UR                  5         f = f)
Nytdl_corruptfilenamer
downloadercurrent_fragmentindexfragment_indexextra_stateT)sanitize_openytdl_filenamejsonloadsread	Exceptionclose)r   rB   stream_	ytdl_datas        r   _read_ytdl_fileFragmentFD._read_ytdl_fileR   s    S(((&&t'9'9#j/'JCP		

6;;=1I$-l$;<N$OPW$XC !	, 77%.|%<]%KM" LLN  	'"&C	' LLNs$   AB BB BB B.c                 L   U R                  U R                  US   5      S5      u  p# SSUS   00nSU;   a  US   US'   UR                  S5      b  US   US'   UR                  [        R
                  " SU05      5        UR                  5         g ! UR                  5         f = f)	NrO   wrR   rS   rT   rU   fragment_countrQ   )rV   rW   r9   writerX   dumpsr\   )r   rB   frag_index_streamr^   rQ   s        r   _write_ytdl_fileFragmentFD._write_ytdl_file_   s    #11$2D2DS_2UWZ[	&"S!12%J
 #,/,>
=)ww'(4/23C/D
+,##DJJj/I$JK##%##%s   AB B#c                    SUS   US   4-  nUU=(       d    UR                  S5      UUR                  S5      S.nSnUS   R                  R                  S	S
5      (       a   U R                  U R                  U5      5      nU=US'   US'   US   R	                  Xg5      u  pU	(       d  gUR                  S5      (       a  UR                  S5      US'   XaS'   g
)Nz	%s-Frag%drG   rT   r8   ctx_id)r;   r8   request_datark   r   dl
continuedlTfrag_resume_lenFfiletimefragment_filetimefragment_filename_sanitized)r9   rJ   filesize_or_none	temp_namedownload)r   rB   frag_urlr:   r<   rl   fragment_filenamefragment_info_dictro   successr^   s              r   _download_fragmentFragmentFD._download_fragmento   s    '3}+=sCS?T*UU#Dy}}^'D(ggh'	
 t9d33"33DNNCT4UVOIXX,-4E0FY''(9N
!!*--'9'='=j'IC#$->)*r   c                     UR                  S5      (       d  g  U R                  US   S5      u  p#X1S'   UR                  5       nUR	                  5         U$ ! [         a    UR                  S5      (       a   g e f = f)Nrr   rbrF   )r9   rV   FileNotFoundErrorrZ   r\   )r   rB   downfrag_sanitizedfrag_contents        r   _read_fragmentFragmentFD._read_fragment   s    ww455	#'#5#5c:W6XZ^#_ D
 .<)*yy{

 ! 	wwv	s   A  A:8A:c                     US   R                  U5        US   R                  5         U R                  U5      (       a  U R                  U5        U R                  R                  SS5      (       d  U R                  US   5        US	 g ! U R                  U5      (       a  U R                  U5        U R                  R                  SS5      (       d  U R                  US   5        US	 f = f)Ndest_streamkeep_fragmentsFrr   )re   flush_FragmentFD__do_ytdl_filerh   rJ   r9   
try_remove)r   rB   r   s      r   _append_fragmentFragmentFD._append_fragment   s    	3$$\2$$&""3''%%c*;;??#3U;;$A BC12	 ""3''%%c*;;??#3U;;$A BC12s   'B	 	A!C*c           
         UR                  SS5      (       d*  SUS   -  nUR                  SS5      nU(       a  USU-  -  nOSnU R                  S	U R                   S
U 35        U R	                  US   5        [        U R                  0 U R                  ESSSSSS.E5      nU R                  US   5      nSnU R                  U5      nUS:  a  SnUR                  USS.5        U R                  U5      (       Ga$  [        R                  R                  U R                  US   5      5      nU R                  R                  SS5      n	U	(       a  U(       a  U R!                  U5        UR                  S5      SL n
US   S:  =(       a    US:H  nU
(       d  U(       a@  U
(       a  SOSnU R#                  U S35        S=US'   nSU;   a  US	 U R%                  U5        OBU	(       d  U(       a  U R!                  U5        S=US'   nU R%                  U5        US   S:X  d   eU R'                  XV5      u  pUR                  UUUUS.5        g )NrF   F%dtotal_fragsad_fragsr    (not including %d ad)unknown (live)[] Total fragments: rO   T)
noprogresstestsleep_intervalmax_sleep_intervalsleep_interval_subtitleswbabrG   rT   rn   rN   rT   z.ytdl file is corruptz2Inconsistent state of incomplete fragment downloadz#. Restarting from the beginning ...)rm   r   rG   complete_frags_downloaded_bytes)
setdefaultr9   r   FD_NAMEreport_destinationr   ydlrJ   rt   rs   updater   ospathisfilerW   r`   report_warningrh   rV   )r   rB   total_frags_strr   rm   rG   	open_mode
resume_lenytdl_file_existsrn   
is_corruptis_inconsistentmessager   s                 r   r@   !FragmentFD._prepare_frag_download   s`   ~~fe,,"S%77Owwz1-H#;h#FF.O4<<.(;O;LMNJ0  ,
kk,
"#(),
  nnS_5	 **;7
>I 	

&
 	
 s##!ww~~d.@.@Z.QRt<J.$$S) WW^4<
"%&6"7!";"O
a3=/L  ''")#FGI9::C()J%,/))#. "',,S19::C()J%%c*+,111#'#5#5k#M 

&&/9
 	r   c                    ^ ^^^^^^ TS   nTS   mTR                  S5      mSUTS   TTS   TS   S.m[        R                  " 5       TS	'   [        U5      mUUUUU UU4S
 jnTS   R                  U5        TS	   $ )Nr   r   rk   downloadingrT   rO   rG   )statusdownloaded_bytesrT   rd   rO   rG   startedc                 b  > U S   S;  a  g T	(       d  TR                  S5      (       a  TS   TS'   Tb  U R                  S5      T:w  a  g TR                  S5      TS'   TR                  S5      TS'   TR                  TS'   U R                  S5      =(       d    S	nU R                  S
0 5      U S'   TS   (       dK  TS   U-   TS   S-   -  T	-  nUTl        TR	                  U R                  S5      5        TR                  TS'   O TR	                  U R                  S5      5        U S   S:X  a%  TS==   S-  ss'   TS   TS'   TR                  5         TR                  =TS'   TS'   TR                  R                  =TS'   TS'   TR                  R                  TS'   TR                  TT5        g )Nr   )r   finishedrd   rk   max_progressprogress_idxelapsedtotal_bytesr   r:   rx   rF   r   rT   r   r   total_bytes_estimater   speedeta)r9   r   poptotalr   thread_reset
downloadedr   smoothr   _hook_progress)
sfrag_total_bytesestimated_sizerB   rk   r:   progressr   stater   s
      r   frag_progress_hook;FragmentFD._start_frag_download.<locals>.frag_progress_hook   s   {"==377+;#<#<*-.>*?&'!aeeHo&?$'GGN$;E.!$'GGN$;E.!'//E) uu]38q&'eeK&<A"# v;:;>NN-.246AB  "0&8 9:08,-&8 9:{j(&'1,'(-.>(?$%%%'QYQdQddE$%,M(N,4NN,A,AAE'NS\#<<..E%Ly1r   rm   )r9   timer   add_progress_hook)	r   rB   r:   r   r   rk   r   r   r   s	   ```  @@@@r   rA   FragmentFD._start_frag_download   s    :;
-(" $ *!"23)J}-
 I%j1%	2 %	2N 	D	##$679~r   c                    US   R                  5         U R                  U5      (       a#  U R                  U R                  US   5      5        [        R                  " 5       US   -
  nUS   S:g  nU(       a  U R                  US   5      nOUS   nU(       d-  U(       a  U R                  US   5        U R                  S5        gU(       a  U R                  US   US   5        UR                  S	5      nU R                  R                  S
5      (       aY  U(       aR  [        R                  " [        5         [        R                  " US   [        R                  " 5       U45        S S S 5        U R                  UUUS   SUUR                  S5      UR                  S5      UR                  S5      S.U5        g! , (       d  f       NZ= f)Nr   rO   r   rG   rH   r   zThe downloaded file is emptyFrq   
updatetimer   rk   r   r   )r   r   rO   r   r   rk   r   r   T)r\   r   r   rW   r   rs   report_error
try_renamer9   rJ   
contextlibsuppressr[   r   utimer   )r   rB   r:   r   to_filer   rp   s          r   _finish_frag_download FragmentFD._finish_frag_download  s}   M  "s##OOD..s:?@))+I.m$+#44S5GH"#DEM 23<=OOC.J@ww23H{{|,,((3HHS_tyy{H.EF 4 	 0+J ggh'GGN3GGN3	
 		  43s   60F::
Gc                    SU;  a  SUS'   US   (       d*  SUS   -  nUR                  SS5      nU(       a  USU-  -  nOSnU R                  S	U R                   S
U 35        U R                  US   5      nUR	                  USS.5        g )NrF   Fr   r   r   r   r   r   r   r   rO   r   )r9   r   r   rt   r   )r   rB   r   r   rG   s        r   _prepare_external_frag_download*FragmentFD._prepare_external_frag_downloadA  s    CK6{"S%77Owwz1-H#;h#FF.O4<<.(;O;LMNnnS_5 	

&
 	r   c                 2   ^ ^^^ 0 mUUU 4S jmUUU 4S jnU$ )Nc                    > U T;  a<  TR                   R                  TR                  TU 5      5      R                  5       TU '   TU    $ r   )r   urlopenr=   rZ   )r;   
_key_cacher:   r   s    r   _get_key&FragmentFD.decrypter.<locals>._get_keyX  sD    *$"&(("2"243D3DYPS3T"U"Z"Z"\
3c?"r   c                   > Uc  g U R                  S5      nU(       a	  US   S:w  a  U$ UR                  S5      =(       d    [        R                  " SU S   5      nUR                  S5      =(       d    T" [        TS5      =(       d    US	   5      US'   TR                  R                  S
S5      (       a  U$ [        [        XS   U5      5      $ )Ndecrypt_infoMETHODzAES-128IVz>8xqmedia_sequenceKEY)hls_aesuriURIr   F)r9   structpackr   rJ   r   r   )fragmentr   r   ivr   r:   r   s       r   decrypt_fragment.FragmentFD.decrypter.<locals>.decrypt_fragment]  s    ##<<7L<#9Y#F##!!$'Z6;;vxHX?Y+ZB#/#3#3E#: $s&.|IGY/Z/q^jkp^q&r 
 {{vu--##4\PUCVXZ[\\r   r   )r   r:   r   r   r   s   `` @@r   	decrypterFragmentFD.decrypterU  s    
	#
	]   r   c           	      .  ^ ^^^ S/m[        U5      mTS:X  a  T R                  " US   0 TD6$ T R                  R                  SS5      nTS:  a  T R	                  T5        [        [        US5      5      nUUUU 4S jn " S S[        R                  R                  5      n[        R                  S	:X  a  S
 nOS nU4S jn/ n	[        U5       HS  u  n
u  pnU" [        R                  " UT-  5      5      nUR                  XZX" U5      X5      nU	R!                  X45        MU     SnU	 H&  u  p U=(       a    U" U5      nUR%                  SS9  M(     TS   (       d  U(       d  ["        eU$ ! ["         a    STS'    N=f = f! UR%                  SS9  f = f)z{
@params (ctx1, fragments1, info_dict1), (ctx2, fragments2, info_dict2), ...
        all args must be either tuple or list
Tr   r   concurrent_fragment_downloads).r   is_livec                 H   > TUS'   XS'   TR                   " XU40 TDUTS.D6$ )Nr   r   )tpeinterrupt_trigger)download_and_append_fragments)	idxrB   	fragmentsr:   r   r   kwargsr   r   s	        r   thread_funcFFragmentFD.download_and_append_fragments_multiple.<locals>.thread_func}  sD    ".C"%55	c-3c9<Pac cr   c                       \ rS rSrS rSrg)?FragmentFD.download_and_append_fragments_multiple.<locals>.FTPEi  c                     g r   r   )r   exc_typeexc_valexc_tbs       r   __exit__HFragmentFD.download_and_append_fragments_multiple.<locals>.FTPE.__exit__  s    r   r   N)r   r   r    r!   r  r#   r   r   r   FTPEr     s    r   r  ntc                       U R                  S5      $ ! [         a    e [        R                  R                   a     M>  f = f)Ng?)resultKeyboardInterrupt
concurrentfuturesTimeoutErrorfutures    r   future_resultHFragmentFD.download_and_append_fragments_multiple.<locals>.future_result  sB    !%}}S11, %--:: ! !s    (A A c                 "    U R                  5       $ r   )r  r  s    r   r  r    s    }}&r   c              3   @   >#    U  H  nTS   (       d    g Uv   M     g 7f)Nr   r   )fgfr   s     r   interrupt_trigger_iterQFragmentFD.download_and_append_fragments_multiple.<locals>.interrupt_trigger_iter  s      (+ s   Fwait)lenr   rJ   r9   _prepare_multiline_statusanyr   r	  r
  ThreadPoolExecutorr   name	enumeratemathceilsubmitappendr  shutdown)r   r   r   max_workersr   r   r  r  r  spinsr   rB   r   r:   r   jobr  r   r   s   ` `              @@r   &download_and_append_fragments_multiple1FragmentFD.download_and_append_fragments_multipleo  s   
 "F4y155tAwI&IIkkoo&EqI!**<8l4)<=>	c 	c	:%%88 	
 77d?!'	 09$,C,#)tyy|!;<=C**[s4J94UW`fCLL#$ 1@
 HC(6M#$6 $'  !#G##  % -',!!$- $'s$   1E..F =F?F  FFc                     g)NFr   )r   s    r   <lambda>FragmentFD.<lambda>  s    er   c                     U $ r   r   )contentr   s     r   r)  r*    s    Gr   )T)is_fatal	pack_funcfinish_funcr   r   c          
      j  ^ ^^^^^^ T R                   R                  SS5      (       d  S mUUUU 4S jmUUU 4S jn	T R                  T5      n
[        R                  " T R                   R                  SS5      TR                  SS5      -  5      nUS:  a  UU4S	 jnU=(       d    [
        R                  R                  U5       n UR                  X5       HI  u  pnTR                  UUS
.5        U	" U
" UT R                  T5      5      UT5      (       a  MA    S S S 5        g    S S S 5        OKU HE  nTS   (       d    O: T" UT5        U	" U
" UT R                  T5      5      US   T5      nU(       a  ME    g   Ub,  TS   R                  U" 5       5        TS   R!                  5         T R#                  TT5      $ ! [         a2    T R                  5         T R                  SSSS9  UR                  SS9  e f = f! , (       d  f       N= f! [         a    TR                  S5      (       a     M  e f = f)Nskip_unavailable_fragmentsTc                     g)NTr   )r^   s    r   r)  :FragmentFD.download_and_append_fragments.<locals>.<lambda>  s    r   c           
      p  >^^^ T
S   (       d  g U S   =mTS'   S TS'   [        T	R                  S5      5      nU R                  S5      nU(       a  SUS   US	   S
-
  4-  US'   T" U R                  S5      =(       d    TS
-
  5      mUUUU4S jn[        TR                  R                  S5      U5       HF  n U R                  S5      TS'   TR	                  TU S   T	UT	R                  S5      5      (       d    g MH     g ! [
        [        4 a  nXel         S nAMg  S nAf[         a    T(       a  e  M  f = f)Nr   r+   rT   
last_errorr8   
byte_rangezbytes=%d-%dstartendr   RangerS   c                 v   > T(       a  X:  a  TS   R                  5         TR                  XUTT5        U TS'   g )Nr   r5  )r\   r)   )r*   r,   r-   rB   fatalr+   r   s      r   error_callback[FragmentFD.download_and_append_fragments.<locals>.download_fragment.<locals>.error_callback  s9    U_&,,.!!#gz5I$'L!r   fragment_retriesrd   r;   rl   )	r   r9   r   rJ   rz   r
   r   errorr   )r   rB   r<   r6  r<  retryr*   r;  r+   r:   r   r-  r   s    `     @@r   download_fragmentCFragmentFD.download_and_append_fragments.<locals>.download_fragment  sC   $Q'19,1GGJ-. $C$Y]]>%BCG!l3J#0Jw4GTYIZ]^I^3_#_  X\\'2FzA~GE( ( &dkkoo6H&I>Z
,4LL9I,JC()22%)WimmTbFce ee [ ">2 "%K$  s   9A D  D5DD54D5c                    > U (       a  TR                  UT" X5      5        gT" US-
  5      (       d  TR                  US5        gUS   R                  5         TR                  SU S35        g)Nr   zfragment not foundr   z	fragment z not found, unable to continueFT)r   r5   r\   r   )r   r+   rB   r-  r.  r   s      r   append_fragmentAFragmentFD.download_and_append_fragments.<locals>.append_fragment  su    %%c9\+NO  j1n--))*6JK
  M"((*!!Ij\9W"XYr   r   r   r   c                 `   > TR                  5       nT" X5        X S   UR                  S5      4$ )Nr+   rr   )copyr9   )r   ctx_copyrB   rA  s     r   rz   DFragmentFD.download_and_append_fragments.<locals>._download_fragment  s0    88:!(5,!7Fc9dddr   )rr   rT   Fz;Interrupted by user. Waiting for all threads to shutdown...)is_errortbr  r   r+   r   r   )rJ   r9   r   r  r  r	  r
  r  mapr   r   r  _finish_multiline_statusr   r"  re   r   r   )r   rB   r   r:   r-  r.  r/  r   r   rD  r   r#  rz   poolr   r+   frag_filenamer  rA  s   `` ```  `         @r   r   (FragmentFD.download_and_append_fragments  s&   
 {{;TBB%H	 	B		  >>)4iiKKOO;Q?#''.Z[B\\^?e
 J
**==kJJd?CxxHZ?f;m

;H.8$   //?$J]J]^aJb/ceoqtuu#( KJ?f KJ  &(+%h4,(43F3Fs3KLhWcNdfikF v  & "$$[]3$$&))#y991 ) 113%%U`ejo & qMMuM- KJ. )  }}Y//s=   G;AF<F<$F<,H<<G88G;;
H	 H20H2r   r   )NN)r   r   r    r!   __doc__r.   r5   r=   rC   r   r`   rh   rz   r   r   r@   rA   r   r   r   r&  r   r#   r   r   r   r%   r%      s|    !FB
P?2n& *	3BH:x"H( 4>B ;L3$_: _:r   r%   )concurrent.futuresr	  r   rX   r  r   r   r   commonr   httpr   aesr   r   
networkingr	   networking.exceptionsr
   r   utilsr   r   r   utils.networkingr   utils.progressr   r   r%   r   r   r   <module>r[     sO        	   "  4   = = = - /!& !t: t:r   