Compare commits

..

8 Commits

Author SHA1 Message Date
bashonly
37ff053333
minutia 2024-01-19 06:15:16 +00:00
bashonly
b0088b0e92
Apply suggestions from code review 2024-01-19 06:08:57 +00:00
bashonly
f806717288
actually check html 2024-01-19 06:02:14 +00:00
bashonly
7b3d6e1887
check if expired vod 2024-01-19 05:57:33 +00:00
bashonly
72800be3e0
single-use var 2024-01-19 05:44:13 +00:00
bashonly
c003b6cf41
oops 2024-01-19 05:41:24 +00:00
bashonly
3c77896933
refactor 2024-01-19 05:35:39 +00:00
bashonly
1832b26f49
Apply suggestions from code review 2024-01-19 05:02:14 +00:00

View File

@ -4,9 +4,12 @@ from .common import InfoExtractor
from ..utils import ( from ..utils import (
ExtractorError, ExtractorError,
clean_html, clean_html,
filter_dict,
get_element_by_id, get_element_by_id,
int_or_none, int_or_none,
join_nonempty,
js_to_json, js_to_json,
qualities,
url_or_none, url_or_none,
urljoin, urljoin,
) )
@ -44,27 +47,22 @@ class KukuluLiveIE(InfoExtractor):
'only_matching': True, 'only_matching': True,
}] }]
def _get_quality_meta(self, video_id, desc, code, force_h264=''): def _get_quality_meta(self, video_id, desc, code, force_h264=None):
description = desc if force_h264 == '' else f'{desc} (force_h264)' desc += ' (force_h264)' if force_h264 else ''
qs = self._download_webpage( qs = self._download_webpage(
'https://live.erinn.biz/live.player.fplayer.php', video_id, 'https://live.erinn.biz/live.player.fplayer.php', video_id,
query={ f'Downloading {desc} quality metadata', f'Unable to download {desc} quality metadata',
query=filter_dict({
'hash': video_id, 'hash': video_id,
'action': f'get{code}liveByAjax', 'action': f'get{code}liveByAjax',
'force_h264': force_h264, 'force_h264': force_h264,
}, }))
note=f'Downloading {description} quality metadata',
errnote=f'Unable to download {description} quality metadata')
return urllib.parse.parse_qs(qs) return urllib.parse.parse_qs(qs)
def _add_quality_formats(self, formats, quality_meta): def _add_quality_formats(self, formats, quality_meta):
vcodec = traverse_obj(quality_meta, ('vcodec', 0)) vcodec = traverse_obj(quality_meta, ('vcodec', 0, {str}))
quality = traverse_obj(quality_meta, ('now_quality', 0)) quality = traverse_obj(quality_meta, ('now_quality', 0, {str}))
quality_priority = { quality_priority = qualities(('low', 'h264', 'high'))(quality)
'high': 3,
'h264': 2,
'low': 1,
}.get(quality, 0)
if traverse_obj(quality_meta, ('hlsaddr', 0, {url_or_none})): if traverse_obj(quality_meta, ('hlsaddr', 0, {url_or_none})):
formats.append({ formats.append({
'format_id': quality, 'format_id': quality,
@ -75,7 +73,7 @@ class KukuluLiveIE(InfoExtractor):
}) })
if traverse_obj(quality_meta, ('hlsaddr_audioonly', 0, {url_or_none})): if traverse_obj(quality_meta, ('hlsaddr_audioonly', 0, {url_or_none})):
formats.append({ formats.append({
'format_id': f'{quality}-audioonly', 'format_id': join_nonempty(quality, 'audioonly'),
'url': quality_meta['hlsaddr_audioonly'][0], 'url': quality_meta['hlsaddr_audioonly'][0],
'ext': 'm4a', 'ext': 'm4a',
'vcodec': 'none', 'vcodec': 'none',
@ -86,25 +84,22 @@ class KukuluLiveIE(InfoExtractor):
video_id = self._match_id(url) video_id = self._match_id(url)
html = self._download_webpage(url, video_id) html = self._download_webpage(url, video_id)
title = clean_html(get_element_by_id('livetitle', html.replace('<SPAN', '<span').replace('SPAN>', 'span>'))) if '>タイムシフトが見つかりませんでした。<' in html:
raise ExtractorError('This stream has expired', expected=True)
title = clean_html(
get_element_by_id('livetitle', html.replace('<SPAN', '<span').replace('SPAN>', 'span>')))
description = self._html_search_meta('Description', html) description = self._html_search_meta('Description', html)
thumbnail = self._html_search_meta(['og:image', 'twitter:image'], html) thumbnail = self._html_search_meta(['og:image', 'twitter:image'], html)
is_live_stream = 'var timeshift = false;' in html if self._search_regex(r'(var\s+timeshift\s*=\s*false)', html, 'is livestream', default=False):
is_vod = 'var timeshift = true;' in html
if is_live_stream:
qualities = [
('high', 'Z'),
('low', 'ForceLow'),
]
formats = [] formats = []
for (desc, code) in qualities: for (desc, code) in [('high', 'Z'), ('low', 'ForceLow')]:
quality_meta = self._get_quality_meta(video_id, desc, code) quality_meta = self._get_quality_meta(video_id, desc, code)
self._add_quality_formats(formats, quality_meta) self._add_quality_formats(formats, quality_meta)
if desc == 'high' and quality_meta.get('vcodec')[0] == 'HEVC': if desc == 'high' and traverse_obj(quality_meta, ('vcodec', 0)) == 'HEVC':
h264_meta = self._get_quality_meta(video_id, desc, code, force_h264='1') self._add_quality_formats(
self._add_quality_formats(formats, h264_meta) formats, self._get_quality_meta(video_id, desc, code, force_h264='1'))
return { return {
'id': video_id, 'id': video_id,
@ -115,42 +110,31 @@ class KukuluLiveIE(InfoExtractor):
'formats': formats, 'formats': formats,
} }
if is_vod: # VOD extraction
player_html = self._download_webpage( player_html = self._download_webpage(
'https://live.erinn.biz/live.timeshift.fplayer.php', video_id, 'https://live.erinn.biz/live.timeshift.fplayer.php', video_id,
query={'hash': video_id}, 'Downloading player html', 'Unable to download player html', query={'hash': video_id})
note='Downloading player html',
errnote='Unable to download player html')
sources_json = self._search_json( sources = traverse_obj(self._search_json(
r'var\s+fplayer_source\s*=', player_html, 'stream data', video_id, r'var\s+fplayer_source\s*=', player_html, 'stream data', video_id,
contains_pattern=r'\[(?s:.+)\]', transform_source=js_to_json) contains_pattern=r'\[(?s:.+)\]', transform_source=js_to_json), lambda _, v: v['file'])
def parse_segment(segment, segment_id, segment_title): def entries(segments, playlist=True):
path = segment.get('file') for i, segment in enumerate(segments, 1):
if not path: yield {
return None 'id': f'{video_id}_{i}' if playlist else video_id,
formats = [{ 'title': f'{title} (Part {i})' if playlist else title,
'url': urljoin('https://live.erinn.biz', path),
'ext': 'mp4',
'protocol': 'm3u8_native',
}]
return {
'id': segment_id,
'title': segment_title,
'description': description, 'description': description,
'timestamp': traverse_obj(segment, ('time_start', {int_or_none})), 'timestamp': traverse_obj(segment, ('time_start', {int_or_none})),
'thumbnail': thumbnail, 'thumbnail': thumbnail,
'formats': formats, 'formats': [{
'url': urljoin('https://live.erinn.biz', segment['file']),
'ext': 'mp4',
'protocol': 'm3u8_native',
}],
} }
if len(sources_json) == 1: if len(sources) == 1:
return parse_segment(sources_json[0], video_id, title) return next(entries(sources, playlist=False))
entries = [] return self.playlist_result(entries(sources), video_id, title, description, multi_video=True)
for i, segment in enumerate(sources_json):
if entry := parse_segment(segment, f'{video_id}_{i}', f'{title} (Part {i + 1})'):
entries.append(entry)
return self.playlist_result(entries, video_id, title, description, multi_video=True)
raise ExtractorError('Could not detect media type')