From d1428eea9b23a9efd3f4be3666d2599dc04c3b6a Mon Sep 17 00:00:00 2001 From: VineFeeder Date: Thu, 28 Aug 2025 12:45:18 +0100 Subject: [PATCH] config/batch rejig --- .../vinefeeder/src/vinefeeder/__main__.py | 64 ++++----------- .../vinefeeder/src/vinefeeder/base_loader.py | 17 ++-- .../vinefeeder/src/vinefeeder/batchloader.py | 26 +++++- .../vinefeeder/src/vinefeeder/config.yaml | 7 +- .../src/vinefeeder/config_loader.py | 79 +++++++++++++++++++ 5 files changed, 129 insertions(+), 64 deletions(-) create mode 100644 packages/vinefeeder/src/vinefeeder/config_loader.py diff --git a/packages/vinefeeder/src/vinefeeder/__main__.py b/packages/vinefeeder/src/vinefeeder/__main__.py index 9b59ca6..2a0ca0f 100644 --- a/packages/vinefeeder/src/vinefeeder/__main__.py +++ b/packages/vinefeeder/src/vinefeeder/__main__.py @@ -17,32 +17,16 @@ from rich.console import Console from .parsing_utils import prettify import click import subprocess -from .batchloader import batchload +#from .batchloader import batchload 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 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" _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). Prefers user config; falls back to package-bundled default. @@ -97,15 +74,9 @@ def load_config_with_fallback() -> tuple[dict, Path | None]: # packaged default with resources.files(_PKG_NAME).joinpath(_CFG_NAME).open("rb") as f: 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: """ @@ -233,7 +204,7 @@ class VineFeeder(QWidget): # Run Batch Button 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.style_batch_button(self.run_batch_button) self.sechighlighted_layout.addWidget(self.run_batch_button) @@ -268,28 +239,27 @@ class VineFeeder(QWidget): self.update_batch_file_indicator() + def _run_batch_button_handler(self): + from .batchloader import batchload + batchload() - def toggle_batch_mode(self): - state = self.batch_slider.value() == 1 - + def toggle_batch_mode(self, value=None): + state = (value == 1) if value is not None else (self.batch_slider.value() == 1) 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: self.toggle_dark_mode() self.run_batch_button.setEnabled(state) self.update_batch_file_indicator() - # Update config (write to the *user* config location) + # Persist to config try: cfg, _ = load_config_with_fallback() cfg["BATCH_DOWNLOAD"] = state - save_user_config(cfg) + save_project_config(cfg) except Exception as e: console.print(f"[{catppuccin_mocha['text2']}][warning] Could not update config.yaml: {e}[/]") - - - def style_batch_button(self, button): diff --git a/packages/vinefeeder/src/vinefeeder/base_loader.py b/packages/vinefeeder/src/vinefeeder/base_loader.py index e6dc8db..a6e1a27 100644 --- a/packages/vinefeeder/src/vinefeeder/base_loader.py +++ b/packages/vinefeeder/src/vinefeeder/base_loader.py @@ -4,14 +4,12 @@ from beaupy import select, select_multiple from rich.console import Console from abc import abstractmethod import os -import platform import sys import time from .pretty import create_clean_panel from .pretty import catppuccin_mocha -import yaml import subprocess -from .__main__ import load_config_with_fallback, save_user_config +from .config_loader import load_config_with_fallback, get_bool console = Console() @@ -38,16 +36,15 @@ class BaseLoader: self.browse_video_list = [] self.category = None - myconfig, _ = load_config_with_fallback() - self.BATCH_DOWNLOAD = myconfig['BATCH_DOWNLOAD'] - self.TERMINAL_RESET = myconfig['TERMINAL_RESET'] - + cfg, _ = load_config_with_fallback() + self.BATCH_DOWNLOAD = bool(cfg.get("BATCH_DOWNLOAD", False)) + self.TERMINAL_RESET = bool(cfg.get("TERMINAL_RESET", False)) + def reset_terminal(self): - if not self.BATCH_DOWNLOAD: + if self.TERMINAL_RESET: if os.name == 'nt': # Windows os.system('cls') - # Optionally, reinitialize ANSI or console buffer here if needed else: # Unix/Linux/macOS try: subprocess.run(['reset'], check=True) @@ -406,7 +403,7 @@ class BaseLoader: # clear for next use 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[/]") time.sleep(5) self.reset_terminal() diff --git a/packages/vinefeeder/src/vinefeeder/batchloader.py b/packages/vinefeeder/src/vinefeeder/batchloader.py index 3aafb6e..efc0ed6 100644 --- a/packages/vinefeeder/src/vinefeeder/batchloader.py +++ b/packages/vinefeeder/src/vinefeeder/batchloader.py @@ -1,9 +1,17 @@ import subprocess import os 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(): + + cfg, _ = load_config_with_fallback() + TERMINAL_RESET = bool(cfg.get("TERMINAL_RESET", False)) try: with open('./batch.txt', 'r') as file: for line in file: @@ -11,13 +19,26 @@ def _batchloader(): if line: print(line) subprocess.run(line, shell=True) - print("Batch processing complete.") yesno = input("delete batch file? (y/n) ") if yesno.lower() == 'y': 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: @@ -31,5 +52,6 @@ def batchload(): thread.start() + if __name__ == "__main__": batchload() \ No newline at end of file diff --git a/packages/vinefeeder/src/vinefeeder/config.yaml b/packages/vinefeeder/src/vinefeeder/config.yaml index cc8d449..5f5698a 100644 --- a/packages/vinefeeder/src/vinefeeder/config.yaml +++ b/packages/vinefeeder/src/vinefeeder/config.yaml @@ -1,5 +1,2 @@ -BATCH_DOWNLOAD: False - -# Set to True if up/down cursor arrows stop working in the -# Terminal window after envied has downloaded. -TERMINAL_RESET: False +BATCH_DOWNLOAD: true +TERMINAL_RESET: true diff --git a/packages/vinefeeder/src/vinefeeder/config_loader.py b/packages/vinefeeder/src/vinefeeder/config_loader.py new file mode 100644 index 0000000..0c04f5a --- /dev/null +++ b/packages/vinefeeder/src/vinefeeder/config_loader.py @@ -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) /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 didn’t 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))