⚡️ Rewrite download manager
This commit is contained in:
parent
e47a92b77e
commit
afc9c112cb
4 changed files with 68 additions and 53 deletions
|
@ -23,9 +23,5 @@ def get_progress():
|
||||||
@app.post("/download")
|
@app.post("/download")
|
||||||
def download():
|
def download():
|
||||||
parent_dir = Path(request.json["parent_dir"])
|
parent_dir = Path(request.json["parent_dir"])
|
||||||
id = request.json["id"]
|
manager.download(parent_dir)
|
||||||
try:
|
|
||||||
manager.download(id, parent_dir)
|
|
||||||
return "OK"
|
return "OK"
|
||||||
except:
|
|
||||||
return "Not ready"
|
|
||||||
|
|
|
@ -11,33 +11,8 @@ const state_list = ref([]);
|
||||||
|
|
||||||
const auto_download = ref(false);
|
const auto_download = ref(false);
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
setInterval(() => {
|
|
||||||
axios.get("http://localhost:8000/progress").then((resp) => {
|
|
||||||
state_list.value = resp.data;
|
|
||||||
for (const [i, s] of state_list.value.entries()) {
|
|
||||||
if (
|
|
||||||
auto_download.value &&
|
|
||||||
counter.value.downloading == 0 &&
|
|
||||||
s.number &&
|
|
||||||
s.title &&
|
|
||||||
s.total == 0
|
|
||||||
) {
|
|
||||||
axios.post("http://localhost:8000/download", {
|
|
||||||
id: i,
|
|
||||||
parent_dir: "/home/zhao/Desktop/tmp",
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
const counter = computed(() => {
|
const counter = computed(() => {
|
||||||
if (state_list.value.length == 0) {
|
const total = state_list.value.length;
|
||||||
return { fetching: true, downloading: false };
|
|
||||||
}
|
|
||||||
let ready = 0;
|
let ready = 0;
|
||||||
let downloading = 0;
|
let downloading = 0;
|
||||||
let finished = 0;
|
let finished = 0;
|
||||||
|
@ -45,30 +20,55 @@ const counter = computed(() => {
|
||||||
if (s.number && s.title && s.total == 0) {
|
if (s.number && s.title && s.total == 0) {
|
||||||
ready++;
|
ready++;
|
||||||
} else if (s.received < s.total) {
|
} else if (s.received < s.total) {
|
||||||
|
ready++;
|
||||||
downloading++;
|
downloading++;
|
||||||
} else if (s.total <= s.received && s.total != 0) {
|
} else if (s.total != 0 && s.received == s.total) {
|
||||||
|
ready++;
|
||||||
finished++;
|
finished++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { ready: ready, downloading: downloading, finished: finished };
|
return {
|
||||||
|
total: total,
|
||||||
|
ready: ready,
|
||||||
|
downloading: downloading,
|
||||||
|
finished: finished,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const progress_info = computed(() => {
|
const progress_info = computed(() => {
|
||||||
const total = state_list.value.length;
|
const { ready, downloading, finished, total } = counter.value;
|
||||||
const { ready, downloading, finished } = counter.value;
|
|
||||||
const fetch_info = "Fetching Information";
|
const fetch_info = "Fetching Information";
|
||||||
|
const ready_info = "Ready";
|
||||||
const download_info = "Downloading";
|
const download_info = "Downloading";
|
||||||
const finished_info = "Downloads Complete";
|
const finished_info = "Downloads Complete";
|
||||||
if (total == 0) {
|
if (ready < total) {
|
||||||
return { display: fetch_info, finished: 0, total: 0 };
|
|
||||||
} else if (ready < total && downloading == 0 && finished == 0) {
|
|
||||||
return { display: fetch_info, finished: ready, total: total };
|
return { display: fetch_info, finished: ready, total: total };
|
||||||
} else if (finished + downloading + ready == total && finished < total) {
|
} else if (ready == total && !downloading && !finished) {
|
||||||
return { display: download_info, finished: finished + downloading, total: total };
|
return { display: ready_info, finished: ready, total: total };
|
||||||
|
} else if (finished < total) {
|
||||||
|
return {
|
||||||
|
display: download_info,
|
||||||
|
finished: finished,
|
||||||
|
total: total,
|
||||||
|
};
|
||||||
} else if (finished == total) {
|
} else if (finished == total) {
|
||||||
return { display: finished_info, finished: finished, total: total };
|
return { display: finished_info, finished: finished, total: total };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function start_download() {
|
||||||
|
axios.post("http://localhost:8000/download", {
|
||||||
|
parent_dir: "/home/zhao/Desktop/tmp",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setInterval(() => {
|
||||||
|
axios.get("http://localhost:8000/progress").then((resp) => {
|
||||||
|
state_list.value = resp.data;
|
||||||
|
});
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -87,7 +87,8 @@ const progress_info = computed(() => {
|
||||||
</div>
|
</div>
|
||||||
<DownloadButton
|
<DownloadButton
|
||||||
@enable-download="auto_download = true"
|
@enable-download="auto_download = true"
|
||||||
v-if="counter.ready == state_list.length"
|
v-if="!auto_download && counter.ready == counter.total"
|
||||||
|
@click="start_download"
|
||||||
></DownloadButton>
|
></DownloadButton>
|
||||||
<TotalProgress v-else v-bind="progress_info"></TotalProgress>
|
<TotalProgress v-else v-bind="progress_info"></TotalProgress>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
from video import Video
|
from video import Video
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
from queue import SimpleQueue
|
||||||
from sanitize_filename import sanitize
|
from sanitize_filename import sanitize
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
|
||||||
class Manager:
|
class Manager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.video_list: list[Video] = []
|
self.video_list: list[Video] = []
|
||||||
self.bvid_set = set()
|
self.bvid_set = set()
|
||||||
|
self.queue = SimpleQueue()
|
||||||
|
|
||||||
|
def get_info_worker(self):
|
||||||
|
while not self.queue.empty():
|
||||||
|
video: Video = self.queue.get()
|
||||||
|
video.get_info()
|
||||||
|
sleep(5)
|
||||||
|
|
||||||
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:
|
||||||
|
@ -18,19 +27,23 @@ class Manager:
|
||||||
if (bvid := video.v.get_bvid()) not in self.bvid_set:
|
if (bvid := video.v.get_bvid()) not in self.bvid_set:
|
||||||
self.bvid_set.add(bvid)
|
self.bvid_set.add(bvid)
|
||||||
self.video_list.append(video)
|
self.video_list.append(video)
|
||||||
Thread(target=video.get_info).start()
|
self.queue.put(video)
|
||||||
|
Thread(target=self.get_info_worker).start()
|
||||||
|
|
||||||
def download(self, id: int, parent_dir: str | Path = Path(".")):
|
def download_worker(self, parent_dir: Path):
|
||||||
|
while not self.queue.empty():
|
||||||
|
video: Video = self.queue.get()
|
||||||
|
filename = sanitize(video.title) + ".m4a"
|
||||||
|
video.download(parent_dir / filename)
|
||||||
|
sleep(5)
|
||||||
|
|
||||||
|
def download(self, parent_dir: str | Path = Path(".")):
|
||||||
if isinstance(parent_dir, str):
|
if isinstance(parent_dir, str):
|
||||||
parent_dir = Path(parent_dir)
|
parent_dir = Path(parent_dir)
|
||||||
if not 0 <= id < len(self.video_list):
|
for video in self.video_list:
|
||||||
raise Exception(f"id ({id}) out of range!")
|
print(video)
|
||||||
video = self.video_list[id]
|
self.queue.put(video)
|
||||||
if not hasattr(video, "title"):
|
Thread(target=self.download_worker, args=(parent_dir,)).start()
|
||||||
raise Exception(f"No information for video {video.number}")
|
|
||||||
filename = sanitize(video.title) + ".m4a"
|
|
||||||
t = Thread(target=video.download, args=(parent_dir / filename,))
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
def get_progress(self):
|
def get_progress(self):
|
||||||
return [
|
return [
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from bilibili_api import video, sync, HEADERS
|
from bilibili_api import video, sync
|
||||||
from httpx import stream
|
from httpx import stream
|
||||||
from os import PathLike
|
from os import PathLike
|
||||||
|
|
||||||
|
HEADERS = {
|
||||||
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/110.0",
|
||||||
|
"Referer": "https://www.bilibili.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Video:
|
class Video:
|
||||||
def __init__(self, video_number: str):
|
def __init__(self, video_number: str):
|
||||||
|
|
Loading…
Reference in a new issue