Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions pmoves/docker-compose.jellyfin-ai.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ x-jellyfin-base: &jellyfin-base
services:
jellyfin:
<<: *jellyfin-base
container_name: ${JELLYFIN_CONTAINER_NAME:-pmoves-jellyfin}
container_name: ${JELLYFIN_CONTAINER_NAME:-pmoves-jellyfin-ai}
profiles: ["default", "jellyfin-ai"]
image: lscr.io/linuxserver/jellyfin:10.11.0
environment:
Expand All @@ -60,11 +60,12 @@ services:
pmoves_app:
aliases:
- jellyfin-ai
pmoves_external:
restart: unless-stopped

jellyfin-vaapi:
<<: *jellyfin-base
container_name: ${JELLYFIN_CONTAINER_NAME:-pmoves-jellyfin}
container_name: ${JELLYFIN_CONTAINER_NAME:-pmoves-jellyfin-ai}
profiles: ["jellyfin-ai-vaapi"]
devices:
- ${JELLYFIN_VAAPI_DEVICE:-/dev/dri/renderD128}:${JELLYFIN_VAAPI_DEVICE:-/dev/dri/renderD128}
Expand All @@ -79,7 +80,7 @@ services:

jellyfin-nvenc:
<<: *jellyfin-base
container_name: ${JELLYFIN_CONTAINER_NAME:-pmoves-jellyfin}
container_name: ${JELLYFIN_CONTAINER_NAME:-pmoves-jellyfin-ai}
profiles: ["jellyfin-ai-nvenc"]
gpus: ${JELLYFIN_NVIDIA_GPUS:-all}
environment:
Expand Down Expand Up @@ -128,6 +129,7 @@ services:
pmoves_app:
aliases:
- jellyfin-qwen-audio
pmoves_external:
restart: unless-stopped
# Uncomment for GPU support
# deploy:
Expand All @@ -152,6 +154,14 @@ services:
- NEO4J_URI=${JELLYFIN_NEO4J_URI:-bolt://jellyfin-neo4j:7687}
- NEO4J_USER=${JELLYFIN_NEO4J_USER:-neo4j}
- NEO4J_PASSWORD=${JELLYFIN_NEO4J_PASSWORD:-mediapassword123}
- SUPABASE_URL=${SUPABASE_URL:-http://host.docker.internal:65421}
- SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY:-}
- SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY:-}
- SUPABASE_JWT_SECRET=${SUPABASE_JWT_SECRET:-}
- AUTH_BOOTSTRAP_MODE=${AUTH_BOOTSTRAP_MODE:-jwt}
- NATS_URL=${NATS_URL:-nats://nats:pmoves@nats:4222}
- TENSORZERO_URL=${TENSORZERO_URL:-http://tensorzero-gateway:3000}
- GPU_ORCHESTRATOR_URL=${GPU_ORCHESTRATOR_URL:-http://gpu-orchestrator:8200}
- JELLYFIN_HWACCEL_MODE=${JELLYFIN_HWACCEL_MODE:-software}
- JELLYFIN_ENABLE_HDR=${JELLYFIN_ENABLE_HDR:-1}
- JELLYFIN_PREFER_AV1=${JELLYFIN_PREFER_AV1:-1}
Expand Down Expand Up @@ -197,6 +207,14 @@ services:
- NEO4J_USER=${JELLYFIN_NEO4J_USER:-neo4j}
- NEO4J_PASSWORD=${JELLYFIN_NEO4J_PASSWORD:-mediapassword123}
- REDIS_URL=${JELLYFIN_REDIS_URL:-redis://jellyfin-redis:6379}
- SUPABASE_URL=${SUPABASE_URL:-http://host.docker.internal:65421}
- SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY:-${SUPABASE_SERVICE_ROLE_KEY:-}}
- SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY:-}
- SUPABASE_JWT_SECRET=${SUPABASE_JWT_SECRET:-}
- AUTH_BOOTSTRAP_MODE=${AUTH_BOOTSTRAP_MODE:-jwt}
- NATS_URL=${NATS_URL:-nats://nats:pmoves@nats:4222}
- TENSORZERO_URL=${TENSORZERO_URL:-http://tensorzero-gateway:3000}
- GPU_ORCHESTRATOR_URL=${GPU_ORCHESTRATOR_URL:-http://gpu-orchestrator:8200}
- JELLYFIN_HWACCEL_MODE=${JELLYFIN_HWACCEL_MODE:-software}
- JELLYFIN_ENABLE_HDR=${JELLYFIN_ENABLE_HDR:-1}
- JELLYFIN_PREFER_AV1=${JELLYFIN_PREFER_AV1:-1}
Expand All @@ -206,6 +224,7 @@ services:
pmoves_api:
aliases:
- jellyfin-api
pmoves_external:
restart: unless-stopped
depends_on:
- ${JELLYFIN_STACK_SERVICE:-jellyfin}
Expand All @@ -229,6 +248,7 @@ services:
pmoves_app:
aliases:
- jellyfin-dashboard
pmoves_external:
restart: unless-stopped
depends_on:
- jellyfin-api-gateway
Expand All @@ -246,3 +266,6 @@ networks:
pmoves_data:
external: true
name: pmoves_data
pmoves_external:
external: true
name: pmoves_external
17 changes: 15 additions & 2 deletions pmoves/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,7 @@ services:
networks:
- pmoves_app
- pmoves_bus
- pmoves_external # Required for host reachability + external media metadata lookups
pmoves-ollama:
<<: *tier-llm-hardened
image: ${PMOVES_OLLAMA_IMAGE:-ollama/ollama:0.12.6@sha256:ea37dcbf693248c80796654500fccf1e12f55da20ec7c78c30870a9a227c4cdd}
Expand Down Expand Up @@ -1889,7 +1890,17 @@ services:
- --config-file
- /app/config/tensorzero.toml
environment:
- TENSORZERO_CLICKHOUSE_URL=${TENSORZERO_CLICKHOUSE_URL:-http://tensorzero:tensorzero@tensorzero-clickhouse:8123/default}
- TENSORZERO_CLICKHOUSE_URL=${TENSORZERO_CLICKHOUSE_GATEWAY_URL:-${TENSORZERO_CLICKHOUSE_URL:-http://tensorzero:tensorzero@tensorzero-clickhouse:8123/default}}
# Keep gateway bootable in local-first mode when cloud provider keys are absent.
- OPENAI_API_KEY=${OPENAI_API_KEY:-local-disabled}
- GROQ_API_KEY=${GROQ_API_KEY:-local-disabled}
- MOONSHOT_API_KEY=${MOONSHOT_API_KEY:-local-disabled}
- OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-local-disabled}
- VENICE_API_KEY=${VENICE_API_KEY:-local-disabled}
- Z_AI_API_KEY=${Z_AI_API_KEY:-local-disabled}
- TOGETHER_AI_API_KEY=${TOGETHER_AI_API_KEY:-local-disabled}
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:-local-disabled}
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:-http://host.docker.internal:4317}
- DOCKED_MODE=${DOCKED_MODE:-true}
- PARENT_SYSTEM=${PARENT_SYSTEM:-PMOVES.AI}
- PARENT_VERSION=${PARENT_VERSION:-1.0.0-hardened}
Expand All @@ -1904,6 +1915,7 @@ services:
- pmoves_api
- pmoves_bus
- pmoves_data
- pmoves_external
extra_hosts:
- host.docker.internal:host-gateway
tensorzero-ui:
Expand All @@ -1913,7 +1925,7 @@ services:
restart: unless-stopped
environment:
- TENSORZERO_GATEWAY_URL=${TENSORZERO_GATEWAY_URL:-http://tensorzero-gateway:3000}
- TENSORZERO_CLICKHOUSE_URL=${TENSORZERO_CLICKHOUSE_URL:-http://tensorzero:tensorzero@tensorzero-clickhouse:8123/default}
- TENSORZERO_CLICKHOUSE_URL=${TENSORZERO_CLICKHOUSE_GATEWAY_URL:-${TENSORZERO_CLICKHOUSE_URL:-http://tensorzero:tensorzero@tensorzero-clickhouse:8123/default}}
- DOCKED_MODE=${DOCKED_MODE:-true}
- PARENT_SYSTEM=${PARENT_SYSTEM:-PMOVES.AI}
- PARENT_VERSION=${PARENT_VERSION:-1.0.0-hardened}
Expand All @@ -1931,6 +1943,7 @@ services:
networks:
- pmoves_app
- pmoves_data
- pmoves_external
gpu-orchestrator:
env_file:
- env.shared
Expand Down
8 changes: 8 additions & 0 deletions pmoves/env.jellyfin-ai.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
SUPABASE_URL=https://supabase.cataclysmstudios.net
SUPABASE_ANON_KEY=anon-key
SUPABASE_SERVICE_ROLE_KEY=service-role-key
SUPABASE_SERVICE_KEY=service-role-key
SUPABASE_JWT_SECRET=${JWT_SECRET}
AUTH_BOOTSTRAP_MODE=jwt

# Core mesh auth + bus (must align with pmoves/env.shared in production)
NATS_URL=nats://nats:pmoves@nats:4222
TENSORZERO_URL=http://tensorzero-gateway:3000
GPU_ORCHESTRATOR_URL=http://gpu-orchestrator:8200

# Jellyfin credentials (username/password OR API key)
JELLYFIN_URL=http://jellyfin:8096
Expand Down
1 change: 1 addition & 0 deletions pmoves/env.shared.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ TENSORZERO_EMBED_BATCH_SIZE=16
TENSORZERO_EMBED_TIMEOUT_SECS=120
# TensorZero ClickHouse - WARNING: Change credentials for production
TENSORZERO_CLICKHOUSE_URL=http://tensorzero-clickhouse:8123
TENSORZERO_CLICKHOUSE_GATEWAY_URL=http://tensorzero:tensorzero@tensorzero-clickhouse:8123/default
TENSORZERO_CLICKHOUSE_USER=CLICKHOUSE_USER_HERE
TENSORZERO_CLICKHOUSE_PASSWORD=CLICKHOUSE_PASSWORD_HERE
TENSORZERO_CLICKHOUSE_DB=tensorzero
Expand Down
4 changes: 2 additions & 2 deletions pmoves/services/jellyfin-bridge/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ FROM python:3.11-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1
RUN pip install --no-cache-dir --upgrade pip
COPY requirements.txt requirements.lock ./
RUN pip install --no-cache-dir --constraint requirements.lock -r requirements.txt
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

# Security: Run as non-root user
Expand Down
9 changes: 4 additions & 5 deletions pmoves/services/jellyfin-bridge/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Prometheus metrics
prometheus-client==0.21.0 \
--hash=sha256:4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166

-r requirements.lock
fastapi==0.121.0
uvicorn[standard]==0.38.0
httpx==0.28.1
prometheus-client==0.21.0
27 changes: 23 additions & 4 deletions pmoves/services/pmoves-yt/yt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1685,10 +1685,29 @@ def yt_info(body: Dict[str,Any] = Body(...)):
url = body.get('url')
if not url: raise HTTPException(400, 'url required')
ydl_opts = _with_ytdlp_defaults({'quiet': True, 'noprogress': True, 'skip_download': True})
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=False)
wanted = {k: info.get(k) for k in ('id','title','uploader','duration','webpage_url')}
return {'ok': True, 'info': wanted}
# Metadata probes must not force a playable/download format because
# upstream extractor availability can vary and cause false 500s.
ydl_opts.pop('format', None)
ydl_opts.pop('merge_output_format', None)
ydl_opts.setdefault('extract_flat', True)
# Ignore external yt-dlp config files to keep API behavior deterministic.
ydl_opts['ignoreconfig'] = True
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=False)
except Exception:
# Conservative fallback that avoids hardened defaults entirely.
fallback_opts = {
'quiet': True,
'noprogress': True,
'skip_download': True,
'extract_flat': True,
'ignoreconfig': True,
}
with yt_dlp.YoutubeDL(fallback_opts) as ydl:
info = ydl.extract_info(url, download=False)
wanted = {k: info.get(k) for k in ('id','title','uploader','duration','webpage_url')}
return {'ok': True, 'info': wanted}

@app.post("/yt/download")
def yt_download(body: Dict[str,Any] = Body(...)):
Expand Down