Skip to content

Commit 18b60f9

Browse files
lockmatrixSomeoneKong
authored andcommitted
git statuscustom
1 parent a75399d commit 18b60f9

File tree

10 files changed

+356
-6
lines changed

10 files changed

+356
-6
lines changed

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ jobs:
8181

8282
- uses: actions/setup-python@v6
8383
with:
84-
python-version: "3.10" # Keep this in sync with test-workflows.yml
84+
python-version: "3.12.8"
8585

8686
- name: Process inputs
8787
id: process_inputs
@@ -175,7 +175,7 @@ jobs:
175175
fetch-depth: 0
176176
- uses: actions/setup-python@v6
177177
with:
178-
python-version: "3.10"
178+
python-version: "3.12.8"
179179

180180
- name: Install Requirements
181181
run: |
@@ -243,7 +243,7 @@ jobs:
243243
merge-multiple: true
244244
- uses: actions/setup-python@v6
245245
with:
246-
python-version: "3.10"
246+
python-version: "3.12.8"
247247

248248
- name: Generate release notes
249249
env:

requirements.txt

Whitespace-only changes.

yt_dlp/YoutubeDL.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3547,7 +3547,7 @@ def ffmpeg_fixup(cndn, msg, cls):
35473547
and info_dict.get('container') == 'm4a_dash',
35483548
'writing DASH m4a. Only some players support this container',
35493549
FFmpegFixupM4aPP)
3550-
ffmpeg_fixup((downloader == 'hlsnative' and not self.params.get('hls_use_mpegts'))
3550+
ffmpeg_fixup((downloader in ('hlsnative', 'hlsnative_fake_header') and not self.params.get('hls_use_mpegts'))
35513551
or (info_dict.get('is_live') and self.params.get('hls_use_mpegts') is None),
35523552
'Possible MPEG-TS in MP4 container or malformed AAC timestamps',
35533553
FFmpegFixupM3u8PP)

yt_dlp/downloader/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def get_suitable_downloader(info_dict, params={}, default=NO_DEFAULT, protocol=N
3636
from .websocket import WebSocketFragmentFD
3737
from .youtube_live_chat import YoutubeLiveChatFD
3838
from .bunnycdn import BunnyCdnFD
39+
from .hls_fake_header import HlsFakeHeaderFD
3940

4041
PROTOCOL_MAP = {
4142
'rtmp': RtmpFD,
@@ -108,6 +109,9 @@ def _get_suitable_downloader(info_dict, protocol, params, default):
108109
if info_dict.get('is_live') and (external_downloader or '').lower() != 'native':
109110
return FFmpegFD
110111

112+
if protocol == 'm3u8_fake_header':
113+
return HlsFakeHeaderFD
114+
111115
if protocol in ('m3u8', 'm3u8_native'):
112116
if info_dict.get('is_live'):
113117
return FFmpegFD

yt_dlp/downloader/fragment.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ def _read_fragment(self, ctx):
143143
down.close()
144144
return frag_content
145145

146+
def _fixup_fragment(self, ctx, frag_bytes):
147+
return frag_bytes
148+
146149
def _append_fragment(self, ctx, frag_content):
147150
try:
148151
ctx['dest_stream'].write(frag_content)
@@ -497,7 +500,8 @@ def _download_fragment(fragment):
497500
'fragment_filename_sanitized': frag_filename,
498501
'fragment_index': frag_index,
499502
})
500-
if not append_fragment(decrypt_fragment(fragment, self._read_fragment(ctx)), frag_index, ctx):
503+
frag_bytes = self._fixup_fragment(ctx, self._read_fragment(ctx))
504+
if not append_fragment(decrypt_fragment(fragment, frag_bytes), frag_index, ctx):
501505
return False
502506
except KeyboardInterrupt:
503507
self._finish_multiline_status()
@@ -511,8 +515,9 @@ def _download_fragment(fragment):
511515
break
512516
try:
513517
download_fragment(fragment, ctx)
518+
frag_bytes = self._fixup_fragment(ctx, self._read_fragment(ctx))
514519
result = append_fragment(
515-
decrypt_fragment(fragment, self._read_fragment(ctx)), fragment['frag_index'], ctx)
520+
decrypt_fragment(fragment, frag_bytes), fragment['frag_index'], ctx)
516521
except KeyboardInterrupt:
517522
if info_dict.get('is_live'):
518523
break
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
from . import HlsFD
3+
4+
5+
class HlsFakeHeaderFD(HlsFD):
6+
"""
7+
For M3U8 with fake header in each frags
8+
"""
9+
10+
FD_NAME = 'hlsnative_fake_header'
11+
12+
has_warned = False
13+
14+
def _fixup_fragment(self, ctx, frag_bytes):
15+
if frag_bytes is None:
16+
return None
17+
ts_start_pos = frag_bytes.find(b'\x47\x40')
18+
frag_bytes = frag_bytes[ts_start_pos:]
19+
20+
no_fake_header = ts_start_pos == 0
21+
if no_fake_header and not self.has_warned:
22+
self.to_screen("")
23+
self.to_screen("There is no fake header")
24+
self.has_warned = True
25+
26+
return frag_bytes

yt_dlp/extractor/_extractors.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@
260260
BiliIntlIE,
261261
BiliIntlSeriesIE,
262262
BiliLiveIE,
263+
BilibiliCheeseIE,
263264
)
264265
from .biobiochiletv import BioBioChileTVIE
265266
from .bitchute import (
@@ -2477,6 +2478,7 @@
24772478
XHamsterUserIE,
24782479
)
24792480
from .xiaohongshu import XiaoHongShuIE
2481+
from .xiaoyuzhou import XiaoYuZhouIE
24802482
from .ximalaya import (
24812483
XimalayaAlbumIE,
24822484
XimalayaIE,

yt_dlp/extractor/xiaoyuzhou.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
from .common import InfoExtractor
3+
from ..utils import (
4+
float_or_none,
5+
int_or_none,
6+
js_to_json,
7+
url_or_none,
8+
)
9+
from ..utils.traversal import traverse_obj
10+
from datetime import datetime
11+
12+
13+
class XiaoYuZhouIE(InfoExtractor):
14+
_VALID_URL = r'https?://www\.xiaoyuzhoufm\.com/episode/(?P<id>[\da-f]+)'
15+
IE_DESC = '小宇宙'
16+
_TESTS = [{
17+
'url': 'https://www.xiaoyuzhoufm.com/episode/670f2a7e0d2f24f289727fdc',
18+
'info_dict': {
19+
'id': '670f2a7e0d2f24f289727fdc',
20+
'ext': 'm4a',
21+
'description': str,
22+
'title': '是不飘了?研究上私募了?没100万也不耽误听',
23+
'duration': 6741,
24+
'uploader': '面基',
25+
'uploader_id': '6388760f22567e8ea6ad070f',
26+
'uploader_url': 'https://www.xiaoyuzhoufm.com/podcast/6388760f22567e8ea6ad070f',
27+
},
28+
}]
29+
30+
def _real_extract(self, url):
31+
display_id = self._match_id(url)
32+
webpage = self._download_webpage(url, display_id)
33+
initial_state = self._search_json(
34+
r'<script id="__NEXT_DATA__" type="application/json">', webpage, 'json_data', display_id)
35+
36+
episode_info = traverse_obj(initial_state, ('props', 'pageProps', 'episode'))
37+
38+
episode_title = traverse_obj(episode_info, ('title', {str}))
39+
audio_url = traverse_obj(episode_info, ('enclosure', 'url', {url_or_none}))
40+
description = traverse_obj(episode_info, ('description', {str}))
41+
duration = traverse_obj(episode_info, ('duration', {float_or_none}))
42+
pubDateStr = traverse_obj(episode_info, ('pubDate', {str}))
43+
44+
upload_datetime = datetime.strptime(pubDateStr, "%Y-%m-%dT%H:%M:%S.%fZ") # `2024-10-16T09:30:00.000Z`格式
45+
46+
# podcast 是指一个播客节目,包含多个 episode,podcast由多个实际user主持
47+
podcast_id = traverse_obj(episode_info, ('pid', {str}))
48+
podcast_title = traverse_obj(episode_info, ('podcast', 'title', {str}))
49+
podcast_description = traverse_obj(episode_info, ('podcast', 'description', {str}))
50+
podcast_url = f'https://www.xiaoyuzhoufm.com/podcast/{podcast_id}'
51+
52+
podcast_user_list = traverse_obj(episode_info, ('podcast', 'podcasters', ...))
53+
54+
ext = None
55+
if '.' in audio_url.split('/')[-1]:
56+
ext = audio_url.split('.')[-1]
57+
58+
formats = []
59+
formats.append({
60+
'url': audio_url,
61+
'vcodec': 'none',
62+
'ext': ext,
63+
})
64+
65+
return {
66+
'id': display_id,
67+
'formats': formats,
68+
'title': episode_title,
69+
'description': description,
70+
'duration': duration,
71+
'timestamp': upload_datetime.timestamp(),
72+
'uploader': podcast_title,
73+
'uploader_id': podcast_id,
74+
'uploader_url': podcast_url,
75+
}

yt_dlp/options.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,12 @@ def _preset_alias_callback(option, opt_str, value, parser):
11161116
'For ffmpeg, arguments can be passed to different positions using the same syntax as --postprocessor-args. '
11171117
'You can use this option multiple times to give different arguments to different downloaders '
11181118
'(Alias: --external-downloader-args)'))
1119+
downloader.add_option(
1120+
'--selenium-browner-timeout', dest='selenium_browner_timeout', metavar='NUMBER', default=20, type='float')
1121+
downloader.add_option(
1122+
'--selenium-browner-no-headless', dest='selenium_browner_headless', action='store_false')
1123+
downloader.add_option(
1124+
'--selenium-browner-headless', dest='selenium_browner_headless', action='store_true')
11191125

11201126
workarounds = optparse.OptionGroup(parser, 'Workarounds')
11211127
workarounds.add_option(

0 commit comments

Comments
 (0)