U
    MfƦ                     @   s,  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
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 G dd deZG dd	 d	eZd
d ZG dd deZ G dd deZ!G dd de!Z"G dd de!Z#G dd de!Z$G dd deZ%G dd deZ&dS )    N   )InfoExtractor   )ExtractorErrorUserNotLivebase_url
clean_htmldict_getfloat_or_noneint_or_nonemake_archive_idparse_durationparse_iso8601parse_qs	qualitiesstr_or_nonetraverse_objtry_getunified_timestampupdate_url_queryurl_or_noneurljoinc                   @   s   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d Zdd Zdd Zd%ddZd&ddZdd Zd d! Zd"d# Zd$S )'TwitchBaseIEz&https?://(?:(?:www|go|m)\.)?twitch\.tvzhttps://api.twitch.tvzhttps://usher.ttvnw.netzhttps://www.twitch.tv/loginz https://passport.twitch.tv/loginZtwitchZ@27111f1b382effad0b6def325caef1909c733fe6a4fbabf54f8d491ef2cf2f14Z@a937f1d22e269e39a03b509f65a7490f9fc247d7f83d6ac1421523e3b68042cbZ@b73ad2bfaecfd30a9e6c28fada15bd97032c83ec77a0440766a56fe0bd632777Z@447aec6a0cc1e8d0a8d7732d47eb0762c336a2294fdb009e9c9d854e49d484b9Z@a647c2a13599e5991e175155f798ca7f1ecddde73f7f341f39009c14dbf59962Z@e1edae8122517d013405f237ffcc124515dc6ded82480a88daef69c83b53ac01Z@36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11Z@3006e77e51b128d838fa4e835723ca4dc9a05c5efd4466c1085215c6e437e65cZ@49b5b8f268cdeb259d75b58dcb0c1a748e3b575003448a2333dc5cdafd49adadZ@8d2793384aac3773beab5e59bd5d6f585aedb923d292800119e03d40cd0f9b41Z@07e99e4d56c5a7c67117a154777b0baf85a5ffefa393b213f4bc712ccaf85dd6)CollectionSideBarFilterableVideoTower_VideosClipsCards__UserChannelCollectionsContentStreamMetadataComscoreStreamingQueryVideoAccessToken_ClipVideoPreviewOverlayVideoMetadata$VideoPlayer_ChapterSelectButtonVideo"VideoPlayer_VODSeekbarPreviewVideoc                 C   s   | j ddgdddd S )N	client_idZue6666qo983tsx6so1t0vnawi233waZTwitchT)ie_keyZ	casesenser   )Z_configuration_arg)self r'   ;/tmp/pip-unpacked-wheel-zk9bgjdq/yt_dlp/extractor/twitch.py
_CLIENT_ID7   s       zTwitchBaseIE._CLIENT_IDc                    s   dd   fdd} jd d\}}d|kr> t| |||d||jd\}}|sbd S td	|d k	rd
}|||d|dd d S )Nc                 S   s   t d|  ddd S )NzUnable to login. Twitch said: Texpected)r   )messager'   r'   r(   fail=   s     z)TwitchBaseIE._perform_login.<locals>.failc                    s    | }|| |j}jd| djdd}t||}|ddd}j|d |t|	 |dd	}t
|d
}	|	r| |	 d|ddkrdS t||dp|d }
j|
d d|dS )Nz&<form[^>]+action=(["\'])(?P<url>.+?)\1zpost urlurl)defaultgroupzhttps://www.twitch.tvtext/plain;charset=UTF-8)ZRefererZOriginContent-Typei  )dataheadersZexpected_status)errorZerror_descriptionZ
error_codezAuthenticated successfullyr,    )NNredirectZredirect_pathzDownloading login redirect page)r4   )Z_hidden_inputsupdater.   _search_regex_LOGIN_POST_URLr   _download_jsonjsondumpsencoder	   get_download_webpage_handle)pageZurlhnoter3   formpage_urlZpost_urlr4   responser5   Zredirect_urlr-   r&   r'   r(   
login_stepA   sL    

   
    
  z/TwitchBaseIE._perform_login.<locals>.login_stepzDownloading login pageZblacklist_messagez
Logging in)usernamepasswordr$   z$(?i)<form[^>]+id="two-factor-submit"ztwo-factor authentication tokenzSubmitting TFA tokentrue)Zauthy_tokenZremember_2fa)r@   _LOGIN_FORM_URLr   r)   researchZ_get_tfa_info)r&   rH   rI   rG   Z
login_pagehandleZredirect_pageZ	tfa_tokenr'   rF   r(   _perform_login<   s4    !    
zTwitchBaseIE._perform_loginc              	   C   s^   zt dd |D }d|d< W n: tk
rX   |D ] }d|d kr2|ddd q2Y nX d S )	Nc                 s   s   | ]}|d  dkr|V  qdS )	format_idSourceNr'   ).0fr'   r'   r(   	<genexpr>~   s      z.TwitchBaseIE._prefer_source.<locals>.<genexpr>
   qualityz	/chunked/r.   rQ   )rV   format_note)nextStopIterationr8   )r&   formatssourcerS   r'   r'   r(   _prefer_source|   s    zTwitchBaseIE._prefer_sourceTc                 C   sN   d| j d}| dd}|r.d|j |d< | jd||t| ||dS )	Nr1   )r2   z	Client-IDzhttps://gql.twitch.tvz
auth-tokenzOAuth Authorizationzhttps://gql.twitch.tv/gql)r3   r4   fatal)r)   Z_get_cookiesr?   valuer;   r<   r=   r>   )r&   video_idopsrB   r^   r4   Zgql_authr'   r'   r(   _download_base_gql   s       zTwitchBaseIE._download_base_gqlc                 C   s4   |D ] }dd| j |d  di|d< q| |||S )NZpersistedQueryr   operationName)versionZ
sha256Hash
extensions)_OPERATION_HASHESrb   )r&   r`   ra   rB   r^   opr'   r'   r(   _download_gql   s    
zTwitchBaseIE._download_gqlc                 C   s:   | d}dd|||f i}|  ||d| dd | S )NZPlaybackAccessTokenquerya?  {
              %s(
                %s: "%s",
                params: {
                  platform: "web",
                  playerBackend: "mediaplayer",
                  playerType: "site"
                }
              )
              {
                value
                signature
              }
            }Downloading z access token GraphQLr3   )rb   )r&   r`   Z
token_kind
param_namemethodra   r'   r'   r(   _download_access_token   s    
  
z#TwitchBaseIE._download_access_tokenc                 C   s$   |r t dd|ddd|igS d S )Nz\d+x\d+(\.\w+)($|(?=[?#]))z0x0\g<1>r   r.   Z
preferencer.   )rL   sub)r&   	thumbnailr'   r'   r(   _get_thumbnails   s     zTwitchBaseIE._get_thumbnailsc                 C   sz   | j | j d| d| d|ddddtddddd	d||d

d}|D ],}|drH|d drHdddgi|d< qH|S )N/z.m3u8mp4rJ   i@B i ZwebZ	twitchwebzav1,h265,h264)
Zallow_sourceZallow_audio_onlyZallow_spectrepplatformZplayerZsupported_codecsZplaylist_include_frameratesigtoken)ri   vcodecZav01Zffmpeg_args_outz-fZdownloader_options)Z_extract_m3u8_formats_USHER_BASErandomrandintr?   
startswith)r&   pathr`   rw   	signaturerZ   fmtr'   r'   r(   _extract_twitch_m3u8_formats   s(      
z)TwitchBaseIE._extract_twitch_m3u8_formatsN)T)T)__name__
__module____qualname__Z_VALID_URL_BASEZ	_API_BASEry   rK   r:   Z_NETRC_MACHINErf   propertyr)   rO   r\   rb   rh   rm   rq   r   r'   r'   r'   r(   r       s6   
@


r   c                   @   s  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dAdB ZdCdD ZdEdF Z	dGdH Z
dIdJ ZdKdL ZdMS )N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=5m10sZv6528877rs   zLCK Summer Split - Week 6 Day 1zre:^https?://.*\.jpg$i8C  iV_UZ20150624z
Riot GamesZ	riotgamesi6  r   zLeague of Legends
start_timeZend_timetitlewas_live)idextr   rp   duration	timestampupload_dateuploaderuploader_id
view_countr   chapterslive_statusskip_downloadTr.   	info_dictparamsz(http://www.twitch.tv/belkao_o/v/11230755Z	v11230755Untitled Broadcastif  iUZ20150816ZBelkAO_oZbelkao_o)
r   r   r   rp   r   r   r   r   r   r   zHTTP Error 404: Not Foundr.   r   r   skipz/http://player.twitch.tv/?t=5m10s&video=v6528877r.   Z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/635475444Z
v635475444i{-  i;^Z20200529i=  iR  zLegends of RuneterraZArt)r   r   r   r   r   r   r   r   r   r   rp   r   ZStoryboardsZsb0mhtml)r   rP   r   r   r   r   r   r   r   r   r   rp   r   columnsrows)formatr   )rB   r.   r   r   zVOD with single chapterz'https://www.twitch.tv/videos/1536751224Zv1536751224z8Porter Robinson Star Guardian Stream Tour with LilyPichui   iS(bZ20220719z;Unable to download JSON metadata: HTTP Error 403: Forbidden)rB   r.   r   r   Zexpected_warningsz8https://www.twitch.tv/tangotek/schedule?vodID=1822395420c              	   C   s   |  |dd|dddd|dddd|ddgd	}t|d
dd}|d krbtd| dddt|d|d< t|ddddthfdd|d< |S )Nr!   r6   )channelLoginvideoIDrc   	variablesr"   F)ZincludePrivater   r#   z#Downloading stream metadata GraphQL).r3   video)get_allzVideo  does not existTr*   ).r3   r   momentsedges.noder   .r3   r   ZseekPreviewsURL
storyboard)rh   r   r   r   )r&   item_idr3   r   r'   r'   r(   _download_info  s<      
zTwitchVodIE._download_infoc           
      C   s   | d}|dkrd}n|dkr&d}nd }d}t|}g }| d}t|tr| D ]4\}}	t|	}	|	slqV||krvqV||	||d qV|d	 | d
pd| dt| d|| di  d| di  dt| dt| d|ddS )NstatusZ	recordingTZrecordedF)smallmediumZlargepreviewrn   Z_idr   r   descriptionlengthchannelZdisplay_namenameZrecorded_atviews)r   r   r   r   
thumbnailsr   r   r   r   is_liver   )	r?   r   
isinstancedictitemsr   appendr   r   )
r&   infor   r   Z
_QUALITIESZquality_keyr   r   thumbnail_idthumbnail_urlr'   r'   r(   _extract_info  sB    



zTwitchVodIE._extract_infoc                 c   s   | ds&t|d}|r"d|iV  d S |d D ]h}t| dd}t| dd}t| d}|d ksp|d kr| d| | q.||| |d	V  q.d S )
Nr   )gamedisplayNamer   ZpositionMillisecondsi  ZdurationMillisecondsr   z2Important chapter information missing for chapter r   )r?   r   r   r   Zreport_warning)r&   r   r   r   Zmomentr   r   r   r'   r'   r(   _extract_chapters  s     


zTwitchVodIE._extract_chaptersc                 C   s   | dp|}|d dkr$d| }t| d}d }|rTtd|rPd\}}nd}|| dpbd	| d
t| d| |t|dd tt|dd tt| dt| dt	| 
|||ddS )Nr   r   vpreviewThumbnailURLz/404_processing_[^.?#]+\.png)TNFr   r   r   lengthSecondsc                 S   s   | d d S )Nownerr   r'   xr'   r'   r(   <lambda>      z/TwitchVodIE._extract_info_gql.<locals>.<lambda>c                 S   s   | d d S )Nr   loginr'   r   r'   r'   r(   r     r   ZpublishedAt	viewCountT)r   r   r   r   r   r   r   r   r   r   r   r   )r?   r   rL   findallr   rq   r   strr   listr   )r&   r   r   vod_idrp   r   r'   r'   r(   _extract_info_gql  s,    

zTwitchVodIE._extract_info_gqlc           	      #   s   |r|sd S | j ||dddp g }|jdd dd t| t|D ]\}}t|d}|d	}|rD|snqD|t| d
| dddddt |d t|dt|d|| t|dt|d fdd|D dV  qDd S )Nz$Downloading storyboard metadata JSONFr^   c                 S   s   t | dpdS )Nwidthr   )r   r?   r   r'   r'   r(   r     r   z1TwitchVodIE._extract_storyboard.<locals>.<lambda>T)keyreversecountimagesZsbr   r   noner   r   heightr   colsc                    s   g | ]}t  |d qS ))r.   r   )r   )rR   r}   baseZfragment_durationr'   r(   
<listcomp>  s   z3TwitchVodIE._extract_storyboard.<locals>.<listcomp>)rP   rW   r   protocolZacodecrx   r.   r   r   fpsr   r   Z	fragments)r;   sortr   	enumerater   r?   lenr   )	r&   r   Zstoryboard_json_urlr   specisr   r   r'   r   r(   _extract_storyboard  s6    
zTwitchVodIE._extract_storyboardc           	   	   C   s   |  |}| |}| ||}| |dd}| d||d |d }|| ||d|d | | ||d< t	j
|}t	j
|j}d	|krt|d	 d
 |d< |dd k	rdtd| dd| jiddgi|d< |S )Nr   r   Zvodr_   r~   r   r   rZ   tr   r   r   Zrechatz https://api.twitch.tv/v5/videos/z	/commentsr$   r<   )r.   r   Z	subtitles)	_match_idr   r   rm   r   extendr   r?   r\   urllibparseurlparser   ri   r   r   r)   )	r&   r.   r   r   r   access_tokenrZ   
parsed_urlri   r'   r'   r(   _real_extract   s:    

    

 
zTwitchVodIE._real_extractN)r   r   r   IE_NAME
_VALID_URLint_TESTSr   r   r   r   r   r   r'   r'   r'   r(   r      s:     $")   *!%!r   c                 C   sd   t | tst| d}|s d S dt d| d| | d| dt| dt| dd	S )
Nr   url_transparentr   zhttps://www.twitch.tv/videos/r   r   r   r   )_typer%   r   r.   r   rp   r   r   )r   r   AssertionErrorr?   r   r%   r
   r   )r   r`   r'   r'   r(   _make_video_resultA  s    
r   c                   @   s0   e Zd ZdZddddddgZdZd	d
 ZdS )TwitchCollectionIEz@https?://(?:(?:www|go|m)\.)?twitch\.tv/collections/(?P<id>[^/]+)z0https://www.twitch.tv/collections/wlDCoH0zEBZZbQZwlDCoH0zEBZZbQz'Overthrow Nook, capitalism for childrenr   r      r.   r   Zplaylist_mincountr   c           	      C   s   |  |}| || jd|idgdd d d }|d}g }|d d	 D ]<}t|ts\qL|d
}t|tsrqLt|}|rL|| qL| j|||dS )NZcollectionIDr   zDownloading collection GraphQLr   r3   
collectionr   r   r   r   Zplaylist_idZplaylist_title)	r   rh   _OPERATION_NAMEr?   r   r   r   r   playlist_result)	r&   r.   collection_idr   r   entriesedger   r   r'   r'   r(   r   `  s<    




  z TwitchCollectionIE._real_extractN)r   r   r   r   r   r   r   r'   r'   r'   r(   r   R  s   	r   c                   @   s   e Zd ZdZdd ZdS )TwitchPlaylistBaseIEd   c                 '   s(  d }| j |f| }| j d tdD ]}| }| j|d< |rL||d< | j|| j|dgd| j d| dd	}|s q$t	| fd
dt
}|s q$|D ]h}	t|	tsq|	d| jkrq|	d}
t|
tsq|
d| jkrq| |
}|r|	d}|V  q|rt|ts* q$q*d S )Nr   r   limitcursorr   rj   zs GraphQL page Fr   c                    s   | d d d   d S )Nr   r3   userr   r'   r   Zentries_keyr'   r(   r     r   z/TwitchPlaylistBaseIE._entries.<locals>.<lambda>Z
__typenamer   )_make_variables_ENTRY_KIND	itertoolsr   copy_PAGE_LIMITrh   r   
_NODE_KINDr   r   r   r   r?   
_EDGE_KIND_extract_entryr   )r&   channel_nameargsr  Zvariables_commonZpage_numr   rA   r   r  r   entryr'   r  r(   _entriesz  sR    
 
 




zTwitchPlaylistBaseIE._entriesN)r   r   r   r  r  r'   r'   r'   r(   r  w  s   r  c                       s   e 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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d.Zd/Zd0Zd1Ze fd2d3Zed4d5 Zed6d7 Zd8d9 Z  ZS ):TwitchVideosIEzGhttps?://(?:(?: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 Datei  z>https://www.twitch.tv/esl_csgo/videos?filter=uploads&sort=timeZ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 VideosZARCHIVEzPast BroadcastsZ	HIGHLIGHTZ
HighlightsZUPLOADZUploadsZPAST_PREMIEREzPast Premieres)ZarchivesZ
highlightsZuploadsZpast_premieresallDateZPopular)timer   r   r   Z	VideoEdgeZVideoc                    s*   t  fddttfD rdS t  S )Nc                 3   s   | ]}|  V  qd S NsuitablerR   Zier.   r'   r(   rT     s     z*TwitchVideosIE.suitable.<locals>.<genexpr>F)anyTwitchVideosClipsIETwitchVideosCollectionsIEsuperr!  clsr.   	__class__r#  r(   r!    s    
zTwitchVideosIE.suitablec                 C   s   | ||  dS )N)ZchannelOwnerLoginZbroadcastTypeZ	videoSort)upper)r  Zbroadcast_typer   r'   r'   r(   r	    s    zTwitchVideosIE._make_variablesc                 C   s   t | S r  )r   )r   r'   r'   r(   r    s    zTwitchVideosIE._extract_entryc                 C   s   |  |}t|}|ddgd }|ddgd }| j|| j}| j| ||j||| d|j d| j	|| j
 dS )	Nfilterr  r   r   r  z - z sorted by r   )r   r   r?   _BROADCASTS_DEFAULT_BROADCASTr   r  r  r  
_SORTED_BY_DEFAULT_SORTED_BY)r&   r.   r  qsZvideo_filterr   	broadcastr'   r'   r(   r   
  s    
 zTwitchVideosIE._real_extract)r   r   r   r   r   collections
namedtupler  r/  r.  r1  r0  r   r
  r  r  classmethodr!  staticmethodr	  r  r   __classcell__r'   r'   r*  r(   r    s   




	;


r  c                   @   s   e Zd ZdZdddddddd	d
gZe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d Zedd Zdd  Zd!S )"r%  z[https?://(?:(?:www|go|m)\.)?twitch\.tv/(?P<id>[^/]+)/(?:clips|videos/*?\?.*?\bfilter=clips)z<https://www.twitch.tv/vanillatv/clips?filter=clips&range=allZ	vanillatvzvanillatv - Clips Top Allr   r   r   z=https://www.twitch.tv/dota2ruhub/videos?filter=clips&range=7dTr   Clipr-  r  Z	LAST_WEEKzTop 7DZLAST_DAYzTop 24HZ
LAST_MONTHzTop 30DZALL_TIMEzTop All)Z24hr7dZ30dr     r   clipZClipEdgec                 C   s   | d|idS )Nr-  )r   Zcriteriar'   )r  Zchannel_filterr'   r'   r(   r	  :  s
     z#TwitchVideosClipsIE._make_variablesc                 C   sx   t | tstt| d}|s$d S dt | d|| d| dt| dt| dt	| d| d	d

S )Nr.   r   r   r   thumbnailURLdurationSeconds	createdAtr   language)
r   r%   r   r.   r   rp   r   r   r   r@  )
r   r   r   r   r?   TwitchClipsIEr%   r
   r   r   )r   Zclip_urlr'   r'   r(   r  C  s    z"TwitchVideosClipsIE._extract_entryc                 C   sZ   |  |}t|}|ddgd }| j|| j}| j| ||j|| d|j dS )Nranger:  r   z	 - Clips r   )	r   r   r?   _RANGE_DEFAULT_CLIPr   r  r-  r  )r&   r.   r  r2  Z
date_ranger<  r'   r'   r(   r   V  s    
z!TwitchVideosClipsIE._real_extractN)r   r   r   r   r   r4  r5  r9  rD  rC  r  r   r
  r  r  r7  r	  r  r   r'   r'   r'   r(   r%    s8   	


r%  c                   @   sd   e 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d Z
e	dd Zdd ZdS )r&  zWhttps?://(?:(?: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 - Collectionsr   r   r   ZCollectionsItemEdge
Collectionc                 C   s   d| iS )NZ
ownerLoginr'   )r  r'   r'   r(   r	  z  s     z)TwitchVideosCollectionsIE._make_variablesc                 C   sl   t | tst| d}|s d S dt |d| | d| dt| dt| dt| dd		S )
Nr   r   z"https://www.twitch.tv/collections/r   r=  r   Z	updatedAtr   )	r   r%   r   r.   r   rp   r   r   r   )	r   r   r   r?   r   r%   r
   r   r   )r   r   r'   r'   r(   r    s    
z(TwitchVideosCollectionsIE._extract_entryc                 C   s&   |  |}| j| ||| ddS )Nz - Collectionsr   )r   r   r  )r&   r.   r  r'   r'   r(   r     s    
 z'TwitchVideosCollectionsIE._real_extractN)r   r   r   r   r   r   r
  r  r  r7  r	  r  r   r'   r'   r'   r(   r&  a  s.   	

r&  c                       s   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e fd#d$Zd%d& Z	  Z
S )'TwitchStreamIEztwitch:streama  (?x)
                    https?://
                        (?:
                            (?:(?:www|go|m)\.)?twitch\.tv/|
                            player\.twitch\.tv/\?.*?\bchannel=
                        )
                        (?P<id>[^/#?]+)
                    zhttp://www.twitch.tv/shroomztvZ12772022048Z	shroomztvrs   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 - @ShroomzTVTieTZ20150122Z	ShroomzTV)r   
display_idr   r   r   r   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/monstercatZ40500071752rF  zre:Monstercatz$md5:0945ad625e615bc8f0469396537d87d9icZ20230222Z
Monstercatr   zre:https://.*.jpg)r   rI  r   r   r   r   r   r   r   r   rp   r   Z
Livestreamr   c                    s2   t  fddttttttfD r&dS t  S )Nc                 3   s   | ]}|  V  qd S r  r   r"  r#  r'   r(   rT     s     z*TwitchStreamIE.suitable.<locals>.<genexpr>F)	r$  r   r   r  r%  r&  rA  r'  r!  r(  r*  r#  r(   r!    s    
zTwitchStreamIE.suitablec                 C   sr  |  | }| |dd|idd|dddddddd	d
|idgd}|d d d }|spt| ddd|d }|st|d| |dd}|dp|}| d||d |d }| | |d}	t	|d}
t
|dd tpi }|d}t
|dd t}tt
|dd t}|p&|}|d}|d krL|d!| d"7 }||||| ||||
|	||d#kd$S )%Nr   r   r   r   r6   FT)r   ZclipSlugZisClipZisLiveZisVodOrCollectionZvodIDr    r   zDownloading stream GraphQLr   r3   r  r   r*   stream)r`   ZchannelNamer   zapi/channel/hlsr_   r~   Zviewersr?  c                 S   s   | d d d S )Nr   r3   r  r'   r   r'   r'   r(   r     r   z.TwitchStreamIE._real_extract.<locals>.<lambda>r   c                 S   s   | d d S )NZbroadcastSettingsr   r'   r   r'   r'   r(   r     r   c                 S   s   | d d d d d S )Nr   r3   r  rJ  ZpreviewImageURLr'   r   r'   r'   r(   r     r   r  )Zrerunlivez ()rK  )r   rI  r   r   r   r   r   r   r   rZ   r   )r   lowerrh   r   r   rm   r?   r   r\   r   r   r   r   r   rq   )r&   r.   r  Zgqlr  rJ  r   Z	stream_idrZ   r   r   Zsq_userr   r   rp   r   Zstream_typer'   r'   r(   r     s     
     


   


zTwitchStreamIE._real_extract)r   r   r   r   r   r   r   r6  r!  r   r8  r'   r'   r*  r(   rH    sl   
  5rH  c                   @   sp   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gZdd ZdS )rA  ztwitch:clipsa2  (?x)
                    https?://
                        (?:
                            clips\.twitch\.tv/(?:embed\?.*?\bclip=|(?:[^/]+/)*)|
                            (?:(?:www|go|m)\.)?twitch\.tv/(?:[^/]+/)?clip/
                        )
                        (?P<id>[^/?#&]+)
                    z0https://clips.twitch.tv/FaintLightGullWholeWheatZ 761769e1eafce0ffebfb4089cb3847cdZ42850523ZFaintLightGullWholeWheatrs   z'EA Play 2016 Live from the Novo Theatrezre:^https?://.*\.jpgi]WZ20160612ZEAZstereotype_Z43566419)
r   rI  r   r   rp   r   r   creatorr   r   )r.   md5r   z;https://clips.twitch.tv/rflegendary/UninterestedBeeDAESuppyTr   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                 C   s  |  |}| |dd|idgdd d d }|s@tdd	d
|d d |d d d}| j|dd| iddd}|rt|dd tp|}g }|dg D ]X}t|tsqt|d}|sq|	t
|||dt|dt|dd qg }	dD ]`}
||
}|sq|
|d}td|}|rT|t|dt|dd  |		| q| jd!|d" d# d$d d%}|d&p||rt| |gnd ||d'|t|d(t|d)t|d*|	t|d+d tt|d,d tt|d-d td.S )/Nr   Zslugr   z%Downloading clip access token GraphQLr   r3   r<  z This clip is no longer availableTr*   ZplaybackAccessTokenr~   r_   )rv   rw   ri   a  {
  clip(slug: "%s") {
    broadcaster {
      displayName
    }
    createdAt
    curator {
      displayName
      id
    }
    durationSeconds
    id
    tiny: thumbnailURL(width: 86, height: 45)
    small: thumbnailURL(width: 260, height: 147)
    medium: thumbnailURL(width: 480, height: 272)
    title
    videoQualities {
      frameRate
      quality
      sourceURL
    }
    viewCount
  }
}zDownloading clip GraphQLFr   c                 S   s   | d d S )Nr3   r<  r'   r   r'   r'   r(   r     r   z-TwitchClipsIE._real_extract.<locals>.<lambda>ZvideoQualitiesZ	sourceURLrV   Z	frameRate)r.   rP   r   r   )Ztinyr   r   )r   r.   z-(\d+)x(\d+)\.r   r   )r   r   z%7C(\d+)(?:-\d+)?.mp4r.   zold id)r/   r   r   r>  r   r?  c                 S   s   | d d S )NZbroadcasterr   r'   r   r'   r'   r(   r     r   c                 S   s   | d d S )Ncuratorr   r'   r   r'   r'   r(   r     r   c                 S   s   | d d S )NrQ  r   r'   r   r'   r'   r(   r     r   )r   Z_old_archive_idsrI  r   rZ   r   r   r   r   rN  r   r   )r   rh   r   rb   r   r   r?   r   r   r   r   r   rL   rM   r8   r   r0   r9   r   r   r   )r&   r.   r`   r<  Zaccess_queryr3   rZ   optionr[   r   r   r   ZthumbZmobjZold_idr'   r'   r(   r   ^  s    
 	 

  


zTwitchClipsIE._real_extractN)r   r   r   r   r   r   r   r'   r'   r'   r(   rA  /  sH   
$rA  )'r4  r  r<   rz   rL   urllib.parser   commonr   utilsr   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&  rH  rA  r'   r'   r'   r(   <module>   s*   T 4  p%+vI8 