mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-10-03 08:42:42 +00:00
Compare commits
3 Commits
e123a48f11
...
bf5d18016b
Author | SHA1 | Date | |
---|---|---|---|
|
bf5d18016b | ||
|
4bc19adc87 | ||
|
b2c01d0498 |
@@ -1,5 +1,6 @@
|
|||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
|
clean_html,
|
||||||
clean_podcast_url,
|
clean_podcast_url,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
parse_iso8601,
|
parse_iso8601,
|
||||||
@@ -17,7 +18,7 @@ class ApplePodcastsIE(InfoExtractor):
|
|||||||
'ext': 'mp3',
|
'ext': 'mp3',
|
||||||
'title': 'Ferreck Dawn - To The Break of Dawn 117',
|
'title': 'Ferreck Dawn - To The Break of Dawn 117',
|
||||||
'episode': 'Ferreck Dawn - To The Break of Dawn 117',
|
'episode': 'Ferreck Dawn - To The Break of Dawn 117',
|
||||||
'description': 'md5:1fc571102f79dbd0a77bfd71ffda23bc',
|
'description': 'md5:8c4f5c2c30af17ed6a98b0b9daf15b76',
|
||||||
'upload_date': '20240812',
|
'upload_date': '20240812',
|
||||||
'timestamp': 1723449600,
|
'timestamp': 1723449600,
|
||||||
'duration': 3596,
|
'duration': 3596,
|
||||||
@@ -58,7 +59,7 @@ class ApplePodcastsIE(InfoExtractor):
|
|||||||
r'<script [^>]*\bid=["\']serialized-server-data["\'][^>]*>', webpage,
|
r'<script [^>]*\bid=["\']serialized-server-data["\'][^>]*>', webpage,
|
||||||
'server data', episode_id, contains_pattern=r'\[{(?s:.+)}\]')[0]['data']
|
'server data', episode_id, contains_pattern=r'\[{(?s:.+)}\]')[0]['data']
|
||||||
model_data = traverse_obj(server_data, (
|
model_data = traverse_obj(server_data, (
|
||||||
'headerButtonItems', lambda _, v: v['$kind'] == 'bookmark' and v['modelType'] == 'EpisodeOffer',
|
'headerButtonItems', lambda _, v: v['$kind'] == 'share' and v['modelType'] == 'EpisodeLockup',
|
||||||
'model', {dict}, any))
|
'model', {dict}, any))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -68,7 +69,8 @@ class ApplePodcastsIE(InfoExtractor):
|
|||||||
or self._yield_json_ld(webpage, episode_id, fatal=False), episode_id, fatal=False),
|
or self._yield_json_ld(webpage, episode_id, fatal=False), episode_id, fatal=False),
|
||||||
**traverse_obj(model_data, {
|
**traverse_obj(model_data, {
|
||||||
'title': ('title', {str}),
|
'title': ('title', {str}),
|
||||||
'url': ('streamUrl', {clean_podcast_url}),
|
'description': ('summary', {clean_html}),
|
||||||
|
'url': ('playAction', 'episodeOffer', 'streamUrl', {clean_podcast_url}),
|
||||||
'timestamp': ('releaseDate', {parse_iso8601}),
|
'timestamp': ('releaseDate', {parse_iso8601}),
|
||||||
'duration': ('duration', {int_or_none}),
|
'duration': ('duration', {int_or_none}),
|
||||||
}),
|
}),
|
||||||
|
@@ -3,15 +3,19 @@ from ..networking.exceptions import HTTPError
|
|||||||
from ..utils import (
|
from ..utils import (
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
UserNotLive,
|
UserNotLive,
|
||||||
|
int_or_none,
|
||||||
|
join_nonempty,
|
||||||
parse_iso8601,
|
parse_iso8601,
|
||||||
str_or_none,
|
str_or_none,
|
||||||
traverse_obj,
|
|
||||||
url_or_none,
|
url_or_none,
|
||||||
)
|
)
|
||||||
|
from ..utils.traversal import traverse_obj
|
||||||
|
|
||||||
|
|
||||||
class FlexTVIE(InfoExtractor):
|
class FlexTVIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?flextv\.co\.kr/channels/(?P<id>\d+)/live'
|
IE_NAME = 'ttinglive'
|
||||||
|
IE_DESC = '띵라이브 (formerly FlexTV)'
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?(?:ttinglive\.com|flextv\.co\.kr)/channels/(?P<id>\d+)/live'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'https://www.flextv.co.kr/channels/231638/live',
|
'url': 'https://www.flextv.co.kr/channels/231638/live',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
@@ -36,21 +40,32 @@ class FlexTVIE(InfoExtractor):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
stream_data = self._download_json(
|
stream_data = self._download_json(
|
||||||
f'https://api.flextv.co.kr/api/channels/{channel_id}/stream',
|
f'https://api.ttinglive.com/api/channels/{channel_id}/stream',
|
||||||
channel_id, query={'option': 'all'})
|
channel_id, query={'option': 'all'})
|
||||||
except ExtractorError as e:
|
except ExtractorError as e:
|
||||||
if isinstance(e.cause, HTTPError) and e.cause.status == 400:
|
if isinstance(e.cause, HTTPError) and e.cause.status == 400:
|
||||||
raise UserNotLive(video_id=channel_id)
|
raise UserNotLive(video_id=channel_id)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
playlist_url = stream_data['sources'][0]['url']
|
formats = []
|
||||||
formats, subtitles = self._extract_m3u8_formats_and_subtitles(
|
for stream in traverse_obj(stream_data, ('sources', ..., {dict})):
|
||||||
playlist_url, channel_id, 'mp4')
|
if stream.get('format') == 'ivs' and url_or_none(stream.get('url')):
|
||||||
|
formats.extend(self._extract_m3u8_formats(
|
||||||
|
stream['url'], channel_id, 'mp4', live=True, fatal=False, m3u8_id='ivs'))
|
||||||
|
for format_type in ['hls', 'flv']:
|
||||||
|
for data in traverse_obj(stream, (
|
||||||
|
'urlDetail', format_type, 'resolution', lambda _, v: url_or_none(v['url']))):
|
||||||
|
formats.append({
|
||||||
|
'format_id': join_nonempty(format_type, data.get('suffixName'), delim=''),
|
||||||
|
'url': data['url'],
|
||||||
|
'height': int_or_none(data.get('resolution')),
|
||||||
|
'ext': 'mp4' if format_type == 'hls' else 'flv',
|
||||||
|
'protocol': 'm3u8_native' if format_type == 'hls' else 'http',
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': channel_id,
|
'id': channel_id,
|
||||||
'formats': formats,
|
'formats': formats,
|
||||||
'subtitles': subtitles,
|
|
||||||
'is_live': True,
|
'is_live': True,
|
||||||
**traverse_obj(stream_data, {
|
**traverse_obj(stream_data, {
|
||||||
'title': ('stream', 'title', {str}),
|
'title': ('stream', 'title', {str}),
|
||||||
|
@@ -572,7 +572,7 @@ class VKUserVideosIE(VKBaseIE):
|
|||||||
IE_DESC = "VK - User's Videos"
|
IE_DESC = "VK - User's Videos"
|
||||||
_BASE_URL_RE = r'https?://(?:(?:m|new)\.)?vk(?:video\.ru|\.com/video)'
|
_BASE_URL_RE = r'https?://(?:(?:m|new)\.)?vk(?:video\.ru|\.com/video)'
|
||||||
_VALID_URL = [
|
_VALID_URL = [
|
||||||
rf'{_BASE_URL_RE}/playlist/(?P<id>-?\d+_\d+)',
|
rf'{_BASE_URL_RE}/playlist/(?P<id>-?\d+_-?\d+)',
|
||||||
rf'{_BASE_URL_RE}/(?P<id>@[^/?#]+)(?:/all)?/?(?!\?.*\bz=video)(?:[?#]|$)',
|
rf'{_BASE_URL_RE}/(?P<id>@[^/?#]+)(?:/all)?/?(?!\?.*\bz=video)(?:[?#]|$)',
|
||||||
]
|
]
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
@@ -602,6 +602,9 @@ class VKUserVideosIE(VKBaseIE):
|
|||||||
}, {
|
}, {
|
||||||
'url': 'https://vk.com/video/playlist/-174476437_2',
|
'url': 'https://vk.com/video/playlist/-174476437_2',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://vkvideo.ru/playlist/-51890028_-2',
|
||||||
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
_VIDEO = collections.namedtuple('Video', ['owner_id', 'id'])
|
_VIDEO = collections.namedtuple('Video', ['owner_id', 'id'])
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user