[ie/tubitv] Improve extractor (#16428)

Closes #16422
Authored by: InvalidUsernameException
This commit is contained in:
InvalidUsernameException
2026-08-26 20:40:14 +00:00
committed by GitHub
parent e164eebe19
commit d1cb4709cc
+17 -32
View File
@@ -1,7 +1,4 @@
import re
from .common import InfoExtractor
from ..networking import Request
from ..utils import (
ExtractorError,
int_or_none,
@@ -9,15 +6,12 @@ from ..utils import (
strip_or_none,
traverse_obj,
url_or_none,
urlencode_postdata,
)
class TubiTvIE(InfoExtractor):
IE_NAME = 'tubitv'
_VALID_URL = r'https?://(?:www\.)?tubitv\.com/(?:[a-z]{2}-[a-z]{2}/)?(?P<type>video|movies|tv-shows)/(?P<id>\d+)'
_LOGIN_URL = 'http://tubitv.com/login'
_NETRC_MACHINE = 'tubitv'
_TESTS = [{
'url': 'https://tubitv.com/movies/100004539/the-39-steps',
'info_dict': {
@@ -27,7 +21,7 @@ class TubiTvIE(InfoExtractor):
'description': 'md5:bb2f2dd337f0dc58c06cb509943f54c8',
'uploader_id': 'abc2558d54505d4f0f32be94f2e7108c',
'release_year': 1935,
'thumbnail': r're:^https?://.+\.(jpe?g|png)$',
'thumbnail': r're:^https?://canvas-lb\.tubitv\.com/.+',
'duration': 5187,
},
'params': {'skip_download': 'm3u8'},
@@ -44,7 +38,7 @@ class TubiTvIE(InfoExtractor):
'season_number': 1,
'uploader_id': '2a9273e728c510d22aa5c57d0646810b',
'release_year': 2011,
'thumbnail': r're:^https?://.+\.(jpe?g|png)$',
'thumbnail': r're:^https?://canvas-lb\.tubitv\.com/.+',
'duration': 1376,
},
'params': {'skip_download': 'm3u8'},
@@ -82,24 +76,11 @@ class TubiTvIE(InfoExtractor):
_UNPLAYABLE_FORMATS = ('hlsv6_widevine', 'hlsv6_widevine_nonclearlead', 'hlsv6_playready_psshv0',
'hlsv6_fairplay', 'dash_widevine', 'dash_widevine_nonclearlead')
def _perform_login(self, username, password):
self.report_login()
form_data = {
'username': username,
'password': password,
}
payload = urlencode_postdata(form_data)
request = Request(self._LOGIN_URL, payload)
request.headers['Content-Type'] = 'application/x-www-form-urlencoded'
login_page = self._download_webpage(
request, None, False, 'Wrong login info')
if not re.search(r'id="tubi-logout"', login_page):
raise ExtractorError(
'Login failed (invalid username/password)', expected=True)
def _real_extract(self, url):
video_id, video_type = self._match_valid_url(url).group('id', 'type')
webpage = self._download_webpage(f'https://tubitv.com/{video_type}/{video_id}/', video_id)
webpage = self._download_webpage(
f'https://tubitv.com/{video_type}/{video_id}/', video_id,
headers=self.geo_verification_headers())
video_data = self._search_json(
r'window\.__data\s*=', webpage, 'data', video_id,
transform_source=js_to_json)['video']['byId'][video_id]
@@ -113,7 +94,11 @@ class TubiTvIE(InfoExtractor):
if resource_type == 'dash':
formats.extend(self._extract_mpd_formats(manifest_url, video_id, mpd_id=resource_type, fatal=False))
elif resource_type in ('hlsv3', 'hlsv6'):
formats.extend(self._extract_m3u8_formats(manifest_url, video_id, 'mp4', m3u8_id=resource_type, fatal=False))
fmts = self._extract_m3u8_formats(manifest_url, video_id, 'mp4', m3u8_id=resource_type, fatal=False)
for fmt in fmts:
if 'Audio Description' in fmt.get('format_note', ''):
fmt['language_preference'] = -10
formats.extend(fmts)
elif resource_type in self._UNPLAYABLE_FORMATS:
drm_formats = True
else:
@@ -162,27 +147,27 @@ class TubiTvShowIE(InfoExtractor):
'id': 'the-joy-of-painting-with-bob-ross',
},
}, {
'url': 'https://tubitv.com/series/2311/the-saddle-club/season-1',
'url': 'https://tubitv.com/series/300000435/the-saddle-club/season-1',
'playlist_count': 26,
'info_dict': {
'id': 'the-saddle-club-season-1',
},
}, {
'url': 'https://tubitv.com/series/2311/the-saddle-club/season-3',
'playlist_count': 19,
'url': 'https://tubitv.com/series/300000435/the-saddle-club/season-2',
'playlist_count': 26,
'info_dict': {
'id': 'the-saddle-club-season-3',
'id': 'the-saddle-club-season-2',
},
}, {
'url': 'https://tubitv.com/series/2311/the-saddle-club/',
'playlist_mincount': 71,
'url': 'https://tubitv.com/series/300000435/the-saddle-club',
'playlist_mincount': 52,
'info_dict': {
'id': 'the-saddle-club',
},
}]
def _entries(self, show_url, playlist_id, selected_season):
webpage = self._download_webpage(show_url, playlist_id)
webpage = self._download_webpage(show_url, playlist_id, headers=self.geo_verification_headers())
data = self._search_json(
r'window\.__REACT_QUERY_STATE__\s*=', webpage, 'data', playlist_id,