Skip to content

Commit 0fe6a35

Browse files
committed
feat: first commit
0 parents  commit 0fe6a35

62 files changed

Lines changed: 4599 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/clean/SKILL.md

Lines changed: 670 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: Build
2+
description: Build Go binary
3+
4+
runs:
5+
using: composite
6+
steps:
7+
- run: go mod download
8+
shell: bash
9+
- run: go build -o castor .
10+
shell: bash

.github/actions/ci/lint/action.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: Lint
2+
description: Run Go linters
3+
4+
runs:
5+
using: composite
6+
steps:
7+
- run: go mod download
8+
shell: bash
9+
- run: go vet ./...
10+
shell: bash
11+
- name: Check formatting
12+
run: |
13+
unformatted=$(gofmt -s -l .)
14+
if [ -n "$unformatted" ]; then
15+
echo "Files not formatted:"
16+
echo "$unformatted"
17+
exit 1
18+
fi
19+
shell: bash

.github/actions/ci/test/action.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: Test
2+
description: Run Go tests
3+
4+
runs:
5+
using: composite
6+
steps:
7+
- run: go mod download
8+
shell: bash
9+
- run: go test -v ./...
10+
shell: bash

.github/workflows/cd.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags: ['v*']
6+
7+
permissions:
8+
contents: write
9+
packages: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
- uses: actions/setup-go@v5
19+
with:
20+
go-version-file: go.mod
21+
- uses: docker/login-action@v3
22+
with:
23+
registry: ghcr.io
24+
username: ${{ github.actor }}
25+
password: ${{ secrets.GITHUB_TOKEN }}
26+
- uses: goreleaser/goreleaser-action@v6
27+
with:
28+
distribution: goreleaser
29+
version: latest
30+
args: release --clean
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}

.github/workflows/ci.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ['**']
6+
paths-ignore:
7+
- 'docs/**'
8+
pull_request:
9+
branches: ['**']
10+
paths-ignore:
11+
- 'docs/**'
12+
13+
jobs:
14+
test:
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
go-version: ['1.25', '1.26']
19+
steps:
20+
- uses: actions/checkout@v4
21+
- uses: actions/setup-go@v5
22+
with:
23+
go-version: ${{ matrix.go-version }}
24+
- uses: ./.github/actions/ci/test
25+
26+
lint:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v4
30+
- uses: actions/setup-go@v5
31+
with:
32+
go-version-file: go.mod
33+
- uses: ./.github/actions/ci/lint

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.debug/
2+
3+
.DS_Store
4+
5+
# Personal config override (keeps private sources/paths out of version control)
6+
config.local.yaml

.goreleaser.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
version: 2
2+
project_name: castor
3+
4+
before:
5+
hooks:
6+
- go mod tidy
7+
8+
builds:
9+
- main: .
10+
env:
11+
- CGO_ENABLED=0
12+
goos: [linux, darwin, windows]
13+
goarch: [amd64, arm64]
14+
ldflags:
15+
- -s -w
16+
- -X 'github.com/stupside/castor/internal/version.Commit={{.Commit}}'
17+
- -X 'github.com/stupside/castor/internal/version.BuildTime={{.Date}}'
18+
- -X 'github.com/stupside/castor/internal/version.Version={{.Version}}'
19+
binary: castor
20+
21+
kos:
22+
- repositories:
23+
- ghcr.io/stupside/castor
24+
tags: [latest, "{{.Tag}}"]
25+
bare: true
26+
labels:
27+
org.opencontainers.image.url: "{{.GitURL}}"
28+
org.opencontainers.image.title: "{{.ProjectName}}"
29+
org.opencontainers.image.source: "{{.GitURL}}"
30+
org.opencontainers.image.version: "{{.Version}}"
31+
org.opencontainers.image.licenses: "MIT"
32+
org.opencontainers.image.revision: "{{.FullCommit}}"
33+
org.opencontainers.image.description: "Cast video streams to networked devices"
34+
org.opencontainers.image.documentation: "{{.GitURL}}/blob/main/README.md"
35+
preserve_import_paths: false
36+
platforms: [linux/amd64, linux/arm64]
37+
38+
changelog:
39+
sort: asc
40+
use: git
41+
format: "{{ .SHA }}: {{ .Message }}{{ with .AuthorUsername }} (@{{ . }}){{ end }}"
42+
filters:
43+
exclude: ["^docs:", "^test:", "^chore:"]
44+
45+
release:
46+
name_template: "v{{ .Version }}"
47+
footer: |
48+
**Full Changelog**: https://github.com/stupside/castor/compare/{{ .PreviousTag }}...{{ if .IsNightly }}nightly{{ else }}{{ .Tag }}{{ end }}
49+
50+
homebrew_casks:
51+
- name: castor
52+
description: "Cast video streams to networked devices"
53+
commit_author:
54+
name: castor
55+
email: git@castor.dev
56+
commit_msg_template: "Brew cask update for {{ .ProjectName }} version {{ .Tag }}"
57+
zap:
58+
trash: ["~/.castor/config.yml"]
59+
delete: ["~/.castor/config.yml"]
60+
repository:
61+
name: "homebrew-tap"
62+
owner: "stupside"
63+
token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}"

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 stupside
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Castor
2+
3+
Castor is a command-line tool that lets you cast online videos to your TV or any networked media device (DLNA, Chromecast) directly from your terminal.
4+
5+
My TV doesn't allow casting from most websites, so I had to find alternatives:
6+
7+
- I tried **screen mirroring**, but it introduced lag and audio/video sync issues.
8+
- I switched to an **HDMI cable**, but it made my computer unusable during playback.
9+
10+
Castor solves this by extracting the video stream, handling format compatibility, and casting directly to the device.
11+
12+
## Requirements
13+
14+
- **Chrome / Chromium** for headless stream extraction
15+
- **ffmpeg** and **ffprobe** for transcoding and format detection
16+
17+
## Usage
18+
19+
### Discover devices on your network
20+
21+
```
22+
castor scan
23+
```
24+
25+
Lists all available casting devices (name, type, address).
26+
27+
Once you find the device you want to cast to, update the `device.name` and `device.type` properties in your `config.yaml`.
28+
29+
Note that DLNA has been tested but Chromecast support is experimental.
30+
31+
### Cast a video URL
32+
33+
```
34+
castor cast url https://example.com/stream.m3u8
35+
```
36+
37+
Castor will resolve the stream (picking the best HLS variant if applicable), transcode if needed, and send it to your configured device.
38+
39+
### Cast a movie or episode using a source
40+
41+
```
42+
castor cast movie --source example tt1234567
43+
castor cast episode --source example tt1234567 --season 1 --episode 3
44+
```
45+
46+
Uses a configured source to find and cast content by ID.
47+
48+
### Cast from a direct page URL
49+
50+
```
51+
castor cast page https://example.com/some-page
52+
```
53+
54+
Extracts streams from a direct URL using the top-level capture config.
55+
56+
## Configuration
57+
58+
Castor uses a simple YAML config file (`config.yaml`) where you define:
59+
60+
- Video sources (proxies, templates, capture patterns)
61+
- Transcoding preferences
62+
- Network and browser settings
63+
- Your target device (name and type)
64+
65+
## Missing features
66+
67+
- Subtitles support
68+
- Seek actions on the TV
69+
70+
## Contributing
71+
72+
Castor might be unstable but work for simple use cases. If you want to help make it better, feel free to open a PR.

0 commit comments

Comments
 (0)