MCPcopy Index your code
hub / github.com/ShukeBta/MediaStationGo

github.com/ShukeBta/MediaStationGo @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
6,356 symbols 28,120 edges 1,108 files 1,396 documented · 22%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

MediaStationGo

MediaStationGo Logo

A lightweight, polished, NAS-friendly private media center

Docker-first setup · Multi-user management · Media library · Metadata · Downloads · Emby-protocol clients · Cloud playback

中文 · Quick Start · Docker Compose · FAQ · Live Demo

Go React Docker License


What is it?

MediaStationGo is a self-hosted media center for personal libraries, home NAS, and home-theater users.

It helps you:

  • Manage movies, TV shows, anime, variety shows, music, and adult libraries.
  • Create multiple user accounts for family members, friends, or different devices.
  • Scan files and enrich posters, summaries, years, seasons, and episodes.
  • Play in the web UI, or log in with a MediaStationGo account from Emby-protocol apps such as Infuse, VidHub, SenPlayer, and Emby clients.
  • Connect qBittorrent for search, subscriptions, downloads, and post-download organization.
  • Connect OpenList, CloudDrive2, WebDAV, and other storage backends with STRMURL or 302 redirect playback.
  • Run on NAS, mini PCs, VPS, Linux, Windows Docker Desktop, or any Docker-friendly host.

The project is moving fast. With the default PostgreSQL deployment, back up both data/ and postgres/.


Key Highlights

  • One server, many clients: deploy MediaStationGo once; you do not need to run a separate Emby server.
  • Emby-protocol compatibility: add the server in third-party players as an Emby/Jellyfin-compatible server, then log in with your MediaStationGo username and password.
  • Multi-user management: supports admins, regular users, account enable/disable, expiry dates, device management, Bot registration, and redeem codes.
  • Local + cloud media in one place: manage local disks, download folders, OpenList, CloudDrive2, WebDAV, and other storage backends from one panel.
  • Download-to-library workflow: connect qBittorrent for search, subscriptions, download completion organization, and metadata matching.
  • NAS-friendly: simple Docker Compose deployment. The primary database lives under postgres/, while runtime secrets and files live under data/.

Who is it for?

  • Beginners who want to edit one docker-compose.yml and start the service.
  • NAS users who want a low-resource media center for local disks and cloud storage.
  • PT/download users who want downloads, organization, metadata, and playback in one panel.
  • External-player users who want to log in to Emby-protocol third-party apps with one MediaStationGo account.
  • Family-sharing users who want separate user accounts without deploying a separate media server for each person.
  • Developers who want to study or extend a Go + React self-hosted media app.

Live Demo

The demo is for feature preview only. Do not save private API keys, tracker cookies, or personal data there.


Quick Start

Docker Compose is the recommended path. Beginners do not need .env, bare-metal binaries, or source builds. Use the single-image SQLite template if you want the smallest possible setup.

mkdir -p MediaStationGo
cd MediaStationGo
# Simplest option: one MediaStationGo container + SQLite
curl -fsSL https://raw.githubusercontent.com/ShukeBta/MediaStationGo/main/docker-compose.simple.yml -o docker-compose.yml
# Or tier 1: MediaStationGo + PostgreSQL
# curl -fsSL https://raw.githubusercontent.com/ShukeBta/MediaStationGo/main/docker-compose.yml -o docker-compose.yml

Edit docker-compose.yml:

vi docker-compose.yml

Start:

docker compose up -d

Open:

http://SERVER_IP:18080

Default login:

Username: admin
Password: admin123

Docker Compose Recommended

The repository docker-compose.yml is the lightweight recommended template: no .env required, and by default it only starts MediaStationGo + PostgreSQL. This is the best starting point for most NAS users.

If you already have an older ./data/mediastation.db, the first start with the new compose file automatically imports it into PostgreSQL. Keep ./data; it still stores the JWT secret, runtime data, and the old SQLite migration source.

Deployment modes

Mode Command Best for
Single image: SQLite docker compose -f docker-compose.simple.yml up -d Beginners and single-user setups that want one image only, no PostgreSQL/Redis
Lightweight: PG only docker compose up -d Most NAS devices, lowest resource use
Standard: PG + Redis docker compose -f docker-compose.standard.yml up -d Multi-user use and frequent Emby client refreshes
Search enhanced: PG + Redis + OpenSearch docker compose -f docker-compose.search.yml up -d Huge libraries and future standalone search indexing

Each compose file is standalone. Do not stack multiple -f files together.

The single-image docker-compose.simple.yml runs only MediaStationGo with a built-in SQLite database — the simplest starting point. Do not set MEDIASTATION_DATABASE_DSN there, or it switches back to PostgreSQL. Move up to the PostgreSQL modes for multi-user or high-concurrency use (keep ./data when you switch). Redis and OpenSearch are enhancement layers, not source databases. Do not enable OpenSearch by default on low-memory NAS devices.

Database Choice And Disabling SQLite

The current Docker Compose setup uses PostgreSQL by default. SQLite is no longer the primary database in the recommended Docker deployment. The runtime database is controlled by:

environment:
  MEDIASTATION_DATABASE_TYPE: postgres
  MEDIASTATION_DATABASE_DSN: postgres://mediastation:mediastation@postgres:5432/mediastation?sslmode=disable

MEDIASTATION_DATABASE_DB_PATH is only used as a one-time migration source for old SQLite data:

  • Fresh installs: docker compose up -d uses PostgreSQL and does not create a new SQLite primary database.
  • Upgrades: if ./data/mediastation.db exists, the first start with the new compose file imports it into PostgreSQL.
  • Migration fills missing rows by primary key and skips rows that already exist. If it fails partway through, a later start continues the remaining tables.
  • After a successful import, PostgreSQL gets a completion marker in the settings table, so the old SQLite file is not imported again.
  • Redis is a hot cache and OpenSearch is a search index; neither is a source database.

Recommended SQLite to PostgreSQL upgrade flow:

docker compose pull mediastation-go
docker compose up -d --no-deps mediastation-go
docker compose logs -f mediastation-go

After you see sqlite data migrated to postgres, or after the web UI shows your users, libraries, and settings correctly, you can stop using the old SQLite file as a migration source.

To make the deployment PostgreSQL-only after migration, keep PostgreSQL selected and point the old SQLite migration path at a non-existent file:

Only do this after the web UI confirms that users, libraries, settings, and media rows are already present in PostgreSQL.

environment:
  MEDIASTATION_DATABASE_TYPE: postgres
  MEDIASTATION_DATABASE_DSN: postgres://mediastation:mediastation@postgres:5432/mediastation?sslmode=disable
  MEDIASTATION_DATABASE_DB_PATH: /data/disabled-sqlite-migration.db

Then rename or move the old host-side SQLite file as an offline backup:

mv data/mediastation.db data/mediastation.sqlite.bak

For bare-metal or custom config.yaml deployments, use the same idea:

database:
  type: postgres
  dsn: postgres://mediastation:mediastation@127.0.0.1:5432/mediastation?sslmode=disable
  db_path: ""

Do not delete ./postgres. After migration, it is the real primary database. Keep ./data too, because it stores the JWT secret and runtime files.

Choose an image source

Both image sources are supported. Pick one and put it in image::

Source Image Best for
GitHub Container Registry (GHCR) ghcr.io/shukebta/mediastation-go:latest Recommended default, follows repository releases
Docker Hub shukbet/mediastationgo:latest Backup source when GHCR is slow or unavailable

To pin a version, first confirm the tag exists on the repository Packages page. Use this format:

image: ghcr.io/shukebta/mediastation-go:<version-tag>
# If GHCR does not have that tag, use Docker Hub as the backup:
# image: shukbet/mediastationgo:MediaStationGo-v0.0.72

For the simplest setup, keep GHCR latest.

Manual pull examples:

# GitHub Container Registry
docker pull ghcr.io/shukebta/mediastation-go:latest

# Docker Hub backup
docker pull shukbet/mediastationgo:latest

Focus on this part:

volumes:
  - ./data:/data
  - ./cache:/cache
  - ./media:/media
  - ./downloads:/downloads

Meaning:

Host path Container path Purpose
./data app /data Settings, JWT secret, old SQLite migration source; the primary DB is under ./postgres
./cache app /cache Cache; safe to clean when needed
./media /media Media libraries; use /media/... in the web UI
./downloads /downloads Download directory and organization source
./postgres PostgreSQL /var/lib/postgresql/data New default primary database; back this up
./redis Redis /data Used only in standard mode; hot cache, rebuildable
./opensearch OpenSearch /usr/share/opensearch/data Used only in search-enhanced mode; higher memory use

If your NAS paths are:

/vol1/1000/Media
/vol1/1000/Downloads

change the compose file to:

volumes:
  - ./data:/data
  - ./cache:/cache
  - /vol1/1000/Media:/media
  - /vol1/1000/Downloads:/downloads

environment:
  MEDIASTATION_MEDIA_DIR: /vol1/1000/Media
  MEDIASTATION_DOWNLOAD_DIR: /vol1/1000/Downloads

Rules:

  • The left side of volumes is the real path on your host/NAS.
  • The right side is the container path. Keep /media and /downloads unless you know why you are changing them.
  • In the web UI, create libraries with container paths such as /media/Movies or /media/TV.
  • Do not write NAS absolute paths as ./vol1/...; ./ means a folder under the current compose directory.
  • On Windows Docker Desktop, paths like D:/Media:/media and D:/Downloads:/downloads are fine.
  • If you only scan/play existing media and never organize into the library, you may add :ro; if you use organize/rename/ingest, the media mount must stay writable.

Minimal compose example

The root docker-compose.yml follows this style:

```yaml services: mediastation-go: # Pick one image source: # GitHub Container Registry (GHCR): image: ghcr.io/shukebta/mediastation-go:latest # Docker Hub backup: # image: shukbet/mediastationgo:latest

restart: unless-stopped
init: true
depends_on:
  postgres:
    condition: service_healthy

# Browser: http://SERVER_IP:18080
ports:
  - "18080:8080"

# Let the container reach qBittorrent running on the host:
# qB URL example: http://host.docker.internal:8085
extra_hosts:
  - "host.docker.internal:host-gateway"

volumes:
  # Application data. Back this up before upgrades.
  - ./data:/data
  - ./cache:/cache

  # Beginners can create ./media and ./downloads.
  # NAS users should replace source with real absolute paths.
  # create_host_path=false prevents Docker from silently creating an empty
  # folder when the host path is wrong.
  - type: bind
    source: ./media
    target: /media
    bind:
      create_host_path: false
  - type: bind
    source: ./downloads
    target: /downloads
    bind:
      create_host_path: false

environment:
  TZ: Asia/Shanghai
  PUID: "1000"
  PGID: "1000"

  MEDIASTATION_APP_HOST: 0.0.0.0
  MEDIASTATION_APP_PORT: 8080
  MEDIASTATION_APP_WEB_DIR: /app/web/dist
  MEDIASTATION_APP_DATA_DIR: /data

  # Lightweight mode uses PostgreSQL by default.
  # Old SQLite data migrates from this path on first start.
  MEDIASTATION_DATABASE_TYPE: postgres
  MEDIASTATION_DATABASE_DSN: postgres://mediastation:mediastation@postgres:5432/mediastation?sslmode=disable
  # After migration, change this to /data/disabled-sqlite-migration.db to disable the SQLite migration source.
  MEDIASTATION_DATABASE_DB_PATH: /data/mediastation.db
  MEDIASTATION_CACHE_CACHE_DIR: /cache

  # Use /media and /downloads in the web UI and downloader by default.
  # Only set MEDIASTATION_*_DIR to real host paths when migrating old
  # libraries/tasks that already stored host paths.
  MEDIASTATION_MEDIA_DIR: /media
  MEDIASTATION_MEDIA_CONTAINER_DIR: /media
  MEDIASTATION_DOWNLOAD_DIR: /downloads
  MEDIASTATION_DOWNLOAD_CONTAINER_DIR: /downloads

postgres: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: mediastation POSTGRES_USER: mediastation POSTGRES_PASSWORD: mediastation volumes: - ./postgres:/var/lib/postgresql/data

Extension points exported contracts — how you extend this code

SiteAdapter (Interface)
SiteAdapter 站点适配器接口。 [7 implementers]
internal/service/site_adapter.go
MediaSearchBackend (Interface)
(no doc) [2 implementers]
internal/repository/media_repository.go
HistoryItem (Interface)
(no doc)
web/src/types/history.ts
NotifyProvider (Interface)
NotifyProvider 定义通知渠道的发送接口。 [5 implementers]
internal/service/notify_svc.go
MediaSearchSyncBackend (Interface)
(no doc) [1 implementers]
internal/repository/media_repository.go
HistoryStats (Interface)
(no doc)
web/src/types/history.ts
DownloadAdapter (Interface)
DownloadAdapter 定义下载客户端的统一接口。 所有下载客户端(qBittorrent / Transmission / Aria2)必须实现此接口。 [3 implementers]
internal/service/download_adapter.go
Media (Interface)
(no doc)
web/src/types/media.ts

Core symbols most depended-on inside this repo

Context
called by 1671
internal/service/service.go
Error
called by 827
internal/service/sse_hub.go
Set
called by 535
internal/service/discover_section_cache.go
Create
called by 526
internal/service/backup.go
Close
called by 328
internal/service/service.go
New
called by 268
internal/repository/repository.go
Write
called by 261
cmd/server/log_rotate.go
Get
called by 241
internal/service/api_config.go

Shape

Function 3,971
Method 1,646
Struct 577
Interface 144
TypeAlias 10
Class 4
FuncType 4

Languages

Go85%
TypeScript15%

Modules by API surface

internal/service/telegram_bot.go25 symbols
web/src/pages/strmPageModel.ts24 symbols
internal/repository/bot_repo.go24 symbols
web/src/utils/groupSeries.ts23 symbols
internal/service/site_rate_limiter.go22 symbols
internal/handler/strm.go21 symbols
internal/handler/emby_routes.go20 symbols
internal/service/storage_upload.go19 symbols
internal/service/sse_hub.go19 symbols
internal/service/site_adapter_test.go19 symbols
internal/service/bot_features.go19 symbols
internal/handler/license_test.go19 symbols

Datastores touched

mediastationDatabase · 1 repos
msgoDatabase · 1 repos

For agents

$ claude mcp add MediaStationGo \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact