mirror of https://github.com/yutto-dev/yutto
✨ feat: add dolby atmos download support (#256)
This commit is contained in:
parent
4f2f9415ba
commit
a896de1e84
|
@ -179,8 +179,8 @@ yutto 支持一些基础参数,无论是批量下载还是单视频下载都
|
|||
#### 指定音频码率等级
|
||||
|
||||
- 参数 `-aq` 或 `--audio-quality`
|
||||
- 可选值 `30280 | 30232 | 30216`
|
||||
- 默认值 `30280`
|
||||
- 可选值 `30251 | 30255 | 30250 | 30280 | 30232 | 30216`
|
||||
- 默认值 `30251`
|
||||
|
||||
码率对应关系如下
|
||||
|
||||
|
@ -188,6 +188,8 @@ yutto 支持一些基础参数,无论是批量下载还是单视频下载都
|
|||
| code | 码率 |
|
||||
| :-: | :-: |
|
||||
| 30251 | - (Hi-Res) |
|
||||
| 30255 | - (杜比音效) |
|
||||
| 30250 | - (杜比全景声) |
|
||||
| 30280 | 320kbps |
|
||||
| 30232 | 128kbps |
|
||||
| 30216 | 64kbps |
|
||||
|
|
|
@ -84,7 +84,7 @@ def cli() -> argparse.ArgumentParser:
|
|||
default=30251,
|
||||
choices=audio_quality_priority_default,
|
||||
type=int,
|
||||
help="音频码率等级(30280:320kbps, 30232:128kbps, 30216:64kbps)",
|
||||
help="音频码率等级(30251:Hi-Res, 30255:Dolby Audio, 30250:Dolby Atmos, 30280:320kbps, 30232:128kbps, 30216:64kbps)",
|
||||
)
|
||||
group_common.add_argument(
|
||||
"--vcodec",
|
||||
|
|
|
@ -177,25 +177,6 @@ async def get_ugc_video_playurl(
|
|||
)
|
||||
if resp_json["data"].get("dash") is None:
|
||||
raise UnSupportedTypeError(f"该视频({format_ids(avid, cid)})尚不支持 DASH 格式")
|
||||
# TODO: 处理 resp_json["data"]["dash"]["dolby"],应当是 Dolby 的音频流
|
||||
# {
|
||||
# "type": 1 | 2, (1: Dolby Audio 杜比音效(例:BV1Fa41127J4),2: Dolby Atmos 杜比全景声(例:BV1eV411W7tt))
|
||||
# "audio": [
|
||||
# {
|
||||
# "id": 30255 | 30250,(好像是只有这俩,分别对应上面两个)
|
||||
# "base_url": "xxxx",
|
||||
# "backup_url": ["xxxx", "xxxx"],
|
||||
# "bandwidth": xxx,
|
||||
# "mime_type": "audio/mp4",
|
||||
# "codecs": "ec-3",
|
||||
# "segment_base": {
|
||||
# "initialization": "xxx",
|
||||
# "index_range": "xxx",
|
||||
# },
|
||||
# "size": xxx,
|
||||
# }
|
||||
# ],
|
||||
# }
|
||||
videos: list[VideoUrlMeta] = (
|
||||
[
|
||||
{
|
||||
|
@ -226,13 +207,26 @@ async def get_ugc_video_playurl(
|
|||
if resp_json["data"]["dash"]["audio"]
|
||||
else []
|
||||
)
|
||||
if resp_json["data"]["dash"]["dolby"] is not None and resp_json["data"]["dash"]["dolby"]["audio"] is not None:
|
||||
dolby_audios_json = resp_json["data"]["dash"]["dolby"]["audio"]
|
||||
audios.extend(
|
||||
{
|
||||
"url": dolby_audio_json["base_url"],
|
||||
"mirrors": dolby_audio_json["backup_url"] if dolby_audio_json["backup_url"] is not None else [],
|
||||
"codec": "eac3", # TODO: 由于这里的 codecid 仍然是 0,所以无法通过 audio_codec_map 转换,暂时直接硬编码
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"quality": dolby_audio_json["id"],
|
||||
}
|
||||
for dolby_audio_json in dolby_audios_json
|
||||
)
|
||||
if resp_json["data"]["dash"]["flac"] is not None and resp_json["data"]["dash"]["flac"]["audio"] is not None:
|
||||
hi_res_audio_json = resp_json["data"]["dash"]["flac"]["audio"]
|
||||
audios.append(
|
||||
{
|
||||
"url": hi_res_audio_json["base_url"],
|
||||
"mirrors": hi_res_audio_json["backup_url"] if hi_res_audio_json["backup_url"] is not None else [],
|
||||
"codec": "fLaC", # TODO: 由于这里的 codecid 仍然是 0,所以无法通过 audio_codec_map 转换,暂时直接硬编码
|
||||
"codec": "flac", # TODO: 同上,硬编码
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"quality": hi_res_audio_json["id"],
|
||||
|
|
|
@ -7,10 +7,10 @@ from yutto.utils.priority import gen_priority_sequence
|
|||
VideoCodecId = Literal[7, 12, 13]
|
||||
VideoCodec = Literal["avc", "hevc", "av1"]
|
||||
AudioCodecId = Literal[0]
|
||||
AudioCodec = Literal["mp4a", "fLaC"]
|
||||
AudioCodec = Literal["mp4a", "flac", "eac3"]
|
||||
|
||||
video_codec_priority_default: list[VideoCodec] = ["avc", "hevc", "av1"]
|
||||
audio_codec_priority_default: list[AudioCodec] = ["mp4a", "fLaC"]
|
||||
audio_codec_priority_default: list[AudioCodec] = ["mp4a", "flac", "eac3"]
|
||||
|
||||
video_codec_map: dict[VideoCodecId, VideoCodec] = {
|
||||
7: "avc",
|
||||
|
|
|
@ -12,10 +12,10 @@ class Media(Enum):
|
|||
|
||||
|
||||
VideoQuality = Literal[127, 126, 125, 120, 116, 112, 80, 74, 64, 32, 16]
|
||||
AudioQuality = Literal[30251, 30280, 30232, 30216]
|
||||
AudioQuality = Literal[30251, 30255, 30250, 30280, 30232, 30216]
|
||||
|
||||
video_quality_priority_default: list[VideoQuality] = [127, 126, 125, 120, 116, 112, 80, 74, 64, 32, 16]
|
||||
audio_quality_priority_default: list[AudioQuality] = [30251, 30280, 30232, 30216]
|
||||
audio_quality_priority_default: list[AudioQuality] = [30251, 30255, 30250, 30280, 30232, 30216]
|
||||
|
||||
video_quality_map = {
|
||||
127: {
|
||||
|
@ -80,6 +80,14 @@ audio_quality_map = {
|
|||
"description": "Hi-Res",
|
||||
"bitrate": 999,
|
||||
}, # Example: BV1eV4y1P7fc
|
||||
30255: {
|
||||
"description": "杜比音效", # Dolby Audio
|
||||
"bitrate": 999,
|
||||
}, # Example: BV1Fa41127J4,但现在好像没了,也没找到其他的杜比音效选项
|
||||
30250: {
|
||||
"description": "杜比全景声", # Dolby Atmos
|
||||
"bitrate": 999,
|
||||
}, # Example: BV1eV411W7tt
|
||||
30280: {
|
||||
"description": "320kbps",
|
||||
"bitrate": 320,
|
||||
|
|
|
@ -261,14 +261,14 @@ async def start_downloader(
|
|||
if not will_download_video:
|
||||
if options["output_format_audio_only"] != "infer":
|
||||
output_format = "." + options["output_format_audio_only"]
|
||||
elif will_download_audio and audio["codec"] == "fLaC": # pyright: ignore [reportOptionalSubscript]
|
||||
elif will_download_audio and audio["codec"] == "flac": # pyright: ignore [reportOptionalSubscript]
|
||||
output_format = ".flac"
|
||||
else:
|
||||
output_format = ".aac"
|
||||
else:
|
||||
if options["output_format"] != "infer":
|
||||
output_format = "." + options["output_format"]
|
||||
elif will_download_audio and audio["codec"] == "fLaC": # pyright: ignore [reportOptionalSubscript]
|
||||
elif will_download_audio and audio["codec"] == "flac": # pyright: ignore [reportOptionalSubscript]
|
||||
output_format = ".mkv" # MP4 does not support FLAC audio
|
||||
|
||||
output_path = output_dir.joinpath(filename + output_format)
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import re
|
||||
import sys
|
||||
|
||||
from yutto.api.ugc_video import AudioUrlMeta, VideoUrlMeta
|
||||
from yutto._typing import AudioUrlMeta, VideoUrlMeta
|
||||
from yutto.bilibili_typing.codec import (
|
||||
AudioCodec,
|
||||
VideoCodec,
|
||||
|
@ -31,14 +31,12 @@ def select_video(
|
|||
gen_vcodec_priority(video_codec) if video_download_codec_priority is None else video_download_codec_priority
|
||||
)
|
||||
|
||||
# fmt: off
|
||||
video_combined_priority = [
|
||||
(vqn, vcodec)
|
||||
for vqn in video_quality_priority
|
||||
# TODO: Dolby Selector
|
||||
for vcodec in video_codec_priority
|
||||
]
|
||||
# fmt: on
|
||||
] # fmt: skip
|
||||
|
||||
for vqn, vcodec in video_combined_priority:
|
||||
for video in videos:
|
||||
|
@ -55,13 +53,11 @@ def select_audio(
|
|||
audio_quality_priority = gen_audio_quality_priority(audio_quality)
|
||||
audio_codec_priority = gen_acodec_priority(audio_codec)
|
||||
|
||||
# fmt: off
|
||||
audio_combined_priority = [
|
||||
(aqn, acodec)
|
||||
for aqn in audio_quality_priority
|
||||
for acodec in audio_codec_priority
|
||||
]
|
||||
# fmt: on
|
||||
] # fmt: skip
|
||||
|
||||
for aqn, acodec in audio_combined_priority:
|
||||
for audio in audios:
|
||||
|
|
|
@ -26,7 +26,6 @@ def size_format(size: float, ndigits: int = 2, base_unit_size: Literal[1024, 100
|
|||
|
||||
def get_char_width(char: str) -> int:
|
||||
"""计算单个字符的宽度"""
|
||||
# fmt: off
|
||||
widths = [
|
||||
(126, 1), (159, 0), (687, 1), (710, 0), (711, 1),
|
||||
(727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),
|
||||
|
@ -36,8 +35,7 @@ def get_char_width(char: str) -> int:
|
|||
(55203, 2), (63743, 1), (64106, 2), (65039, 1), (65059, 0),
|
||||
(65131, 2), (65279, 1), (65376, 2), (65500, 1), (65510, 2),
|
||||
(120831, 1), (262141, 2), (1114109, 1),
|
||||
]
|
||||
# fmt: on
|
||||
] # fmt: skip
|
||||
|
||||
o = ord(char)
|
||||
if o == 0xE or o == 0xF:
|
||||
|
|
Loading…
Reference in New Issue