Go MIT

castor

Point it at any web page and it finds the video, extracts the stream, transcodes it and casts in real time to your TV. It even burns subtitles….

S

stupside

Dernière activité 28 sept. 2026
stupside/castor

2,4 k

étoiles

87

forks

3

issues ouvertes

chromecastdlnaffmpegiptvstreamingvideo

Ce README est souvent en anglais.

Castor

stupside%2Fcastor | Trendshift

Latest Release Go Reference Homebrew License Build Status

Castor

Cast web video to your TV without screen mirroring. Castor extracts streams, converts incompatible formats, and optionally generates subtitles. Run locally or offload media processing to a NAS.

Castor bundles no content or sources and refuses DRM. Use only content you are authorized to access; see Purpose and disclaimer.

Browsing titles in the castor TUI
Run castor cast to browse titles and cast, without leaving the terminal.

Quick start

Install on macOS (other platforms) and find your TV:

brew install --cask stupside/tap/castor
castor scan

Save config.yaml in your working directory:

device:
  name: "Living Room TV"   # exact name from `castor scan`
  type: dlna               # or: chromecast, roku

Cast a page:

castor cast player https://example.com/watch/some-video

castor scan found nothing? See Troubleshooting.

Commands

Command What it does
castor scan List the devices on your network
castor cast player <url> Cast a web page with an embedded video player
castor cast url <url> Cast a direct stream or video URL
castor cast Browse titles and cast, interactively (needs a TMDB key)
castor cast movie <id> Resolve a movie id against your sources and cast
castor cast episode <id> --season N --episode N Same, for a TV episode
castor media-server Probe, rank, convert, and serve streams
castor scraping-server Extract stream candidates using Chrome
castor api-server Discover/control devices and orchestrate casts

castor cast --dry-run ... prints the streams it found instead of casting. Run castor --help for all flags.

Installation

Use a native binary on your TV's network, with these tools on PATH:

Tool Version Used for
Chrome / Chromium Any recent Finding the video on a page
ffmpeg 7.1+ Converting the video for your TV
ffprobe 7.1+ Reading the video's format

Encoding uses a working GPU encoder, falling back to software.

  • macOS: brew install --cask stupside/tap/castor.
  • Linux: download castor_<version>_linux_amd64.tar.gz (or _arm64) from the latest release and put castor on your PATH.
  • Windows: download the release ZIP for your architecture and put castor.exe on PATH. Install tools with winget install Gyan.FFmpeg and winget install Google.Chrome. For SmartScreen, choose More info → Run anyway; allow firewall access on private networks for discovery.
  • From source: see CONTRIBUTING.md.

Configuration

Castor reads config.yaml (or --config <path>), then overlays git-ignored config.local.yaml. Environment variables such as CASTOR_CAST__MAX_HEIGHT=720 override both. CLI casting needs device; other keys have defaults. Keep secrets out of git; see SECURITY.md.

Subtitles

Subtitles are burned into served, read-once video (e.g. DLNA), not self-fetching Chromecast/Roku playback. The appropriate default model downloads once to your cache.

cast:
  subtitles: en            # a language code, or auto to detect it; unset for none
whisper:
  # model_path: ""         # ggml-tiny.en for en, multilingual ggml-tiny otherwise

Set whisper.model_path to use a larger model (e.g. multilingual ggml-base.bin). English-only models reject other languages and auto.

Video quality

Choose the tallest stream within this ceiling and scale known taller video down:

cast:
  max_height: 2160         # default: 1080

Sources

Title commands substitute IDs into your source templates, trying proxies in order. Add only sites you are authorized to use:

sources:
  - proxies: ["https://your-source.example"]   # base URLs, tried in order
    templates:
      movie: "/embed/movie/{itemID}"
      episode: "/embed/tv/{itemID}/{season}-{episode}"

TMDB key

Only the interactive browser needs a TMDB key:

tmdb:
  api_key: "<KEY>"

Run castor on another machine

A shared media server

Run on the server with server.token set:

castor media-server   # listens on :8410 (server.listen)

On your computer:

server:
  url: http://my-nas:8410
  token: "<a long random string, the same on both>"

Your computer discovers and controls the TV; the server processes media. Closing the terminal leaves playback running; Ctrl+C stops it. Cast preferences come from the client, the Whisper model from media. Set server.advertise to an address the TV can reach; use HTTPS outside a trusted network.

The API, for apps and integrations

Run each command in a separate process; API must reach the TV's network:

castor media-server      # :8410
castor scraping-server   # :8412
castor api-server        # :8411

Set server.url: http://localhost:8410 and scraping.url: http://localhost:8412 for API. Configure independent server.token, scraping.token, and api.token; $TOKEN below is the API token.

curl -X POST http://localhost:8411/castor.v1.DeviceService/ListDevices \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' -d '{}'

curl -X POST http://localhost:8411/castor.v1.CastService/Cast \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"target": {"deviceId": "<id from ListDevices>"}, "source": {"stream": {"url": "https://example.com/video.m3u8"}}}'

For a page, use "source": {"pages": {"urls": ["https://example.com/watch"]}}. Stop ends a cast; Watch streams feedback (use buf curl or a generated client). CLI clients connect with api.url and api.token.

Page casts go API → scraping → media; direct streams bypass scraping. Media never receives webpages. Without api.url, CLI starts missing services on loopback. See ARCHITECTURE.md for contracts, ownership, and lifecycle.

Supported devices

Protocol Works with Status
DLNA / UPnP (MediaRenderer:1) Most smart TVs, and players like Kodi, VLC, and Plex Tested on Samsung
Chromecast Google Cast devices Experimental, not yet tried on real hardware
Roku Roku TVs and players, through a sideloaded channel Experimental, not yet tried on real hardware

Roku setup

Castor sideloads a playback channel:

  1. Turn on Developer Mode (once, by hand): on the remote press Home x3, Up x2, Right, Left, Right, Left, Right, enable developer mode, and set a web-server password. The device reboots.
  2. Put the password in your config (out of git, see Configuration):
    devices:
      roku:
        password: "<dev-web-server-password>"   # first cast only
  3. Cast. Castor sideloads its channel automatically; later casts reuse it.

For a published channel, set devices.roku.app_id instead; no developer mode/password needed. Relayed Roku playback runs about 30 s behind.

Troubleshooting

castor scan finds nothing: pin the device by IP

Discovery cannot cross VLANs/subnets and is blocked on Android/Termux. Set host to skip discovery:

device:
  name: "Living Room TV"   # now just a label
  type: dlna
  host: 192.168.0.3        # the device's LAN IP

For DLNA, host can be a full description URL (e.g. http://192.168.0.3:9197/dmr). On Android/Termux, leave network.interface empty.

The page won't play

The page's video must start without a click. DRM streams are refused.

The device loads the stream but plays nothing

Force served playback rather than handing the TV a link:

cast:
  delivery: serve   # "auto" (the default) decides per source

Try once with CASTOR_CAST__DELIVERY=serve; it costs bandwidth and CPU. castor --debug explains delivery decisions.

Docker

The image includes Chrome, ffmpeg, and ffprobe. --device /dev/dri enables Intel VA-API; otherwise encoding uses software.

Warning

The Compose stack targets Linux host networking for LAN discovery and device-reachable media URLs. On macOS/Windows, use the native binary for discovery. Docker Desktop 4.34+ has opt-in host networking, but cannot bind directly to the host's network interfaces.

docker run --rm --network host ghcr.io/stupside/castor:latest scan

docker run --rm --network host --device /dev/dri \
  -v "$PWD/config.yaml:/config.yaml" \
  -v castor-cache:/root/.cache \
  ghcr.io/stupside/castor:latest \
  cast player https://example.com/watch/some-video

The cache volume preserves Whisper models. On Linux, put CASTOR_SERVER__TOKEN, CASTOR_SCRAPING__TOKEN, and CASTOR_API__TOKEN in git-ignored .env, then run docker compose up -d. API and media use host networking; scraping is published only on loopback. Remove the /dev/dri mapping on hosts without Intel VA-API. A standalone bridged media container needs -p 8410:8410 and server.advertise set to a device-reachable address.

Tags: :latest (stable), :canary (preview), or a pinned :vX.Y.Z.

Purpose and disclaimer

No bundled video or sources; no DRM decryption or circumvention. You are responsible for lawful use and compliance with site terms. Provided as-is for lawful, personal, and educational use.

Contributing

See CONTRIBUTING.md, and ARCHITECTURE.md for how castor works inside.

Projets similaires

Cast media files to Smart TVs and Chromecast devices.

Goaudiocastchromecast
Aalexballas
1,1 k étoiles82

Cast All The Things allows you to send videos from many, many online sources to your Chromecast.

Python
Sskorokithakis
3,7 k étoiles175

A self-hosted web application that lets you stream Live TV, Movies, and Series from your Xtream Codes or M3U provider directly in your browser. It's built with performance in mind and handles large libraries smoothly.

JavaScript
Ttechnomancer702
1,5 k étoiles247