Cleaned code

This commit is contained in:
2026-09-07 10:49:35 -06:00
parent 13e5d34446
commit 2e8a80c045
19 changed files with 142 additions and 161 deletions
+1
View File
@@ -12,3 +12,4 @@ build/
.idea/ .idea/
*.swp *.swp
*~ *~
tmp
+118 -143
View File
@@ -1,7 +1,7 @@
from dataclasses import dataclass from dataclasses import dataclass
from flask import Flask, render_template, request, jsonify from flask import Flask, render_template, request, jsonify
from threading import RLock, Thread from threading import Thread
import time import time
from yt_dlp import YoutubeDL from yt_dlp import YoutubeDL
from yt_dlp.utils import DownloadError, ExtractorError from yt_dlp.utils import DownloadError, ExtractorError
@@ -16,13 +16,19 @@ class ReleaseInfo:
artist: str artist: str
title: str title: str
art_url: str art_url: str
is_album: bool
is_topic: bool
@dataclass
class ReleaseStatus:
info: ReleaseInfo | None
status: str status: str
class YtdlpErrorCode(Exception): class RipError(Exception):
def __init__(self, code): def __init__(self, msg):
super().__init__(f"Some videos failed with code {code}") super().__init__(msg)
self.code = code
def create_or_wipe_folder(path: str) -> None: def create_or_wipe_folder(path: str) -> None:
@@ -41,6 +47,7 @@ def get_content_json(url: str):
def download_content(path: str, url: str) -> None: def download_content(path: str, url: str) -> None:
try:
with YoutubeDL( with YoutubeDL(
{ {
"format": "m4a/bestaudio/best", "format": "m4a/bestaudio/best",
@@ -55,7 +62,61 @@ def download_content(path: str, url: str) -> None:
) as ydl: ) as ydl:
error_code = ydl.download([url]) error_code = ydl.download([url])
if error_code: if error_code:
raise YtdlpErrorCode(error_code) raise RipError(f"Content download failed ({error_code})")
except DownloadError:
raise RipError("Content Download Failed")
except ExtractorError:
raise RipError("Content Extraction Failed")
def find_release_info(url: str) -> ReleaseInfo:
try:
info = get_content_json(url)
except DownloadError:
raise RipError("Info Download Failed")
except ExtractorError:
raise RipError("Info Extraction Failed")
entries = info.get("entries")
if entries is None:
raise RipError("Entries is none")
first_entry = next(iter(entries), None)
if not first_entry:
raise RipError("Entries is empty")
artist = first_entry.get("uploader")
if artist is None:
raise RipError("Uploader tag is none")
is_topic = False
if " - Topic" in artist:
is_topic = True
artist = artist.replace(" - Topic", "")
title = info.get("title")
if title is None:
raise RipError("Title tag is none")
is_album = False
if "Album - " in title:
is_album = True
title = title.replace("Album - ", "")
thumbnails = info.get("thumbnails")
if thumbnails is None:
raise RipError("Thumbnails is none")
art_url = thumbnails[1]["url"]
if not is_album:
raise RipError("Failed, not an album")
return ReleaseInfo(artist, title, art_url, is_album, is_topic)
def find_tmp_path() -> str: def find_tmp_path() -> str:
@@ -63,9 +124,7 @@ def find_tmp_path() -> str:
return f"{project_root_path}/tmp" return f"{project_root_path}/tmp"
def rip_worker( def rip_worker(rip_queue: list[str], status_callback: Callable[[ReleaseInfo | str, bool],]):
rip_queue: list[str], status_callback: Callable[[ReleaseInfo],], finish_callback: Callable[[ReleaseInfo],]
):
tmp_path = find_tmp_path() tmp_path = find_tmp_path()
while True: while True:
@@ -73,144 +132,55 @@ def rip_worker(
time.sleep(1) time.sleep(1)
continue continue
status_callback("Gathering Info", False)
url = rip_queue.pop(0)
create_or_wipe_folder(tmp_path) create_or_wipe_folder(tmp_path)
current_url = rip_queue.pop(0)
release_info = ReleaseInfo(
"",
current_url,
"https://imgs.search.brave.com/LeS4HHKZ1oz1T15VY5MwiUjWDjLiYKj0vgRABB3D2BY/rs:fit:860:0:0:0/g:ce/aHR0cHM6Ly90My5m/dGNkbi5uZXQvanBn/LzA2Lzg2LzE5LzM0/LzM2MF9GXzY4NjE5/MzQwN19ESFp3amV5/ZEJPUjF0RURrTEF6/d00zdzVrWXN0Unp6/Qi5qcGc",
"Starting",
)
status_callback(release_info)
is_album = False
is_topic = False
# Info json --------------------------------------------------
release_info.status = "Gathering Info"
status_callback(release_info)
try: try:
info = get_content_json(current_url) info = find_release_info(url)
status_callback(info, False)
except DownloadError: status_callback("Downloading Content", False)
release_info.status = "Info Download Failed"
finish_callback(release_info)
continue
except ExtractorError: download_content(tmp_path, url)
release_info.status = "Info Extraction Failed"
finish_callback(release_info)
continue
entries = info.get("entries") except RipError as e:
if entries is None: status_callback(repr(e), True)
release_info.status = "Entries is none"
finish_callback(release_info)
continue
first_entry = next(iter(entries), None) else:
if not first_entry: status_callback("Finished Sucessfully", True)
release_info.status = "Entries is empty"
finish_callback(release_info)
continue
artist = first_entry.get("uploader")
if artist is None:
release_info.status = "Uploader tag is none"
finish_callback(release_info)
continue
if " - Topic" in artist:
is_topic = True
artist = artist.replace(" - Topic", "")
release_info.artist = artist
title = info.get("title")
if title is None:
release_info.status = "Title tag is none"
finish_callback(release_info)
continue
if "Album - " in title:
is_album = True
title = title.replace("Album - ", "")
release_info.title = title
thumbnails = info.get("thumbnails")
if thumbnails is None:
release_info.status = "Thumbnails is none"
finish_callback(release_info)
continue
art_url = thumbnails[1]["url"]
release_info.art_url = art_url
if not is_album:
release_info.status = "Failed, not an album"
finish_callback(release_info)
continue
release_info.status = "Finished gathering info"
status_callback(release_info)
# Info json --------------------------------------------------
release_info.status = "Downloading"
status_callback(release_info)
try:
download_content(tmp_path, current_url)
except DownloadError:
release_info.status = "Content Download Failed"
finish_callback(release_info)
continue
except YtdlpErrorCode:
release_info.status = "Content Download Failed with code"
finish_callback(release_info)
continue
except ExtractorError:
release_info.status = "Content Extraction Failed"
finish_callback(release_info)
continue
release_info.status = "Writting Metadata"
status_callback(release_info)
release_info.status = "Finished Successfully"
finish_callback(release_info)
if __name__ == "__main__": if __name__ == "__main__":
app = Flask(__name__) app = Flask(__name__)
rip_queue = [] rip_queue: list[str] = []
finished_queue = [] finished_queue: list[ReleaseStatus] = []
current_release_info = ReleaseInfo("", "", "", "Waiting") current_release_info: ReleaseInfo | None = None
current_release_status_message: str = ""
def get_current_release_info(release_info: ReleaseInfo): def get_current_release_status(x: ReleaseInfo | str, finished: bool):
global current_release_info
current_release_info = release_info
def get_current_release_info_on_finish(release_info: ReleaseInfo):
global current_release_info global current_release_info
global current_release_status_message
global finished_queue global finished_queue
current_release_info = ReleaseInfo("", "", "", "Waiting")
finished_queue.append(release_info) if type(x) is ReleaseInfo:
current_release_info = x
elif type(x) is str:
current_release_status_message = x
if finished:
finished_queue.append(ReleaseStatus(current_release_info, current_release_status_message))
current_release_info = None
current_release_status_message = "Waiting"
if len(finished_queue) > 30: if len(finished_queue) > 30:
finished_queue.pop(0) finished_queue.pop(0)
ripping_thread = Thread( ripping_thread = Thread(target=rip_worker, args=(rip_queue, get_current_release_status), daemon=True).start()
target=rip_worker, args=(rip_queue, get_current_release_info, get_current_release_info_on_finish), daemon=True
).start()
@app.route("/") @app.route("/")
def index(): def index():
@@ -219,26 +189,31 @@ if __name__ == "__main__":
@app.route("/rip", methods=["POST"]) @app.route("/rip", methods=["POST"])
def rip(): def rip():
url = request.form.get("url") url = request.form.get("url")
if url is None:
return jsonify({"success": False, "message": "Url is None"})
rip_queue.append(url) rip_queue.append(url)
return jsonify({"success": True, "message": f"Added, {url}!"}) return jsonify({"success": True, "message": f"Added, {url}!"})
@app.route("/status", methods=["GET"]) @app.route("/status", methods=["GET"])
def status(): def status():
return jsonify( data = {"success": True, "queue": rip_queue, "finishedQueue": [], "status": current_release_status_message}
{
"success": True, for q in finished_queue:
"queue": rip_queue, if q.info is None:
"finishedQueue": [ continue
{"artist": q.artist, "title": q.title, "status": q.status, "art_url": q.art_url}
for q in finished_queue data["finishedQueue"].append(
], {"artist": q.info.artist, "title": q.info.title, "status": q.status, "art_url": q.info.art_url}
"currentReleaseInfo": {
"artist": current_release_info.artist,
"title": current_release_info.title,
"status": current_release_info.status,
"art_url": current_release_info.art_url,
},
}
) )
if current_release_info is not None:
data["currentReleaseInfo"] = {
"artist": current_release_info.artist,
"title": current_release_info.title,
"art_url": current_release_info.art_url,
}
return jsonify(data)
app.run() app.run()
+6 -1
View File
@@ -106,8 +106,13 @@
const response = await fetch("/status", { method: "GET" }); const response = await fetch("/status", { method: "GET" });
const statusJson = await response.json(); const statusJson = await response.json();
if ("currentReleaseInfo" in statusJson) {
const currentInfo = statusJson.currentReleaseInfo; const currentInfo = statusJson.currentReleaseInfo;
statusMessage.innerHTML = createCard(currentInfo.artist, currentInfo.title, currentInfo.status, currentInfo.art_url); statusMessage.innerHTML = createCard(currentInfo.artist, currentInfo.title, statusJson.status, currentInfo.art_url);
}
else {
statusMessage.innerHTML = `<p>${statusJson.status}</p>`;
}
queueTableBody.innerHTML = ""; queueTableBody.innerHTML = "";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.