- tmdb.py: store release_date year in cache, expose as tmdb_year - main.py + app.js: use tmdb_year when subtitle has no year - Dockerfile: add gosu + abc user for PUID/PGID runtime privilege drop - entrypoint.sh: new entrypoint handling PUID/PGID ownership of /app/data Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+7
-1
@@ -2,13 +2,19 @@ FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update -qq && apt-get install -y -qq ffmpeg && rm -rf /var/lib/apt/lists/*
|
||||
RUN apt-get update -qq \
|
||||
&& apt-get install -y -qq ffmpeg gosu \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& groupadd -r abc \
|
||||
&& useradd -r -g abc abc
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
|
||||
|
||||
@@ -101,6 +101,8 @@ TMDB_API_KEY=xxx docker compose up -d
|
||||
| `TMDB_API_KEY` | — | Clé API TMDB (obligatoire pour posters/backdrops) |
|
||||
| `TZ` | `UTC` | Fuseau horaire |
|
||||
| `AUTO_DL_INTERVAL` | `3600` | Intervalle (secondes) entre deux checks auto-DL |
|
||||
| `PUID` | `0` | UID Unix du propriétaire des fichiers (Unraid : `99`) |
|
||||
| `PGID` | `0` | GID Unix du propriétaire des fichiers (Unraid : `100`) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
PUID=${PUID:-0}
|
||||
PGID=${PGID:-0}
|
||||
|
||||
if [ "$PUID" != "0" ] || [ "$PGID" != "0" ]; then
|
||||
groupmod -o -g "$PGID" abc 2>/dev/null || true
|
||||
usermod -o -u "$PUID" abc 2>/dev/null || true
|
||||
mkdir -p /app/data
|
||||
chown -R "$PUID:$PGID" /app/data 2>/dev/null || true
|
||||
exec gosu abc "$@"
|
||||
else
|
||||
exec "$@"
|
||||
fi
|
||||
@@ -32,7 +32,7 @@ async def _run_auto_dl_check() -> int:
|
||||
for c in concerts:
|
||||
if not dm.already_enqueued(c["url"]):
|
||||
m = re.search(r"\b(20\d{2})\b", c.get("subtitle", ""))
|
||||
year = int(m.group(1)) if m else None
|
||||
year = int(m.group(1)) if m else c.get("tmdb_year")
|
||||
await dm.enqueue(c["url"], c["title"], c.get("subtitle", ""), year, cat)
|
||||
total += 1
|
||||
return total
|
||||
|
||||
+1
-1
@@ -307,7 +307,7 @@ $('btn-download').addEventListener('click', async () => {
|
||||
|
||||
try {
|
||||
const yearMatch = (c.subtitle || '').match(/\b(20\d{2})\b/);
|
||||
const year = yearMatch ? parseInt(yearMatch[1]) : null;
|
||||
const year = yearMatch ? parseInt(yearMatch[1]) : (c.tmdb_year || null);
|
||||
const res = await fetch('/api/download', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
|
||||
@@ -33,9 +33,14 @@ def _init_db():
|
||||
tmdb_id INTEGER,
|
||||
poster TEXT,
|
||||
backdrop TEXT,
|
||||
year INTEGER,
|
||||
cached_at TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
try:
|
||||
conn.execute("ALTER TABLE tmdb_cache ADD COLUMN year INTEGER")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _search(query: str) -> list[dict]:
|
||||
@@ -72,15 +77,15 @@ def lookup(arte_id: str, title: str, subtitle: str) -> dict | None:
|
||||
cutoff = (datetime.now() - timedelta(days=_CACHE_DAYS)).isoformat()
|
||||
with sqlite3.connect(_DB) as conn:
|
||||
row = conn.execute(
|
||||
"SELECT tmdb_id, poster, backdrop FROM tmdb_cache WHERE arte_id=? AND cached_at>?",
|
||||
"SELECT tmdb_id, poster, backdrop, year FROM tmdb_cache WHERE arte_id=? AND cached_at>?",
|
||||
(arte_id, cutoff),
|
||||
).fetchone()
|
||||
|
||||
if row is not None:
|
||||
tmdb_id, poster, backdrop = row
|
||||
tmdb_id, poster, backdrop, year = row
|
||||
if tmdb_id is None:
|
||||
return None # cached "no match"
|
||||
return _build(tmdb_id, poster, backdrop)
|
||||
return _build(tmdb_id, poster, backdrop, year)
|
||||
|
||||
# Query TMDB
|
||||
query = f"{title} {subtitle}".strip()
|
||||
@@ -90,21 +95,24 @@ def lookup(arte_id: str, title: str, subtitle: str) -> dict | None:
|
||||
tmdb_id = match["id"] if match else None
|
||||
poster = match.get("poster_path") if match else None
|
||||
backdrop = match.get("backdrop_path") if match else None
|
||||
rd = (match.get("release_date") or "")[:4] if match else ""
|
||||
year = int(rd) if rd.isdigit() else None
|
||||
|
||||
with sqlite3.connect(_DB) as conn:
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO tmdb_cache VALUES (?,?,?,?,?)",
|
||||
(arte_id, tmdb_id, poster, backdrop, datetime.now().isoformat()),
|
||||
"INSERT OR REPLACE INTO tmdb_cache VALUES (?,?,?,?,?,?)",
|
||||
(arte_id, tmdb_id, poster, backdrop, year, datetime.now().isoformat()),
|
||||
)
|
||||
|
||||
return _build(tmdb_id, poster, backdrop) if tmdb_id else None
|
||||
return _build(tmdb_id, poster, backdrop, year) if tmdb_id else None
|
||||
|
||||
|
||||
def _build(tmdb_id: int, poster: str | None, backdrop: str | None) -> dict:
|
||||
def _build(tmdb_id: int, poster: str | None, backdrop: str | None, year: int | None = None) -> dict:
|
||||
return {
|
||||
"tmdb_id": tmdb_id,
|
||||
"tmdb_poster": f"{_IMG_BASE}/w500{poster}" if poster else None,
|
||||
"tmdb_backdrop": f"{_IMG_BASE}/w1280{backdrop}" if backdrop else None,
|
||||
"tmdb_year": year,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user