Delete plex/#!/usr/nas_setup.py

This commit is contained in:
vijay 2026-06-10 07:37:14 +00:00
parent 84f2ce7d6f
commit 8951f2fc24

View File

@ -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()