Files
MeBox/Dockerfile
T
Kiro 8824638efb feat: hwaccel + Fanart/TheTVDB + AI + Discover + NFO + Tasks + Recycle bin
Backend
  - service/transcoder.go: encoder selector (software / nvenc / qsv /
    vaapi) with proper hwaccel + scale_* filters per encoder; configurable
    bitrate/preset/height/segment-seconds via transcoder.* config; new
    Active() snapshot + ActiveJob struct for the Tasks panel; unit-tested
    via buildFFmpegArgs(...).
  - service/thetvdb.go: TheTVDB v4 provider — login() caches the JWT for
    24h, SearchSeries() returns Match struct.
  - service/fanart.go: Fanart.tv provider — high-res movie artwork keyed
    by TMDb id; used to upgrade poster/backdrop after a successful match.
  - service/scraper.go: provider chain reworked — anime → Bangumi, tv →
    TheTVDB, default → TMDb, with optional Fanart upgrade post-match.
  - service/discover.go: TMDb /trending/movie/day + /movie/popular for
    the Discover rail.
  - service/ai.go: OpenAI-compatible client. SmartSearch() turns a free-
    form query into a structured SearchIntent JSON; Recommend() emits a
    short list of titles given the user's history. Disabled when
    ai.api_key is empty.
  - service/nfo.go: per-movie .nfo writer (Kodi/Jellyfin schema) +
    library-scope batch exporter.
  - service/media.go: SoftDelete / Restore / Purge / ListRecycleBin
    helpers backed by gorm Unscoped().
  - service/service.go: container wires Fanart, TheTVDB, Discover, AI,
    NFO; everything still tears down cleanly via Close().
  - config: new transcoder.* section (encoder, preset, video_bitrate,
    max_rate, buf_size, max_height, segment_seconds) with sensible
    defaults.

Handlers / routes
  - new files: discover.go, recycle.go, nfo.go, ai.go, tasks.go.
  - registers GET /tasks, /discover/{trending,popular},
    /ai/{status,search,recommend}; admin-only GET /recycle and
    DELETE/POST /media/:id (soft delete / restore / purge); admin-only
    POST /media/:id/nfo and /libraries/:id/nfo.

Frontend
  - new pages: DiscoverPage, TasksPage, RecycleBinPage; SearchPage gains
    an optional AI smart-search toggle that calls /api/ai/search.
  - MediaDetailPage gains admin actions for 导出 NFO and 移至回收站.
  - new api/ helpers: ai.ts, discover.ts, recycle.ts, tasks.ts.
  - App.tsx routes /discover, /tasks, /recycle (last two admin-only).
  - Layout sidebar groups now include Discover + Tasks + Recycle Bin.

Docker / config
  - Dockerfile: adds intel-media-driver / libva-utils / mesa-va-gallium
    so QSV + VAAPI work out of the box on Intel iGPUs.
  - docker-compose.yml: documents devices + group_add + nvidia runtime
    overrides for hardware transcoding.

Verified: go build, go vet, go test (incl. new TestBuildFFmpegArgs across
software / nvenc / qsv / vaapi encoder profiles); tsc -b && vite build
emits 22 route chunks plus the deferred hls chunk; main bundle 248 KB /
83 KB gzipped.
2026-05-14 16:22:08 +00:00

95 lines
3.4 KiB
Docker

# syntax=docker/dockerfile:1.6
# =============================================================================
# Multi-architecture build for MediaStationGo.
#
# Stage 1 (frontend) : Node 20 -> static SPA bundle
# Stage 2 (backend) : Go 1.25 -> single static binary (CGO_ENABLED=0)
# Stage 3 (runtime) : Alpine 3.19 -> ffmpeg + tzdata + non-root user
#
# Build:
# docker buildx build --platform linux/amd64,linux/arm64 \
# -t mediastation-go:latest --push .
# =============================================================================
# ---- Stage 1: frontend (always build on the host architecture) -------------
FROM --platform=$BUILDPLATFORM node:20-alpine AS frontend
WORKDIR /app/web
COPY web/package*.json ./
RUN npm ci
COPY web/ .
RUN npm run build
# ---- Stage 2: backend (cross-compiled to TARGETPLATFORM) -------------------
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS backend
ARG TARGETOS
ARG TARGETARCH
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
COPY --from=frontend /app/web/dist ./web/dist
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -trimpath -ldflags="-s -w" -o mediastation-go ./cmd/server
# ---- Stage 3: runtime ------------------------------------------------------
FROM alpine:3.19
# ffmpeg/intel-media-driver/libva enable QSV / VAAPI on Intel iGPUs.
# NVENC requires the proprietary NVIDIA Container Toolkit on the host —
# no extra packages needed inside the image, only --gpus all on docker run.
RUN apk add --no-cache \
ffmpeg \
intel-media-driver \
libva-utils \
mesa-va-gallium \
tzdata \
ca-certificates \
wget \
su-exec \
&& rm -rf /var/cache/apk/*
# Non-root user for the long-running process.
RUN addgroup -S mediastation && adduser -S mediastation -G mediastation
WORKDIR /app
COPY --from=backend /app/mediastation-go /usr/local/bin/mediastation-go
COPY --from=frontend /app/web/dist /app/web/dist
RUN mkdir -p /data /cache /media \
&& chown -R mediastation:mediastation /data /cache /media
# Default environment (overridable via docker-compose / `docker run -e`).
ENV MEDIASTATION_APP_PORT=8080 \
MEDIASTATION_APP_DATA_DIR=/data \
MEDIASTATION_APP_WEB_DIR=/app/web/dist \
MEDIASTATION_DATABASE_DB_PATH=/data/mediastation.db \
MEDIASTATION_CACHE_CACHE_DIR=/cache \
MEDIASTATION_LOGGING_LEVEL=info \
TZ=Asia/Shanghai
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD wget -q --spider http://127.0.0.1:8080/api/health || exit 1
# Tiny entrypoint that lets us swap to a different UID/GID via PUID/PGID
# (handy on NAS deployments where bind-mounted volumes belong to a non-root
# user). When PUID == 0 we skip su-exec entirely and run as root.
RUN printf '#!/bin/sh\n\
PUID=${PUID:-$(id -u mediastation)}\n\
PGID=${PGID:-$(id -g mediastation)}\n\
if [ "$PUID" != "$(id -u mediastation)" ] || [ "$PGID" != "$(id -g mediastation)" ]; then\n\
deluser mediastation 2>/dev/null || true\n\
delgroup mediastation 2>/dev/null || true\n\
addgroup -g "$PGID" -S mediastation\n\
adduser -u "$PUID" -G mediastation -S mediastation\n\
fi\n\
chown -R mediastation:mediastation /data /cache 2>/dev/null || true\n\
chown mediastation:mediastation /media 2>/dev/null || true\n\
if [ "$PUID" = "0" ]; then\n\
exec mediastation-go\n\
fi\n\
exec su-exec mediastation mediastation-go\n' > /entrypoint.sh \
&& chmod +x /entrypoint.sh
CMD ["/entrypoint.sh"]