diff --git a/.gitignore b/.gitignore index bed6e62..b04caee 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ videos/ .vscode/settings.json bilibili_archive_dir/ dist/ + +.ia_keys.txt +.cookies.txt diff --git a/README.md b/README.md index 1a7fb3b..4b7648c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # biliarchiver -> 基于 bilix 的 BiliBili 存档工具 +> Archiving tool for Bilibili based on bilix + +[![PyPI version](https://badge.fury.io/py/biliarchiver.svg)](https://badge.fury.io/py/biliarchiver) ## Install diff --git a/biliarchiver/cli_tools/bili_archive_bvids.py b/biliarchiver/cli_tools/bili_archive_bvids.py index 460ac67..69cf0d3 100644 --- a/biliarchiver/cli_tools/bili_archive_bvids.py +++ b/biliarchiver/cli_tools/bili_archive_bvids.py @@ -62,7 +62,7 @@ def check_ia_item_exist(client: Client, identifier: str) -> bool: raise ValueError(f'Unexpected code: {r_json["code"]}') -def _down( +async def _down( bvids: str, skip_ia_check: bool, from_browser: Optional[str], @@ -77,8 +77,7 @@ def _down( pypi_project="biliarchiver", self_version=BILI_ARCHIVER_VERSION ) - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) + loop = asyncio.get_event_loop() d = DownloaderBilibili( hierarchy=True, @@ -150,9 +149,7 @@ def _down( continue if len(tasks) >= config.video_concurrency: - loop.run_until_complete( - asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - ) + await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) tasks_check() print(f"=== {bvid} ({index+1}/{len(bvids_list)}) ===") @@ -164,9 +161,7 @@ def _down( tasks.append(task) while len(tasks) > 0: - loop.run_until_complete( - asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - ) + await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) tasks_check() print("DONE") diff --git a/biliarchiver/cli_tools/down_command.py b/biliarchiver/cli_tools/down_command.py index e517f01..53afb15 100644 --- a/biliarchiver/cli_tools/down_command.py +++ b/biliarchiver/cli_tools/down_command.py @@ -40,7 +40,9 @@ def down(**kwargs): from biliarchiver.cli_tools.bili_archive_bvids import _down try: - _down(**kwargs) + import asyncio + + asyncio.run(_down(**kwargs)) except KeyboardInterrupt: print("KeyboardInterrupt") finally: diff --git a/biliarchiver/cli_tools/up_command.py b/biliarchiver/cli_tools/up_command.py index fadbc1c..b49c094 100644 --- a/biliarchiver/cli_tools/up_command.py +++ b/biliarchiver/cli_tools/up_command.py @@ -34,7 +34,9 @@ BILIBILI_VIDEOS_SUB_1_COLLECTION = "bilibili_videos_sub_1" default=False, help=_("使用 `$storage_home_dir/videos` 目录下的所有视频"), ) -@click.option("--update-existing", is_flag=True, default=False, help=_("更新已存在的 item")) +@click.option( + "--update-existing", "-u", is_flag=True, default=False, help=_("更新已存在的 item") +) @click.option( "--collection", "-c", diff --git a/biliarchiver/rest_api/bilivid.py b/biliarchiver/rest_api/bilivid.py new file mode 100644 index 0000000..5580d8b --- /dev/null +++ b/biliarchiver/rest_api/bilivid.py @@ -0,0 +1,30 @@ +from biliarchiver.cli_tools.bili_archive_bvids import _down +from biliarchiver._biliarchiver_upload_bvid import upload_bvid +from biliarchiver.config import config + + +class BiliVideo: + def __init__(self, bvid) -> None: + if not bvid.startswith("BV"): + bvid = "BV" + bvid + self.bvid = bvid + + def __str__(self) -> str: + return self.bvid + + async def down(self): + await _down( + bvids=self.bvid, + skip_ia_check=True, + from_browser=None, + min_free_space_gb=1, + skip_to=0, + ) + + async def up(self): + upload_bvid( + self.bvid, + update_existing=False, + collection="default", + delete_after_upload=False, + ) diff --git a/biliarchiver/rest_api/main.py b/biliarchiver/rest_api/main.py new file mode 100644 index 0000000..0b1aacf --- /dev/null +++ b/biliarchiver/rest_api/main.py @@ -0,0 +1,68 @@ +import asyncio +from asyncio import Queue +from fastapi import FastAPI, BackgroundTasks +from pydantic import BaseModel +from biliarchiver.rest_api.bilivid import BiliVideo +from datetime import datetime +from biliarchiver.version import BILI_ARCHIVER_VERSION + +app = FastAPI() + +queue = Queue() + + +class Video: + def __init__(self, vid): + self.vid = vid + + +@app.get("/") +async def root(): + return { + "status": "ok", + "biliarchiver": {"version": BILI_ARCHIVER_VERSION}, + "api": {"version": 1}, + "timestamp": int(datetime.now().timestamp()), + } + + +@app.put("/archive/{vid}") +@app.post("/archive/{vid}") +async def add(vid: str): + video = BiliVideo(vid) + await queue.put(video) + return {"success": True, "vid": vid} + + +@app.get("/archive") +async def get(): + return {"success": True, "queue": map(str, queue)} + + +@app.get("/archive/{vid}") +async def get(vid: str): + if vid in queue: + return {"success": True, "vid": vid} + return {"success": False, "vid": vid} + + +@app.delete("/archive/{vid}") +async def delete(vid: str): + return {"success": True, "vid": vid} + + +async def scheduler(): + while True: + print("Getting a video URL... If no video URL is printed, the queue is empty.") + video = await queue.get() + print(f"Start donwloading {video}") + await video.down() + print(f"Start uploading {video}") + await video.up() + + +@app.on_event("startup") +async def startup_event(): + bg_task = BackgroundTasks() + bg_task.add_task(scheduler) + asyncio.create_task(scheduler()) diff --git a/biliarchiver/rest_api/scheduler.py b/biliarchiver/rest_api/scheduler.py new file mode 100644 index 0000000..56b7dcf --- /dev/null +++ b/biliarchiver/rest_api/scheduler.py @@ -0,0 +1,28 @@ +import asyncio +from biliarchiver.rest_api.bilivid import BiliVideo + + +class ArchiveScheduler: + def __init__(self) -> None: + self.queue = [] + self.loop = asyncio.get_event_loop() + self.loop.run_until_complete(self.main()) + self.should_stop = False + + async def main(self): + while True: + if self.should_stop: + break + if len(self.queue) > 0: + vid = self.queue.pop(0) + await vid.down() + await vid.up() + else: + await asyncio.sleep(5) + + def add(self, vid: BiliVideo): + self.queue.append(vid) + + def stop(self): + self.should_stop = True + self.loop.close() diff --git a/pyproject.toml b/pyproject.toml index e27a25c..1872808 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,10 @@ browser-cookie3 = "^0.19.1" click = "^8.1.6" click-option-group = "^0.5.6" +[tool.poetry.group.api.dependencies] +fastapi = "^0.101.1" +uvicorn = {extras = ["standard"], version = "^0.23.2"} + [tool.poetry.scripts] biliarchiver = "biliarchiver.cli_tools.biliarchiver:biliarchiver"