]>
jfr.im git - yt-dlp.git/blob - yt_dlp/extractor/tubitv.py
3 from .common
import InfoExtractor
4 from ..networking
import Request
14 class TubiTvIE(InfoExtractor
):
18 https?://(?:www\.)?tubitv\.com/(?:video|movies|tv-shows)/
21 _LOGIN_URL
= 'http://tubitv.com/login'
22 _NETRC_MACHINE
= 'tubitv'
23 _GEO_COUNTRIES
= ['US']
25 'url': 'https://tubitv.com/movies/383676/tracker',
26 'md5': '566fa0f76870302d11af0de89511d3f0',
31 'description': 'md5:ff320baf43d0ad2655e538c1d5cd9706',
32 'uploader_id': 'f866e2677ea2f0dff719788e4f7f9195',
34 'thumbnail': r
're:^https?://.+\.(jpe?g|png)$',
38 'url': 'http://tubitv.com/video/283829/the_comedian_at_the_friday',
39 'md5': '43ac06be9326f41912dc64ccf7a80320',
43 'title': 'The Comedian at The Friday',
44 'description': 'A stand up comedian is forced to look at the decisions in his life while on a one week trip to the west coast.',
45 'uploader_id': 'bc168bee0d18dd1cb3b86c68706ab434',
47 'skip': 'Content Unavailable'
49 'url': 'http://tubitv.com/tv-shows/321886/s01_e01_on_nom_stories',
50 'only_matching': True,
52 'url': 'https://tubitv.com/movies/560057/penitentiary?start=true',
56 'title': 'Penitentiary',
57 'description': 'md5:8d2fc793a93cc1575ff426fdcb8dd3f9',
58 'uploader_id': 'd8fed30d4f24fcb22ec294421b9defc2',
61 'skip': 'Content Unavailable'
64 # DRM formats are included only to raise appropriate error
65 _UNPLAYABLE_FORMATS
= ('hlsv6_widevine', 'hlsv6_widevine_nonclearlead', 'hlsv6_playready_psshv0',
66 'hlsv6_fairplay', 'dash_widevine', 'dash_widevine_nonclearlead')
68 def _perform_login(self
, username
, password
):
74 payload
= urlencode_postdata(form_data
)
75 request
= Request(self
._LOGIN
_URL
, payload
)
76 request
.headers
['Content-Type'] = 'application/x-www-form-urlencoded'
77 login_page
= self
._download
_webpage
(
78 request
, None, False, 'Wrong login info')
79 if not re
.search(r
'id="tubi-logout"', login_page
):
81 'Login failed (invalid username/password)', expected
=True)
83 def _real_extract(self
, url
):
84 video_id
= self
._match
_id
(url
)
85 video_data
= self
._download
_json
(f
'https://tubitv.com/oz/videos/{video_id}/content', video_id
, query
={
86 'video_resources': ['dash', 'hlsv3', 'hlsv6', *self
._UNPLAYABLE
_FORMATS
],
88 title
= video_data
['title']
93 for resource
in video_data
['video_resources']:
94 if resource
['type'] in ('dash', ):
95 formats
+= self
._extract
_mpd
_formats
(resource
['manifest']['url'], video_id
, mpd_id
=resource
['type'], fatal
=False)
96 elif resource
['type'] in ('hlsv3', 'hlsv6'):
97 formats
+= self
._extract
_m
3u8_formats
(resource
['manifest']['url'], video_id
, 'mp4', m3u8_id
=resource
['type'], fatal
=False)
98 elif resource
['type'] in self
._UNPLAYABLE
_FORMATS
:
101 if not formats
and drm_formats
:
102 self
.report_drm(video_id
)
103 elif not formats
and not video_data
.get('policy_match'): # policy_match is False if content was removed
104 raise ExtractorError('This content is currently unavailable', expected
=True)
107 for thumbnail_url
in video_data
.get('thumbnails', []):
108 if not thumbnail_url
:
111 'url': self
._proto
_relative
_url
(thumbnail_url
),
115 for sub
in video_data
.get('subtitles', []):
116 sub_url
= sub
.get('url')
119 subtitles
.setdefault(sub
.get('lang', 'English'), []).append({
120 'url': self
._proto
_relative
_url
(sub_url
),
123 season_number
, episode_number
, episode_title
= self
._search
_regex
(
124 r
'^S(\d+):E(\d+) - (.+)', title
, 'episode info', fatal
=False, group
=(1, 2, 3), default
=(None, None, None))
130 'subtitles': subtitles
,
131 'thumbnails': thumbnails
,
132 'description': video_data
.get('description'),
133 'duration': int_or_none(video_data
.get('duration')),
134 'uploader_id': video_data
.get('publisher_id'),
135 'release_year': int_or_none(video_data
.get('year')),
136 'season_number': int_or_none(season_number
),
137 'episode_number': int_or_none(episode_number
),
138 'episode_title': episode_title
142 class TubiTvShowIE(InfoExtractor
):
143 _VALID_URL
= r
'https?://(?:www\.)?tubitv\.com/series/[0-9]+/(?P<show_name>[^/?#]+)'
145 'url': 'https://tubitv.com/series/3936/the-joy-of-painting-with-bob-ross?start=true',
146 'playlist_mincount': 390,
148 'id': 'the-joy-of-painting-with-bob-ross',
152 def _entries(self
, show_url
, show_name
):
153 show_webpage
= self
._download
_webpage
(show_url
, show_name
)
155 show_json
= self
._parse
_json
(self
._search
_regex
(
156 r
'window\.__data\s*=\s*({[^<]+});\s*</script>',
157 show_webpage
, 'data'), show_name
, transform_source
=js_to_json
)['video']
159 for episode_id
in show_json
['fullContentById'].keys():
160 if traverse_obj(show_json
, ('byId', episode_id
, 'type')) == 's':
162 yield self
.url_result(
163 'tubitv:%s' % episode_id
,
164 ie
=TubiTvIE
.ie_key(), video_id
=episode_id
)
166 def _real_extract(self
, url
):
167 show_name
= self
._match
_valid
_url
(url
).group('show_name')
168 return self
.playlist_result(self
._entries
(url
, show_name
), playlist_id
=show_name
)