feat: add dolby atmos download support (#256)

This commit is contained in:
Nyakku Shigure 2024-03-31 03:07:44 +08:00 committed by GitHub
parent 4f2f9415ba
commit a896de1e84
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 38 additions and 40 deletions

View File

@ -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 |

View File

@ -76,7 +76,7 @@ def cli() -> argparse.ArgumentParser:
default=127,
choices=video_quality_priority_default,
type=int,
help="视频清晰度等级127:8K, 126: Dolby Vision, 125:HDR, 120:4K, 116:1080P60, 112:1080P+, 80:1080P, 74:720P60, 64:720P, 32:480P, 16:360P",
help="视频清晰度等级127:8K, 126:Dolby Vision, 125:HDR, 120:4K, 116:1080P60, 112:1080P+, 80:1080P, 74:720P60, 64:720P, 32:480P, 16:360P",
)
group_common.add_argument(
"-aq",
@ -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",

View File

@ -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 杜比音效BV1Fa41127J42: 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"],

View File

@ -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",

View File

@ -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,

View File

@ -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)

View File

@ -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:

View File

@ -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: