From cc924028ed6fc2a52e3942ac51eb51a4dd65c3a4 Mon Sep 17 00:00:00 2001 From: robo-dani Date: Sat, 23 Mar 2024 15:52:19 +0800 Subject: [PATCH] feat: support downloading video collections (#15) * feat: add download seasons(video collection) * feat: add download season command * feat: create additional folder in season mode * doc: add doc for season mode * doc: keep trailing whitespace * chore: improve season error msg --- README.md | 16 ++++++++++++ src/bilifm/command.py | 29 ++++++++++++++++++++++ src/bilifm/season.py | 58 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 src/bilifm/season.py diff --git a/README.md b/README.md index efc81f3..fd13cbd 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,22 @@ cookies 的获取: - cookies 转换为json:[在线 cookies 转换](https://uutool.cn/cookie2json/) +### season 模式 +下载视频合集 +```bash +bilifm season $uid $sid [OPTIONS] +``` +- uid, sid 的获取: + 打开视频合集网页, 从URL中获取 + + https://space.bilibili.com/23263470/channel/collectiondetail?sid=1855309 + + 例如上面链接, uid为23263470, sid为1855309. (目前uid可以随意填写) +- Options: + - -o, --directory 选择音频保存地址 + + + ## Features - ~~python 版本限制未知~~ diff --git a/src/bilifm/command.py b/src/bilifm/command.py index 1fccbec..ee82c3a 100644 --- a/src/bilifm/command.py +++ b/src/bilifm/command.py @@ -1,7 +1,11 @@ +import os + import typer +from typing_extensions import Annotated from .audio import Audio from .fav import Fav +from .season import Season from .user import User app = typer.Typer() @@ -37,3 +41,28 @@ def fav(media_id: str, cookies_path: str): audio.download() typer.echo("Download complete") + + +@app.command() +def season( + uid: str, + sid: str, + directory: Annotated[str, typer.Option("-o", "--directory")] = "", +): + sea = Season(uid, sid) + ret = sea.get_videos() + if not ret: + typer.Exit(1) + return + + if directory: + os.chdir(directory) + + if not os.path.isdir(sea.name): + os.makedirs(sea.name) + os.chdir(sea.name) + + for id in sea.videos: + audio = Audio(id) + audio.download() + typer.echo("Download complete") diff --git a/src/bilifm/season.py b/src/bilifm/season.py new file mode 100644 index 0000000..489df64 --- /dev/null +++ b/src/bilifm/season.py @@ -0,0 +1,58 @@ +"""download bilibili season archive, 视频合集下载""" + +import typer + +from .util import request + + +class Season: + # api refer https://github.com/SocialSisterYi/bilibili-API-collect/blob/f9ee5c3b99335af6bef0d9d902101c565b3bea00/docs/video/collection.md + season_url: str = ( + "https://api.bilibili.com/x/polymer/web-space/seasons_archives_list" + ) + + def __init__(self, uid: str, sid: str, page_size=30) -> None: + self.uid = uid + self.season_id = sid + self.page_size = page_size + self.videos = [] + + def get_videos(self): + params = { + "mid": self.uid, + "season_id": self.season_id, + "sort_reverse": False, + "page_num": 1, + "page_size": self.page_size, + } + + res = request( + method="get", url=self.season_url, params=params, wbi=True, dm=True + ).json() + + code = res.get("code", -404) + if code != 0: + # uid 错误好像无影响 + if code == "-404": + typer.echo(f"Error: uid {self.uid} or sid {self.season_id} error.") + else: + type.echo("Error: unknown error") + typer.echo(f"code: {res['code']}") + if res.get("message", None): + typer.echo(f"msg: {res['message']}") + return False + + self.total = res["data"]["meta"]["total"] + self.name = res["data"]["meta"]["name"] + + max_pn = self.total // 50 + for i in range(1, max_pn + 2): + params["page_num"] = i + + res = request( + method="get", url=self.season_url, params=params, wbi=True, dm=True + ).json() + bvids = [d["bvid"] for d in res["data"]["archives"]] + self.videos.extend(bvids) + + return True