Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provide audio quality option 添加下载音质的 CLI 选项 #19

Merged
merged 8 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,6 @@ temp/
.vscode/
.DS_Store

.pdm-python
.pdm-python

.idea/
30 changes: 26 additions & 4 deletions src/bilifm/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import requests
import typer

from .util import get_signed_params
from .util import AudioQualityEnums, get_signed_params


class Audio:
Expand All @@ -16,7 +16,7 @@ class Audio:

headers = {}

def __init__(self, bvid: str) -> None:
def __init__(self, bvid: str, audio_quality: AudioQualityEnums) -> None:
if bvid is None:
raise ValueError("bvid is None")

Expand All @@ -40,6 +40,8 @@ def __init__(self, bvid: str) -> None:
"Referer": "https://www.bilibili.com/video/{bvid}".format(bvid=self.bvid),
}

self.audio_quality = audio_quality.quality_id

# 获取cid和title
if len(bvid) == 12:
# BV号
Expand Down Expand Up @@ -76,9 +78,29 @@ def download(self):
self.playUrl, params=params, headers=self.headers
).json()

baseUrl = json["data"]["dash"]["audio"][0]["baseUrl"]
if json["data"] is None:
typer.echo(
f" `data` field is not valid with url: {self.playUrl} and params : {params}"
)
return

audio = json["data"]["dash"]["audio"]
if not audio:
typer.echo(
f" `audio` field is empty with url: {self.playUrl} and params : {params}"
)
return

base_url = None
for au in audio:
if au["id"] == self.audio_quality:
base_url = au["baseUrl"]

# no audio url corresponding to current audio quality
if base_url is None:
base_url = audio[0]["baseUrl"]

response = requests.get(url=baseUrl, headers=self.headers, stream=True)
response = requests.get(url=base_url, headers=self.headers, stream=True)

total_size = int(response.headers.get("content-length", 0))
temp_size = 0
Expand Down
39 changes: 29 additions & 10 deletions src/bilifm/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,32 @@
from .season import Season
from .series import Series
from .user import User
from .util import Directory, Path
from .util import AudioQuality, AudioQualityEnums, Directory, Path

app = typer.Typer()


@app.command()
def bv(bv: str, directory: Directory = None):
audio = Audio(bv)
def bv(
bv: str,
directory: Directory = None,
audio_quality: AudioQuality = AudioQualityEnums.k192.value,
):
audio = Audio(bv, audio_quality)
audio.download()


@app.command()
def uid(uid: str, directory: Directory = None):
def uid(
uid: str,
directory: Directory = None,
audio_quality: AudioQuality = AudioQualityEnums.k192.value,
):
user = User(uid)

for video in user.videos:
bv = video["bvid"]
audio = Audio(bv)
audio = Audio(bv, audio_quality)
audio.download()

typer.echo("Download complete")
Expand All @@ -35,21 +43,27 @@ def fav(
media_id: str,
cookies_path: str = Path,
directory: Directory = None,
audio_quality: AudioQuality = AudioQualityEnums.k192.value,
):
with open(cookies_path, "r") as f:
cookies = f.read()

fav = Fav(media_id, cookies)

for bvid in fav.id_list:
audio = Audio(bvid)
audio = Audio(bvid, audio_quality)
audio.download()

typer.echo("Download complete")


@app.command()
def season(uid: str, sid: str, directory: Directory = None):
def season(
uid: str,
sid: str,
directory: Directory = None,
audio_quality: AudioQuality = AudioQualityEnums.k192.value,
):
sea = Season(uid, sid)
audio_generator = sea.get_videos()
if not audio_generator:
Expand All @@ -62,13 +76,18 @@ def season(uid: str, sid: str, directory: Directory = None):

for audios in audio_generator:
for id in audios:
audio = Audio(id)
audio = Audio(id, audio_quality)
audio.download()
typer.echo("Download complete")


@app.command()
def series(uid: str, sid: str, directory: Directory = None):
def series(
uid: str,
sid: str,
directory: Directory = None,
audio_quality: AudioQuality = AudioQualityEnums.k64,
):
"""Download bilibili video series

The api of series lacks the series name, executing
Expand All @@ -82,6 +101,6 @@ def series(uid: str, sid: str, directory: Directory = None):

for audios in audio_generator:
for id in audios:
audio = Audio(id)
audio = Audio(id, audio_quality)
audio.download()
typer.echo("Download complete")
25 changes: 25 additions & 0 deletions src/bilifm/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import random
import time
import urllib.parse
from enum import Enum
from functools import reduce
from hashlib import md5
from typing import Callable
Expand Down Expand Up @@ -97,6 +98,24 @@
]


# 音质映射到具体值
audio_quality_map = {
"64": 30216,
"132": 30232,
"192": 30280,
}


class AudioQualityEnums(str, Enum):
k64 = "64"
k132 = "132"
k192 = "192"

@property
def quality_id(self):
return audio_quality_map[self._value_]


def getMixinKey(orig: str):
"对 imgKey 和 subKey 进行字符顺序打乱编码"
return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, "")[:32]
Expand Down Expand Up @@ -214,3 +233,9 @@ def wrapped_request(*args, **kwargs):
return None

return wrapped_request


AudioQuality = Annotated[
AudioQualityEnums,
typer.Option("--quality", "-q", help="audio quality", case_sensitive=False),
]
Loading