ShukeBta 91df7521ce fix: 资源占用/登录稳定性/QB整理入库/第三方播放404 综合修复
资源占用(Docker 部署 CPU/内存长期居高):
- 云盘探测预算改为按尝试扣减,杜绝队列满时对每个文件反复入队
  并刷出数万条 WARN(实测日志 41165 条)
- 探测队列满时给文件挂 30 分钟退避 + 告警限速为每分钟一条
- 扫描时每个文件的海报/背景图由同步下载(单张最长 20s)改为
  后台预取队列,云盘大库扫描不再串行拉图数小时
- PlaybackInfo 的云盘 ffprobe 探测改异步(原同步最长 8s,
  既拖慢起播又放大云盘流量),带单飞去重
- 访问日志跳过 /api/health 与静态资源;logging.level/format
  配置真正生效(此前是死配置)

登录稳定性(经常登录报错):
- refresh token 未及时落库期间,刷新请求可识别「待落库令牌」,
  不再把用户踢回登录页;轮换/登出后取消后台补写,防止旧令牌复活

QB 下载整理入库:
- 新增 download.path_mappings 设置:自定义下载器→本程序路径映射
  (每行 客户端路径=本地路径),并复用 compose 环境变量映射规则
- 应用重启后补整理最近 24h 内完成的种子(此前重启即永久漏掉)
- 下载客户端初始化失败仍注册并惰性重连(容器启动顺序免疫)
- 硬链接跨文件系统(EXDEV)自动降级为复制,保种语义不变

第三方播放器 404:
- 播放处理器不再把所有错误吞成 404:媒体不存在→404,
  云盘解析失败/STRM 关闭→502+原因
- 存库的云盘播放 URL 规范化为相对路径,免疫扫描时固化的旧 host
- 云盘媒体 SupportsDirectPlay=false,强制走带鉴权的 DirectStream
2026-06-12 04:31:34 +00:00
2026-06-11 18:57:02 +08:00

MediaStationGo

MediaStationGo Logo

A lightweight, polished, NAS-friendly private media center

Go single-binary backend · React frontend · Docker-first deployment · Emby-compatible APIs · Multi-source metadata · PT subscriptions

中文 · Quick Start · Docker Deploy · Screenshots · Live Demo

Go React TypeScript Docker License Use


✨ Overview

MediaStationGo is an open-source media center for personal libraries, family NAS setups, and home-theater enthusiasts. It combines library management, metadata scraping, web playback, third-party client compatibility, PT site search, subscription-based downloads, and AI-assisted recommendations into one lightweight Go service with a polished React interface.

It is designed for users who want to:

  • Manage movies, TV shows, anime, variety shows, adult content, and music from one place.
  • Prefer local NFO/images first, then enrich missing metadata from TMDb, Douban, Bangumi, TheTVDB, Fanart, JavBus, and JavDB.
  • Search PT sites, subscribe to resources, enqueue downloads, and organize completed files from one panel.
  • Connect external clients such as Infuse, VidHub, SenPlayer, and other Emby/Jellyfin-compatible apps.
  • Deploy easily on NAS, Windows, Linux, macOS, or Docker without leaking private tracker tokens to the frontend.

The project is under active development. For production use, pin a release image tag and back up /data regularly.


🌱 Open Source Promise

MediaStationGo follows a fully open-source path. The core media library, metadata scraping, playback, subscriptions, downloads, external-client compatibility, and operations features are developed in this repository. The project learns from excellent open-source projects such as MoviePilot in areas like site aggregation, subscription downloads, post-download organization, and Emby/Jellyfin client compatibility, while keeping MediaStationGo as an independent implementation and avoiding incompatible code reuse.

The current base license is GPL-3.0, and contributions are welcome under that license: site adapters, scraping rules, UI improvements, documentation, and bug fixes all help the project grow. The maintainers also state the intended usage boundary: MediaStationGo is provided for personal learning, home NAS, self-hosted media, and non-commercial scenarios. Without explicit written permission from the author, do not use this project or derivative versions for commercial resale, paid hosting, paid SaaS, pre-installed commercial devices, closed-source redistribution, or other profit-oriented commercial use.

Note: GPL-3.0 is a free software license, and the formal grant is defined by the repository LICENSE file. The non-commercial commitment above expresses the maintainer's intended usage boundary and commercial cooperation requirements. For commercial cooperation, enterprise deployment, or redistribution, contact the author for additional authorization first.

Source Availability and Docker Support Boundary

  • The public repository currently uses GPL-3.0 as its base license. If a component is GPL-derived, distributing it only as a Docker image does not remove the corresponding source-distribution obligations.
  • The project can still define its official support scope as Docker-first / Docker-only support: Docker Compose, GHCR images, and container deployment docs are maintained as the supported path, while bare-metal binaries can be community/best-effort.
  • If some future functionality needs to be closed-source, keep it as a separate plugin, private service, or independently implemented module whose license boundary is clean. GPL-covered code should remain available under GPL terms.
  • The README non-commercial statement describes the maintainer's intended usage boundary and commercial authorization requirement; the formal code license remains governed by LICENSE.

🚀 Live Demo

The demo is for feature preview only. Do not store private API keys, tracker tokens, or personal media information there.


🧭 Feature Overview

Area Capabilities
Libraries Movies, TV, anime, variety, music, adult content; folder covers, series, seasons, and episodes
Scanning Recursive scanning, ffprobe probing, filename parsing, season/episode recognition, duplicate prevention
Local metadata NFO, poster, fanart, season poster, episode image, local adult artwork first
Online metadata TMDb, TheTVDB, Bangumi, Douban, Fanart.tv, JavBus/JavDB page scraping
Playback Direct streaming, HTTP Range seeking, HLS transcoding, external subtitles, progress, resume, external players
Discovery TMDb / Douban / Bangumi recommendation rails and subscription entry points
PT sites Site management, M-Team API token, cross-site search, download URL resolution
Subscriptions RSS/search subscriptions, resolution/quality/effects/release-group rules, wash toggle and priorities
Downloads qBittorrent task cards, status, speed, progress, uploaded/downloaded size, private URL redaction
Compatibility Emby-style APIs for Infuse, VidHub, SenPlayer, and similar clients
Operations Runtime status, task queue, duplicate files, recycle bin, file manager, storage settings, notifications
AI OpenAI-compatible API settings, AI search, recommendations, and operations assistant

🖼️ Screenshots

Screenshots below were captured from a running local instance. Personal media, local paths, accounts, API keys, tokens, and secrets have been visually redacted.

Core Experience
Login & Home Library Overview
Login Home
Libraries Library Detail
Libraries Library Detail
Poster Wall Media Detail
Poster Wall Media Detail
Player Discover
Player Discover
Smart Search DLNA Cast
Smart Search DLNA
Personal Space & Playback
AI Assistant Favorites
AI Assistant Favorites
Playlists Watch History
Playlists Watch History
Profile Downloads
Profile Downloads
Downloads, Subscriptions & Sites
Download Clients Subscriptions
Download Clients Subscriptions
Site Search Sites & Downloaders
Site Search Sites
Administration & Operations
Media & Users Tools
Admin Tools
Storage & Files Runtime Status
Storage Stats
Settings Tasks
Settings Tasks
Duplicates Recycle Bin
Duplicates Recycle Bin
Scheduler File Manager
Scheduler Files
STRM Storage Config
STRM Storage Config
Notifications Operations Assistant
Notifications Operations Assistant

🧱 Tech Stack

Layer Technology Notes
Backend Go 1.25+ Single-binary deployment, low resource usage
Web framework Gin REST APIs, auth middleware, static file serving
Database SQLite + GORM Simple backup and migration for personal/NAS usage
Frontend React 18 + TypeScript Typed component-based UI
Build tool Vite Fast frontend development and production builds
Styling Tailwind CSS Unified bright visual system and responsive layout
State Zustand Lightweight auth and permission state
Playback HTML5 Video / HLS / FFmpeg Direct play, Range seek, HLS transcoding, subtitles
Metadata TMDb / Douban / Bangumi / TheTVDB / Fanart / JavBus / JavDB Posters, backdrops, descriptions, ratings, episode metadata
Downloads qBittorrent / PT site adapters Search, subscriptions, task cards, private URL redaction
Compatibility Emby-style API / DLNA External clients and player integrations
Deployment Docker / Docker Compose / Shell / PowerShell NAS, Linux, Windows, and macOS friendly
CI/CD GitHub Actions / GHCR Version tags or manual Actions runs publish multi-arch Docker images and release packages

📦 Quick Start

The recommended beginner path is now editing real paths directly in docker-compose.yml. This is easier for new NAS, VPS, and Docker users because the host paths are visible in one file.

1. Create a deployment directory

mkdir -p ~/MediaStationGo
cd ~/MediaStationGo
mkdir -p data cache media downloads

2. Download compose

curl -fsSL https://raw.githubusercontent.com/ShukeBta/MediaStationGo/main/docker-compose.yml -o docker-compose.yml

If GitHub Raw is slow, create docker-compose.yml manually and paste the template from the repository root.

3. Edit real host paths

Open the compose file:

vi docker-compose.yml

Find the media and download volume lines, then replace the left side with your real NAS/server paths:

    volumes:
      - ./data:/data
      - ./cache:/cache
      - /vol1/1000/Docker/moviepilot-v2/media:/media:ro
      - /vol1/1000/qBittorrent/downloads:/downloads

Then find the path mapping variables under environment and write the same real paths there:

    environment:
      MEDIASTATION_MEDIA_DIR: /vol1/1000/Docker/moviepilot-v2/media
      MEDIASTATION_MEDIA_CONTAINER_DIR: /media
      MEDIASTATION_DOWNLOAD_DIR: /vol1/1000/qBittorrent/downloads
      MEDIASTATION_DOWNLOAD_CONTAINER_DIR: /downloads
Location Meaning
Media volume left side Real host/NAS media directory, e.g. /volume1/media, /mnt/media, /vol1/1000/Docker/moviepilot-v2/media
Download volume left side Real host/NAS download directory, e.g. /volume1/downloads, /mnt/downloads, /vol1/1000/qBittorrent/downloads
MEDIASTATION_MEDIA_DIR Must match the media volume left side
MEDIASTATION_DOWNLOAD_DIR Must match the download volume left side

Do not write NAS absolute paths as ./vol1/.... A leading ./ means a directory under the current compose project.

4. Start

docker compose pull
docker compose up -d

If your system only has the legacy command:

docker-compose pull
docker-compose up -d

5. Open the app

http://<server-ip>:18080

Default account:

admin / admin123

Change the admin password immediately after first login.

6. Paths inside the web UI

The simple compose maps host directories to stable container paths:

Host directory Container path Use in the web UI
MEDIASTATION_MEDIA_DIR /media /media/Movies, /media/TV, /media/TV/CDrama
MEDIASTATION_DOWNLOAD_DIR /downloads Downloader save root: /downloads

This is a Docker bind mount. It does not copy files and does not consume double disk space.

7. Update

Use the update helper to pull the new image and remove old MediaStationGo image layers:

curl -fsSL https://cdn.jsdelivr.net/gh/ShukeBta/MediaStationGo@main/scripts/docker-compose-update.sh -o docker-compose-update.sh
chmod +x docker-compose-update.sh
./docker-compose-update.sh

Advanced options

The default compose intentionally stays small. If you need the container to expose the same raw host paths, Telegram proxy variables, hardware acceleration, or additional transcoding options, see:

docker-compose.advanced.yml

Optional: Use .env for Paths

If you already know Docker Compose well, or if you reuse the same compose file across multiple machines, you can put paths in .env. This is optional, not the beginner path:

cat > .env <<'EOF'
MEDIASTATION_MEDIA_DIR=/vol1/1000/Docker/moviepilot-v2/media
MEDIASTATION_DOWNLOAD_DIR=/vol1/1000/qBittorrent/downloads
MEDIASTATION_HTTP_PORT=18080
TZ=Asia/Shanghai
PUID=1000
PGID=1000
EOF

When using .env, keep the default variable-style volume lines in docker-compose.yml:

- ${MEDIASTATION_MEDIA_DIR:-./media}:/media:ro
- ${MEDIASTATION_DOWNLOAD_DIR:-./downloads}:/downloads

Fixed Version Deployment

For production, pin a release tag so latest does not change unexpectedly. Without .env, edit the image line directly:

image: ghcr.io/shukebta/mediastation-go:MediaStationGo-v0.0.32

If you use .env, you can also set:

MEDIASTATION_IMAGE_TAG=MediaStationGo-v0.0.32

Then run:

docker compose pull
docker compose up -d

External Network and v2rayA

If your NAS already uses v2rayA redirect / transparent proxy with routing rules, MediaStationGo usually does not need extra HTTP_PROXY / HTTPS_PROXY variables.

Avoid stacking proxy variables in .env, docker-compose.yml, or the Docker daemon unless you intentionally use an application-level proxy. Stacked proxies can break GHCR pulls and site APIs.

qBittorrent URL

If qBittorrent runs on the same NAS/host, do not use 127.0.0.1 from inside MediaStationGo. Use:

http://host.docker.internal:8085

If qBittorrent also runs in Docker, mount the same host download directory as /downloads in both containers. Use /downloads as the subscription save root.

With smart classification enabled, downloads are saved to folders such as /downloads/动画电影, /downloads/国产剧, and /downloads/综艺.

Cloud Drives, OpenList, and CloudDrive2

MediaStationGo supports OpenList, Alist, WebDAV, 115, Quark, and CloudDrive2 as external storage backends. For most users, OpenList, CloudDrive2, or Alist is the recommended bridge layer: they can integrate many cloud drives such as 115, 123Pan, Aliyun Drive, and Quark, while MediaStationGo can use OpenList/Alist APIs or WebDAV endpoints for browsing, library mounting, local-media upload, and authenticated proxy playback.

Typical OpenList setup:

  1. Mount your 115 / 123Pan / Aliyun / Quark drive inside OpenList.
  2. Select OpenList in MediaStationGo → External Storage.
  3. Set OpenList Server URL to the management/API endpoint, for example http://NAS-IP:5244.
  4. Set WebDAV URL to the WebDAV endpoint, for example http://NAS-IP:5244/dav/.
  5. Do not use https:// unless OpenList is actually behind an HTTPS reverse proxy. Propfind "https://...": http: server gave HTTP response to HTTPS client means an HTTP service was entered as HTTPS.

Typical CloudDrive2 setup:

  1. Mount your 115 / 123Pan / Aliyun / Quark drive inside CloudDrive2.
  2. Select CloudDrive2 in MediaStationGo → External Storage.
  3. Fill the CloudDrive2 WebDAV URL, for example http://host.docker.internal:19798/dav or http://NAS-IP:19798/dav.
  4. Save the config, then browse the cloud directory or mount it as a media library.

The native 115 adapter still supports cookie / QR login, directory browsing, and 302 playback. For local file upload, prefer OpenList / CloudDrive2 / Alist bridging instead of maintaining every provider's private chunk-upload protocol inside this project.


🐳 Docker Compose Configuration

The default repository docker-compose.yml is intentionally simple. Beginners should write real host paths directly on the left side of volumes, then keep MEDIASTATION_MEDIA_DIR and MEDIASTATION_DOWNLOAD_DIR aligned with those same paths. .env variables are optional for advanced reuse:

Variable Default Description
MEDIASTATION_IMAGE_TAG latest Image tag. Pin a release for production.
MEDIASTATION_HTTP_PORT 18080 Host access port
MEDIASTATION_DATA_DIR ./data Persistent data directory
MEDIASTATION_CACHE_DIR ./cache Image and transcoding cache
MEDIASTATION_MEDIA_DIR ./media Host media library root; on NAS use an absolute path such as /your-nas/media
MEDIASTATION_DOWNLOAD_DIR ./downloads Host download target; on NAS use an absolute path such as /your-nas/downloads
PUID / PGID 1000 / 1000 Linux/NAS file permission mapping
TZ Asia/Shanghai Container timezone

View logs:

docker logs -f mediastation-go

Update:

curl -fsSL https://cdn.jsdelivr.net/gh/ShukeBta/MediaStationGo@main/scripts/docker-compose-update.sh -o docker-compose-update.sh
chmod +x docker-compose-update.sh
./docker-compose-update.sh

Note: plain docker compose pull && docker compose up -d switches to the new image but does not remove old images. The helper keeps the currently running MediaStationGo image, removes unused older images from the same repository, and runs docker image prune -f for dangling layers. To aggressively remove all unused images, run PRUNE_ALL_UNUSED=1 ./docker-compose-update.sh.

Stop:

docker compose down

Back up data:

tar -czf mediastationgo-data-backup.tgz ./data

🖥️ One-Click Deployment Scripts

If you do not want Docker, run MediaStationGo directly on the host. The scripts build the frontend, compile the backend, start the service, and verify /api/health.

Linux / macOS

git clone https://github.com/ShukeBta/MediaStationGo.git
cd MediaStationGo
chmod +x scripts/deploy.sh
PORT=18080 DATA_DIR=/opt/mediastation/data CACHE_DIR=/opt/mediastation/cache ./scripts/deploy.sh

Windows PowerShell

git clone https://github.com/ShukeBta/MediaStationGo.git
cd MediaStationGo
.\scripts\deploy.ps1 -Port 18080 -DataDir D:\MediaStationGo\data -CacheDir D:\MediaStationGo\cache

The scripts will:

  1. Install frontend dependencies and build web/dist
  2. Compile the Go backend into bin/
  3. Create data and cache directories
  4. Stop any previous process and start a new one
  5. Verify the service through /api/health

🧩 Release Package Deployment

Each release provides multi-platform archives:

Platform Package example
Linux x86_64 MediaStationGo-v0.0.32-linux-amd64.tar.gz
Linux ARM64 MediaStationGo-v0.0.32-linux-arm64.tar.gz
Windows x86_64 MediaStationGo-v0.0.32-windows-amd64.zip
macOS Intel MediaStationGo-v0.0.32-darwin-amd64.tar.gz
macOS Apple Silicon MediaStationGo-v0.0.32-darwin-arm64.tar.gz

Linux example:

tar -xzf MediaStationGo-v0.0.32-linux-amd64.tar.gz
cd MediaStationGo-v0.0.32-linux-amd64
MEDIASTATION_APP_PORT=18080 ./mediastation-go

Windows example:

Expand-Archive .\MediaStationGo-v0.0.32-windows-amd64.zip
cd .\MediaStationGo-v0.0.32-windows-amd64
$env:MEDIASTATION_APP_PORT = "18080"
.\mediastation-go.exe

Release binaries listen on 8080 by default. Set MEDIASTATION_APP_PORT=18080 as shown above if you want the same port as the Docker examples.


🛠️ Local Development

Requirements

Component Version Purpose
Go 1.25+ Backend build and tests
Node.js 20+ Frontend build
FFmpeg / ffprobe Recommended Media probing and transcoding
Docker Optional Container deployment and multi-arch builds
qBittorrent Optional Download integration testing

Build Locally

cp config.example.yaml config.yaml
cd web
npm ci
npm run build
cd ..
go build -o bin/mediastation-go ./cmd/server
./bin/mediastation-go

Windows:

Copy-Item config.example.yaml config.yaml
Set-Location web
npm ci
npm run build
Set-Location ..
go build -o bin\mediastation-go.exe .\cmd\server
.\bin\mediastation-go.exe

Common Commands

make build       # Build frontend and backend
make test        # Run Go tests
make smoke       # Smoke test
make docker      # docker compose up -d
make deploy      # Linux one-click deploy
make docker-push # Multi-arch buildx push

🏗️ Repository Layout

MediaStationGo/
├── cmd/server/                 # Server entry point
├── internal/
│   ├── config/                  # Config loading and defaults
│   ├── database/                # SQLite initialization and migrations
│   ├── handler/                 # HTTP API, Emby API, admin endpoints
│   ├── middleware/              # Auth, permission, logging middleware
│   ├── model/                   # GORM models
│   ├── repository/              # Data access layer
│   └── service/                 # Scanner, scraper, playback, downloads, subscriptions
├── web/
│   ├── public/                  # favicon and static public assets
│   ├── src/                     # React pages, components, API clients, stores
│   └── dist/                    # Frontend build output, ignored by git
├── scripts/                     # Deploy, package, Docker scripts
├── docs/                        # Design docs, screenshots, architecture notes
├── docker-compose.yml           # Default Docker Compose deployment
├── Dockerfile                   # Multi-stage image build
├── config.example.yaml          # Config template
└── README.md / README_EN.md     # Documentation

⚙️ Configuration

Configuration precedence, from low to high:

  1. Built-in defaults
  2. config.yaml
  3. config/*.yaml
  4. MEDIASTATION_ environment variables
  5. Runtime settings stored in the database

Common variables:

Variable Default Description
MEDIASTATION_APP_HOST 0.0.0.0 Listen address
MEDIASTATION_APP_PORT 8080 Listen port
MEDIASTATION_APP_WEB_DIR ./web/dist Frontend static bundle
MEDIASTATION_APP_DATA_DIR ./data App data directory
MEDIASTATION_DATABASE_DB_PATH ./data/mediastation.db SQLite database path
MEDIASTATION_CACHE_CACHE_DIR ./cache Image/transcode cache
MEDIASTATION_SECRETS_JWT_SECRET Auto-generated JWT and encrypted settings seed
MEDIASTATION_APP_CORS_ORIGINS empty Extra CORS origins
MEDIASTATION_TELEGRAM_API_BASE_URL https://api.telegram.org Telegram Bot API base URL; use a reverse proxy when Telegram is blocked or slow
MEDIASTATION_TELEGRAM_PROXY_URL empty Telegram outbound proxy, e.g. http://172.17.0.1:7890 or socks5://172.17.0.1:1080

Runtime settings from the admin UI:

  • API keys: TMDb, Bangumi, TheTVDB, Fanart, OpenAI Compatible.
  • Sites: M-Team, NexusPHP, Unit3D, custom RSS.
  • Download clients: qBittorrent, Transmission, Aria2.
  • Notifications: Telegram, Bark, Webhook, Email. Telegram channels can use a per-channel API base URL or proxy, and test errors redact Bot Tokens automatically.
  • Playback profiles, permissions, scheduler tasks, storage settings.

👥 Users and Permissions

  • The default administrator is created on first startup as admin / admin123. This account can be renamed, but it cannot be deleted or demoted and always keeps the highest privileges.
  • The open-source edition allows up to 20 users by default to reduce abuse on home NAS or public test instances. Binding a private license server can raise the quota according to the activated license policy.
  • Users created from the admin panel are “viewer users” by default: they can log in through the Web UI and Emby-compatible clients, browse libraries, play media, use external players, favorite items, and keep watch history.
  • Viewer users cannot scan libraries, rescrape metadata, delete media, probe media tracks, export NFO files, manage files, manage STRM links, manage download clients, create download tasks, or create/run subscriptions.
  • Because playback necessarily streams media data to the client, MediaStationGo can block download-management features and torrent/download tasks, but it cannot fully prevent an authorized browser or external player from saving an already authorized stream at the protocol level.

🔐 Private License Server

MediaStationGo includes a server-side bridge for the private standalone MediaStationLicenseServer:

  • License server: ShukeBta/MediaStationLicenseServer; a local backup may live at C:\Users\Administrator\WorkBuddy\license_server_backup.
  • MediaStationGo exposes /api/license/activate, /api/license/status, and /api/license/heartbeat; these backend routes proxy the License Server and do not expose the HMAC secret to browsers.
  • License Server public endpoints are /api/v1/activate, /api/v1/status/:fingerprint, and /api/v1/heartbeat.
  • Configure license.server_url and license.hmac_secret under Settings → License Server, then bind a key on the License page.
  • Without a valid license, MediaStationGo stays in open-source mode. With a valid license, the current implementation raises the user quota to the licensed tier.

Example environment variables:

MEDIASTATION_LICENSE_SERVER_URL=http://127.0.0.1:8001
MEDIASTATION_LICENSE_HMAC_SECRET=must-match-LICENSE_HMAC_SECRET

🎞️ On-Demand FFmpeg / ffprobe

MediaStationGo does not keep ffmpeg or ffprobe running as resident daemons. They are launched only when needed:

  • ffprobe runs during library scanning or manual media-track probing.
  • ffmpeg runs when browser direct play is not suitable and HLS transcoding is required.
  • Admin tool-status checks or manual tool installation may briefly execute version checks/install logic.

When playback stops, a transcode job is cancelled, or the service shuts down, the corresponding transcoding process is stopped. If there is no scanning, probing, or transcoding, ffmpeg/ffprobe should not continuously consume CPU.

The default HLS profile is NAS-friendly: MEDIASTATION_TRANSCODER_ENABLED=true is the global switch, and disabling it prevents ffmpeg transcode jobs from starting; MEDIASTATION_TRANSCODER_HARDWARE_ACCEL=false is the hardware acceleration switch, and hardware encoders are used only when it is enabled together with MEDIASTATION_TRANSCODER_ENCODER=nvenc/qsv/vaapi; MEDIASTATION_TRANSCODER_REALTIME=true throttles input to playback speed, MEDIASTATION_TRANSCODER_THREADS=2 caps software encoding threads, MEDIASTATION_TRANSCODER_MAX_CONCURRENT=1 limits simultaneous transcodes, and MEDIASTATION_TRANSCODER_IDLE_TIMEOUT_SECONDS=120 stops ffmpeg after the player stops requesting segments.

The default Docker image now uses a trimmed runtime layer and does not bundle Intel VAAPI / mesa driver packages by default, reducing the Docker Hub vulnerability-scan surface. If you need a custom Intel VAAPI/QSV image, build with docker buildx build --build-arg WITH_VAAPI=true ...; NVIDIA NVENC still mainly depends on NVIDIA Container Toolkit on the host and GPU access when the container runs.


🔍 Metadata Strategy

MediaStationGo avoids unnecessary repeated scraping and tries not to overwrite good local metadata:

  1. Read local NFO, poster, fanart, season poster, and episode images first.
  2. Parse media type, title, year, season, and episode from file paths.
  3. Fill missing data through TMDb, TheTVDB, Bangumi, and Douban.
  4. Use Fanart.tv for higher-quality artwork when available.
  5. Adult content prefers local NFO/images, then enriches from public JavBus/JavDB pages.
  6. Existing local metadata is not blindly overwritten.

Recommended layout:

/media/Movies/Inception (2010)/Inception (2010).mkv
/media/TV/Some Show/Season 01/Some Show S01E01.mkv
/media/Anime/Anime Title/Season 01/Anime Title S01E01.mkv
/media/Variety/Show Name/Season 2026/Show Name S2026E01.mkv
/media/Adult/ABCD-123/ABCD-123.mp4

Common local artwork names:

poster.jpg
fanart.jpg
folder.jpg
season01-poster.jpg
S01E01-thumb.jpg
movie.nfo
tvshow.nfo
episode.nfo

Smart Classification Directory Rules

MediaStationGo separates download classification from final media organization:

  1. Download stage: subscriptions and site-search downloads are saved under the downloader root by category.
  2. Organization stage: manual or automatic organization moves files into the media library root, then into type and category folders.

Recommended host directories:

/your-nas/downloads
/your-nas/media/电影
/your-nas/media/电视剧

Container paths:

/downloads
/media/电影
/media/电视剧

Download classification examples:

/downloads/动画电影
/downloads/国产剧
/downloads/国漫
/downloads/华语电影
/downloads/日番
/downloads/外语电影
/downloads/综艺

Organized media examples:

/media/电视剧/国产剧/Show Name (2026)/Season 01/Show Name - S01E01 - 第 1 集.mkv
/media/电视剧/国漫/Anime Name (2026)/Season 01/Anime Name - S01E01 - 第 1 集.mkv
/media/电视剧/欧美剧/Show Name (2026)/Season 01/Show Name - S01E01 - 第 1 集.mkv
/media/电视剧/日番/Anime Name (2026)/Season 01/Anime Name - S01E01 - 第 1 集.mkv
/media/电视剧/日韩剧/Show Name (2026)/Season 01/Show Name - S01E01 - 第 1 集.mkv
/media/电视剧/综艺/Variety Name (2026)/Season 2026/Variety Name - S2026E01 - 第 1 集.mp4
/media/电影/动画电影/Movie Name (2026)/Movie Name (2026) - 1080p.mkv
/media/电影/华语电影/Movie Name (2026)/Movie Name (2026) - 1080p.mkv
/media/电影/外语电影/Movie Name (2026)/Movie Name (2026) - 1080p.mkv

If the library root is set directly to /media, the organizer automatically adds the 电影/ or 电视剧/ type folder when smart classification is enabled. If the library root is already /media/电影 or /media/电视剧, it will not add the type folder again.

Automatic and manual organization are separate switches:

  • downloads.smart_classify: controls whether subscription/site-search downloads are automatically routed into category-specific save paths and qB categories; enabled by default.
  • organizer.smart_classify: controls smart category folders only.
  • organizer.auto_after_download / organize.auto: controls whether completed downloads are organized automatically.
  • If auto organization is disabled, use the Tools page to organize a library or a single media item manually.

Organization and Scraping Naming Templates

Use separate organization templates by media type. TV shows, anime, and variety shows should keep title, year, season folder, season/episode number, and episode title. Movies should keep title, year, part marker, and video format.

Recommended template for TV / anime / variety:

{{title}}{% if year %} ({{year}}){% endif %}/Season {{season}}/{{title}} - {{season_episode}}{% if part %}-{{part}}{% endif %}{% if episode %} - 第 {{episode}} 集{% endif %}{{fileExt}}

Example output:

Some Show (2024)/Season 01/Some Show - S01E01 - 第 1 集.mkv
Some Anime (2025)/Season 02/Some Anime - S02E03 - 第 3 集.mkv
Some Variety (2026)/Season 2026/Some Variety - S2026E01 - 第 1 集.mp4

Recommended template for movies:

{{title}}{% if year %} ({{year}}){% endif %}/{{title}}{% if year %} ({{year}}){% endif %}{% if part %}-{{part}}{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}{{fileExt}}

Example output:

Inception (2010)/Inception (2010) - 1080p.mkv
Dune (2021)/Dune (2021)-CD1 - 2160p.mkv

Common variables:

Variable Description
title Media title, preferably from local NFO or online metadata
year Year, appended when available
season Season number, used for Season 01 folders
season_episode Season/episode code, such as S01E01 or S2026E01
episode Episode number, used for Chinese episode titles
part Part marker, such as CD1 or Part1
videoFormat Video format, such as 1080p, 2160p, or WEB-DL
fileExt Original file extension, such as .mkv or .mp4

🔎 Discovery, Search & Subscriptions

Multi-source discovery

Discover supports:

  • TMDb: trending, popular movies, popular TV, top-rated movies.
  • Douban: hot movies, top movies, hot TV.
  • Bangumi: calendar and anime entries.

Smart search can combine:

  • Existing local library content.
  • Online results from TMDb, Douban, and Bangumi.
  • Subscription keywords and media types.

Subscription rules

Rule Description
Media type Movie, TV, anime, variety, or auto-detect
Search mode Keyword or IMDB ID
Resolution Best, 2160p, 1080p, 720p
Quality REMUX, BluRay, WEB-DL, HDTV
Effects HDR, Dolby Vision, Atmos
Release groups Preferred release groups
Exclude words Filter CAM, TS, low-quality releases
Wash Disabled by default; can prioritize resolution, quality, effects, or seeders

Download and subscription cards show only safe display metadata such as title, poster, speed, progress, and size. Raw torrent URLs are hidden to prevent tracker token leaks in multi-user deployments.


🔌 External Clients & Emby Compatibility

MediaStationGo exposes Emby/Jellyfin-style APIs for clients such as:

  • Infuse
  • VidHub
  • SenPlayer
  • Other Emby/Jellyfin-compatible players

Server URL:

http://<server-ip>:18080

If a client cannot connect, check:

  1. Docker port mapping, typically 18080:8080.
  2. Firewall access from LAN to port 18080.
  3. Username/password.
  4. Reverse proxy handling of /api, video streams, and Range requests.

Functional Reference to MoviePilot

For external-client compatibility and media workflow integration, MediaStationGo references MoviePilot's mature product direction: a unified media library, subscription downloads, post-download organization, and Emby/Jellyfin-compatible APIs that connect the Web management interface with clients such as Infuse, VidHub, and SenPlayer. MediaStationGo does not aim to replace Emby/Jellyfin; instead, it provides the common browsing, playback, poster wall, season/episode hierarchy, progress tracking, and external-client access capabilities inside a lightweight Go service.

Current compatibility focus:

  • Library, collection, season, and episode hierarchy output.
  • Basic metadata output such as posters, backdrops, descriptions, year, and ratings.
  • Stream URLs, HTTP Range support, playback progress, and resume.
  • Emby/Jellyfin-style endpoints required for external-client login, browsing, and playback.

Still being improved:

  • More complete Emby/Jellyfin device capability negotiation.
  • More detailed transcoding profiles and subtitle capability declarations.
  • Multi-user permissions, library filtering, and playback-history synchronization.
  • Closed-loop integration with subscriptions, post-download organization, and upgrade rules.

MoviePilot is licensed under GPL-3.0. MediaStationGo references its public product ideas and interaction patterns only, and does not copy private data, secrets, tracker accounts, or incompatible implementations.


🧠 AI and External Services

Configure external services in the admin UI:

Service Purpose
TMDb Movie/TV posters, backdrops, descriptions
Bangumi Anime and Chinese anime metadata
TheTVDB Additional TV/season/episode metadata
Fanart.tv High-quality logos and artwork
Douban Chinese movie/TV search and recommendation supplement
OpenAI Compatible AI search, recommendations, operations assistant

For M-Team, use an API Access Token:

Control Panel → Lab → Access Token
HTTP Header: x-api-key

Avoid using cookies for open API calls to reduce account risk.



🔐 Privacy and Safety

The repository ignores personal/runtime data by default:

  • data/, cache/, logs/
  • .tmp-deploy-data/, .tmp-deploy-server.*
  • .mediastation.pid
  • config.yaml, .env*
  • *.db, *.db-wal, *.log
  • web/dist/, node_modules/, bin/
  • API keys, cookies, tokens, passwords, certificates, and secret files

Before pushing, run:

git status --short
git ls-files | grep -E 'data/|cache/|\.db|\.log|jwt_secret|config.yaml|\.env|token|apikey|password' || true

❓ FAQ

Pulling the GHCR image fails with EOF.

EOF usually means the connection from your server/NAS to GHCR was interrupted. It is normally a network or registry connectivity issue, not a compose syntax issue. Try:

# 1. Clear any stale GHCR login state
docker logout ghcr.io || true

# 2. Pull the image directly
docker pull ghcr.io/shukebta/mediastation-go:latest

# 3. On x86_64/AMD64 hosts, retry with an explicit platform
docker pull --platform linux/amd64 ghcr.io/shukebta/mediastation-go:latest

# 4. Start after the pull succeeds
docker compose up -d

If the server is behind a restricted network, configure a Docker daemon proxy that can reach GHCR. A shell-only proxy is often not inherited by the Docker service. The default compose file uses pull_policy: missing to avoid contacting GHCR on every container restart.

If your media path is an absolute NAS path, use /your-nas/... instead of ./your-nas/...; the latter is relative to the compose directory.

The Docker deployment starts but the browser cannot open the site.

Check container status and logs:

docker ps
docker logs -f mediastation-go

Use the host port, usually http://<server-ip>:18080.

External clients report that the server does not respond.

Check firewall rules, Docker port mappings, reverse proxy configuration, and LAN access to 18080. The container listens on 8080; the host default is 18080.

Posters are missing.

Check:

  1. Local poster.jpg, fanart.jpg, and NFO files.
  2. TMDb / Bangumi / Douban connectivity.
  3. Proxy settings if the host is behind a restricted network.
  4. Whether file names contain clear title, year, season, and episode information.

Why are raw download URLs hidden?

PT download URLs often include private tokens. Download and subscription views intentionally hide raw URLs and only show safe metadata such as title, poster, speed, progress, and size.

Which Docker package should be kept?

Keep ghcr.io/shukebta/mediastation-go. The old mediastationgo package can be removed to avoid users pulling the wrong image.


🗺️ Roadmap

  • Broader Emby/Jellyfin client compatibility.
  • Stronger adult metadata handling from local files and public pages.
  • More granular subscription wash and post-download organization rules.
  • Better mobile and TV interaction patterns.
  • Plugin-style site adapters and notification providers.
  • More end-to-end tests and automated screenshot generation.

🤝 Contributing

Issues, pull requests, site adapters, scraping rules, UI improvements, and documentation fixes are welcome.

Before submitting changes, please run:

go test ./...
cd web && npm run build

👥 Developer Group


🍜 Donation

If MediaStationGo saves you time, feel free to buy the author a bowl of noodles.

WeChat Donation QR

⭐ Star History

Star History Chart

📄 License and Non-Commercial Statement

This project uses GPL-3.0 as its base license. See LICENSE for details. The maintainers also state and request the following usage boundary:

  • The project is intended for personal learning, home NAS, self-hosted media, non-commercial research, and community collaboration.
  • Without explicit written permission from the author, do not use this project or derivative versions for commercial resale, paid hosting, paid SaaS, pre-installed commercial devices, closed-source redistribution, or other profit-oriented commercial use.
  • For commercial cooperation, enterprise deployment, custom development, integrated redistribution, or commercial authorization, contact the author first to confirm the authorization scope.
  • If there is any interpretive difference between the README non-commercial statement and the formal GPL-3.0 license text, the code license is governed by LICENSE; commercial usage should additionally obtain author permission.

Made with ❤️ by ShukeBta

S
Description
No description provided
Readme 76 MiB
Languages
Go 74.3%
TypeScript 25.6%