Add qt support, some ui design changes and remove batch download support.
This commit is contained in:
@@ -1,2 +1,4 @@
|
|||||||
/save/
|
/save/
|
||||||
/temp/
|
/temp/
|
||||||
|
/main.build/
|
||||||
|
/main.dist/
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 372 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -1,6 +1,8 @@
|
|||||||
import base64
|
import base64
|
||||||
import binascii
|
import binascii
|
||||||
import json
|
import json
|
||||||
|
import platform
|
||||||
|
import shutil
|
||||||
import urllib
|
import urllib
|
||||||
import winreg
|
import winreg
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -25,7 +27,7 @@ def key_exists(hive, sub_key):
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create_url_scheme():
|
def create_url_scheme(main_file_path, work_dir):
|
||||||
try:
|
try:
|
||||||
scheme = "PlaylistSaver"
|
scheme = "PlaylistSaver"
|
||||||
base = r"Software\Classes\\" + scheme
|
base = r"Software\Classes\\" + scheme
|
||||||
@@ -40,23 +42,23 @@ def create_url_scheme():
|
|||||||
command_key = winreg.CreateKey(open_key, "command")
|
command_key = winreg.CreateKey(open_key, "command")
|
||||||
|
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
command = f"\"{sys.executable}\" \"%1\""
|
command = f"\"{sys.executable}\" --new-work-dir \"{work_dir}\" \"%1\""
|
||||||
else:
|
else:
|
||||||
command = f"\"{sys.executable}\" \"{os.path.abspath(__file__)}\" \"%1\""
|
command = f"\"{sys.executable}\" \"{main_file_path}\" --new-work-dir \"{work_dir}\" \"%1\""
|
||||||
|
|
||||||
winreg.SetValueEx(command_key, None, 0, winreg.REG_SZ, command)
|
winreg.SetValueEx(command_key, None, 0, winreg.REG_SZ, command)
|
||||||
|
|
||||||
logger.info("URL scheme registered.")
|
logger.info("URL scheme registered.")
|
||||||
|
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error("Unable to create URL scheme:", e)
|
logger.error("Unable to create URL scheme: %s", e)
|
||||||
|
|
||||||
def check_url_scheme():
|
def check_url_scheme(main_file_path, work_dir):
|
||||||
try:
|
try:
|
||||||
if not key_exists(winreg.HKEY_LOCAL_MACHINE, "PlaylistSaver"):
|
if not key_exists(winreg.HKEY_LOCAL_MACHINE, "PlaylistSaver"):
|
||||||
create_url_scheme()
|
create_url_scheme(main_file_path, work_dir)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
create_url_scheme()
|
create_url_scheme(main_file_path, work_dir)
|
||||||
|
|
||||||
def read_cookies(cookie_path):
|
def read_cookies(cookie_path):
|
||||||
try:
|
try:
|
||||||
@@ -65,7 +67,7 @@ def read_cookies(cookie_path):
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.error("Cookies file not found.")
|
logger.error("Cookies file not found.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("An unexpected error occurred while reading cookies:", e)
|
logger.error("An unexpected error occurred while reading cookies: %s", e)
|
||||||
|
|
||||||
def save_cookies(cookies, cookie_path):
|
def save_cookies(cookies, cookie_path):
|
||||||
try:
|
try:
|
||||||
@@ -73,13 +75,13 @@ def save_cookies(cookies, cookie_path):
|
|||||||
with open(cookie_path, "w", encoding='utf-8') as f:
|
with open(cookie_path, "w", encoding='utf-8') as f:
|
||||||
f.write(cookies)
|
f.write(cookies)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("An unexpected error occurred while saving cookies:", e)
|
logger.error("An unexpected error occurred while saving cookies: %s", e)
|
||||||
|
|
||||||
def save_base64_netscape_cookie(cookies_encoded, cookie_path):
|
def save_base64_netscape_cookie(cookies_encoded, cookie_path):
|
||||||
try:
|
try:
|
||||||
cookies = base64.b64decode(cookies_encoded).decode("utf-8")
|
cookies = base64.b64decode(cookies_encoded).decode("utf-8")
|
||||||
except binascii.Error:
|
except binascii.Error:
|
||||||
logger.error("Unable to decode base64 cookie:", cookies_encoded)
|
logger.error("Unable to decode base64 cookie: %s", cookies_encoded)
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("==== COOKIE FILE ====")
|
logger.debug("==== COOKIE FILE ====")
|
||||||
@@ -89,16 +91,16 @@ def save_base64_netscape_cookie(cookies_encoded, cookie_path):
|
|||||||
|
|
||||||
save_cookies(cookies, cookie_path)
|
save_cookies(cookies, cookie_path)
|
||||||
|
|
||||||
def parser_url_scheme(url, work_dir: Path):
|
def parser_url_scheme(url, cookie_path: Path):
|
||||||
logger.debug("Parsing URL scheme:", url)
|
logger.debug("Parsing URL scheme: %s", url)
|
||||||
|
|
||||||
url = urllib.parse.urlparse(unquote(sys.argv[1]))
|
url = urllib.parse.urlparse(unquote(url))
|
||||||
parameters = urllib.parse.parse_qs(url.query)
|
parameters = urllib.parse.parse_qs(url.query)
|
||||||
|
|
||||||
func_map = {
|
func_map = {
|
||||||
"base64cookies": {
|
"base64cookies": {
|
||||||
"func": save_base64_netscape_cookie,
|
"func": save_base64_netscape_cookie,
|
||||||
"args": [parameters["base64cookies"][0], work_dir]
|
"args": [parameters["base64cookies"][0], cookie_path]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +109,7 @@ def parser_url_scheme(url, work_dir: Path):
|
|||||||
if match_func:
|
if match_func:
|
||||||
match_func(*func_map[arg_name].get("args", []))
|
match_func(*func_map[arg_name].get("args", []))
|
||||||
else:
|
else:
|
||||||
logger.warning("Unknown parameter:", arg_name, " Value:", parameters[arg_name])
|
logger.warning("Unknown parameter: %s Value: %s", arg_name, parameters[arg_name])
|
||||||
|
|
||||||
def save_json(data: dict, dest):
|
def save_json(data: dict, dest):
|
||||||
try:
|
try:
|
||||||
@@ -115,11 +117,88 @@ def save_json(data: dict, dest):
|
|||||||
with open(dest, "w", encoding='utf-8') as f:
|
with open(dest, "w", encoding='utf-8') as f:
|
||||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Unable to save json:", e)
|
logger.error("Unable to save json: %s", e)
|
||||||
|
|
||||||
def read_json(path):
|
def read_json(path):
|
||||||
try:
|
try:
|
||||||
with open(path, "r", encoding='utf-8') as f:
|
with open(path, "r", encoding='utf-8') as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Unable to read json:", e)
|
logger.error("Unable to read json: %s", e)
|
||||||
|
|
||||||
|
def find_mpv_path(program_dir: Path):
|
||||||
|
local_candidates = [
|
||||||
|
]
|
||||||
|
|
||||||
|
platform_name = platform.system().lower()
|
||||||
|
machine = platform.machine().lower()
|
||||||
|
|
||||||
|
if platform.system().lower() == "windows" and ("amd64" in machine or "x86_64" in machine):
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "nt", "x64", "mpv.exe"))
|
||||||
|
elif platform.system().lower() == "windows" and ("arm64" in machine or "aarch64" in machine):
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "nt", "arm", "mpv.exe"))
|
||||||
|
elif platform.system().lower() == "windows" and machine in {"x86", "i386", "i686"}:
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "nt", "x86", "mpv.exe"))
|
||||||
|
|
||||||
|
if platform.system().lower() == "darwin" and ("amd64" in machine or "x86_64" in machine):
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "darwin", "x64", "mpv"))
|
||||||
|
elif platform.system() == "darwin" and ("arm64" in machine or "aarch64" in machine):
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "darwin", "arm", "mpv"))
|
||||||
|
|
||||||
|
if platform.system().lower() == "linux" and ("amd64" in machine or "x86_64" in machine):
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "linux", "x64", "mpv"))
|
||||||
|
elif platform.system().lower() == "linux" and ("arm64" in machine or "aarch64" in machine):
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "linux", "arm", "mpv"))
|
||||||
|
elif platform.system().lower() == "linux" and machine in {"x86", "i386", "i686"}:
|
||||||
|
local_candidates.append(Path(program_dir, "bin", "mpv", "linux", "x86", "mpv.exe"))
|
||||||
|
|
||||||
|
for candidate in local_candidates:
|
||||||
|
if candidate.exists() and candidate.is_file():
|
||||||
|
return candidate
|
||||||
|
|
||||||
|
# failback to PATH mpv (if available)
|
||||||
|
return shutil.which("mpv")
|
||||||
|
|
||||||
|
def find_http_status(exc: Exception):
|
||||||
|
seen = set()
|
||||||
|
stack = [exc]
|
||||||
|
|
||||||
|
while stack:
|
||||||
|
cur = stack.pop()
|
||||||
|
if cur is None or id(cur) in seen:
|
||||||
|
continue
|
||||||
|
seen.add(id(cur))
|
||||||
|
|
||||||
|
status = getattr(cur, "status", None) or getattr(cur, "code", None)
|
||||||
|
if status is not None:
|
||||||
|
return status
|
||||||
|
|
||||||
|
stack.extend([
|
||||||
|
getattr(cur, "__cause__", None),
|
||||||
|
getattr(cur, "__context__", None),
|
||||||
|
])
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def cookie_string_to_netscape(cookie_str):
|
||||||
|
lines = ["# Netscape HTTP Cookie File"]
|
||||||
|
|
||||||
|
for pair in cookie_str.split(";"):
|
||||||
|
pair = pair.strip()
|
||||||
|
if not pair or "=" not in pair:
|
||||||
|
continue
|
||||||
|
|
||||||
|
name, value = pair.split("=", 1) # ← 關鍵修正
|
||||||
|
|
||||||
|
lines.append("\t".join([
|
||||||
|
".youtube.com",
|
||||||
|
"TRUE",
|
||||||
|
"/",
|
||||||
|
"TRUE",
|
||||||
|
"9999999999",
|
||||||
|
name.strip(),
|
||||||
|
value.strip()
|
||||||
|
]))
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
Reference in New Issue
Block a user