mirror of
https://github.com/vinefeeder/TwinVine.git
synced 2026-07-15 18:10:04 +02:00
config/batch rejig
This commit is contained in:
@@ -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 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))
|
||||||
Reference in New Issue
Block a user