diff --git a/Dockerfile b/Dockerfile index 9f10120..dba10d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,28 @@ -# Stage 1: Build Image (Frontend) -FROM node:20-alpine AS frontend-builder +# Stage 1: Build Frontend +FROM --platform=linux/amd64 node:20-alpine AS frontend-builder WORKDIR /app/frontend COPY frontend-react/package*.json ./ RUN npm install COPY frontend-react/ . RUN npm run build -# Stage 2: Build Image (Backend) -FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS backend-builder +# Stage 2: Build Backend for linux/amd64 +FROM --platform=linux/amd64 golang:1.24-alpine AS backend-builder WORKDIR /app/backend -ARG TARGETOS TARGETARCH - COPY backend/go.mod backend/go.sum ./ RUN go mod download COPY backend/ . # Build static binary for Linux amd64 -RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-w -s" -o server cmd/server/main.go +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server cmd/server/main.go -# Stage 3: Final Image -FROM alpine:latest +# Stage 3: Final Image (linux/amd64 only for Synology NAS) +FROM --platform=linux/amd64 alpine:latest WORKDIR /app # Install runtime dependencies -RUN apk add --no-cache sqlite ca-certificates tzdata python3 py3-pip -RUN pip3 install --break-system-packages --ignore-installed yt-dlp || true +RUN apk add --no-cache sqlite ca-certificates tzdata # Copy backend binary COPY --from=backend-builder /app/backend/server . @@ -33,14 +30,13 @@ COPY --from=backend-builder /app/backend/server . # Copy frontend build to the expected static directory COPY --from=frontend-builder /app/frontend/dist ./dist - - -# Create data directory -RUN mkdir -p data +# Create data directory for SQLite database +RUN mkdir -p /app/data # Environment variables ENV PORT=8000 ENV DATABASE_URL=/app/data/streamflow.db +ENV TZ=Asia/Ho_Chi_Minh # Expose port EXPOSE 8000 diff --git a/README.md b/README.md index e308826..9637cf4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# kv-netflix V4 +# kv-netflix V6 A high-performance video streaming web application with a pure Go backend and modern React + Tailwind frontend. @@ -10,6 +10,7 @@ A high-performance video streaming web application with a pure Go backend and mo - **HLS Streaming** - Native HLS playback with proxy support - **Android TV** - Native TV app with D-pad controls and 10s skip - **PWA Support** - Install as a progressive web app +- **Episode Progress Tracking** - Auto-save progress, continue watching with seek - **Docker Ready** - Multi-stage build for Synology NAS (linux/amd64) ## Tech Stack @@ -23,21 +24,45 @@ A high-performance video streaming web application with a pure Go backend and mo ## Quick Start -### Docker (Recommended) +### Docker (Recommended for Synology NAS) +**Prerequisites:** +- Synology NAS with Container Manager (Docker) installed +- SSH access enabled (optional, for CLI) or use Container Manager GUI + +**Option 1: Container Manager GUI (Recommended for Synology)** + +1. Open **Container Manager** on your Synology NAS +2. Go to **Registry** tab and add your Forgejo registry: + - Registry URL: `git.khoavo.myds.me` + - Username: `vndangkhoa` + - Password: `Thieugia19` +3. Search for `vndangkhoa/kv-netflix` and download `v6` tag +4. Create a new container: + - **Image**: `git.khoavo.myds.me/vndangkhoa/kv-netflix:v6` + - **Container name**: `streamflow` + - **Network**: Bridge mode, map port `3478` (local) → `8000` (container) + - **Environment**: Add `TZ=Asia/Ho_Chi_Minh` + - **Volume**: Create folder `docker/streamflow/data` on NAS, map to `/app/data` + - **Restart policy**: `Unless stopped` +5. Start the container + +**Option 2: Docker Compose (SSH/CLI)** + +Create `docker-compose.yml` on your NAS: ```yaml -# docker-compose.yml version: '3.8' services: streamflow: - image: git.khoavo.myds.me/vndangkhoa/kv-netflix:v4 + image: git.khoavo.myds.me/vndangkhoa/kv-netflix:v6 container_name: streamflow platform: linux/amd64 ports: - "3478:8000" environment: - DATABASE_URL=/app/data/streamflow.db + - PORT=8000 - TZ=Asia/Ho_Chi_Minh volumes: - ./data:/app/data @@ -51,7 +76,14 @@ services: ``` ```bash +# Login to registry first +docker login git.khoavo.myds.me -u vndangkhoa -p Thieugia19 + +# Start container docker-compose up -d + +# Check logs +docker-compose logs -f ``` Access at: `http://YOUR_NAS_IP:3478` @@ -119,7 +151,17 @@ Streamflow/ ## Changelog -### v4 (Current) +### v6 (Current) +- Episode progress tracking with auto-save (every 5s + on pause) +- Continue Watching section with progress bars +- Seek to saved position minus 20 seconds on return +- Fixed ophim image URLs (migrated to img.ophim.live) +- Removed broken wsrv.nl proxy dependency +- Episode badge and progress bar in MovieCard +- Pushed to Forgejo: `git.khoavo.myds.me/vndangkhoa/kv-netflix:v6` +- Docker multi-stage build optimized for Synology NAS (linux/amd64) + +### v4 - Deployed v4 to Forgejo and Docker Registry - Refactored frontend and cleaned up repository diff --git a/docker-compose.yml b/docker-compose.yml index 9bbfb65..29e583d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.8' services: streamflow: - image: git.khoavo.myds.me/vndangkhoa/kv-netflix:v4 + image: git.khoavo.myds.me/vndangkhoa/kv-netflix:v6 container_name: streamflow platform: linux/amd64 ports: @@ -12,10 +12,11 @@ services: - PORT=8000 - TZ=Asia/Ho_Chi_Minh volumes: + # Synology: Use relative path for data persistence - ./data:/app/data restart: unless-stopped healthcheck: - test: [ "CMD", "wget", "-q", "--spider", "http://localhost:8000/api/health" ] + test: ["CMD", "wget", "-q", "--spider", "http://localhost:8000/api/health"] interval: 30s timeout: 10s retries: 3 diff --git a/frontend-react/src/components/Hero.tsx b/frontend-react/src/components/Hero.tsx index 766f4cb..25406b6 100644 --- a/frontend-react/src/components/Hero.tsx +++ b/frontend-react/src/components/Hero.tsx @@ -32,7 +32,7 @@ export const Hero = ({ movies, variant = 'default' }: HeroProps) => { }; // Helper to generate robust image URLs - const getImageUrl = (url: string | undefined, width: number, blur: number = 0) => { + const getImageUrl = (url: string | undefined) => { if (!url) return ''; let cleanUrl = url; if (url.startsWith('//')) { @@ -52,12 +52,12 @@ export const Hero = ({ movies, variant = 'default' }: HeroProps) => {