]>
jfr.im git - yt-dlp.git/blob - yt_dlp/extractor/plutotv.py
2 from __future__
import unicode_literals
7 from . common
import InfoExtractor
21 class PlutoTVIE ( InfoExtractor
):
22 _VALID_URL
= r
'https?://(?:www\.)?pluto\.tv/on-demand/(?P<video_type>movies|series)/(?P<slug>.*)/?$'
23 _INFO_URL
= 'https://service-vod.clusters.pluto.tv/v3/vod/slugs/'
24 _INFO_QUERY_PARAMS
= {
27 'clientID' : compat_str ( uuid
. uuid1 ()),
28 'clientModelNumber' : 'na' ,
29 'serverSideAds' : 'false' ,
30 'deviceMake' : 'unknown' ,
33 'deviceVersion' : 'unknown' ,
34 'sid' : compat_str ( uuid
. uuid1 ()),
38 'url' : 'https://pluto.tv/on-demand/series/i-love-money/season/2/episode/its-in-the-cards-2009-2-3' ,
39 'md5' : 'ebcdd8ed89aaace9df37924f722fd9bd' ,
41 'id' : '5de6c598e9379ae4912df0a8' ,
43 'title' : 'It \' s In The Cards' ,
44 'episode' : 'It \' s In The Cards' ,
45 'description' : 'The teams face off against each other in a 3-on-2 soccer showdown. Strategy comes into play, though, as each team gets to select their opposing teams’ two defenders.' ,
46 'series' : 'I Love Money' ,
53 'url' : 'https://pluto.tv/on-demand/series/i-love-money/season/1/' ,
56 'id' : '5de6c582e9379ae4912dedbd' ,
57 'title' : 'I Love Money - Season 1' ,
61 'url' : 'https://pluto.tv/on-demand/series/i-love-money/' ,
64 'id' : '5de6c582e9379ae4912dedbd' ,
65 'title' : 'I Love Money' ,
69 'url' : 'https://pluto.tv/on-demand/movies/arrival-2015-1-1' ,
70 'md5' : '3cead001d317a018bf856a896dee1762' ,
72 'id' : '5e83ac701fa6a9001bb9df24' ,
75 'description' : 'When mysterious spacecraft touch down across the globe, an elite team - led by expert translator Louise Banks (Academy Award® nominee Amy Adams) – races against time to decipher their intent.' ,
81 def _to_ad_free_formats ( self
, video_id
, formats
):
84 for format
in formats
:
85 res
= self
._ download
_ webpage
(
86 format
. get ( 'url' ), video_id
, note
= 'Downloading m3u8 playlist' ,
90 first_segment_url
= re
. search (
91 r
'^(https?://.*/)0\-(end|[0-9]+)/[^/]+\.ts$' , res
,
93 if not first_segment_url
:
96 compat_urlparse
. urljoin ( first_segment_url
. group ( 1 ), '0-end/master.m3u8' ))
98 for m3u8_url
in m3u8_urls
:
99 ad_free_formats
. extend (
100 self
._ extract
_ m
3u8_ formats
(
101 m3u8_url
, video_id
, 'mp4' , 'm3u8_native' ,
102 m3u8_id
= 'hls' , fatal
= False ))
103 self
._ sort
_ formats
( ad_free_formats
)
104 return ad_free_formats
106 def _get_video_info ( self
, video_json
, slug
, series_name
= None ):
107 video_id
= video_json
. get ( '_id' , slug
)
109 for video_url
in try_get ( video_json
, lambda x
: x
[ 'stitched' ][ 'urls' ], list ) or []:
110 if video_url
. get ( 'type' ) != 'hls' :
112 url
= url_or_none ( video_url
. get ( 'url' ))
114 self
._ extract
_ m
3u8_ formats
(
115 url
, video_id
, 'mp4' , 'm3u8_native' ,
116 m3u8_id
= 'hls' , fatal
= False ))
119 'formats' : self
._ to
_ ad
_ free
_ formats
( video_id
, formats
),
120 'title' : video_json
. get ( 'name' ),
121 'description' : video_json
. get ( 'description' ),
122 'duration' : float_or_none ( video_json
. get ( 'duration' ), scale
= 1000 ),
126 'series' : series_name
,
127 'episode' : video_json
. get ( 'name' ),
128 'season_number' : int_or_none ( video_json
. get ( 'season' )),
129 'episode_number' : int_or_none ( video_json
. get ( 'number' )),
133 def _real_extract ( self
, url
):
134 path
= compat_urlparse
. urlparse ( url
). path
135 path_components
= path
. split ( '/' )
136 video_type
= path_components
[ 2 ]
137 info_slug
= path_components
[ 3 ]
138 video_json
= self
._ download
_ json
( self
._ INFO
_U RL
+ info_slug
, info_slug
,
139 query
= self
._ INFO
_ QUERY
_ PARAMS
)
141 if video_type
== 'series' :
142 series_name
= video_json
. get ( 'name' , info_slug
)
143 season_number
= int_or_none ( try_get ( path_components
, lambda x
: x
[ 5 ]))
144 episode_slug
= try_get ( path_components
, lambda x
: x
[ 7 ])
147 for season
in video_json
[ 'seasons' ]:
148 if season_number
is not None and season_number
!= int_or_none ( season
. get ( 'number' )):
150 for episode
in season
[ 'episodes' ]:
151 if episode_slug
is not None and episode_slug
!= episode
. get ( 'slug' ):
153 videos
. append ( self
._ get
_ video
_ info
( episode
, episode_slug
, series_name
))
155 raise ExtractorError ( 'Failed to find any videos to extract' )
156 if episode_slug
is not None and len ( videos
) == 1 :
158 playlist_title
= series_name
159 if season_number
is not None :
160 playlist_title
+= ' - Season %d ' % season_number
161 return self
. playlist_result ( videos
,
162 playlist_id
= video_json
. get ( '_id' , info_slug
),
163 playlist_title
= playlist_title
)
164 return self
._ get
_ video
_ info
( video_json
, info_slug
)