🚸 Select download path

This commit is contained in:
zhbaor 2023-03-04 18:18:39 +08:00
parent afc9c112cb
commit 3b5a998aaa
7 changed files with 303 additions and 18 deletions

View file

@ -1,12 +1,23 @@
from bottle import request, response, Bottle, HTTPResponse from bottle import request, response, Bottle, static_file
from manager import Manager from manager import Manager
from json import dumps from json import dumps
from pathlib import Path from pathlib import Path
from tkinter import filedialog as fd
manager = Manager() manager = Manager()
app = Bottle() app = Bottle()
@app.get("/")
def frontend():
return static_file("index.html", root="frontend/dist")
@app.get("/<filepath:path>")
def frontend(filepath):
return static_file(filepath, root="frontend/dist")
@app.post("/video") @app.post("/video")
def add_videos(): def add_videos():
nvlist = request.json["nvlist"].split() nvlist = request.json["nvlist"].split()
@ -20,8 +31,14 @@ def get_progress():
return dumps(manager.get_progress()) return dumps(manager.get_progress())
@app.post("/download") @app.get("/download")
def download(): def download():
parent_dir = Path(request.json["parent_dir"]) manager.download()
manager.download(parent_dir)
return "OK" return "OK"
@app.get("/path")
def get_path():
path = fd.askdirectory()
manager.path = path
return path

View file

@ -57,14 +57,12 @@ const progress_info = computed(() => {
}); });
function start_download() { function start_download() {
axios.post("http://localhost:8000/download", { axios.get("/download");
parent_dir: "/home/zhao/Desktop/tmp",
});
} }
onMounted(() => { onMounted(() => {
setInterval(() => { setInterval(() => {
axios.get("http://localhost:8000/progress").then((resp) => { axios.get("/progress").then((resp) => {
state_list.value = resp.data; state_list.value = resp.data;
}); });
}, 200); }, 200);

View file

@ -8,18 +8,38 @@ const nvlist = ref("");
const axios = inject("axios"); const axios = inject("axios");
const path = ref("");
onMounted(() => { onMounted(() => {
input.value.focus(); input.value.focus();
}); });
function sendNVList() { function sendNVList() {
axios.post("http://localhost:8000/video", { nvlist: nvlist.value }); axios.post("/video", { nvlist: nvlist.value });
emit("change-stage"); emit("change-stage");
} }
function get_path() {
axios.get("/path").then(({ data }) => {
path.value = data;
input.value.focus();
});
}
</script> </script>
<template> <template>
<div class="container-fluid vh-100 bg-body-secondary d-flex flex-column p-3"> <div class="container-fluid vh-100 bg-body-secondary d-flex flex-column p-3">
<div class="mb-3 row g-2">
<div class="col-auto">
<label class="col-form-label">Download Path:</label>
</div>
<div class="col">
<input class="form-control" type="text" v-model="path" />
</div>
<div class="col-auto">
<button class="btn btn-primary" @click="get_path">Choose</button>
</div>
</div>
<textarea <textarea
ref="input" ref="input"
v-model="nvlist" v-model="nvlist"

10
main.py Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env python3
import webview
from backend import app
if __name__ == "__main__":
# Create a standard webview window
window = webview.create_window(
"badl - BiliBili Audio Downloader", app, width=500, height=700
)
webview.start()

View file

@ -11,12 +11,13 @@ class Manager:
self.video_list: list[Video] = [] self.video_list: list[Video] = []
self.bvid_set = set() self.bvid_set = set()
self.queue = SimpleQueue() self.queue = SimpleQueue()
self.path = ""
def get_info_worker(self): def get_info_worker(self):
while not self.queue.empty(): while not self.queue.empty():
video: Video = self.queue.get() video: Video = self.queue.get()
video.get_info() video.get_info()
sleep(5) sleep(1)
def add_videos_by_number(self, video_numbers: list[str]): def add_videos_by_number(self, video_numbers: list[str]):
for video_number in video_numbers: for video_number in video_numbers:
@ -34,12 +35,16 @@ class Manager:
while not self.queue.empty(): while not self.queue.empty():
video: Video = self.queue.get() video: Video = self.queue.get()
filename = sanitize(video.title) + ".m4a" filename = sanitize(video.title) + ".m4a"
video.download(parent_dir / filename) while True:
sleep(5) try:
video.download(parent_dir / filename)
break
except:
sleep(1)
sleep(1)
def download(self, parent_dir: str | Path = Path(".")): def download(self):
if isinstance(parent_dir, str): parent_dir = Path(self.path)
parent_dir = Path(parent_dir)
for video in self.video_list: for video in self.video_list:
print(video) print(video)
self.queue.put(video) self.queue.put(video)

239
poetry.lock generated
View file

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry and should not be changed by hand. # This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand.
[[package]] [[package]]
name = "aiohttp" name = "aiohttp"
@ -1005,7 +1005,7 @@ reference = "mirrors"
name = "packaging" name = "packaging"
version = "23.0" version = "23.0"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -1152,6 +1152,22 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple" url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors" reference = "mirrors"
[[package]]
name = "proxy-tools"
version = "0.1.0"
description = "Proxy Implementation"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "proxy_tools-0.1.0.tar.gz", hash = "sha256:ccb3751f529c047e2d8a58440d86b205303cf0fe8146f784d1cbcd94f0a28010"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]] [[package]]
name = "pyasn1" name = "pyasn1"
version = "0.4.8" version = "0.4.8"
@ -1169,6 +1185,138 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple" url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors" reference = "mirrors"
[[package]]
name = "pycairo"
version = "1.23.0"
description = "Python interface for cairo"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "pycairo-1.23.0-cp310-cp310-win32.whl", hash = "sha256:564601e5f528531c6caec1c0177c3d0709081e1a2a5cccc13561f715080ae535"},
{file = "pycairo-1.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:e7cde633986435d87a86b6118b7b6109c384266fd719ef959883e2729f6eafae"},
{file = "pycairo-1.23.0-cp311-cp311-win32.whl", hash = "sha256:3a71f758e461180d241e62ef52e85499c843bd2660fd6d87cec99c9833792bfa"},
{file = "pycairo-1.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:2dec5378133778961993fb59d66df16070e03f4d491b67eb695ca9ad7a696008"},
{file = "pycairo-1.23.0-cp37-cp37m-win32.whl", hash = "sha256:d6bacff15d688ed135b4567965a4b664d9fb8de7417a7865bb138ad612043c9f"},
{file = "pycairo-1.23.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ec305fc7f2f0299df78aadec0eaf6eb9accb90eda242b5d3492544d3f2b28027"},
{file = "pycairo-1.23.0-cp38-cp38-win32.whl", hash = "sha256:1a6d8e0f353062ad92954784e33dbbaf66c880c9c30e947996c542ed9748aaaf"},
{file = "pycairo-1.23.0-cp38-cp38-win_amd64.whl", hash = "sha256:82e335774a17870bc038e0c2fb106c1e5e7ad0c764662023886dfcfce5bb5a52"},
{file = "pycairo-1.23.0-cp39-cp39-win32.whl", hash = "sha256:a4b1f525bbdf637c40f4d91378de36c01ec2b7f8ecc585b700a079b9ff83298e"},
{file = "pycairo-1.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:87efd62a7b7afad9a0a420f05b6008742a6cfc59077697be65afe8dc73ae15ad"},
{file = "pycairo-1.23.0.tar.gz", hash = "sha256:9b61ac818723adc04367301317eb2e814a83522f07bbd1f409af0dada463c44c"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pycparser"
version = "2.21"
description = "C parser in Python"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pygobject"
version = "3.42.2"
description = "Python bindings for GObject Introspection"
category = "main"
optional = false
python-versions = "^3.6"
files = [
{file = "PyGObject-3.42.2.tar.gz", hash = "sha256:21524cef33100c8fd59dc135948b703d79d303e368ce71fa60521cc971cd8aa7"},
]
[package.dependencies]
pycairo = ">=1.16,<2.0"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pyobjc-core"
version = "9.0.1"
description = "Python<->ObjC Interoperability Module"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "pyobjc-core-9.0.1.tar.gz", hash = "sha256:5ce1510bb0bdff527c597079a42b2e13a19b7592e76850be7960a2775b59c929"},
{file = "pyobjc_core-9.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b614406d46175b1438a9596b664bf61952323116704d19bc1dea68052a0aad98"},
{file = "pyobjc_core-9.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bd397e729f6271c694fb70df8f5d3d3c9b2f2b8ac02fbbdd1757ca96027b94bb"},
{file = "pyobjc_core-9.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d919934eaa6d1cf1505ff447a5c2312be4c5651efcb694eb9f59e86f5bd25e6b"},
{file = "pyobjc_core-9.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:67d67ca8b164f38ceacce28a18025845c3ec69613f3301935d4d2c4ceb22e3fd"},
{file = "pyobjc_core-9.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:39d11d71f6161ac0bd93cffc8ea210bb0178b56d16a7408bf74283d6ecfa7430"},
{file = "pyobjc_core-9.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25be1c4d530e473ed98b15063b8d6844f0733c98914de6f09fe1f7652b772bbc"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pyobjc-framework-cocoa"
version = "9.0.1"
description = "Wrappers for the Cocoa frameworks on macOS"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "pyobjc-framework-Cocoa-9.0.1.tar.gz", hash = "sha256:a8b53b3426f94307a58e2f8214dc1094c19afa9dcb96f21be12f937d968b2df3"},
{file = "pyobjc_framework_Cocoa-9.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5f94b0f92a62b781e633e58f09bcaded63d612f9b1e15202f5f372ea59e4aebd"},
{file = "pyobjc_framework_Cocoa-9.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f062c3bb5cc89902e6d164aa9a66ffc03638645dd5f0468b6f525ac997c86e51"},
{file = "pyobjc_framework_Cocoa-9.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0b374c0a9d32ba4fc5610ab2741cb05a005f1dfb82a47dbf2dbb2b3a34b73ce5"},
{file = "pyobjc_framework_Cocoa-9.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8928080cebbce91ac139e460d3dfc94c7cb6935be032dcae9c0a51b247f9c2d9"},
{file = "pyobjc_framework_Cocoa-9.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:9d2bd86a0a98d906f762f5dc59f2fc67cce32ae9633b02ff59ac8c8a33dd862d"},
{file = "pyobjc_framework_Cocoa-9.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2a41053cbcee30e1e8914efa749c50b70bf782527d5938f2bc2a6393740969ce"},
]
[package.dependencies]
pyobjc-core = ">=9.0.1"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pyobjc-framework-webkit"
version = "9.0.1"
description = "Wrappers for the framework WebKit on macOS"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "pyobjc-framework-WebKit-9.0.1.tar.gz", hash = "sha256:82ed0cb273012b48f7489072d6e00579f42d54bc4543471c262db3e5c4bb9e87"},
{file = "pyobjc_framework_WebKit-9.0.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:037082f72fa1f1d87889fdc172726c3381769de24ca5207d596f3925df9b25f0"},
{file = "pyobjc_framework_WebKit-9.0.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:952685b820545036833ed737600d32c344916a83b2af4e04acb4b618aaac9431"},
{file = "pyobjc_framework_WebKit-9.0.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:28a7859401b5af7c47e17612b4b3baca6669e76f974f6f6bfe5e93921a00adec"},
]
[package.dependencies]
pyobjc-core = ">=9.0.1"
pyobjc-framework-Cocoa = ">=9.0.1"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]] [[package]]
name = "pypng" name = "pypng"
version = "0.20220715.0" version = "0.20220715.0"
@ -1186,6 +1334,35 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple" url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors" reference = "mirrors"
[[package]]
name = "pythonnet"
version = "2.5.2"
description = ".Net and Mono integration for Python"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "pythonnet-2.5.2-cp27-cp27m-win32.whl", hash = "sha256:d519bbc7b1cd3999651efc594d91cb67c46d1d8466dad3d83b578102e58d05bd"},
{file = "pythonnet-2.5.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c02f53d0e61b202cddf3198fac9553d5b4ee0ea0cc4fe658c2ed69ab24def276"},
{file = "pythonnet-2.5.2-cp35-cp35m-win32.whl", hash = "sha256:840bdef89b378663d73f74f18895b6d8630d1f5671457a1db5ffb68179d85582"},
{file = "pythonnet-2.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:d8e5b27de1e2cfb69b88782ac5cdf605b1a73598a85d86570e46961126628dbb"},
{file = "pythonnet-2.5.2-cp36-cp36m-win32.whl", hash = "sha256:62645c29840c4a877d66e047f3e065b2e5a1a66431a99bce8d42a5af3a093ee1"},
{file = "pythonnet-2.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:058e536062d1585d07ec5f2cf16aefcfc8eb8179faa90e5db0063d358469d025"},
{file = "pythonnet-2.5.2-cp37-cp37m-win32.whl", hash = "sha256:cc77fc63e2afb0a80199ab44ced4fdfb78c19d8030063c345c80740d15380dd9"},
{file = "pythonnet-2.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:80c8f5c9bd10440a73eb6aedbbacb2f3dd7701b474816f5ef7636f529d838d38"},
{file = "pythonnet-2.5.2-cp38-cp38-win32.whl", hash = "sha256:41a607b7304e9efc6d4d8db438d6018a17c6637e8b8998848ff5c2a7a1b4687c"},
{file = "pythonnet-2.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:00a4fed9fc05b4efbe8947c79dc0799cffbca4c89e3e068e70b6618f20c906f2"},
{file = "pythonnet-2.5.2.tar.gz", hash = "sha256:b7287480a1f6ae4b6fc80d775446d8af00e051ca1646b6cc3d32c5d3a461ede3"},
]
[package.dependencies]
pycparser = "*"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]] [[package]]
name = "pytz" name = "pytz"
version = "2022.7.1" version = "2022.7.1"
@ -1223,6 +1400,39 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple" url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors" reference = "mirrors"
[[package]]
name = "pywebview"
version = "4.0.2"
description = "Build GUI for your Python program with JavaScript, HTML, and CSS."
category = "main"
optional = false
python-versions = "*"
files = [
{file = "pywebview-4.0.2-py3-none-any.whl", hash = "sha256:c94065f16978badf29d80043d7c0c86c99793b199c46cfe3f1d15271908e2670"},
{file = "pywebview-4.0.2.tar.gz", hash = "sha256:59383610af1326e1b52b06d58262ce7cc54818e644aded9409751b81efb4857a"},
]
[package.dependencies]
bottle = "*"
proxy-tools = "*"
pyobjc-core = {version = "*", markers = "sys_platform == \"darwin\""}
pyobjc-framework-Cocoa = {version = "*", markers = "sys_platform == \"darwin\""}
pyobjc-framework-WebKit = {version = "*", markers = "sys_platform == \"darwin\""}
pythonnet = {version = "*", markers = "sys_platform == \"win32\""}
QtPy = {version = "*", markers = "sys_platform == \"openbsd6\""}
[package.extras]
cef = ["cefpython3"]
gtk = ["PyGObject"]
pyside2 = ["PySide2", "QtPy"]
pyside6 = ["PySide6", "QtPy"]
qt = ["PyQt5", "QtPy", "pyqtwebengine"]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]] [[package]]
name = "pyyaml" name = "pyyaml"
version = "6.0" version = "6.0"
@ -1307,6 +1517,29 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple" url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors" reference = "mirrors"
[[package]]
name = "qtpy"
version = "2.3.0"
description = "Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6)."
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "QtPy-2.3.0-py3-none-any.whl", hash = "sha256:8d6d544fc20facd27360ea189592e6135c614785f0dec0b4f083289de6beb408"},
{file = "QtPy-2.3.0.tar.gz", hash = "sha256:0603c9c83ccc035a4717a12908bf6bc6cb22509827ea2ec0e94c2da7c9ed57c5"},
]
[package.dependencies]
packaging = "*"
[package.extras]
test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]] [[package]]
name = "requests" name = "requests"
version = "2.28.2" version = "2.28.2"
@ -1670,4 +1903,4 @@ reference = "mirrors"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "355be7949f7315d306dda590f37dc6c75b8c29130154e934c9b50285807faab5" content-hash = "1d4e00a5f792bb7ab25726a3edc04cc9e398e71c7f9b9ce7a896ba3f5603842c"

View file

@ -10,6 +10,8 @@ python = "^3.11"
bilibili-api-python = "^15.1.0" bilibili-api-python = "^15.1.0"
sanitize-filename = "^1.2.0" sanitize-filename = "^1.2.0"
bottle = "^0.12.23" bottle = "^0.12.23"
pywebview = "^4.0.2"
pygobject = "^3.42.2"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
black = "^23.1.0" black = "^23.1.0"