
    uki                         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 ddl	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 ddlm Z m!Z!  G d d	e      Z" G d
 de"      Z#d Z$ G d de"      Z% G d de"      Z& G d de&      Z' G d de'      Z( G d de&      Z) G d de&      Z* G d de'      Z+ G d de"      Z,y)    N   )InfoExtractor   )	HTTPError)ExtractorErrorUserNotLivebase_url
clean_htmldict_getfloat_or_noneint_or_nonejoin_nonemptymake_archive_idparse_durationparse_iso8601parse_qs	qualitiesstr_or_nonetry_getunified_timestampupdate_url_queryurl_or_noneurljoin)traverse_objvaluec                       e Zd ZdZdZdZdZdZdZddd	d
ddddddddZ	e
d        Zd Zd ZddZddZd Zd ZddZy)TwitchBaseIEz&https?://(?:(?:www|go|m)\.)?twitch\.tvzhttps://api.twitch.tvzhttps://usher.ttvnw.netzhttps://www.twitch.tv/loginz https://passport.twitch.tv/logintwitch@016e1e4ccee0eb4698eb3bf1a04dc1c077fb746c78c82bac9a8f0289658fbd1a@67004f7881e65c297936f32c75246470629557a393788fb5a69d6d9a25a8fd5f@90c33f5e6465122fba8f9371e2a97076f9ed06c6fed3788d002ab9eba8f91d88@1844261bb449fa51e6167040311da4a7a5f1c34fe71c71a3e0c4f551bc30c698@5247910a19b1cd2b760939bf4cba4dcbd3d13bdf8c266decd16956f6ef814077@b57f9b910f8cd1a4659d894fe7550ccc81ec9052c01e438b290fd66a040b9b93@e1edae8122517d013405f237ffcc124515dc6ded82480a88daef69c83b53ac01@9515480dee68a77e667cb19de634739d33f243572b007e98e67184b1a5d8369f@45111672eea2e507f8ba44d101a61862f9c56b11dee09a15634cb75cb9b9084d@71835d5ef425e154bf282453a926d99b328cdc5e32f36d3a209d0f4778b41203@07e99e4d56c5a7c67117a154777b0baf85a5ffefa393b213f4bc712ccaf85dd6)CollectionSideBarFilterableVideoTower_VideosClipsCards__UserShareClipRenderStatusChannelCollectionsContentStreamMetadataComscoreStreamingQueryVideoPreviewOverlayVideoMetadata$VideoPlayer_ChapterSelectButtonVideo"VideoPlayer_VODSeekbarPreviewVideoc                 4    | j                  ddgdd      d   S )N	client_idue6666qo983tsx6so1t0vnawi233waTwitchT)ie_key	casesenser   )_configuration_arg)selfs    R/home/cdr/jupyterlab/.venv/lib/python3.12/site-packages/yt_dlp/extractor/twitch.py
_CLIENT_IDzTwitchBaseIE._CLIENT_ID9   s3    &&:;HX\ ' ^^_a 	a    c           	      .    d  fd} j                   j                  d d      \  }}d|v r t        |              |||d|| j                  d      \  }}|sy t	        j
                  d|        j                  d      } |||d	|d
d       y y )Nc                 "    t        d|  d      )NzUnable to login. Twitch said: Texpected)r   )messages    r=   failz)TwitchBaseIE._perform_login.<locals>.fail?   s     0	:TK Kr?   c                    j                  |       }|j                  |       |j                  }j                  d| dj                  d      }t        ||      }|ddd}j                  |d |t        j                  |      j                         |d	      }t        |d
      }	|	r |	       d|j                  dd      v ryt        ||j                  d      xs |d         }
j                  |
d d|      S )Nz&<form[^>]+action=(["\'])(?P<url>.+?)\1zpost urlurl)defaultgroupzhttps://www.twitch.tvtext/plain;charset=UTF-8)RefererOriginContent-Typei  )dataheadersexpected_status)errorerror_description
error_codezAuthenticated successfullyrD    )NNredirectredirect_pathzDownloading login redirect page)rO   )_hidden_inputsupdaterG   _search_regex_LOGIN_POST_URLr   _download_jsonjsondumpsencoder   get_download_webpage_handle)pageurlhnoterN   formpage_urlpost_urlrO   responserQ   redirect_urlrE   r<   s              r=   
login_stepz/TwitchBaseIE._perform_login.<locals>.login_stepC   s   &&t,DKKxxH))94D$8$8 * GH x2H $1 :G **$4::d+;+B+B+D + 6H X'STEU+x||Ir/JJ!"Z(EH_,EGL 00d$E 1 ! !r?   zDownloading login pageblacklist_messagez
Logging in)usernamepasswordr6   z$(?i)<form[^>]+id="two-factor-submit"ztwo-factor authentication tokenzSubmitting TFA tokentrue)authy_tokenremember_2fa)r`   _LOGIN_FORM_URLr
   r>   research_get_tfa_info)	r<   rk   rl   ri   
login_pagehandleredirect_page	tfa_tokenrE   s	   `       @r=   _perform_loginzTwitchBaseIE._perform_login>   s    	K	!B "::  $(@B
F *,J'( *$$!__/!v 99<mLX**+LMI}f.D( &G  Yr?   c                     	 t        d |D              }d|d<   y # t        $ r& |D ]  }d|d   v s|j                  ddd         Y y w xY w)Nc              3   2   K   | ]  }|d    dk(  s|  yw)	format_idSourceN ).0fs     r=   	<genexpr>z.TwitchBaseIE._prefer_source.<locals>.<genexpr>   s     K+(0J!Ks   
   qualityz	/chunked/rG   r|   )r   format_note)nextStopIterationrX   )r<   formatssourcer   s       r=   _prefer_sourcezTwitchBaseIE._prefer_source~   sb    		KWKKF "F9 	 !E(*HH#%'/ 	s    A	A	A	c                     d| j                   d}| j                  d      j                  d      }|rd|j                  z   |d<   | j	                  d||t        j                  |      j                         ||      S )	NrJ   )rM   z	Client-IDhttps://gql.twitch.tv
auth-tokenzOAuth Authorizationzhttps://gql.twitch.tv/gql)rN   rO   fatal)r>   _get_cookiesr_   r   r[   r\   r]   r^   )r<   video_idopsrc   r   rO   gql_auths          r=   _download_base_gqlzTwitchBaseIE._download_base_gql   s    6
 $$%<=AA,O'/(..'@GO$""'4C'')5 # * 	*r?   c                 j    |D ]  }dd| j                   |d      di|d<    | j                  |||      S )NpersistedQueryr   operationName)version
sha256Hash
extensions)_OPERATION_HASHESr   )r<   r   r   rc   r   ops         r=   _download_gqlzTwitchBaseIE._download_gql   sR     	B  "&"8"8O9L"M# B|	 &&xd;;r?   c                 b    | d}dd|d|d|di}| j                  ||d| d      d	   |   S )
NPlaybackAccessTokenqueryz{
              z(
                z: "a  ",
                params: {
                  platform: "web",
                  playerBackend: "mediaplayer",
                  playerType: "site"
                }
              )
              {
                value
                signature
              }
            }Downloading z access token GraphQLrN   )r   )r<   r   
token_kind
param_namemethodr   s         r=   _download_access_tokenz#TwitchBaseIE._download_access_token   sa    <23 J2
  &&c:,&;<>>DFFLN 	Nr?   c                 F    |rt        j                  dd|      ddd|igS d S )Nz\d+x\d+(\.\w+)($|(?=[?#]))z0x0\g<1>r   rG   
preferencerG   )rq   sub)r<   	thumbnails     r=   _get_thumbnailszTwitchBaseIE._get_thumbnails   sB     	 667iP
 9
 	"
 "	"r?   c                    	 | j                  | j                   d| d| d|ddddt        j                  dd      ddd	d||d

      }|D ]y  }|j!                  d      r9|d   j)                  d      r%|j+                  di       j-                  dd dgi       |sP|j+                  di       j-                  d!d"d#gi       d|d$<   { |S # t        $ r"}t        |j                  t              rA|j                  j                  dk7  s(|j                  j                  j                  d      dk7  r t        |j                  j                  j                         t        j                  hdt        hf      xs i }|j!                  d      dv rFd}	| j#                  d      j!                  d      rt	        d|	 d      | j%                  d|	        t'        dd|d      x}
rt	        |
d       d }~ww xY w)%N/z.m3u8mp4rm   i@B i web	twitchwebzav1,h265,h264)
allow_sourceallow_audio_onlyallow_spectrepplatformplayersupported_codecsplaylist_include_frameratesigtokenr   i  zcontent-typezapplication/jsonr   rS   )vod_manifest_restrictedunauthorized_entitlementsz&access to this subscriber-only contentr   r   zYour account does not have TrB   z,You must be logged into an account that has rQ   z: )	from_dictdelimvcodecav01downloader_optionsffmpeg_args_outz-fffmpeg_argsz-live_start_index0is_from_start)_extract_m3u8_formats_USHER_BASErandomrandintr   
isinstancecauser   statusrg   
get_headerr   readr\   loadsdictr_   r   raise_login_requiredr   
startswith
setdefaultrX   )r<   pathr   r   	signaturelive_from_startr   e
error_info
common_msg	error_msgfmts               r=   _extract_twitch_m3u8_formatsz)TwitchBaseIE._extract_twitch_m3u8_formats   s	   	00##$AdV1XJe<h$*(.%+: %)(728$"V 1 G@  	,Cwwx S]%=%=f%E3R8??ARUY[`Ta@bc3R8??QdfiPj@kl'+O$	, 7  	qww	277>>S(77##..~>BTT%agg&6&6&;&;&=aRVQW?XY_]_J~~l+/ggE
$$%<=AA,O(+Fzl)S^bcc)),XYcXd*ef),:]abbyb$Y>>#	s   AC	 	
G5DG00G5N)T)F)__name__
__module____qualname___VALID_URL_BASE	_API_BASEr   rp   rZ   _NETRC_MACHINEr   propertyr>   rx   r   r   r   r   r   r   r}   r?   r=   r   r   "   s    ?O'I+K3O8ON `'i^!c%g\"da[0r.p a a>@
*<N,"*r?   r   c                      e Zd ZdZdZddddddd	d
ddedddddgddddiddddddddddded
ddidd d!dd"d#dd"d$dd"d%dd"d&dd"d'd(ddd)ddd*d+dd,ddd,d-d.dd-d)d/dgdded0ddidd1d'd(d2d3dd)ddd*d+dd,ddd,d-d.dd-d)d/dgddeeed4d3dd5d6d7d8d9dd:d;ddd<d=dd;ddgdded0ddid>gd?d@dd"gZdA ZdB ZdC Z	dD Z
dE ZdF ZyG)HTwitchVodIEz
twitch:vodal  (?x)
                    https?://
                        (?:
                            (?:(?:www|go|m)\.)?twitch\.tv/(?:[^/]+/v(?:ideo)?|videos)/|
                            player\.twitch\.tv/\?.*?\bvideo=v?|
                            www\.twitch\.tv/[^/]+/schedule\?vodID=
                        )
                        (?P<id>\d+)
                    z0http://www.twitch.tv/riotgames/v/6528877?t=5m10sv6528877r   zLCK Summer Split - Week 6 Day 1zre:^https?://.*\.jpg$i8C  iV_U20150624z
Riot Games	riotgamesi6  r   zLeague of Legends
start_timeend_timetitlewas_live)idextr   r   duration	timestampupload_dateuploaderuploader_id
view_countr   chapterslive_statusskip_downloadTrG   	info_dictparamsz(http://www.twitch.tv/belkao_o/v/11230755	v11230755Untitled Broadcastif  iU20150816BelkAO_obelkao_o)
r   r   r   r   r   r   r   r   r   r   zHTTP Error 404: Not FoundrG   r   r   skipz/http://player.twitch.tv/?t=5m10s&video=v6528877rG   only_matchingz$https://www.twitch.tv/videos/6528877z+https://m.twitch.tv/beagsandjam/v/247478721z2https://www.twitch.tv/northernlion/video/291940395z)https://player.twitch.tv/?video=480452374z&https://www.twitch.tv/videos/635475444
v635475444i{-  i;^20200529i=  iR  zLegends of RuneterraArt)r   r   r   r   r   r   r   r   r   r   r   r   Storyboardssb0mhtml)r   r{   r   r   r   r   r   r   r   r   r   r   r   columnsrows)formatr   )rc   rG   r   r   zVOD with single chapterz'https://www.twitch.tv/videos/1536751224v1536751224z8Porter Robinson Star Guardian Stream Tour with LilyPichui   iS(b20220719z;Unable to download JSON metadata: HTTP Error 403: Forbidden)rc   rG   r   r   expected_warningsz8https://www.twitch.tv/tangotek/schedule?vodID=1822395420c           	          | j                  |dd|dddd|dddd|ddgd	      }t        |d
d      }|t        d| dd      t        |d      |d<   t        |ddddt        hfd      |d<   |S )Nr2   rT   )channelLoginvideoIDr   	variablesr3   F)includePrivater  r4   z#Downloading stream metadata GraphQL).rN   video)get_allzVideo  does not existTrB   ).rN   r  momentsedges.noder  .rN   r  seekPreviewsURL
storyboard)r   r   r   r   )r<   item_idrN   r  s       r=   _download_infozTwitchVodIE._download_info  s    !!!0$&& "H&+& "F&+&& 2)3, T#95I= 6'/!BTRR'.efi*3):[MJTY[l r?   c                    |j                  d      }|dk(  rd}n
|dk(  rd}nd }d}t        |      }g }|j                  d      }t        |t              rE|j	                         D ]2  \  }}	t        |	      }	|	s||vr|j                  |	 ||      d       4 |d	   |j                  d
      xs d|j                  d      t        |j                  d            ||j                  di       j                  d      |j                  di       j                  d      t        |j                  d            t        |j                  d            |ddS )Nr   	recordingTrecordedF)smallmediumlargepreviewr   _idr   r   descriptionlengthchanneldisplay_namenamerecorded_atviews)r   r   r(  r   
thumbnailsr   r   r   r   is_liver   )	r_   r   r   r   itemsr   appendr   r   )
r<   infor   r0  
_QUALITIESquality_keyr/  r&  thumbnail_idthumbnail_urls
             r=   _extract_infozTwitchVodIE._extract_info  sM   (#[ Gz!GG1

+
((9%gt$/6}} 	+m +M :$z1!!("-l";# 	 u+XXg&>*>88M2#DHHX$67$B/33NC88Ir266v>&txx'>?%dhhw&78
 	
r?   c              #   V  K   |j                  d      st        |d      }|rd|i y |d   D ]w  }t        |j                  d      d      }t        |j                  d      d      }t        |j                  d            }||| j	                  d| |       m|||z   |d	 y y w)
Nr  )gamedisplayNamer   positionMillisecondsi  durationMillisecondsr(  z2Important chapter information missing for chapter r   )r_   r   r   r   report_warning)r<   r3  r  r:  momentr   r   r,  s           r=   _extract_chapterszTwitchVodIE._extract_chapters  s     xx	"&=>Do%9o 	F$VZZ0F%GNJ"6::.D#EtLHvzz-89D!X%5##&XY]X^$_ahi(&1 	s   B'B)c                 b   |j                  d      xs |}|d   dk7  rd| }t        |j                  d            }d }|r/t        j                  d|      r|j                  d      dk(  }d }nd}||j                  d	      xs d
|j                  d      t	        |j                  d            | j                  |      t        |d t              t        |d t              t        |j                  d            t	        |j                  d            t        | j                  ||            |ddS )Nr   r   vpreviewThumbnailURLz/404_processing_[^.?#]+\.pngbroadcastTypeARCHIVEFr   r   r(  lengthSecondsc                     | d   d   S )Nownerr;  r}   xs    r=   <lambda>z/TwitchVodIE._extract_info_gql.<locals>.<lambda>  s    '
=0I r?   c                     | d   d   S )NrH  loginr}   rI  s    r=   rK  z/TwitchVodIE._extract_info_gql.<locals>.<lambda>  s    1W:g3F r?   publishedAt	viewCountT)r   r   r(  r   r/  r   r   r   r   r   r0  r   )r_   r   rq   findallr   r   r   strr   listr@  )r<   r3  r  vod_idr   r0  s         r=   _extract_info_gqlzTwitchVodIE._extract_info_gql  s   $*7!9\F)> ?@	zz99E ((?3y@ 	 XXg&>*>88M2#DHH_$=>..y9&I3O"4)FL*488M+BC%dhh{&;<T33D'BC
 	
r?   c              #   r  K   |r|sy | j                  ||dd      xs g }|j                  d d       t        |      }t        |      D ]  \  }}t	        |j                  d            }|j                  d      }	|	r|s6|t        |	      z  }
d	| d
ddddt        ||	d         t	        |j                  d            t	        |j                  d            ||z  t	        |j                  d            t	        |j                  d            |	D cg c]  }t        ||      |
d c}d  y c c}w w)Nz$Downloading storyboard metadata JSONFr   c                 >    t        | j                  d            xs dS )Nwidthr   )r   r_   rI  s    r=   rK  z1TwitchVodIE._extract_storyboard.<locals>.<lambda>!  s    AEE'N ; @q r?   T)keyreversecountimagessbr  r	  noner   rX  heightr  cols)rG   r   )r{   r   r   protocolacodecr   rG   rX  r_  fpsr  r
  	fragments)r[   sortr	   	enumerater   r_   lenr   )r<   r  storyboard_json_urlr   specbaseisr[  r\  fragment_durationr   s               r=   _extract_storyboardzTwitchVodIE._extract_storyboard  sB    2""#6Agot"u{y{ 			@$	O+,dO 	DAqg/EUU8_Fu (3v; 6!!X+#  tVAY/$QUU7^4%aeeHo6x'#AEE&M2&quuV}5 %&  #4. 1 & 	&&s   DD7D2(D7c           	         | j                  |      }| j                  |      }| j                  ||      }| j                  |dd      }| j	                  d||d   |d   | j                  d            }|j                  | j                  ||j                  d      |j                  d	                   | j                  |       ||d
<   t        j                  j                  |      }t        j                  j                  |j                        }d|v rt        |d   d         |d<   |j                  d      %dt!        d| dd| j"                  i      ddgi|d<   |S )Nr  r   vodr   r   r   )r   r  r   r   tr   r   r   rechatz https://api.twitch.tv/v5/videos/z	/commentsr6   r\   )rG   r   	subtitles)	_match_idr  rT  r   r   	get_paramextendrn  r_   r   urllibparseurlparser   r   r   r   r>   )	r<   rG   rS  r  r3  access_tokenr   
parsed_urlr   s	            r=   _real_extractzTwitchVodIE._real_extract<  sh   $##F+%%eV42267DI336<0,{2K NN+<= 4 ? 	t//		,8OQUQYQYZdQefgG$!Y\\**3/
%%j&6&67%<!/c
1!>D88K ,+:6()L'O " !D r?   N)r   r   r   IE_NAME
_VALID_URLint_TESTSr  r8  r@  rT  rn  r|  r}   r?   r=   r   r      sv   GJ B61#%$& #$ %0 &'
. T
/: :)1#%"%
 T
 ,'* A 6 = D ; 8!$&#% #$ #0 #& $3 #' %"" &19
> T
A#H 7!$&#% #$ #0 #& $3 #' %"" &1? 
D !
I(R *8O$&#% #$ $0 &1%
* T
 \\58 JIgFRB#
J*
>Br?   r   c                 0   t        | t              sJ | j                  d      }|sy dt        j	                         d|z   d| | j                  d      | j                  d      t        | j                  d            t        | j                  d            d	S )
Nr   url_transparentrB  https://www.twitch.tv/videos/r   rC  rF  rO  )_typer9   r   rG   r   r   r   r   )r   r   r_   r   r9   r   r   r  r   s     r=   _make_video_resultr  ^  s    dD!!!xx~H"$$&Hn.xj9'"XX34!$((?";<!$((;"78	 	r?   c                   2    e Zd ZdZdZddddddgZd	Zd
 Zy)TwitchCollectionIEztwitch:collectionz@https?://(?:(?:www|go|m)\.)?twitch\.tv/collections/(?P<id>[^/]+)z0https://www.twitch.tv/collections/o9zZer3IQBhTJwo9zZer3IQBhTJwzPlaythrough Archivesr   r      rG   r   playlist_mincountr*   c                    | j                  |      }| j                  || j                  d|idgd      d   d   d   }|j                  d      }g }|d   d	   D ]T  }t	        |t
              s|j                  d
      }t	        |t
              s6t        |      }|sD|j                  |       V | j                  |||      S )NcollectionIDr  zDownloading collection GraphQLr   rN   
collectionr   r1  r  r  playlist_idplaylist_title)	rt  r   _OPERATION_NAMEr_   r   r   r  r2  playlist_result)	r<   rG   collection_idr  r   entriesedger  r  s	            r=   r|  z TwitchCollectionIE._real_extract}  s    s+''!%!5!5,m<  -.
 /01
 289
 :FG
 w'w'0 	&DdD)88F#DdD)&t,Eu%	& ##u $ F 	Fr?   N)r   r   r   r}  r~  r  r  r|  r}   r?   r=   r  r  o  s8    !GTJA"+
   F *OFr?   r  c                       e Zd ZdZd Zy)TwitchPlaylistBaseIEd   c           	   '     K   d} | j                   |g| }| j                   dt        j                  d      D ]-  }|j	                         }| j
                  |d<   |r||d<   | j                  || j                  |dgd| j                   d| d	
      }|s yt        |fdt              }|s y|D ]  }	t        |	t              s|	j                  d      | j                  k7  r3|	j                  d      }
t        |
t              sU|
j                  d      | j                  k7  rt| j                  |
      }|s|	j                  d      }|  |rt        |t               r. y yw)z
        Subclasses must define _make_variables() and _extract_entry(),
        as well as set _OPERATION_NAME, _ENTRY_KIND, _EDGE_KIND, and _NODE_KIND
        Nrl  r   limitcursorr  r   zs GraphQL page FrV  c                 &    | d   d   d      d   S )Nr   rN   userr  r}   )rJ  entries_keys    r=   rK  z/TwitchPlaylistBaseIE._entries.<locals>.<lambda>  s    !VV 4[ A' J r?   
__typenamer  )_make_variables_ENTRY_KIND	itertoolsr[  copy_PAGE_LIMITr   r  
_NODE_KINDr   rR  r   r   r_   
_EDGE_KIND_extract_entryrQ  )r<   channel_nameargsr  variables_commonpage_numr  ra   r  r  r  entryr  s               @r=   _entrieszTwitchPlaylistBaseIE._entries  s    
 /4//DtD))*!,!* !	H(--/I!%!1!1Ig&,	(#%%%)%9%9!*   t/xjI & D JDRE  !$-88L)T__<xx'!$-88L)T__<++D1!XXh/FK  FC!8C!	s   D<E/ )E/+E/N)r   r   r   r  r  r}   r?   r=   r  r    s    K)r?   r  c                   ,    e Zd ZdZdZdZdZed        Zy)TwitchVideosBaseIEr+   r  	VideoEdgeVideoc                 *    | ||j                         dS )N)channelOwnerLoginrD  	videoSort)upper)r  broadcast_typere  s      r=   r  z"TwitchVideosBaseIE._make_variables  s     ".+
 	
r?   N)	r   r   r   r  r  r  r  staticmethodr  r}   r?   r=   r  r    s(    3OKJJ
 
r?   r  c                   T    e Zd ZdZdZddddddd	dd
ddddddddddddddddddddddddddddddddddddg	Z ej                  dddg      Z ed d!      Z	 ed"d#       ed$d%       ed&d'       ed(d)      e	d*Z
d+Zed,d-Ze fd.       Zed/        Zd0 Z xZS )1TwitchVideosIEztwitch:videoszGhttps?://(?:(?:www|go|m)\.)?twitch\.tv/(?P<id>[^/]+)/(?:videos|profile)z0https://www.twitch.tv/spamfish/videos?filter=allspamfishz$spamfish - All Videos sorted by Dater  i  r  z;https://www.twitch.tv/spamfish/videos?filter=all&sort=viewsz'spamfish - All Videos sorted by Populari  z5https://www.twitch.tv/spamfish/videos?filter=archivesz)spamfish - Past Broadcasts sorted by Date   z7https://www.twitch.tv/spamfish/videos?filter=highlightsz$spamfish - Highlights sorted by Datez>https://www.twitch.tv/esl_csgo/videos?filter=uploads&sort=timeesl_csgoz!esl_csgo - Uploads sorted by Date   z;https://www.twitch.tv/spamfish/videos?filter=past_premieresz(spamfish - Past Premieres sorted by Dater   z)https://www.twitch.tv/spamfish/videos/allTr  z'https://m.twitch.tv/spamfish/videos/allz%https://www.twitch.tv/spamfish/videos	BroadcasttypelabelNz
All VideosrE  zPast Broadcasts	HIGHLIGHT
HighlightsUPLOADUploadsPAST_PREMIEREzPast Premieres)archives
highlightsuploadspast_premieresallDatePopular)timer.  c                 d    t        fdt        t        fD              rdS t        |         S )Nc              3   @   K   | ]  }|j                          y wNsuitabler~   ierG   s     r=   r   z*TwitchVideosIE.suitable.<locals>.<genexpr>'  s      0Br{{3' 0   F)anyTwitchVideosClipsIETwitchVideosCollectionsIEsuperr  clsrG   	__class__s    `r=   r  zTwitchVideosIE.suitable$  s@      0'-3/ 0 0  	, W%c*		,r?   c                     t        |       S r  )r  )r  s    r=   r  zTwitchVideosIE._extract_entry,  s    !$''r?   c                    | j                  |      }t        |      }|j                  ddg      d   }|j                  ddg      d   }| j                  j                  || j                        }| j                  | j                  ||j                  |      || d|j                   d| j                  j                  || j                               S )	Nfilterr  r   re  r  z - z sorted by r  )rt  r   r_   _BROADCASTS_DEFAULT_BROADCASTr  r  r  r  
_SORTED_BY_DEFAULT_SORTED_BY)r<   rG   r  qsvideo_filterre  	broadcasts          r=   r|  zTwitchVideosIE._real_extract0  s    ~~c*c]vvh03vvfvh'*$$((t7N7NO	##MM,	=$.IOO#4 5!__00t7N7NOPR	 $ T 	Tr?   )r   r   r   r}  r~  r  collections
namedtupler  r  r  r  r  classmethodr  r  r  r|  __classcell__r  s   @r=   r  r    s~   G[J B;
 ! M>
 ! G@
  	 I;
 ! P8
 	 M?
 	 ; 9 7s<F| '&&{VW4EFI"46i):;\:Xy1#O5EF!K  "J
 , , ( (Tr?   r  c                       e Zd ZdZdZddddddd	d
dgZ ej                  dddg      Z edd      Z	 edd      e	 edd       edd      dZ
dZdZdZdZdZed        Zed        Zd Zy) r  ztwitch:videos:clipsz[https?://(?:(?:www|go|m)\.)?twitch\.tv/(?P<id>[^/]+)/(?:clips|videos/*?\?.*?\bfilter=clips)z<https://www.twitch.tv/vanillatv/clips?filter=clips&range=all	vanillatvzvanillatv - Clips Top Allr  r   r  z=https://www.twitch.tv/dota2ruhub/videos?filter=clips&range=7dTr  Clipr  r  	LAST_WEEKzTop 7DLAST_DAYzTop 24H
LAST_MONTHzTop 30DALL_TIMEzTop All)24hr7d30dr     r,   clipClipEdgec                     | d|idS )Nr  )rM  criteriar}   )r  channel_filters     r=   r  z#TwitchVideosClipsIE._make_variables`  s     ".
 	
r?   c                    t        | t              sJ t        | j                  d            }|sy dt        j                         | j                  d      || j                  d      | j                  d      t        | j                  d            t        | j                  d            t        | j                  d            | j                  d	      d

S )NrG   r  r   r   thumbnailURLdurationSeconds	createdAtrO  language)
r  r9   r   rG   r   r   r   r   r   r  )	r   r   r   r_   TwitchClipsIEr9   r   r   r   )r  clip_urls     r=   r  z"TwitchVideosClipsIE._extract_entryi  s    $%%%txx/&#**,((4.XXg&.1%dhh/@&AB*488K+@A%dhh{&;<,
 	
r?   c                 ,   | j                  |      }t        |      }|j                  ddg      d   }| j                  j                  || j                        }| j                  | j                  ||j                        || d|j                         S )Nranger  r   z	 - Clips r  )	rt  r   r_   _RANGE_DEFAULT_CLIPr  r  r  r  )r<   rG   r  r  
date_ranger  s         r=   r|  z!TwitchVideosClipsIE._real_extract|  s    ~~c*c]VVGdV,Q/
{{z4+=+=>##MM,4$*^9TZZLA $ C 	Cr?   N)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  >  s    #GoJ N0
  OF ";!!&8W*=>Dh/MZ+L),J	*	F K(OKJJ
 
 
 
$Cr?   r  c                   n    e Zd ZdZdZddddddd	d
ddddgZdZdZdZdZ	e
d        Ze
d        Zd Zy)r  ztwitch:videos:collectionszWhttps?://(?:(?:www|go|m)\.)?twitch\.tv/(?P<id>[^/]+)/videos/*?\?.*?\bfilter=collectionsz8https://www.twitch.tv/spamfish/videos?filter=collectionsr  zspamfish - Collectionsr     r  z:https://www.twitch.tv/monstercat/videos?filter=collections
monstercatzmonstercat - Collections   r.   r  CollectionsItemEdge
Collectionc                 
    d| iS )N
ownerLoginr}   )r  s    r=   r  z)TwitchVideosCollectionsIE._make_variables  s     ,
 	
r?   c                 \   t        | t              sJ | j                  d      }|sy dt        j	                         |d| | j                  d      | j                  d      t        | j                  d            t        | j                  d            t        | j                  d            d		S )
Nr   r  z"https://www.twitch.tv/collections/r   r   rF  	updatedAtrO  )	r  r9   r   rG   r   r   r   r   r   )r   r   r_   r  r9   r   r   r   )r  r  s     r=   r  z(TwitchVideosCollectionsIE._extract_entry  s    $%%%&(//17GXXg&.1%dhh&?@*488K+@A%dhh{&;<

 
	
r?   c                 p    | j                  |      }| j                  | j                  |      || d      S )Nz - Collectionsr  )rt  r  r  )r<   rG   r  s      r=   r|  z'TwitchVideosCollectionsIE._real_extract  s@    ~~c*##MM,'\*^>: $ < 	<r?   N)r   r   r   r}  r~  r  r  r  r  r  r  r  r  r|  r}   r?   r=   r  r    s    )GkJ J-
  L/
  F" 2OK&JJ
 

 
 
"<r?   r  c                        e Zd ZdZdZddddddd	d
dddeddd	idddd	ddd	ddd	ddd	ddddddd	dddddddd dd!id"gZd#Ze fd$       Z	e
d%        Zd& Z xZS )'TwitchStreamIEztwitch:streama  (?x)
                    https?://
                        (?:
                            (?:(?:www|go|m)\.)?twitch\.tv/|
                            player\.twitch\.tv/\?.*?\bchannel=
                        )
                        (?P<id>[^/#?]+)
                    zhttp://www.twitch.tv/shroomztv12772022048	shroomztvr   z;re:^ShroomzTV [0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}$zGH1Z1 - lonewolfing with ShroomzTV | A3 Battle Royale later - @ShroomzTVTieT20150122	ShroomzTV)r   
display_idr   r   r(  r0  r   r   r   r   r   r   zUser does not existr   z+http://www.twitch.tv/miracle_doto#profile-0r  z)https://player.twitch.tv/?channel=lotsofszhttps://go.twitch.tv/foodzhttps://m.twitch.tv/foodz https://www.twitch.tv/monstercat40500071752r  zre:Monstercatz$md5:0945ad625e615bc8f0469396537d87d9ic20230222
Monstercatr0  zre:https://.*.jpg)r   r  r   r(  r0  r   r   r   r   r   r   r   
Livestreamr   r   c           	          t        fdt        t        t        t        t
        t        fD              rdS t        | !        S )Nc              3   @   K   | ]  }|j                          y wr  r  r  s     r=   r   z*TwitchStreamIE.suitable.<locals>.<genexpr>  s      $Br{{3' $r  F)	r  r   r  r  r  r  r  r  r  r  s    `r=   r  zTwitchStreamIE.suitable   sL      $&"'-!3# $ $  	, W%c*	,r?   c           
          t        | t              r| j                  d      sy | d   }dt        j	                         d|z   d| | j                  d      t        | j                  d            xs ddS )	Nr   rG   rB  r  r   rN  r   )r  r9   r   rG   r   r   )r   r   r_   r   r9   r   r  s     r=   r  zTwitchStreamIE._extract_entry  sn    $%TXXd^:!((*.28*=XXg&*488M+BCHq
 	
r?   c                    | j                  |      j                         }| j                  |d|dddd|dddddddd	d
|idgd      }|d   d   d   }|st        | dd      |d   }|st	        |      t        |j                  d            }| j                  d      ri| j                  | d       t        | j                  |d d      d       }|r#|j                  d      |xs t        d      k\  r|S | j                  d|       | j                  |dd      }|j                  d      xs |}	| j                  d||d   |d         }
| j!                  |
       |j                  d      }t#        |d  t$              xs i }|j                  d!      }t#        |d" t&              }t)        t#        |d# t&                    }|xs |}|j                  d$      }|d%v r	|d&| d'z  }|	|||| j+                  |      |||||
|d(k(  d)S )*Nr/   T)r  includeIsDJr  r0   rT   F)r*  clipSlugisClipisLiveisVodOrCollectionvodIDr1   rM  zDownloading stream GraphQLr   rN   r  r  rB   stream)r   r  r   z,: Extracting VOD to download live from startr  r   infz9Unable to extract the VOD associated with this livestreamchannelNamer   zapi/channel/hlsr   r   viewersc                     | d   d   d   S )Nr   rN   r  r}   rI  s    r=   rK  z.TwitchStreamIE._real_extract.<locals>.<lambda>S  s    1ff)= r?   r;  c                     | d   d   S )NbroadcastSettingsr   r}   rI  s    r=   rK  z.TwitchStreamIE._real_extract.<locals>.<lambda>V  s    q!45g> r?   c                 $    | d   d   d   d   d   S )Nr   rN   r  r+  previewImageURLr}   rI  s    r=   rK  z.TwitchStreamIE._real_extract.<locals>.<lambda>Y  s    1Q4</9:KL r?   r  )rerunlivez ()r5  )r   r  r   r(  r/  r   r   r   r   r   r0  )rt  lowerr   r   r   r   r_   ru  	to_screenr   r  popfloatr>  r   r   r   r   r   rQ  r   r   )r<   rG   r  gqlr  r+  r   r  rz  	stream_idr   r   sq_userr   r(  r   r   stream_types                     r=   r|  zTwitchStreamIE._real_extract  s   ~~c*002  !1$0#' ":+ "#").
 "7%|4!( )+*. 1vf~f% .04A A h|44%fjj&=>	>>+,NNl^+WXY|T6BDIE;/I4MuNKVb   d 22(M3 JJt$4	33|\'-BLQ\D]_G$ZZ	*
#=tDJ;;}->E  L! 	 (Ljj(++r+a((E &&..y9 '"$"f,
 	
r?   )r   r   r   r}  r~  r  r  r  r  r  r  r  r|  r  r  s   @r=   r  r    s    GJ 0%Rd#%#&
 T
 &'* = ; + * 2&$A#%$'$,
 \
!A3Fh K	, 	, 
 
S
r?   r  c            
       .   e Zd ZdZdZddi ddddd	d
dddddeddddddddgdddddddeddd d!d"d#d$i dd%dd&d	d
dd'dd(dedddd)dd*dd+gdd+dd,dd-dedd.d d/d0d1gd"d2d-d3d4d-d3d5d-d3d6d-d3d7d-d3d8d-d3gZd9 Zy:);r  ztwitch:clipsa2  (?x)
                    https?://
                        (?:
                            clips\.twitch\.tv/(?:embed\?.*?\bclip=|(?:[^/]+/)*)|
                            (?:(?:www|go|m)\.)?twitch\.tv/(?:[^/]+/)?clip/
                        )
                        (?P<id>[^/?#&]+)
                    z0https://clips.twitch.tv/FaintLightGullWholeWheat 761769e1eafce0ffebfb4089cb3847cdr   	396245304r  FaintLightGullWholeWheatr   r   r   z'EA Play 2016 Live from the Novo Theatrer       r   r   zre:^https?://.*\.jpgr   i]Wr   20160612creatorsEAr*  
channel_id25163635channel_is_verifiedFchannel_follower_countr   stereotype_r   43566419)rG   md5r   zLhttps://www.twitch.tv/xqc/clip/CulturedAmazingKuduDatSheffy-TiZ_-ixAGYR3y2Uy e90fe616b36e722a8cfa562547c543f0
3207364882z-CulturedAmazingKuduDatSheffy-TiZ_-ixAGYR3y2UyzA day in the life of xQc<   iog20250325xQc71092938T
okSTFUdude	744085721
categorieszJust Chattingz;https://clips.twitch.tv/rflegendary/UninterestedBeeDAESuppyr  zDhttps://www.twitch.tv/sergeynixon/clip/StormyThankfulSproutFutureManzEhttps://clips.twitch.tv/embed?clip=InquisitiveBreakableYogurtJebaitedzChttps://m.twitch.tv/rossbroadcast/clip/ConfidentBraveHumanChefFrankzDhttps://go.twitch.tv/rossbroadcast/clip/ConfidentBraveHumanChefFrankz1https://m.twitch.tv/clip/FaintLightGullWholeWheatc                    | j                  |      }| j                  |dd|idgd      d   d   d   }|st        dd	
      |d   d   |d   d   d}t        |ddt        hf      xs i }t        |ddt        hf      xs i }g }t        |j                  d            }|j                  t        |dd dt        |      hfdt        hfdt        hfdt
        hft        |      hdf             t        |j                  d            }	t        |dd f      D ]p  }
|j                  t        |
d   |      t        d|
j                  d            t        |
j                  d            t        |
j                  d            |	dd       r g }t        |j                  d            }|r|j                  d|dd       t        |j                  d            x}r|j                  d|d d       t        |j                  d            }|r||k7  r|j                  d!|dd       | j                  d"|d    d#   d$d %      }|j                  d&      xs ||rt!        | |      gnd |||d't        |d(t        hfd)t        hfd*t        hfd+t"        hfd,d-t        ht$        t&        fd,d-t        hfd,d&t        hfd,d.d/t        hfd,d0t(        hfd1d-t        hfd1d&t        hfd2d-t        ht$        t&        t$        fd3      S )4Nr-   slugr  zDownloading clip GraphQLr   rN   r  z This clip is no longer availableTrB   playbackAccessTokenr   r   )r   r   assetsr   aspectRatiovideoQualitiesc                     t        |d         S N	sourceURLr   _rB  s     r=   rK  z-TwitchClipsIE._real_extract.<locals>.<lambda>      S^_`al_mSn r?   r_  r   r   	frameRate)rG   r{   r_  rc  aspect_ratioc                     t        |d         S r^  r`  ra  s     r=   rK  z-TwitchClipsIE._real_extract.<locals>.<lambda>  rc  r?   portrait)rG   r{   r_  rc  re  r   r   rH   )r   rG   r   r#  z%7C(\d+)(?:-\d+)?.mp4rG   zold id)rH   r   )r   _old_archive_idsr  r   r/  r   r  rO  r  broadcasterr;  	followers
totalCount	isPartnercuratorr:  )r   r   r   r   rE  r*  rG  rJ  rI  r   r   rV  )rt  r   r   r   r   r   r_   rv  r   rQ  r   r   r2  r   r   rY   r   r   r  r  bool)r<   rG   rX  r  access_queryasset_defaultasset_portraitr   default_aspect_ratioportrait_aspect_ratior   r/  thumb_asset_default_urlthumb_asset_portrait_urlthumb_default_urlold_ids                   r=   r|  zTwitchClipsIE._real_extract  s   ~~c"!!!8$d^  '(
 )*+
 ,23
 4:;  2TC C -.{;/09
 %THa$+@AGR%dXq4&,ABHb,]->->}-MN|M4DFn"2"F!GH#cU+ ;-0-1"#789q
 4  	 !.n.@.@.O P">4DFn3op 	FNN'{(;\J*:vzz)7LM%fjj&;<$VZZ%<= 5 	 
"-m.?.?.O"P". 
 (3>3E3En3U'VV#V /  
 ((@A!26M!M(   ##$<gbk%>PRZdh#i ((4.(DCIv!> ?t$
 4!C5).>*[M:)M?;*MC5&#N)=3%@,dSE:+8+|VaUb*c(5{TF'K&u= )4#7%}seVS&Q" 
 	
r?   N)r   r   r   r}  r~  r  r  r|  r}   r?   r=   r  r  p  s(   GJ B1
+
4
 5
 >	

 
 #
 0
 
 :
 
 t
 *
 "5
 %c
 
  :!
, ^1
,
I
 5
 /	

 
 #
 0
 
 :
 
 u
 *
 "4
 %c
 
  ;!
" ?+#
0 M
 V W U V Cw>F@U
r?   r  )-r  r  r\   r   rq   urllib.parserw  commonr   networking.exceptionsr   utilsr   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   utils.traversalr   r   r   r   r  r  r  r  r  r  r  r  r  r}   r?   r=   <module>r     s        	  ! -     * 2G= GTo, od""F "FJ,< ,^
- 
iT' iTXFC. FCR5< 4 5<pn
' n
b`
L `
r?   