config/batch rejig

This commit is contained in:
VineFeeder
2025-08-28 12:45:18 +01:00
parent 4232af387c
commit d1428eea9b
5 changed files with 129 additions and 64 deletions
+17 -47
View File
@@ -17,32 +17,16 @@ from rich.console import Console
from .parsing_utils import prettify from .parsing_utils import prettify
import click import click
import subprocess import subprocess
from .batchloader import batchload #from .batchloader import batchload
import pkgutil import pkgutil
#import inspect from .pretty import catppuccin_mocha
from .config_loader import load_config_with_fallback, get_bool, project_config_path, save_project_config
PAGE_SIZE = 8 # size of beaupy pagination PAGE_SIZE = 8 # size of beaupy pagination
console = Console() console = Console()
catppuccin_mocha = {
# Colors based on "CatppuccinMocha" from Gogh themes
"bg": "rgb(30,30,46)",
"text": "rgb(205,214,244)",
"text2": "rgb(162,169,193)", # slightly darker
"black": "rgb(69,71,90)",
"bright_black": "rgb(88,91,112)",
"red": "rgb(243,139,168)",
"green": "rgb(166,227,161)",
"yellow": "rgb(249,226,175)",
"blue": "rgb(137,180,250)",
"pink": "rgb(245,194,231)",
"cyan": "rgb(148,226,213)",
"gray": "rgb(166,173,200)",
"bright_gray": "rgb(186,194,222)",
"dark_gray": "rgb(54,54,84)",
}
""" """
@@ -73,18 +57,11 @@ Example usage:
_PKG_NAME = "vinefeeder" _PKG_NAME = "vinefeeder"
_CFG_NAME = "config.yaml" _CFG_NAME = "config.yaml"
def _user_config_dir() -> Path:
# XDG on Linux; AppData\Roaming on Windows; ~/.config on others
if os.name == "nt":
base = os.environ.get("APPDATA") or (Path.home() / "AppData" / "Roaming")
return Path(base) / "VineFeeder"
xdg = os.environ.get("XDG_CONFIG_HOME")
return (Path(xdg) if xdg else Path.home() / ".config") / "vinefeeder"
def _user_config_path() -> Path:
return _user_config_dir() / _CFG_NAME
def load_config_with_fallback() -> tuple[dict, Path | None]:
'''def load_config_with_fallback() -> tuple[dict, Path | None]:
""" """
Returns (config_dict, user_path_if_used_or_None). Returns (config_dict, user_path_if_used_or_None).
Prefers user config; falls back to package-bundled default. Prefers user config; falls back to package-bundled default.
@@ -97,15 +74,9 @@ def load_config_with_fallback() -> tuple[dict, Path | None]:
# packaged default # packaged default
with resources.files(_PKG_NAME).joinpath(_CFG_NAME).open("rb") as f: with resources.files(_PKG_NAME).joinpath(_CFG_NAME).open("rb") as f:
data = yaml.safe_load(f) or {} data = yaml.safe_load(f) or {}
return data, None return data, None'''
def save_user_config(cfg: dict) -> Path:
"""Writes config to the user path, creating the directory as needed."""
p = _user_config_path()
p.parent.mkdir(parents=True, exist_ok=True)
with p.open("w", encoding="utf-8") as f:
yaml.safe_dump(cfg, f, default_flow_style=False)
return p
def derive_loader_class_name(service_modname: str) -> str: def derive_loader_class_name(service_modname: str) -> str:
""" """
@@ -233,7 +204,7 @@ class VineFeeder(QWidget):
# Run Batch Button # Run Batch Button
self.run_batch_button = QPushButton("Run Batch") self.run_batch_button = QPushButton("Run Batch")
self.run_batch_button.clicked.connect(batchload) self.run_batch_button.clicked.connect(self._run_batch_button_handler)
self.run_batch_button.setEnabled(False) # Initially disabled self.run_batch_button.setEnabled(False) # Initially disabled
self.style_batch_button(self.run_batch_button) self.style_batch_button(self.run_batch_button)
self.sechighlighted_layout.addWidget(self.run_batch_button) self.sechighlighted_layout.addWidget(self.run_batch_button)
@@ -268,28 +239,27 @@ class VineFeeder(QWidget):
self.update_batch_file_indicator() self.update_batch_file_indicator()
def _run_batch_button_handler(self):
from .batchloader import batchload
batchload()
def toggle_batch_mode(self): def toggle_batch_mode(self, value=None):
state = self.batch_slider.value() == 1 state = (value == 1) if value is not None else (self.batch_slider.value() == 1)
if state: if state:
self.batch_label.setStyleSheet("color: lightgreen; padding-left: 5px; border: none;") self.batch_label.setStyleSheet("color: lightgreen; padding-left: 5px; border: none")
else: else:
self.toggle_dark_mode() self.toggle_dark_mode()
self.run_batch_button.setEnabled(state) self.run_batch_button.setEnabled(state)
self.update_batch_file_indicator() self.update_batch_file_indicator()
# Update config (write to the *user* config location) # Persist to config
try: try:
cfg, _ = load_config_with_fallback() cfg, _ = load_config_with_fallback()
cfg["BATCH_DOWNLOAD"] = state cfg["BATCH_DOWNLOAD"] = state
save_user_config(cfg) save_project_config(cfg)
except Exception as e: except Exception as e:
console.print(f"[{catppuccin_mocha['text2']}][warning] Could not update config.yaml: {e}[/]") console.print(f"[{catppuccin_mocha['text2']}][warning] Could not update config.yaml: {e}[/]")
def style_batch_button(self, button): def style_batch_button(self, button):
@@ -4,14 +4,12 @@ from beaupy import select, select_multiple
from rich.console import Console from rich.console import Console
from abc import abstractmethod from abc import abstractmethod
import os import os
import platform
import sys import sys
import time import time
from .pretty import create_clean_panel from .pretty import create_clean_panel
from .pretty import catppuccin_mocha from .pretty import catppuccin_mocha
import yaml
import subprocess import subprocess
from .__main__ import load_config_with_fallback, save_user_config from .config_loader import load_config_with_fallback, get_bool
console = Console() console = Console()
@@ -38,16 +36,15 @@ class BaseLoader:
self.browse_video_list = [] self.browse_video_list = []
self.category = None self.category = None
myconfig, _ = load_config_with_fallback() cfg, _ = load_config_with_fallback()
self.BATCH_DOWNLOAD = myconfig['BATCH_DOWNLOAD'] self.BATCH_DOWNLOAD = bool(cfg.get("BATCH_DOWNLOAD", False))
self.TERMINAL_RESET = myconfig['TERMINAL_RESET'] self.TERMINAL_RESET = bool(cfg.get("TERMINAL_RESET", False))
def reset_terminal(self): def reset_terminal(self):
if not self.BATCH_DOWNLOAD: if self.TERMINAL_RESET:
if os.name == 'nt': # Windows if os.name == 'nt': # Windows
os.system('cls') os.system('cls')
# Optionally, reinitialize ANSI or console buffer here if needed
else: # Unix/Linux/macOS else: # Unix/Linux/macOS
try: try:
subprocess.run(['reset'], check=True) subprocess.run(['reset'], check=True)
@@ -406,7 +403,7 @@ class BaseLoader:
# clear for next use # clear for next use
time.sleep(1) time.sleep(1)
if self.TERMINAL_RESET: if self.TERMINAL_RESET and not self.BATCH_DOWNLOAD:
console.print(f"[{catppuccin_mocha['text2']}]Preparing to reset Terminal[/]") console.print(f"[{catppuccin_mocha['text2']}]Preparing to reset Terminal[/]")
time.sleep(5) time.sleep(5)
self.reset_terminal() self.reset_terminal()
@@ -1,9 +1,17 @@
import subprocess import subprocess
import os import os
import threading import threading
from rich.console import Console
from .pretty import catppuccin_mocha
import time
from .config_loader import load_config_with_fallback, get_bool
console = Console()
def _batchloader(): def _batchloader():
cfg, _ = load_config_with_fallback()
TERMINAL_RESET = bool(cfg.get("TERMINAL_RESET", False))
try: try:
with open('./batch.txt', 'r') as file: with open('./batch.txt', 'r') as file:
for line in file: for line in file:
@@ -11,13 +19,26 @@ def _batchloader():
if line: if line:
print(line) print(line)
subprocess.run(line, shell=True) subprocess.run(line, shell=True)
print("Batch processing complete.") print("Batch processing complete.")
yesno = input("delete batch file? (y/n) ") yesno = input("delete batch file? (y/n) ")
if yesno.lower() == 'y': if yesno.lower() == 'y':
os.remove("./batch.txt") os.remove("./batch.txt")
print("batch.txt deleted.\n\nReady.") console.print(f"batch.txt deleted.\n\n[{catppuccin_mocha['pink']}]Ready.")
if TERMINAL_RESET:
console.print(f"[{catppuccin_mocha['text2']}]Preparing to reset Terminal[/]")
time.sleep(5)
if os.name == 'nt': # Windows
os.system('cls')
else: # Unix/Linux/macOS
try:
subprocess.run(['reset'], check=True)
console.print(f"[{catppuccin_mocha['pink']}]Ready![/]")
except Exception:
os.system('clear') # fallback if 'reset' is not available
except FileNotFoundError: except FileNotFoundError:
@@ -31,5 +52,6 @@ def batchload():
thread.start() thread.start()
if __name__ == "__main__": if __name__ == "__main__":
batchload() batchload()
@@ -1,5 +1,2 @@
BATCH_DOWNLOAD: False BATCH_DOWNLOAD: true
TERMINAL_RESET: true
# Set to True if up/down cursor arrows stop working in the
# Terminal window after envied has downloaded.
TERMINAL_RESET: False
@@ -0,0 +1,79 @@
from __future__ import annotations
from pathlib import Path
import os
import yaml
from importlib import resources
from typing import Tuple, Optional, Dict, Any
# Optional: allow a one-line override without changing code.
# If VINEFEEDER_CONFIG is set, we'll use that file.
ENV_VAR = "VINEFEEDER_CONFIG"
PKG_NAME = "vinefeeder"
CFG_NAME = "config.yaml"
def project_config_path() -> Path:
"""
Resolve the config file path with this priority:
1) $VINEFEEDER_CONFIG if set
2) <package_dir>/config.yaml (the repo copy beside the code)
3) importlib.resources fallback (works when installed as a wheel)
"""
# 1) explicit override via env
env_path = os.environ.get(ENV_VAR)
if env_path:
p = Path(env_path).expanduser().resolve()
if p.exists():
return p
# 2) the config.yaml living next to this file (repo/dev layout)
here = Path(__file__).resolve().parent
local_cfg = here / CFG_NAME
if local_cfg.exists():
return local_cfg
# 3) installed package data (site-packages / wheel)
try:
# resources.files returns a Traversable
f = resources.files(PKG_NAME).joinpath(CFG_NAME)
with resources.as_file(f) as p:
if p.exists():
return p
except Exception:
pass
# If we get here, we didnt find it. Return where it *should* be in dev.
return local_cfg
def load_config_with_fallback() -> Tuple[Dict[str, Any], Optional[Path]]:
"""
Load YAML config from the resolved project path.
Returns (config_dict, path_used).
"""
cfg_path = project_config_path()
try:
data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) or {}
return data, cfg_path
except FileNotFoundError:
# Consistent shape even if missing
return {}, None
def save_project_config(cfg: Dict[str, Any]) -> Path:
"""
Save back to the *project* config path (beside the code).
Useful during development; may fail if running from a read-only install.
"""
p = project_config_path()
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text(yaml.safe_dump(cfg, default_flow_style=False), encoding="utf-8")
return p
# Convenience helpers if you want one-liners elsewhere:
def get_bool(key: str, default: bool = False) -> bool:
cfg, _ = load_config_with_fallback()
return bool(cfg.get(key, default))