mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2026-07-21 17:42:28 +00:00
[ie/showroom] Rework extractors (#17142)
Closes #2072, Closes #7297 Authored by: doe1080
This commit is contained in:
parent
59d9ae606a
commit
6a188aed91
@ -1718,7 +1718,10 @@ from .shahid import (
|
||||
from .sharepoint import SharePointIE
|
||||
from .shemaroome import ShemarooMeIE
|
||||
from .shiey import ShieyIE
|
||||
from .showroomlive import ShowRoomLiveIE
|
||||
from .showroomlive import (
|
||||
ShowRoomLiveIE,
|
||||
ShowRoomVodIE,
|
||||
)
|
||||
from .sibnet import SibnetEmbedIE
|
||||
from .simplecast import (
|
||||
SimplecastEpisodeIE,
|
||||
|
||||
@ -1,80 +1,134 @@
|
||||
import datetime as dt
|
||||
import json
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
ExtractorError,
|
||||
UserNotLive,
|
||||
clean_html,
|
||||
extract_attributes,
|
||||
int_or_none,
|
||||
urljoin,
|
||||
str_or_none,
|
||||
url_or_none,
|
||||
)
|
||||
from ..utils.traversal import (
|
||||
find_element,
|
||||
require,
|
||||
traverse_obj,
|
||||
)
|
||||
|
||||
|
||||
class ShowRoomLiveIE(InfoExtractor):
|
||||
_WORKING = False
|
||||
_VALID_URL = r'https?://(?:www\.)?showroom-live\.com/(?!onlive|timetable|event|campaign|news|ranking|room)(?P<id>[^/?#&]+)'
|
||||
_TEST = {
|
||||
'url': 'https://www.showroom-live.com/48_Nana_Okada',
|
||||
IE_NAME = 'showroom:live'
|
||||
IE_DESC = 'SHOWROOM'
|
||||
|
||||
_VALID_URL = r'https?://(?:www\.)?showroom-live\.com/r/(?P<id>[\w-]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://www.showroom-live.com/r/48_Yui_Oguri',
|
||||
'only_matching': True,
|
||||
}
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
broadcaster_id = self._match_id(url)
|
||||
webpage = self._download_webpage(
|
||||
url, broadcaster_id, headers={'Accept-Language': 'ja'})
|
||||
nuxt_data = self._search_nuxt_json(webpage, broadcaster_id)['data']
|
||||
|
||||
webpage = self._download_webpage(url, broadcaster_id)
|
||||
cookies = self._get_cookies(url)
|
||||
sr_id = traverse_obj(cookies, ('sr_id', 'value', {str}, filter))
|
||||
if not sr_id:
|
||||
self.raise_login_required()
|
||||
|
||||
room_id = self._search_regex(
|
||||
(r'SrGlobal\.roomId\s*=\s*(\d+)',
|
||||
r'(?:profile|room)\?room_id\=(\d+)'), webpage, 'room_id')
|
||||
room_profile = traverse_obj(nuxt_data, (
|
||||
f'roomProfile-{broadcaster_id}-{sr_id}', {dict}))
|
||||
start_timestamp = traverse_obj(room_profile, ('current_live_started_at', {int_or_none}))
|
||||
is_live = traverse_obj(room_profile, ('is_onlive', {bool}))
|
||||
|
||||
room = self._download_json(
|
||||
urljoin(url, f'/api/room/profile?room_id={room_id}'),
|
||||
broadcaster_id)
|
||||
if not is_live:
|
||||
if start_timestamp:
|
||||
start_time = dt.datetime.fromtimestamp(
|
||||
start_timestamp, dt.timezone.utc,
|
||||
).astimezone().strftime('%Y-%m-%d %H:%M:%S %Z')
|
||||
|
||||
is_live = room.get('is_onlive')
|
||||
if is_live is not True:
|
||||
raise ExtractorError(f'{broadcaster_id} is offline', expected=True)
|
||||
self.raise_no_formats(
|
||||
f'Next livestream is scheduled to start at {start_time}', expected=True)
|
||||
|
||||
uploader = room.get('performer_name') or broadcaster_id
|
||||
title = room.get('room_name') or room.get('main_name') or uploader
|
||||
return {
|
||||
'id': broadcaster_id,
|
||||
'live_status': 'is_upcoming',
|
||||
'release_timestamp': start_timestamp,
|
||||
}
|
||||
raise UserNotLive(video_id=broadcaster_id)
|
||||
|
||||
room_id = traverse_obj(room_profile, ('room_id', {str_or_none}))
|
||||
room_name = traverse_obj(room_profile, (
|
||||
('room_name', 'main_name'), {clean_html}, filter, any))
|
||||
|
||||
streaming_url_list = self._download_json(
|
||||
urljoin(url, f'/api/live/streaming_url?room_id={room_id}'),
|
||||
broadcaster_id)['streaming_url_list']
|
||||
|
||||
formats = []
|
||||
for stream in streaming_url_list:
|
||||
stream_url = stream.get('url')
|
||||
if not stream_url:
|
||||
continue
|
||||
stream_type = stream.get('type')
|
||||
if stream_type == 'hls':
|
||||
m3u8_formats = self._extract_m3u8_formats(
|
||||
stream_url, broadcaster_id, ext='mp4', m3u8_id='hls',
|
||||
live=True)
|
||||
for f in m3u8_formats:
|
||||
f['quality'] = int_or_none(stream.get('quality', 100))
|
||||
formats.extend(m3u8_formats)
|
||||
elif stream_type == 'rtmp':
|
||||
stream_name = stream.get('stream_name')
|
||||
if not stream_name:
|
||||
continue
|
||||
formats.append({
|
||||
'url': stream_url,
|
||||
'play_path': stream_name,
|
||||
'page_url': url,
|
||||
'player_url': 'https://www.showroom-live.com/assets/swf/v3/ShowRoomLive.swf',
|
||||
'rtmp_live': True,
|
||||
'ext': 'flv',
|
||||
'format_id': 'rtmp',
|
||||
'format_note': stream.get('label'),
|
||||
'quality': int_or_none(stream.get('quality', 100)),
|
||||
})
|
||||
'https://www.showroom-live.com/api/live/streaming_url',
|
||||
broadcaster_id, query={'room_id': room_id})
|
||||
m3u8_url = traverse_obj(streaming_url_list, (
|
||||
'streaming_url_list', lambda _, v: v['type'] == 'hls_all',
|
||||
'url', {url_or_none}, any, {require('m3u8 URL')}))
|
||||
|
||||
return {
|
||||
'id': str(room.get('live_id') or broadcaster_id),
|
||||
'title': title,
|
||||
'description': room.get('description'),
|
||||
'timestamp': int_or_none(room.get('current_live_started_at')),
|
||||
'uploader': uploader,
|
||||
'uploader_id': broadcaster_id,
|
||||
'view_count': int_or_none(room.get('view_num')),
|
||||
'formats': formats,
|
||||
'is_live': True,
|
||||
'title': room_name,
|
||||
'channel': room_name,
|
||||
'channel_id': broadcaster_id,
|
||||
'formats': self._extract_m3u8_formats(m3u8_url, broadcaster_id, 'mp4'),
|
||||
'is_live': is_live,
|
||||
'release_timestamp': start_timestamp,
|
||||
**traverse_obj(room_profile, {
|
||||
'id': ('live_id', {str_or_none}),
|
||||
'channel_follower_count': ('follower_num', {int_or_none}),
|
||||
'channel_is_verified': ('is_official', {bool}),
|
||||
'description': ('description', {clean_html}, filter),
|
||||
'genres': ('genre_name', {clean_html}, filter, all, filter),
|
||||
'tags': ('live_tags', ..., 'name', {clean_html}, filter, all, filter),
|
||||
'thumbnail': ('image_square', {url_or_none}),
|
||||
'view_count': ('view_num', {int_or_none}),
|
||||
}),
|
||||
}
|
||||
|
||||
|
||||
class ShowRoomVodIE(InfoExtractor):
|
||||
IE_NAME = 'showroom:vod'
|
||||
|
||||
_VALID_URL = r'https?://(?:www\.)?showroom-live\.com/episode/watch\?(?:[^#]+&)?id=(?P<id>\w+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://www.showroom-live.com/episode/watch?id=214',
|
||||
'info_dict': {
|
||||
'id': '214',
|
||||
'ext': 'mp4',
|
||||
'title': 'aaa',
|
||||
},
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
episode_id = self._match_id(url)
|
||||
webpage = self._download_webpage(url, episode_id)
|
||||
episode_data = traverse_obj(webpage, (
|
||||
{find_element(id='episode-data', html=True)},
|
||||
{extract_attributes}, 'data-episode', {json.loads}, {dict}))
|
||||
|
||||
streaming_url_list = self._download_json(
|
||||
'https://www.showroom-live.com/api/episode/streaming_url',
|
||||
episode_id, query={'episode_id': episode_id})
|
||||
m3u8_url = traverse_obj(streaming_url_list, (
|
||||
'streaming_url_list', 'hls_all',
|
||||
'hls_all', {url_or_none}, {require('m3u8 URL')}))
|
||||
|
||||
return {
|
||||
'id': episode_id,
|
||||
'formats': self._extract_m3u8_formats(m3u8_url, episode_id, 'mp4'),
|
||||
'thumbnail': traverse_obj(streaming_url_list, ('thumbnail_url', {url_or_none})),
|
||||
**traverse_obj(episode_data, {
|
||||
'title': ('title', {clean_html}, filter),
|
||||
'description': ('description', {clean_html}, filter),
|
||||
'duration': ('video_time', {int_or_none}),
|
||||
'timestamp': ('display_started_at', {int_or_none}),
|
||||
}),
|
||||
**traverse_obj(episode_data, ('series', {
|
||||
'series': ('name', {clean_html}, filter),
|
||||
'series_id': ('id', {str_or_none}),
|
||||
})),
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user