{"id":48540357,"url":"https://github.com/derekshreds/snacks","last_synced_at":"2026-04-10T04:20:09.319Z","repository":{"id":186664588,"uuid":"675538344","full_name":"derekshreds/Snacks","owner":"derekshreds","description":"Highly efficient automated video library encoder","archived":false,"fork":false,"pushed_at":"2026-04-08T02:54:48.000Z","size":1134,"stargazers_count":14,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-04-08T03:28:17.655Z","etag":null,"topics":["decoding","encoding","transcoding","video","video-processing"],"latest_commit_sha":null,"homepage":"https://snacksvideo.com","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/derekshreds.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-08-07T06:46:20.000Z","updated_at":"2026-04-08T02:52:44.000Z","dependencies_parsed_at":"2023-11-21T01:42:23.906Z","dependency_job_id":"8706644a-ca49-4d3a-a12c-b130850e032f","html_url":"https://github.com/derekshreds/Snacks","commit_stats":null,"previous_names":["derekshreds/snacks"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/derekshreds/Snacks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekshreds%2FSnacks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekshreds%2FSnacks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekshreds%2FSnacks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekshreds%2FSnacks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/derekshreds","download_url":"https://codeload.github.com/derekshreds/Snacks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekshreds%2FSnacks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31539230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decoding","encoding","transcoding","video","video-processing"],"created_at":"2026-04-08T04:02:26.991Z","updated_at":"2026-04-10T04:20:09.302Z","avatar_url":"https://github.com/derekshreds.png","language":"C#","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"snacks.ico\" alt=\"Snacks\" width=\"80\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eSnacks\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003cstrong\u003eAutomated Video Library Encoder\u003c/strong\u003e\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  Batch transcode your entire video library with hardware acceleration.\u003cbr\u003e\n  Runs on your NAS via Docker or locally on Windows as a desktop app.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/version-2.2.3-8b5cf6?style=flat-square\" alt=\"Version\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/.NET-10.0-512bd4?style=flat-square\" alt=\".NET 10\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Electron-41-47848f?style=flat-square\" alt=\"Electron\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-green?style=flat-square\" alt=\"License\"\u003e\n\u003c/p\u003e\n\n---\n\n## Features\n\n- **Hardware accelerated encoding** -- NVIDIA NVENC, Intel QSV/VAAPI, AMD AMF/VAAPI\n- **H.265, H.264, and AV1** -- encode to any modern codec with hardware or software\n- **Smart filtering** -- skips files that already meet your quality targets\n- **Persistent database** -- SQLite tracks all files across restarts, no re-scanning needed\n- **Retry with fallback** -- strips subtitles, tries software decode + HW encode, then full software\n- **Real-time progress** -- live encoding progress via SignalR WebSockets\n- **Batch processing** -- process individual files, folders, or entire libraries\n- **NAS-friendly** -- designed for QNAP, Synology, and other Docker-capable NAS devices\n- **Desktop app** -- native Windows installer with local GPU support\n- **Automatic scanning** -- watch directories for automatic re-scanning on a configurable interval\n- **4K controls** -- configurable bitrate multiplier or skip 4K content entirely\n- **Per-file logging** -- every encode writes a log file to disk, viewable in the app or on the NAS\n- **Stop vs Cancel** -- stop an encode for later, or cancel it permanently\n- **Change detection** -- replaced files are automatically detected and re-queued\n- **Transfer-safe scanning** -- files modified within the last 30 minutes are skipped to avoid mid-transfer processing\n- **Settings backup** -- atomic writes with `.bak` fallback for crash resilience\n- **Distributed encoding** -- cluster multiple Snacks instances to distribute encoding across your network\n- **Automatic node discovery** -- nodes find each other automatically, no manual IP configuration needed\n- **Dark mode UI** -- clean, responsive interface that works on desktop, tablet, and mobile\n\n---\n\n## Installation\n\n### Option 1: QNAP / Synology NAS (Docker)\n\nSnacks runs as a Docker container with your video library mounted as a volume.\n\n**1. Pull the image:**\n\n```bash\ndocker pull derekshreds/snacks-docker:latest\n```\n\n**2. Create the application** in Container Station (QNAP) or Docker (Synology) using this compose config:\n\n```yaml\nservices:\n  snacks:\n    image: derekshreds/snacks-docker:latest\n    container_name: snacks\n    ## Host networking required for cluster UDP broadcast discovery to reach the LAN.\n    ## Bridge mode only forwards unicast traffic, so broadcasts never arrive.\n    network_mode: host\n    volumes:\n      ## CHANGE THIS to your actual media folder on the NAS\n      - /share/Public/Media:/app/work/uploads\n      ## Transcoding logs\n      - /share/CACHEDEV1_DATA/snacks/logs:/app/work/logs\n      ## Persist settings and database across container updates\n      - /share/CACHEDEV1_DATA/snacks/config:/app/work/config\n    environment:\n      - ASPNETCORE_ENVIRONMENT=Production\n      - SNACKS_WORK_DIR=/app/work\n      - FFMPEG_PATH=/usr/lib/jellyfin-ffmpeg/ffmpeg\n      - FFPROBE_PATH=/usr/lib/jellyfin-ffmpeg/ffprobe\n      ## VAAPI driver — auto-detection tries iHD then i965. Override here if needed:\n      #- LIBVA_DRIVER_NAME=iHD\n    devices:\n      ## Intel QSV hardware acceleration (TS-453E J6412)\n      - /dev/dri:/dev/dri\n    ## QNAP lacks standard video/render groups — privileged grants /dev/dri access\n    privileged: true\n    restart: unless-stopped\n    healthcheck:\n      test: [\"CMD\", \"curl\", \"-f\", \"http://localhost:6767/Home/Health\"]\n      interval: 30s\n      timeout: 10s\n      retries: 3\n      start_period: 40s\n```\n\n**3. Update the volume path** to point to your actual media library:\n\n| NAS | Typical Path |\n|-----|-------------|\n| QNAP | `/share/CACHEDEV1_DATA/Multimedia` or `/share/Public/Media` |\n| Synology | `/volume1/video` or `/volume1/Media` |\n\n**4. Access Snacks** at `http://YOUR-NAS-IP:6767`\n\n---\n\n### Option 2: Windows Desktop App\n\nSnacks can run as a standalone desktop app with native GPU acceleration.\n\n**Prerequisites:**\n- Windows 10/11\n- A supported GPU (NVIDIA, Intel, or AMD) with up-to-date drivers\n- [FFmpeg](https://www.gyan.dev/ffmpeg/builds/) (`ffmpeg-release-full` build)\n\n**Building from source:**\n\n1. Clone the repository\n2. Download FFmpeg from [gyan.dev](https://www.gyan.dev/ffmpeg/builds/) (release full build)\n3. Place `ffmpeg.exe` and `ffprobe.exe` in `electron-app/ffmpeg/`\n4. Run `build-installer.bat`\n5. Install from `electron-app/dist/Snacks Setup 2.2.3.exe`\n\n**For development:**\n\n```cmd\nrun-electron-dev.bat\n```\n\nThis publishes the backend and launches Snacks in dev mode without creating an installer.\n\n---\n\n## Usage\n\n### Browse \u0026 Select\n\nClick **Browse Library** to open the file browser.\n\n- **NAS mode** -- browse within your mounted media directory\n- **Desktop mode** -- browse any drive or folder on your PC\n\nNavigate into folders, view video files, and choose what to process:\n\n- **Process This Folder** -- encode only files in the current folder\n- **Process Folder + Subfolders** -- encode everything recursively\n- **Select individual files** -- check specific files to process\n\n### Configure\n\nClick the **gear icon** to open encoding settings:\n\n| Setting | Description |\n|---------|-------------|\n| Output Format | MKV (default) or MP4 |\n| Video Codec | H.265/HEVC, H.264/AVC, or AV1 |\n| Hardware Acceleration | Auto Detect, Intel QSV, AMD VAAPI, NVIDIA NVENC, or None |\n| Target Bitrate | Default 3500 kbps -- files above this get compressed |\n| 4K Bitrate Multiplier | 2x--8x multiplier for 4K content (default 4x) |\n| Skip 4K Videos | Leave 4K content untouched |\n| English Only Audio | Remove non-English audio tracks |\n| English Only Subtitles | Keep only English subtitle tracks |\n| Remove Black Borders | Auto-detect and crop letterboxing |\n| Output Directory | Where encoded files are saved (blank = same as original) |\n| Replace Original Files | Delete original and move encoded file to its location |\n| Retry on Failure | Fall back to software encoding if hardware fails |\n\n### Automatic Scanning\n\nSnacks can watch directories and automatically re-scan them on a configurable interval.\n\n- Open the **Settings** panel and enable **Auto Scan**\n- Set the scan interval (how often Snacks checks for new or changed files)\n- Add directories to the watch list using the **Watch This Folder** button in the directory browser\n- Snacks tracks all file states in a SQLite database so previously processed files are never re-scanned\n- Failed files are tracked with failure counts and won't be endlessly retried\n- Files modified within the last 30 minutes are skipped to avoid processing mid-transfer\n- If a file is replaced with a significantly different version (\u003e10% size change), it's automatically re-queued\n- Partial `[snacks]` files from interrupted encodes are detected, deleted, and the original is re-queued\n\nSettings are saved server-side in `settings.json` (with automatic `.bak` backup) and persist across container restarts and devices.\n\n### Distributed Encoding (Cluster)\n\nSnacks can distribute encoding work across multiple machines on your network.\n\n- Open the **Settings** panel and enable **Cluster Mode**\n- Set a **shared secret** that all nodes will use to authenticate with each other\n- Nodes on the local network discover each other automatically\n- One instance acts as the **coordinator**, assigning jobs to available **worker nodes**\n- Source files are transferred to workers before encoding and results are transferred back on completion\n- If a worker goes offline mid-encode, the job is automatically reassigned to another node\n- Job state transitions (queued, assigned, transferring, encoding, completed, failed) are tracked in the database\n- The cluster status panel shows discovered nodes with health indicators and active jobs\n\n### Monitor\n\nThe main dashboard shows:\n- **Now Processing** -- current file with live progress bar (always visible regardless of page)\n- **Queue** -- upcoming files sorted by bitrate (highest first), with filter tabs for All, Pending, Completed, and Failed\n- **Stats** -- pending, processing, completed, and failed counts\n- **Pagination** -- first/prev/next/last page navigation\n\nClick the terminal icon on any item to view detailed FFmpeg logs -- logs are persisted to disk and viewable even after a restart.\n\n### Queue Management\n\n- **Stop (Encode Later)** -- removes an item from the queue with a yellow \"Stopped\" badge. It will be re-queued on the next auto-scan.\n- **Cancel (Don't Reprocess)** -- permanently cancels an item. It will not be re-queued unless you manually select it again.\n- **Process Selected override** -- explicitly selecting a file in the browser always queues it, regardless of its database status (failed, cancelled, completed).\n- **Pause/Resume** -- pause state is saved across restarts. If the queue was paused when the container stopped, it stays paused.\n\n### Logs\n\n- Every encode writes a log file to the `logs` directory (e.g., `The Matrix (1999)_a3f2b1c4.log`)\n- Logs are viewable in the app by clicking the terminal icon on any queue item\n- On NAS deployments, logs are accessible via the mounted logs volume\n\n---\n\n## How It Works\n\n1. **Scan** -- Snacks probes each file with FFprobe to determine codec, bitrate, and resolution\n2. **Filter** -- Files already meeting your quality targets are skipped automatically\n3. **Encode** -- FFmpeg encodes with hardware acceleration when available, falling back to software\n4. **Validate** -- Output is verified by comparing duration to the original\n5. **Retry** -- On failure, retries without subtitles, then software decode + HW encode, then full software\n6. **Clean up** -- Original files are never modified; encoded files get a `[snacks]` tag\n\n### File Naming\n\n- Encoded files are saved as `Movie Name [snacks].mkv` alongside the original (or in the output directory if configured)\n- If **Replace Original Files** is enabled, the original is deleted and the encoded file is moved to the original's location without the `[snacks]` tag\n- Original files are never modified during encoding\n\n### Smart Filtering\n\nFiles are automatically skipped if they already meet requirements:\n\n- Already target codec and below target bitrate (1080p: 1.2x target, 4K: configurable multiplier)\n- Already encoded (filename contains `[snacks]`)\n\n---\n\n## Hardware Acceleration\n\n### Supported Platforms\n\n| Platform | NAS (Docker) | Desktop (Windows) |\n|----------|:---:|:---:|\n| NVIDIA NVENC | CUDA | CUDA |\n| Intel | VAAPI (CQP) | QSV (VBR) |\n| AMD | VAAPI (CQP) | AMF (VBR) |\n| Software (x265/SVT-AV1) | Always available | Always available |\n\n### NAS Notes\n\n- **QNAP TS-453E (J6412)**: Uses VAAPI with CQP rate control. VBR is not supported on Elkhart Lake.\n- **Software decode fallback**: Codecs that VAAPI can't decode (e.g., AV1 on older Intel hardware) are automatically decoded in software while still using VAAPI for hardware encoding.\n- The container uses [jellyfin-ffmpeg](https://github.com/jellyfin/jellyfin-ffmpeg) which includes full VAAPI/QSV support.\n- `privileged: true` is required on QNAP for `/dev/dri` access.\n- Hardware detection runs automatically on first encode and caches the result.\n\n### Desktop Notes\n\n- NVIDIA GPUs use NVENC with VBR for precise bitrate control.\n- Intel/AMD use QSV/AMF respectively with proper bitrate targeting.\n- Auto-detect tests each encoder at startup and picks the best available.\n\n---\n\n## Troubleshooting\n\n**No directories in browser (NAS)**\n```bash\ndocker exec snacks ls -la /app/work/uploads/\n```\nVerify your volume mount points to a directory with video files.\n\n**Hardware acceleration not detected**\n```bash\n# Check GPU access inside the container\ndocker exec snacks vainfo\ndocker exec snacks ls -la /dev/dri/\n```\n\n**Encoding produces larger files (NAS/VAAPI)**\n\nVAAPI CQP mode doesn't have precise bitrate control. The quality parameter is automatically scaled based on the target, but results vary by content. Files that end up larger than the original are automatically discarded.\n\n**Progress bar not updating**\n\nCheck that the backend is running and SignalR is connected (green dot in the navbar). Progress updates are throttled to every 2 seconds.\n\n---\n\n## Project Structure\n\n```\nSnacks/\n  Snacks/                 ASP.NET Core 10.0 backend + web UI\n    Controllers/           API endpoints\n    Services/              Transcoding, file handling, FFprobe, AutoScan, cluster services\n    Data/                  SQLite database context, migrations, repository\n    Models/                WorkItem, MediaFile, EncoderOptions, ClusterConfig, JobAssignment\n    Hubs/                  SignalR real-time communication\n    Views/                 Razor pages\n    wwwroot/               Static assets (JS, CSS, fonts)\n  release-notes/          Per-version release notes\n  electron-app/           Electron desktop wrapper\n    main.js               Electron main process\n    backend/              Published .NET backend (gitignored)\n    ffmpeg/               Bundled FFmpeg binaries (gitignored)\n  docker-compose.gpu.yml  GPU overlay for Linux NAS (VAAPI/QSV)\n  build-and-export.bat    Build \u0026 push Docker image\n  build-installer.bat     Build Windows installer\n  build-electron.bat      Build Electron app\n  run-electron-dev.bat    Run desktop app in dev mode\n  deploy-compose.yml      Docker Compose for NAS deployment\n  start-snacks.bat     Start backend (Windows)\n  start-snacks.sh      Start backend (Linux/Docker)\n```\n\n---\n\n## Building\n\n### Docker Image (for NAS)\n\n```cmd\nbuild-and-export.bat\n```\n\nBuilds the Docker image and pushes to Docker Hub as both `derekshreds/snacks-docker:latest` and `derekshreds/snacksweb:latest`.\n\n### Windows Installer\n\n```cmd\nbuild-installer.bat\n```\n\nCreates a self-contained Windows installer at `electron-app/dist/` with the .NET runtime, FFmpeg, and desktop shortcuts bundled.\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eSnacks\u003c/strong\u003e v2.2.3 \u0026copy; 2026 Derek Morris\n\u003c/p\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderekshreds%2Fsnacks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fderekshreds%2Fsnacks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderekshreds%2Fsnacks/lists"}