castor

stupsideMIT活跃维护

把任意网页里的视频抓出来,实时转码后投到电视上播放,还能把字幕烧进画面。

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

v2.5.0发布于 2026-10-27 21:55 UTC2,532star +3 / 7 天102fork同步于 2026-11-10 11:43 UTC

怎么上手

由 README 提炼,执行前请确认
brew install --cask stupside/tap/castor   # macOS
npm install -g @castor-dev/cli            # any platform, Node 20+
硬件要求按 README 说明

README 未说明显存要求;转码优先使用 ffmpeg 可用的硬件编码器,否则回退到软件编码;Docker 镜像在 Intel GPU 上通过 VA-API 编码(需加 --device /dev/dri)。

支持 Apple Silicon有 Docker 镜像
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

把任意网页里的视频抓出来、转码并实时投到电视上,连字幕一起烧进去

把任意网页里的视频抓出来,实时转码后投到电视上播放,还能把字幕烧进画面。

核心能力

  • 用无头 Chrome 打开页面并捕获视频流
  • 用 ffmpeg 按电视能力实时转码并烧入字幕
  • 支持 DLNA、Chromecast、Roku 三种投屏协议
  • castor scan 自动发现局域网内的电视
  • 拆成 API、抓取、媒体三个服务,可单独部署到 NAS

容易踩的坑

必须自行安装 Chrome 和 ffmpeg + ffprobe 7.1+ 并加入 PATH;页面里的视频必须无需点击即可自动播放,且拒绝 DRM 流;设备发现只在同一子网内有效,Android/Termux 上需手动设置 device.host 为电视 IP;使用 TUI 浏览片源需自备 TMDB API key 并配置 sources。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v2.5.0
  1. v2.5.0最新正式版2026-10-27 · 2026-10-27 21:55 UTC

    2.5.0 (2026-10-27)

    Features

    • cast: let the interactive cast run without a configured device (61c8490)
    • settings: read the user's config directory, then the working directory's (a726b44)

    Bug Fixes

    • deps: move to Go 1.27.3 and next 16.4.3 for known vulnerabilities (f16ef1f)
    • settings: check required sections and name failures by config key (71a077c)

    Documentation

    • architecture: update the architecture documentation (15d0616)
    • contributing: require Go 1.27.1 and set out what castor will not take (54d4398)
    • give telemetry its own section in CONTRIBUTING (ea35704)
    • readme: add a table of the platforms castor runs on (2410b80)
    • readme: list community projects, starting with castor-android (435ea38)
    • readme: rewrite as a short onboarding page (02ef689)
    • security: report vulnerabilities privately and warn about open servers (61e4908)

    Continuous Integration

    • scan Go and app dependencies for vulnerabilities (87307d4)
  2. v2.4.02026-10-26 · 2026-10-26 15:50 UTC
    查看更新说明

    2.4.0 (2026-10-26)

    Features

    • cast: begin a cast at a position (c3fde9f)
    • cast: follow the device's link while it plays (c7c3af8)
    • cast: go back to a better ranked link once the cast plays well (0162f91)
    • cast: let the device play out what it took before stopping (d0caa8d)
    • device: report the device's position and its viewer's pause (0408dd5)
    • dlna: seek within the stream castor serves (cc89147)
    • rank: rank links by the language of their sound first (b833922)

    Bug Fixes

    • cast: count what the encoders made where they read the buffer (30bc249)
    • dlna: drop Samsung's sec:CaptionInfoEx (3e8b521)
    • execute: keep every failure an attempt reports (8f7f9ee)
    • probe: weigh each audio track on its own bitrate (fd3a603)
    • stream: keep a paused device's connection open (931677f)

    Refactors

    • device: carry a located device through whole (2adc65e)
    • output: answer segment requests through the opening (5af01c1)
    • run every state machine through one typed machine (047076b)
  3. v2.3.02026-10-22 · 2026-10-22 13:56 UTC
    查看更新说明

    2.3.0 (2026-10-22)

    Features

    • release: give the npm launcher search keywords (#77) (c0dc517)

    Documentation

    • readme: add an npm version badge (1711a67)
  4. v2.2.02026-10-22 · 2026-10-22 11:24 UTC
    查看更新说明

    2.2.0 (2026-10-22)

    Features

    • release: ship the project docs in every npm package (34ff4d9)

    Bug Fixes

    • media: read HLS MIME aliases and report Stop as stopped (#74) (56ac869)
  5. v2.1.02026-10-22 · 2026-10-22 06:39 UTC
    查看更新说明

    2.1.0 (2026-10-22)

    Features

    • release: publish the cli to npm through trusted publishing (aa2510c)
    • telemetry: namespace OTel names and make logs say why (e993388)
    • telemetry: record state machines as one span per state (7aaf50b)
    • telemetry: second-scale duration buckets, semconv 1.43 and service version (217f29d)

    Bug Fixes

    • codec: weigh a video encode above an audio one when picking a format (d466da9)
    • release: restore postflight_steps in the brew cask (#73) (3d022c0)

    Refactors

    • release: give brew its own job and run both channels after publish (0b8d943)

    Documentation

    • readme: lead the quick start with brew, npm and a source build (7869786)
    • telemetry: add a provisioned Grafana dashboard and the local collector recipe (0a24a99)

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Castor

    Cast web video to your TV, even when it has no built-in casting like Chromecast. Point it at any web page and it finds the video, transcodes it, and streams it to your TV in real time. It even burns in subtitles.

    It runs as one command on your laptop, or as services you can move to a NAS.

    [!IMPORTANT] Castor ships no content and no sources, and refuses DRM streams. Use it only for video you are allowed to watch.

    Install

    brew install --cask stupside/tap/castor   # macOS
    npm install -g @castor-dev/cli            # any platform, Node 20+
    

    Or download the latest release, or build from source.

    [!NOTE] Castor needs Chrome and ffmpeg + ffprobe 7.1+ on your PATH. On Windows: winget install Google.Chrome and winget install Gyan.FFmpeg, then allow Castor on private networks.

    Quick start

    Settings go in a config.yaml (where).

    Cast a page or a video URL

    Give castor a page that plays a video: it finds the stream, converts what your TV can't play, and starts playback.

    1. Find your TV:

      castor scan
      
    2. Add it to config.yaml, with the name and type the scan printed:

      device:
        name: "Living Room TV"
        type: dlna   # dlna, chromecast, or roku
      
    3. Cast a page, or a direct stream or video file:

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

    Useful flags: --at 1h12m to start at a position, --dry-run to list the streams found without casting, --debug to see why castor does what it does.

    Browse titles in the TUI

    castor cast opens a title browser in your terminal: search TMDB or browse what is trending, pick a title and a TV, and castor finds it on your sources.

    1. Add a free TMDB key and the sites you are authorized to use:

      tmdb:
        api_key: "<KEY>"
      sources:
        - proxies: ["https://your-source.example"]
          templates:
            movie: "/embed/movie/{itemID}"
            episode: "/embed/tv/{itemID}/{season}-{episode}"
      
    2. Run it. The configured device, if any, is preselected:

      castor cast
      

    To skip the TUI, castor cast movie <id> and castor cast episode <id> --season N --episode N cast to the configured device.

    How it works

    Castor is one binary made of three services:

    • API server finds your TVs and controls playback. Every client talks to it.
    • Scraping server opens the page in headless Chrome and captures the video stream.
    • Media server transcodes with ffmpeg when your TV needs it, and serves the stream.
    flowchart LR
      client["castor CLI / TUI<br/>or another app"] -- castor.v1 API --> api["API server"]
      api --> scraping["Scraping server<br/>(Chrome)"]
      api --> media["Media server<br/>(ffmpeg)"]
      api -- controls playback --> tv["TV"]
      media -- video --> tv
    

    castor cast starts all three in its own process, so there is nothing to set up. Each one is also a command (castor api-server, castor media-server, castor scraping-server) you can run on another machine. Give castor its URL in config.yaml and it uses that server; anything without a URL still runs locally.

    SetupRun on the NASAdd to your config.yaml
    Everything on your computer (default)nothingnothing
    Transcoding on the NAScastor media-serverservers.media.url and its token
    Everything on the NASdocker compose up -dservers.api.url and its token

    Configuration

    The annotated config.yaml describes every setting. Castor reads it from your user config directory or the current directory:

    SystemUser config directory
    Linux~/.config/castor/
    macOS~/Library/Application Support/castor/
    Windows%AppData%\castor\

    Layers merge in this order, each over the one before:

    1. castor/config.yaml in your user config directory
    2. config.yaml in the current directory
    3. the file passed with --config <path>
    4. CASTOR_ environment variables, such as CASTOR_CAST__MAX_HEIGHT=720

    Keep secrets, like your TMDB key, in a git-ignored config.local.yaml next to the file. Coming from 1.x? See the migration guide.

    Support

    TVs

    ProtocolStatusReported working on
    DLNA / UPnPMain targetSamsung Q70 and Q80 (#15), Philips 50PUD6654 (#23)
    ChromecastExperimentalXiaomi TV Box (#5), LG C2 in Chromecast mode, from the Android client (#68)
    RokuExperimentalNot tested on hardware yet

    Also reported working, without saying which protocol:

    Cast to another TV? Tell us how it went in the What device do you cast to? discussion.

    1. Enable Developer Mode: on the remote, press Home three times, Up twice, then Right Left Right Left Right, and set a web server password.
    2. Put that password in servers.api.devices.roku.password in config.local.yaml.
    3. Cast: castor installs its channel the first time.

    Where castor runs

    PlatformInstall withNotes
    macOS, Intel and Apple siliconHomebrew, npm, release
    Linux, x86-64 and arm64npm, release, DockerThe Docker image encodes on Intel GPUs (VA-API)
    Windows, x86-64 and arm64npm, releaseAllow castor on private networks
    Android, in TermuxNot documented yetReported by @d4nnABR (#24). Discovery fails there, so set device.host to the TV's IP
    Android, as an appcastor-androidA community project

    Castor uses a hardware encoder when ffmpeg has one that works, and software otherwise.

    Self-host on a NAS

    The Docker image bundles Chrome and ffmpeg. Run it with Linux host networking, so the NAS can find your TVs and they can reach it.

    Transcoding only

    Your computer still controls the TV; the NAS transcodes.

    1. On the NAS, with servers.media.token in its config.yaml (add --device /dev/dri for Intel VA-API):

      docker run -d --network host -v "$PWD/config.yaml:/config.yaml:ro" \
        ghcr.io/stupside/castor:latest media-server
      
    2. On your computer:

      servers:
        media:
          url: http://my-nas:8410
          token: "<same token as the NAS>"
      

    The whole stack

    The NAS runs all three services; your computer, and any other client, only sends commands.

    1. On the NAS, next to docker-compose.yml and a config.yaml (it can be empty), put one token per service in .env:

      CASTOR_SERVERS__API__TOKEN=<random>
      CASTOR_SERVERS__MEDIA__TOKEN=<random>
      CASTOR_SERVERS__SCRAPING__TOKEN=<random>
      
    2. Run docker compose up -d. Remove its /dev/dri lines if the NAS has no Intel GPU.

    3. On your computer:

      servers:
        api:
          url: http://my-nas:8411
          token: "<CASTOR_SERVERS__API__TOKEN>"
      

    Ports, HTTPS and image tags are in ARCHITECTURE.md.

    Build on the API

    Everything the CLI does goes through the public castor.v1 API: list devices, find the streams on a page, start, watch or stop a cast. Use it over Connect, with generated clients or plain HTTP and JSON.

    Community projects

    Built something on castor? Open a pull request to add it here.

    Troubleshooting

    SymptomCheck
    No devices foundDiscovery stays on one subnet. Set device.host to the TV's IP (always on Android/Termux).
    Two devices share a nameSet device.id to the ID castor scan prints.
    Page video not foundThe video must start without a click; DRM streams are refused.
    TV loads but cannot playForce relayed playback: CASTOR_CAST__DELIVERY=serve castor --debug cast url <url>.
    TV cannot fetch the videoAllow Castor through the firewall; check servers.media.advertise.
    PortDirectionUsed for
    UDP 1900DiscoveryFinding DLNA TVs and Rokus (SSDP)
    UDP 5353DiscoveryFinding Chromecasts (mDNS)
    A random LAN port, or TCP 8410TV to castorThe TV fetching the video from the embedded media server, or from a standalone one
    TCP 8411, 8412Clients to castorA standalone API server and scraping server
    TCP 8009, 8060Castor to TVControlling a Chromecast, or a Roku (port 80 to install the channel)

    A DLNA TV is controlled on whatever port it advertises.

    Contributing

    Bug reports, device reports and fixes are welcome: CONTRIBUTING.md explains how to build castor and what fits the project. Castor is provided as is, for personal and educational use; you are responsible for using it lawfully and within each site's terms.