From 8951f2fc24563aa3adfb488828d6e6c45567279b Mon Sep 17 00:00:00 2001 From: vijay Date: Wed, 10 Jun 2026 07:37:14 +0000 Subject: [PATCH] Delete plex/#!/usr/nas_setup.py --- plex/#!/usr/nas_setup.py | 254 --------------------------------------- 1 file changed, 254 deletions(-) delete mode 100644 plex/#!/usr/nas_setup.py diff --git a/plex/#!/usr/nas_setup.py b/plex/#!/usr/nas_setup.py deleted file mode 100644 index 91c6a91..0000000 --- a/plex/#!/usr/nas_setup.py +++ /dev/null @@ -1,254 +0,0 @@ -#!/usr/bin/env python3 -""" -nas_setup.py -============ -One-time setup script to run on your Synology NAS via SSH. -Installs SQLite triggers into the Plex database and starts the redirect proxy. - -This script reads automation_config.json for all paths — no arguments needed. - -USAGE: - python /volume1/Plex/scripts/nas_setup.py # Install triggers + patch existing - python /volume1/Plex/scripts/nas_setup.py --dry-run # Preview only, no changes - python /volume1/Plex/scripts/nas_setup.py --remove # Remove triggers - -Run order: - 1. Stop Plex Media Server - 2. Run this script (installs triggers, patches existing .strm rows) - 3. Start nas_strm_proxy.py in the background - 4. Start Plex Media Server -""" - -import os -import sys -import json -import sqlite3 -import argparse -import subprocess - -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) -CONFIG_FILE = os.path.join(SCRIPT_DIR, "automation_config.json") - -TRIGGER_NAMES = ["strm_proxy_insert", "strm_proxy_update"] - - -def load_config(): - if not os.path.exists(CONFIG_FILE): - print(f"[-] Cannot find {CONFIG_FILE}") - print(f" Make sure this script is in the same folder as automation_config.json") - sys.exit(1) - with open(CONFIG_FILE, "r") as f: - return json.load(f) - - -def build_triggers(strm_root: str, proxy_base: str) -> tuple: - root_len = len(strm_root.rstrip("/")) - like_pattern = f"{strm_root.rstrip('/')}/%.strm" - - # Convert stored NAS path → proxy URL: - # /volume1/Plex/Library/Streams/Movies/Hindi/Film.strm - # → http://127.0.0.1:8086/Movies/Hindi/Film.mp4 - url_expr = f"'{proxy_base}' || REPLACE(substr(NEW.file, {root_len + 1}), '.strm', '.mp4')" - - insert_sql = f""" -CREATE TRIGGER IF NOT EXISTS strm_proxy_insert -AFTER INSERT ON media_parts -WHEN NEW.file LIKE '{like_pattern}' -BEGIN - UPDATE media_parts SET file = {url_expr} WHERE id = NEW.id; -END; -""".strip() - - update_sql = f""" -CREATE TRIGGER IF NOT EXISTS strm_proxy_update -AFTER UPDATE OF file ON media_parts -WHEN NEW.file LIKE '{like_pattern}' -BEGIN - UPDATE media_parts SET file = {url_expr} WHERE id = NEW.id; -END; -""".strip() - - return insert_sql, update_sql - - -def check_plex_running(): - """Warn if Plex appears to be running — writing to a live DB risks corruption.""" - try: - out = subprocess.check_output(["pgrep", "-f", "Plex Media Server"], text=True).strip() - if out: - print("=" * 65) - print("[!] WARNING: Plex Media Server appears to be RUNNING!") - print("[!] Writing to the Plex database while Plex is open can") - print("[!] corrupt it. Stop Plex first, then run this script.") - print("[!] On Synology: synoservice --stop 'pkgctl-Plex Media Server'") - print("=" * 65) - ans = input("Continue anyway? (yes/no): ").strip().lower() - if ans != "yes": - print("[*] Aborted.") - sys.exit(0) - except (subprocess.CalledProcessError, FileNotFoundError): - pass # pgrep not found or no matching process — assume safe - - -def install_triggers(db_path: str, strm_root: str, proxy_base: str, dry_run: bool): - print(f"\n[*] Database : {db_path}") - print(f"[*] STRM root : {strm_root}") - print(f"[*] Proxy base : {proxy_base}") - - if not os.path.exists(db_path): - print(f"\n[-] ERROR: Plex database not found at:\n {db_path}") - print(" Has Plex been started at least once to create its database?") - sys.exit(1) - - insert_sql, update_sql = build_triggers(strm_root, proxy_base) - - if dry_run: - print("\n[DRY RUN] SQL that would be installed:\n") - print("-- INSERT TRIGGER:\n" + insert_sql) - print("\n-- UPDATE TRIGGER:\n" + update_sql) - print("\n[DRY RUN] No changes made.") - return - - try: - conn = sqlite3.connect(db_path) - cursor = conn.cursor() - - # Drop old triggers if they exist - cursor.execute( - "SELECT name FROM sqlite_master WHERE type='trigger' AND name IN (?,?)", - TRIGGER_NAMES, - ) - existing = [r[0] for r in cursor.fetchall()] - if existing: - print(f"[!] Removing old triggers: {existing}") - for name in existing: - cursor.execute(f"DROP TRIGGER IF EXISTS {name}") - conn.commit() - - print("[*] Installing INSERT trigger...") - cursor.executescript(insert_sql) - print("[*] Installing UPDATE trigger...") - cursor.executescript(update_sql) - conn.commit() - - cursor.execute( - "SELECT name FROM sqlite_master WHERE type='trigger' AND name IN (?,?)", - TRIGGER_NAMES, - ) - installed = [r[0] for r in cursor.fetchall()] - conn.close() - - print(f"[+] Triggers installed: {installed}") - - except sqlite3.Error as e: - print(f"[-] SQLite error: {e}") - sys.exit(1) - - -def patch_existing(db_path: str, strm_root: str, proxy_base: str, dry_run: bool): - """Directly UPDATE existing media_parts rows that still have raw .strm paths.""" - print("\n[*] Patching already-scanned .strm rows in media_parts...") - strm_root = strm_root.rstrip("/") - root_len = len(strm_root) - like = f"{strm_root}/%.strm" - - try: - conn = sqlite3.connect(db_path) - cursor = conn.cursor() - cursor.execute( - "SELECT id, file FROM media_parts WHERE file LIKE ? AND deleted_at IS NULL", - (like,), - ) - rows = cursor.fetchall() - - if not rows: - print("[*] No unpatched .strm rows found — nothing to do.") - conn.close() - return - - print(f"[*] Found {len(rows)} row(s) to patch:") - for part_id, file_path in rows: - rel = file_path[root_len:] - proxy_url = proxy_base + rel.replace(".strm", ".mp4") - print(f" {file_path}") - print(f" → {proxy_url}") - if not dry_run: - cursor.execute("UPDATE media_parts SET file = ? WHERE id = ?", (proxy_url, part_id)) - - if not dry_run: - conn.commit() - print(f"\n[+] Patched {len(rows)} row(s).") - else: - print(f"\n[DRY RUN] Would patch {len(rows)} row(s) — no changes made.") - - conn.close() - - except sqlite3.Error as e: - print(f"[-] SQLite error during patch: {e}") - sys.exit(1) - - -def remove_triggers(db_path: str): - print("[*] Removing STRM proxy triggers...") - try: - conn = sqlite3.connect(db_path) - for name in TRIGGER_NAMES: - conn.execute(f"DROP TRIGGER IF EXISTS {name}") - print(f"[+] Dropped: {name}") - conn.commit() - conn.close() - print("[+] Done. Plex will now store raw .strm paths again on next scan.") - except sqlite3.Error as e: - print(f"[-] SQLite error: {e}") - sys.exit(1) - - -def main(): - parser = argparse.ArgumentParser( - description="One-time Plex DB trigger installer for NAS-native STRM playback." - ) - parser.add_argument("--dry-run", action="store_true", help="Preview changes, write nothing") - parser.add_argument("--remove", action="store_true", help="Remove installed triggers") - args = parser.parse_args() - - print("=" * 65) - print(" PLEX STRM TRIGGER SETUP") - print("=" * 65) - - cfg = load_config() - - db_path = cfg.get("plex_db_path", ( - "/volume1/Plex/Library/Application Support/" - "Plex Media Server/Plug-in Support/Databases/" - "com.plexapp.plugins.library.db" - )) - strm_root = cfg.get("output_dir", "/volume1/Plex/Library/Streams").rstrip("/") - proxy_port = cfg.get("nas_proxy_port", 8086) - proxy_base = f"http://127.0.0.1:{proxy_port}" - - if args.remove: - remove_triggers(db_path) - return - - check_plex_running() - install_triggers(db_path, strm_root, proxy_base, args.dry_run) - patch_existing(db_path, strm_root, proxy_base, args.dry_run) - - if not args.dry_run: - print() - print("=" * 65) - print("[+] Setup complete!") - print() - print("Next steps:") - print(f" 1. Start the redirect proxy (keep it running permanently):") - print(f" nohup python {SCRIPT_DIR}/nas_strm_proxy.py > /tmp/strm_proxy.log 2>&1 &") - print() - print(f" 2. Start Plex Media Server") - print(f" synoservice --start 'pkgctl-Plex Media Server'") - print() - print(f" 3. Trigger a library scan in Plex, or run run_automation.py") - print("=" * 65) - - -if __name__ == "__main__": - main()