Compare commits

..

No commits in common. "834a5907c1e6e12430c145681c23c48f3c6eb557" and "4cc9137f11932887be7452d33c856d697da594fc" have entirely different histories.

View File

@ -1,24 +1,19 @@
from .common import InfoExtractor
from ..utils import (
extract_attributes,
get_element_text_and_html_by_tag,
int_or_none,
join_nonempty,
str_or_none,
try_call,
traverse_obj,
unified_timestamp,
strip_or_none,
)
from ..utils.traversal import traverse_obj
class DuoplayIE(InfoExtractor):
_VALID_URL = r'https://duoplay\.ee/(?P<id>\d+)/[\w-]+/?(?:\?(?:[^#]+&)?ep=(?P<ep>\d+))?'
_VALID_URL = r'https://duoplay\.ee/(?P<id>\d+)/'
_TESTS = [{
'note': 'Siberi võmm S02E12',
'url': 'https://duoplay.ee/4312/siberi-vomm?ep=24',
'md5': '1ff59d535310ac9c5cf5f287d8f91b2d',
'info_dict': {
'id': '4312_24',
'id': '4312',
'ext': 'mp4',
'title': 'Operatsioon "Öö"',
'thumbnail': r're:https://.+\.jpg(?:\?c=\d+)?$',
@ -26,18 +21,19 @@ class DuoplayIE(InfoExtractor):
'upload_date': '20170523',
'timestamp': 1495567800,
'series': 'Siberi võmm',
'series_id': '4312',
'series_id': 4312,
'season': 'Season 2',
'season_number': 2,
'episode': 'Operatsioon "Öö"',
'episode_number': 12,
'episode_id': 24,
},
}, {
'note': 'Empty title',
'url': 'https://duoplay.ee/17/uhikarotid?ep=14',
'md5': '6aca68be71112314738dd17cced7f8bf',
'info_dict': {
'id': '17_14',
'id': '17',
'ext': 'mp4',
'title': 'Episode 14',
'thumbnail': r're:https://.+\.jpg(?:\?c=\d+)?$',
@ -45,37 +41,36 @@ class DuoplayIE(InfoExtractor):
'upload_date': '20100916',
'timestamp': 1284661800,
'series': 'Ühikarotid',
'series_id': '17',
'series_id': 17,
'season': 'Season 2',
'season_number': 2,
'episode': 'Episode 14',
'episode_number': 14,
'episode_id': 14,
},
}]
def _real_extract(self, url):
telecast_id, episode = self._match_valid_url(url).groups()
video_id = join_nonempty(telecast_id, episode, delim='_')
webpage = self._download_webpage(url, video_id)
video_player = try_call(lambda: extract_attributes(
get_element_text_and_html_by_tag('video-player', webpage)[1]))
if not video_player or not video_player.get('manifest-url'):
self.raise_no_formats('No video found', expected=True)
def decode_quot(s: str):
return s.replace("&quot;", '"')
episode_attr = self._parse_json(video_player.get(':episode') or '', video_id, fatal=False) or {}
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
manifest_url = self._search_regex(r'<video-player[^>]+manifest-url="([^"]+)"', webpage, 'video-player')
episode_attr = self._search_regex(r'<video-player[^>]+:episode="([^"]+)"', webpage, 'episode data')
ep = self._parse_json(episode_attr, video_id, decode_quot)
return {
'id': video_id,
'formats': self._extract_m3u8_formats(video_player['manifest-url'], video_id, 'mp4'),
**traverse_obj(episode_attr, {
'title': (None, ('subtitle', ('episode_id', {lambda x: f'Episode {x}'}))),
'description': 'synopsis',
'thumbnail': ('images', 'original'),
'timestamp': ('airtime', {lambda x: unified_timestamp(x + ' +0200')}),
'series': 'title',
'series_id': ('telecast_id', {str_or_none}),
'season_number': ('season_id', {int_or_none}),
'episode': 'subtitle',
'episode_number': (None, ('episode_nr', 'episode_id'), {int_or_none}),
}, get_all=False),
# fallback to absolute "episode_id" value
'title': traverse_obj(ep, 'subtitle') or f"Episode {traverse_obj(ep, 'episode_id')}",
'description': strip_or_none(traverse_obj(ep, 'synopsis')),
'thumbnail': traverse_obj(ep, ('images', 'original')),
'formats': self._extract_m3u8_formats(manifest_url, video_id, 'mp4'),
'timestamp': unified_timestamp(traverse_obj(ep, 'airtime') + ' +0200'),
'series': traverse_obj(ep, 'title'),
'series_id': traverse_obj(ep, 'telecast_id'),
'season_number': traverse_obj(ep, 'season_id'),
'episode': traverse_obj(ep, 'subtitle'),
# fallback to absolute "episode_id" value
'episode_number': traverse_obj(ep, 'episode_nr') or traverse_obj(ep, 'episode_id'),
'episode_id': traverse_obj(ep, 'episode_id'),
}