3
b`e                 @   sl  d dl m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 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 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 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 )$    )unicode_literalsN   )InfoExtractor   )compat_kwargscompat_parse_qs
compat_strcompat_urllib_parse_urlencodecompat_urllib_parse_urlparse)
clean_htmlExtractorErrorint_or_none
orderedSetparse_durationparse_iso8601try_getunified_timestampupdate_url_queryurl_or_noneurljoinc               @   sP   e Zd ZdZdZdZdZdZdZdZ	dd	 Z
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kimne78kx3ncx6brgo4mv6wki5h1kotwitchc             C   s>   t |tsd S |jd}|r:td| j||jdf ddd S )Nerrorz%s returned error: %s - %smessageT)expected)
isinstancedictgetr   IE_NAME)selfresponser    r!   GC:\Users\Broad\Desktop\All-Down\binaries\youtube_dl\extractor\twitch.py_handle_error*   s    

zTwitchBaseIE._handle_errorc             O   sR   |j di j }| j|d< ||d< | jd| j|f |f|t|}| j| |S )Nheadersz	Client-IDz%s/%s)r   copy
_CLIENT_ID_download_json	_API_BASEr   r#   )r   pathitem_idargskwargsr$   r    r!   r!   r"   	_call_api3   s    

zTwitchBaseIE._call_apic             C   s   | j   d S )N)_login)r   r!   r!   r"   _real_initialize=   s    zTwitchBaseIE._real_initializec                s   j  \}}|d krd S dd   fdd}jjd d\}}d|krV t| |||d||jd\}}|szd S tjd	|d k	rjd
}|||d|dd d S )Nc             S   s   t d|  ddd S )Nz Unable to login. Twitch said: %sT)r   )r   )r   r!   r!   r"   failE   s    z!TwitchBaseIE._login.<locals>.failc                s   j | }|j| |j }jd| djdd}t||}||dd}j|d |tj|j	 |dd}|j
d	pz|j
d
}	|	r |	 d|j
ddkrdS t||j
dp|d }
j|
d d|dS )Nz&<form[^>]+action=(["\'])(?P<url>.+?)\1zpost urlurl)defaultgroupztext/plain;charset=UTF-8)RefererOriginzContent-Typei  )datar$   expected_statuserror_description
error_codezAuthenticated successfullyr    redirectZredirect_pathzDownloading login redirect page)r$   )NN)_hidden_inputsupdategeturl_search_regex_LOGIN_POST_URLr   r'   jsondumpsencoder   _download_webpage_handle)pageurlhnoter6   formpage_urlpost_urlr$   r    r   redirect_url)r0   r   r!   r"   
login_stepI   s0    



z'TwitchBaseIE._login.<locals>.login_stepzDownloading login pageZblacklist_messagez
Logging in)usernamepassword	client_idz$(?i)<form[^>]+id="two-factor-submit"ztwo-factor authentication tokenzSubmitting TFA tokentrue)Zauthy_tokenZremember_2fa)_get_login_inforD   _LOGIN_FORM_URLr   r&   research_get_tfa_info)r   rM   rN   rL   
login_pagehandleZredirect_pageZ	tfa_tokenr!   )r0   r   r"   r.   @   s*    !
zTwitchBaseIE._loginc             C   sl   yt dd |D }d|d< W n> tk
r\   x(|D ] }d|d kr4|jddd q4W Y nX | j| 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/r1   rY   )r^   format_note)nextStopIterationr=   _sort_formats)r   formatssourcer[   r!   r!   r"   _prefer_source   s    
zTwitchBaseIE._prefer_sourceN)__name__
__module____qualname___VALID_URL_BASEr(   _USHER_BASErR   r@   r&   _NETRC_MACHINEr#   r-   r/   r.   re   r!   r!   r!   r"   r       s   	
Dr   c               @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
TwitchItemBaseIEc             C   s"   | j | jd||f |d| j S )Nzkraken/videos/%s%szDownloading %s info JSON)_extract_infor-   
_ITEM_TYPE)r   itemr*   r!   r!   r"   _download_info   s    zTwitchItemBaseIE._download_infoc             C   s2  | j | j|}| jd| j|f |d| j }g }|d }t|j }xtt|j  ddD ]\}}g }	xdt|D ]X\}
}||
 }|d ||dkrdndd	}t	j
d
|}|rt|jd|d< |	j| qpW | j|	 t|}d|d |f |d< d|d |f |d< |	|d< |j| qZW | j||d |d S )Nzapi/videos/%s%szDownloading %s playlist JSONchunksr   )startr1   liver   )r1   rX   r^   z^(?P<height>\d+)[Pp]heightz%s_%didz
%s part %dtitlerc   )rp   _ITEM_SHORTCUTr-   rn   listkeys	enumeratezipvaluesrS   rT   intr3   appendrb   r   playlist_result)r   r*   infor    entriesrq   	qualitiesnumfragmentrc   Zfmt_numZfragment_fmtrX   fmtmentryr!   r!   r"   _extract_media   s2    
zTwitchItemBaseIE._extract_mediac             C   s   |j d}|dkrd}n|dkr&d}nd }|d |j dp<d|j d	t|j d
|j d|j di j d|j di j dt|j dt|j d|d
S )Nstatus	recordingTrecordedF_idrv   zUntitled Broadcastdescriptionlengthpreviewchanneldisplay_namenameZrecorded_atviews)
ru   rv   r   duration	thumbnailuploaderuploader_id	timestamp
view_countis_live)r   r   r   )r   r   r   r   r!   r!   r"   rm      s     
zTwitchItemBaseIE._extract_infoc             C   s   | j | j|S )N)r   	_match_id)r   r1   r!   r!   r"   _real_extract   s    zTwitchItemBaseIE._real_extractN)rf   rg   rh   rp   r   rm   r   r!   r!   r!   r"   rl      s   rl   c               @   s6   e Zd ZdZdej ZdZdZddddd	d
dZ	dS )TwitchVideoIEztwitch:videoz%s/[^/]+/b/(?P<id>\d+)videoaz*http://www.twitch.tv/riotgames/b/577357806Z
a577357806z0Worlds Semifinals - Star Horn Royal Club vs. OMG)ru   rv      zHTTP Error 404: Not Found)r1   	info_dictplaylist_mincountskipN)
rf   rg   rh   r   r   ri   
_VALID_URLrn   rw   _TESTr!   r!   r!   r"   r      s   
r   c               @   s@   e Zd ZdZdej ZdZdZddddd	d
ddddgZ	dS )TwitchChapterIEztwitch:chapterz%s/[^/]+/c/(?P<id>\d+)chaptercz-http://www.twitch.tv/acracingleague/c/5285812Zc5285812z,ACRL Off Season - Sports Cars @ Nordschleife)ru   rv      zHTTP Error 404: Not Found)r1   r   r   r   z,http://www.twitch.tv/tsm_theoddone/c/2349361T)r1   only_matchingN)
rf   rg   rh   r   r   ri   r   rn   rw   _TESTSr!   r!   r!   r"   r      s   
r   c               @   s   e Zd ZdZdZdZdZddddd	d
dddde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 gZd%d& Z	d'S )(TwitchVodIEz
twitch:voda(  (?x)
                    https?://
                        (?:
                            (?:(?:www|go|m)\.)?twitch\.tv/(?:[^/]+/v(?:ideo)?|videos)/|
                            player\.twitch\.tv/\?.*?\bvideo=v?
                        )
                        (?P<id>\d+)
                    vodvz0http://www.twitch.tv/riotgames/v/6528877?t=5m10sZv6528877mp4zLCK Summer Split - Week 6 Day 1zre:^https?://.*\.jpg$i8C  i=_UZ20150624z
Riot GamesZ	riotgamesi6  )ru   extrv   r   r   r   upload_dater   r   r   
start_timeskip_downloadT)r1   r   paramsz(http://www.twitch.tv/belkao_o/v/11230755Z	v11230755zUntitled Broadcastif  iU20150816ZBelkAO_oZbelkao_o)
ru   r   rv   r   r   r   r   r   r   r   zHTTP Error 404: Not Found)r1   r   r   r   z/http://player.twitch.tv/?t=5m10s&video=v6528877)r1   r   z$https://www.twitch.tv/videos/6528877z+https://m.twitch.tv/beagsandjam/v/247478721z2https://www.twitch.tv/northernlion/video/291940395z)https://player.twitch.tv/?video=480452374c             C   s   | j |}| j| j|}| jd| |d| j }| jd| j|tddddd|d |d df |d	d
d}| j| ||d< t	|}t
|j}d|krt|d d |d< |jdd k	rdtd| d| jiddgi|d< |S )Nzapi/vods/%s/access_tokenzDownloading %s access tokenz%s/vod/%s.m3u8?%srP   	twitchwebtokensig)allow_sourceallow_audio_onlyallow_spectreplayerplaylist_include_framerateZnauthZnauthsigr   m3u8_native)entry_protocolrc   tr   r   r   Zrechatz+https://api.twitch.tv/v5/videos/%s/commentsrO   rA   )r1   r   	subtitles)r   rp   rw   r-   rn   _extract_m3u8_formatsrj   r	   re   r
   r   queryr   r   r   r&   )r   r1   r*   r   access_tokenrc   
parsed_urlr   r!   r!   r"   r   8  s<    



zTwitchVodIE._real_extractN)
rf   rg   rh   r   r   rn   rw   r}   r   r   r!   r!   r!   r"   r      sR   

r   c               @   s4   e Zd ZdZdZdd Zdd Zdd Zd	d
 ZdS )TwitchPlaylistBaseIEz-kraken/channels/%s/videos/?offset=%d&limit=%dd   c                s   j d| |d}|jdp$|jd}g }d} j}d}d }xtjdD ]}	 j  j|||f |d j|pl|	f }
 j|
}|sP t|
jd	}| r|rt	||kr j
d
| d}|}d}qH|j| |s|rt	||krP ||7 }qHW  j fddt|D ||S )Nzkraken/channels/%szDownloading channel info JSONr   r   r   Fr   zDownloading %s JSON page %sZ_totalzITwitch pagination is broken on twitch side, requesting all videos at onceTz(all at once)c                s   g | ]} j |qS r!   )_make_url_result)rZ   r   )r   r!   r"   
<listcomp>  s    z:TwitchPlaylistBaseIE._extract_playlist.<locals>.<listcomp>)r-   r   _PAGE_LIMIT	itertoolscount_PLAYLIST_PATH_PLAYLIST_TYPE_extract_playlist_pager   lenreport_warningextendr   r   )r   
channel_idr   channel_namer   offsetlimitZbroken_paging_detectedZcounter_overridecounterr    page_entriestotalr!   )r   r"   _extract_playlisth  sD    

z&TwitchPlaylistBaseIE._extract_playlistc             C   sB   y"dt j| }| j|t j |dS  tk
r<   | j|S X d S )Nzv%s)video_id)r   r   
url_resultie_keyAssertionError)r   r1   r   r!   r!   r"   r     s
    z%TwitchPlaylistBaseIE._make_url_resultc             C   s    |j d}|rdd |D S g S )Nvideosc             S   s   g | ]}|d  qS )r1   r!   )rZ   r   r!   r!   r"   r     s    z?TwitchPlaylistBaseIE._extract_playlist_page.<locals>.<listcomp>)r   )r   r    r   r!   r!   r"   r     s    
z+TwitchPlaylistBaseIE._extract_playlist_pagec             C   s   | j | j|S )N)r   r   )r   r1   r!   r!   r"   r     s    z"TwitchPlaylistBaseIE._real_extractN)	rf   rg   rh   r   r   r   r   r   r   r!   r!   r!   r"   r   d  s   )r   c               @   s:   e Zd ZdZdej ZdZdddddd	d
ddgZdS )TwitchProfileIEztwitch:profilez$%s/(?P<id>[^/]+)/profile/?(?:\#.*)?$profilez&http://www.twitch.tv/vanillatv/profileZ	vanillatvZ	VanillaTV)ru   rv   i  )r1   r   r   z$http://m.twitch.tv/vanillatv/profileT)r1   r   N)	rf   rg   rh   r   r   ri   r   r   r   r!   r!   r!   r"   r     s   
r   c               @   s    e Zd Zdej Zejd ZdS )TwitchVideosBaseIEz%s/(?P<id>[^/]+)/videosz&broadcast_type=N)rf   rg   rh   r   ri   _VALID_URL_VIDEOS_BASEr   r   r!   r!   r!   r"   r     s   
r   c               @   sD   e Zd ZdZdej Zejd ZdZddddd	d
dddgZ	dS )TwitchAllVideosIEztwitch:videos:allz%s/allzarchive,upload,highlightz
all videosz)https://www.twitch.tv/spamfish/videos/allspamfishSpamfish)ru   rv   ie  )r1   r   r   z'https://m.twitch.tv/spamfish/videos/allT)r1   r   N)
rf   rg   rh   r   r   r   r   r   r   r   r!   r!   r!   r"   r     s   

r   c               @   sD   e Zd ZdZdej Zejd ZdZddddd	d
dddgZ	dS )TwitchUploadsIEztwitch:videos:uploadsz
%s/uploadsZuploaduploadsz-https://www.twitch.tv/spamfish/videos/uploadsr   r   )ru   rv   r   )r1   r   r   z+https://m.twitch.tv/spamfish/videos/uploadsT)r1   r   N)
rf   rg   rh   r   r   r   r   r   r   r   r!   r!   r!   r"   r     s   

r   c               @   sD   e Zd ZdZdej Zejd ZdZddddd	d
dddgZ	dS )TwitchPastBroadcastsIEztwitch:videos:past-broadcastsz%s/past-broadcastsarchivezpast broadcastsz5https://www.twitch.tv/spamfish/videos/past-broadcastsr   r   )ru   rv   r   )r1   r   r   z3https://m.twitch.tv/spamfish/videos/past-broadcastsT)r1   r   N)
rf   rg   rh   r   r   r   r   r   r   r   r!   r!   r!   r"   r     s   

r   c               @   sD   e Zd ZdZdej Zejd ZdZddddd	d
dddgZ	dS )TwitchHighlightsIEztwitch:videos:highlightsz%s/highlightsZ	highlightZ
highlightsz0https://www.twitch.tv/spamfish/videos/highlightsr   r   )ru   rv   i%  )r1   r   r   z.https://m.twitch.tv/spamfish/videos/highlightsT)r1   r   N)
rf   rg   rh   r   r   r   r   r   r   r   r!   r!   r!   r"   r     s   

r   c                   sz   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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	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 - @ShroomzTVTieTZ20150122Z	ShroomzTV)ru   
display_idr   rv   r   r   r   r   r   r   r   r   )r1   r   r   z+http://www.twitch.tv/miracle_doto#profile-0)r1   r   z)https://player.twitch.tv/?channel=lotsofszhttps://go.twitch.tv/foodzhttps://m.twitch.tv/foodc                s<   t  fddttttttttt	f	D r,dS t
t| j S )Nc             3   s   | ]}|j  V  qd S )N)suitable)rZ   ie)r1   r!   r"   r\   2  s    z*TwitchStreamIE.suitable.<locals>.<genexpr>F)anyr   r   r   r   r   r   r   r   TwitchClipsIEsuperr   r   )clsr1   )	__class__)r1   r"   r   /  s    zTwitchStreamIE.suitablec             C   s  | j |}| jd|j  |djd}|s:td| dd|jdi jdpR|j }| jd	| |d
}dddtjddddd|d jd|d jdd	}| jd| j	|t
|f |d}| j| |jd}t|jd}|d }	| j|	jdp|	jd}
|	jd}g }xV|d j D ]F\}}tjd|}|s6q|j|t|jdt|jdd qW t|d ||
|||	jd|	jd|||dd S )!Nz!kraken/streams/%s?stream_type=allzDownloading stream JSONstreamz%s is offlineT)r   r   r   zapi/channels/%s/access_tokenz Downloading channel access tokenrP   i@B i r   4r   zutf-8r   )	r   r   r   pr   r   Zsegment_preferencer   r   z%s/api/channel/hls/%s.m3u8?%sr   Zviewers
created_atr   r   r   z$(?P<width>\d+)x(?P<height>\d+)\.jpg$widthrt   )r1   r   rt   r   )ru   r   rv   r   
thumbnailsr   r   r   r   rc   r   )r   r-   lowerr   r   randomrandintrC   r   rj   r	   re   r   _live_titleitemsrS   rT   r~   r}   r3   r   )r   r1   r   r   r   r   rc   r   r   r   rv   r   r   thumbnail_keythumbnail_urlr   r!   r!   r"   r   >  sb    






zTwitchStreamIE._real_extract)rf   rg   rh   r   r   r}   r   classmethodr   r   __classcell__r!   r!   )r   r"   r     s2   

r   c               @   sV   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gZdd ZdS )r   ztwitch:clipszqhttps?://(?:clips\.twitch\.tv/(?:embed\?.*?\bclip=|(?:[^/]+/)*)|(?:www\.)?twitch\.tv/[^/]+/clip/)(?P<id>[^/?#&]+)z0https://clips.twitch.tv/FaintLightGullWholeWheatZ 761769e1eafce0ffebfb4089cb3847cdZ42850523r   z'EA Play 2016 Live from the Novo Theatrezre:^https?://.*\.jpgi]WZ20160612ZEAZstereotype_Z43566419)	ru   r   rv   r   r   r   creatorr   r   )r1   md5r   z;https://clips.twitch.tv/rflegendary/UninterestedBeeDAESuppyT)r1   r   zDhttps://www.twitch.tv/sergeynixon/clip/StormyThankfulSproutFutureManzEhttps://clips.twitch.tv/embed?clip=InquisitiveBreakableYogurtJebaitedc             C   s  | j |}| jd|tjdd| ij d| jidd d }|sLtdd	d
g }xb|jdg D ]R}t|t	snq^t
|jd}|sq^|j||jdt|jdt|jdd q^W | j| g }xfd"D ]^}|j|}	|	sq||	d}
tjd|	}|r|
jt|jdt|jdd |j|
 qW |jdp8||jdpF||t|jdt|jdt|jd|t|dd tt|dd tt|d d td!
S )#Nzhttps://gql.twitch.tv/gqlr   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	Client-ID)r6   r$   r6   clipz This clip is no longer availableT)r   ZvideoQualities	sourceURLr^   	frameRate)r1   rX   rt   fpstinysmallmedium)ru   r1   z-(\d+)x(\d+)\.r   r   )rt   r   ru   rv   ZdurationSeconds	viewCount	createdAtc             S   s   | d d S )NZbroadcasterdisplayNamer!   )xr!   r!   r"   <lambda>  s    z-TwitchClipsIE._real_extract.<locals>.<lambda>c             S   s   | d d S )Ncuratorr  r!   )r  r!   r!   r"   r    s    c             S   s   | d d S )Nr  ru   r!   )r  r!   r!   r"   r    s    )
ru   rv   rc   r   r   r   r   r  r   r   )r
  r  r  )r   r'   rA   rB   rC   r&   r   r   r   r   r   r~   r   rb   rS   rT   r=   r}   r3   r   r   r   )r   r1   r   r  rc   optionrd   r   thumbnail_idr  thumbmobjr!   r!   r"   r     s\    






zTwitchClipsIE._real_extractN)rf   rg   rh   r   r   r   r   r!   r!   r!   r"   r     s(   

r   )(
__future__r   r   rS   r   rA   commonr   compatr   r   r   r	   r
   utilsr   r   r   r   r   r   r   r   r   r   r   r   rl   r   r   r   r   r   r   r   r   r   r   r   r   r!   r!   r!   r"   <module>   s,   4r<q< 