Initial release — MediaTracker v1.0
Dockerized media library scanner for NAS drives. Identifies movies and series from filenames, fetches posters via the public IMDB suggestion API (no key required), and exposes a dark-themed web UI with multilingual search support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
108
generate-compose.py
Normal file
108
generate-compose.py
Normal file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
generate-compose.py
|
||||
Reads .env and generates docker-compose.override.yml with NAS volumes.
|
||||
No external dependencies required.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ENV_FILE = Path(".env")
|
||||
OUTPUT_FILE = Path("docker-compose.override.yml")
|
||||
|
||||
OVERRIDE_HEADER = """\
|
||||
# Auto-generated by generate-compose.py — do not edit manually.
|
||||
# Re-run the script after changing NAS_* entries in .env.
|
||||
|
||||
services:
|
||||
backend:
|
||||
volumes:
|
||||
"""
|
||||
|
||||
|
||||
def load_env(path: Path) -> dict:
|
||||
env = {}
|
||||
if not path.exists():
|
||||
print(f"[ERROR] {path} not found. Copy .env.example to .env first.")
|
||||
sys.exit(1)
|
||||
with path.open(encoding="utf-8") as fh:
|
||||
for line in fh:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" not in line:
|
||||
continue
|
||||
key, _, value = line.partition("=")
|
||||
key = key.strip()
|
||||
# Strip inline comments
|
||||
value = value.split("#")[0].strip()
|
||||
env[key] = value
|
||||
return env
|
||||
|
||||
|
||||
def parse_nas_entries(env: dict) -> list[tuple[str, str, str]]:
|
||||
"""Return list of (key, name, host_path) sorted by key."""
|
||||
nas_pattern = re.compile(r"^NAS_(\d+)$")
|
||||
entries = []
|
||||
for key, value in env.items():
|
||||
match = nas_pattern.match(key)
|
||||
if not match:
|
||||
continue
|
||||
if "|" not in value:
|
||||
print(f"[WARN] {key}={value!r} — expected format 'Name|/host/path', skipping.")
|
||||
continue
|
||||
name, _, host_path = value.partition("|")
|
||||
entries.append((key, name.strip(), host_path.strip()))
|
||||
entries.sort(key=lambda t: int(t[0].split("_")[1]))
|
||||
return entries
|
||||
|
||||
|
||||
def validate_paths(entries: list[tuple[str, str, str]]) -> None:
|
||||
for key, name, host_path in entries:
|
||||
if not Path(host_path).exists():
|
||||
print(f"[WARN] {key} — host path does not exist: {host_path!r}")
|
||||
else:
|
||||
print(f"[OK] {key} — {name!r} → {host_path}")
|
||||
|
||||
|
||||
def generate_override(entries: list[tuple[str, str, str]]) -> str:
|
||||
lines = [OVERRIDE_HEADER]
|
||||
for idx, (key, name, host_path) in enumerate(entries, start=1):
|
||||
container_path = f"/nas/nas{idx}"
|
||||
lines.append(f" - {host_path}:{container_path}:ro # {name}")
|
||||
# Pass NAS_X env vars into the container so config.py can read the names
|
||||
lines.append(" environment:")
|
||||
for idx, (key, name, host_path) in enumerate(entries, start=1):
|
||||
lines.append(f" - {key}={name}|/nas/nas{idx}")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
print("=" * 55)
|
||||
print(" MediaTracker — generate-compose.py")
|
||||
print("=" * 55)
|
||||
|
||||
env = load_env(ENV_FILE)
|
||||
entries = parse_nas_entries(env)
|
||||
|
||||
if not entries:
|
||||
print("[ERROR] No NAS_* entries found in .env. Add at least one NAS.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\nFound {len(entries)} NAS source(s):\n")
|
||||
validate_paths(entries)
|
||||
|
||||
content = generate_override(entries)
|
||||
OUTPUT_FILE.write_text(content, encoding="utf-8")
|
||||
|
||||
print(f"\n[DONE] {OUTPUT_FILE} generated with {len(entries)} volume(s).")
|
||||
print("\nNext step:")
|
||||
print(" docker compose -f docker-compose.yml -f docker-compose.override.yml up -d --build\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user