115 lines
11 KiB
Markdown
115 lines
11 KiB
Markdown
# Terebi
|
|
|
|
A native macOS player for local media, yt-dlp-supported videos (including YouTube) and Miruro episodes, with ordered playback queues, saved playback positions, compact mode and Chromecast support.
|
|
|
|
## Build and install
|
|
|
|
Requires macOS 15+, Xcode Command Line Tools with Swift 6, Python 3.9+ and Homebrew build tools. Build natively on Apple Silicon or Intel; Rosetta and cross-architecture builds are not supported.
|
|
|
|
```sh
|
|
brew install pkg-config meson ninja
|
|
# Intel Macs also need: brew install nasm
|
|
make install
|
|
export PATH="$HOME/.local/bin:$PATH"
|
|
```
|
|
|
|
Open **Terebi** from `~/Applications` or Spotlight. The CLI is installed at `~/.local/bin/terebi`; add that directory to your shell's `PATH` to keep it available.
|
|
|
|
The first build downloads dependencies. Quit Terebi before updating, then run `make install` again. To install elsewhere, use `make install APPDIR="/Applications"` (requires a writable directory) or set `PREFIX` to change the CLI prefix.
|
|
|
|
To run without installing, use `make run`. The built `.build/terebi.app` is self-contained; no separate FFmpeg, Python or yt-dlp installation is needed at runtime. Builds are ad-hoc signed, not notarized. Bundled licenses and source archives are in the app's Resources; public binary redistribution needs a separate license audit.
|
|
|
|
## Usage
|
|
|
|
- **Local files:** use **⌘O**, drag files onto the player, or choose Finder's **Open With**. Multiple files form a queue in natural filename order, with automatic advance. Use **View → Show Queue** to play, reorder or remove items; **+ → file icon** or dropping files onto the sidebar appends them. The queue lasts only for the session; opening other media replaces it.
|
|
- **Streams:** use **Open Stream…** (**⇧⌘O**) or drop an HTTP(S) video link. To append without replacing playback, press the sidebar's **+**, then the **link icon**: the URL field opens upwards; **Return** fetches and adds the video. The link icon toggles the field; **Esc** dismisses it and cancels a pending fetch. Fetch errors leave the queue unchanged. Links are passed to the bundled yt-dlp without a site allowlist; extraction must return a single streamable video, not a playlist or channel. Miruro keeps its dedicated resolver: links must use `https://barelystarted.miruro.tv/watch/<opaque-id>/<slug>?ep=<episode>` with an explicit positive episode number.
|
|
- **Stream queues:** integrations can supply an ordered yt-dlp/Miruro queue with `--new-instance --queue-file /absolute/queue.json`, or append without interrupting the running player using `--enqueue --queue-file /absolute/queue.json` (also for a single item). Enqueue starts playback if the player is empty or not running. The same sidebar supports play, reorder, remove, previous/next and automatic advance. Unresolved titles, including the selected row, load serially at lower priority without waiting for playback loading, buffering or quality extraction. YouTube uses a title-only oEmbed request; other sites use yt-dlp metadata and Miruro uses optional episode metadata. Arrival still depends on the site/network; failed lookups retain the supplied label, and full playback metadata takes precedence. Playback sources still resolve fresh when selected or revisited; local-file batches still use natural filename order. yt-dlp items use the original page URL for resume and version-1 progress reports; recognized YouTube video URLs still canonicalize.
|
|
- **Seeking:** click or drag the progress track or thumb to seek. The thumb centers on the cursor, clamped to the track endpoints.
|
|
- **Miruro metadata:** titles and opening/ending intervals load independently of playback when available. Small rounded gaps mark interval boundaries in the slider. Inside a segment, **Skip Opening** or **Skip Ending** appears at the top-right below the titlebar for up to ten seconds or until the segment ends; clicking seeks to its end. A light background fill grows as the offer expires, with a short entrance/exit transition; Reduce Motion uses stepped countdown updates without the transition. Ignored offers stay dismissed until the media is closed or replaced. Missing/invalid metadata leaves playback usable, and timings may differ between cuts. Nothing skips automatically.
|
|
- **Resume:** videos resume their saved position; finished videos restart from the beginning. Live and audio-only media do not save progress.
|
|
- **Compact mode:** press **P** for a floating player; double-click it to restore. Drag noninteractive areas to move the window. The queue starts hidden each time you enter compact mode; **⇧⌘L** or **gear → Show Queue** expands it below the video. Its top fade has a 12-point solid section and a 20-point transition, with the first row starting below both. The same shortcut toggles the normal sidebar, whose visibility is preserved when leaving compact mode. Use the titlebar pin to keep the normal window on top.
|
|
- **Quality:** yt-dlp defaults to SDR up to 1080p when resolution is reported. Missing resolution/codec hints are left to native probing. Use **gear → Quality** for other reported resolutions or automatic quality.
|
|
|
|
### Keyboard shortcuts
|
|
|
|
| Action | Default shortcut |
|
|
| --- | --- |
|
|
| Play / pause | Space or K |
|
|
| Seek backward / forward 5 seconds | ← / → |
|
|
| Seek backward / forward 10 seconds | J / L |
|
|
| Step one frame backward / forward | , / . |
|
|
| Volume down / up | ↓ / ↑ |
|
|
| Mute / unmute | M |
|
|
| Fullscreen | F or ⌃⌘F; Esc to leave |
|
|
| Compact mode | P or ⌃⌘P |
|
|
| Show/hide queue (normal or compact) | ⇧⌘L |
|
|
| Always on top | ⇧P |
|
|
| Close media | ⇧⌘W |
|
|
| Quit | Q or ⌘Q |
|
|
|
|
### Chromecast
|
|
|
|
Open media, select the **Cast** icon or **Playback → Cast to Device**, and choose a receiver on the same LAN. Allow macOS Local Network access and incoming firewall connections. Use **Find Cast Devices…** to retry discovery.
|
|
|
|
Playback controls and queue navigation work on the receiver. **Play on This Mac** returns to local playback at the receiver's position. Keep the Mac connected: it relays the media and prevents idle system sleep during playback, while allowing display sleep when casting. Closing the lid or explicitly sleeping the Mac can interrupt playback.
|
|
|
|
Cast output is limited to 1080p/30 fps; frame stepping and stream quality changes are local-only. Use Cast only on a trusted network. AirPlay is not supported.
|
|
|
|
## Command line
|
|
|
|
```sh
|
|
terebi "/path/to/video.mp4"
|
|
terebi 'https://youtu.be/jNQXAC9IVRw'
|
|
terebi --new-instance --no-config "/path/to/video.mp4"
|
|
terebi --enqueue --queue-file "/absolute/private/session/queue.json"
|
|
terebi --help
|
|
```
|
|
|
|
The CLI opens one file or supported stream, reusing the running player by default. With no arguments, it opens or activates the player. `--new-instance` starts a separate player; `--no-config` uses built-in settings on a fresh launch. Put these options before the media argument. Before installation, use `.build/terebi` instead of `terebi`.
|
|
|
|
For native episode-URL playback, ordered stream queues, external resolved sources and progress reporting, see the [integration contract](docs/miruro-playback-handoff.md).
|
|
|
|
## Configuration
|
|
|
|
The optional config file is `~/.config/terebi/config.toml`, or `$XDG_CONFIG_HOME/terebi/config.toml` when `XDG_CONFIG_HOME` is absolute. To print all supported settings and key bindings:
|
|
|
|
```sh
|
|
terebi --default-config
|
|
```
|
|
|
|
Copy the settings you want to change into the config file; omitted settings keep their defaults. Settings load at startup, so restart the player after editing. Changes made through menus are session-only.
|
|
|
|
The queue shortcut can be rebound with `show_queue` and `hide_queue` under `[keys]`; give both actions the same chord to keep a single toggle.
|
|
|
|
### Miruro providers
|
|
|
|
Choose **Playback → Miruro → Video Host** or **Caption Provider** in Terebi's menu bar, or use **gear → Miruro**, to change providers for the session. Choices retain both provider and track: `ssub` (soft subtitles), `sub` (hard subtitles), or `dub` (dubbed audio). Video and caption providers are independent; available choices come from the episode response. These menus do not write the config file.
|
|
|
|
Optional startup preferences:
|
|
|
|
```toml
|
|
[miruro]
|
|
video_provider = ""
|
|
caption_provider = ""
|
|
```
|
|
|
|
An empty or omitted preference means **Auto**. Automatic video selection prefers Japanese Sun, then the returned provider order; each provider's variant order is respected. A bare name such as `"bee"` prefers that provider's Japanese variant; `"bee:ssub"` or `"sun:sub"` selects a specific variant. Dub requires an explicit choice such as `"bun:dub"`—it is never an automatic language fallback. Dub-only episodes retain their choices in the menu after Automatic reports that no Japanese source is available.
|
|
|
|
Automatic captions prefer the selected provider/track, then a compatible track from that provider, Sun, and returned order. Caption discovery is independent of video compatibility, including iframe-only providers. Missing preferences fall back to automatic selection. Provider names accept up to 128 ASCII letters, digits, underscores or hyphens, optionally followed by `:ssub`, `:sub` or `:dub`. Unknown config keys and non-string values are rejected.
|
|
|
|
Native playback supports the returned proxy configuration and HLS query/segment-origin rules used by Bee/Hop. MegaPlay iframe sources used by Bun are extracted natively; no embedded browser, browser cookies or advertising scripts are run. Unsupported embed hosts fail rather than being passed to the native decoder. Source expiry and upstream deployment changes can still interrupt playback.
|
|
|
|
## Limitations
|
|
|
|
- SDR output only; HDR is not supported.
|
|
- No embedded or YouTube captions, manual audio-track selection, rotation or deinterlacing. External WebVTT subtitles are supported for resolved streams.
|
|
- yt-dlp support does not guarantee playback: extraction must yield HTTP(S)/HLS media without download-only fragment assembly. Audio-only results with explicit codec metadata are unsupported. Private, age-restricted, region-blocked or sign-in-required videos may fail; browser cookies are not used. Rebuild and reinstall for bundled extractor updates.
|
|
- Seeking can be slow on long-GOP or unindexed media. Live streams cannot be sought, and expired stream URLs are not automatically refreshed.
|
|
- Audio-device changes during playback are not handled.
|
|
|
|
## Development
|
|
|
|
Install FFmpeg for test fixtures (`brew install ffmpeg`), then run `make check`. The suite requires a graphical macOS session and a working audio device; it launches players and plays short test audio. See the [Makefile](Makefile) for individual check targets.
|
|
|
|
For the focused native compact-queue smoke (transparent, noninteractive app window), run `TEREBI_CHECK_COMPACT_QUEUE_ONLY=1 make check-startup`. `make check-window check-config` covers dropdown geometry, resizing, metadata aspect changes, restoration and configurable queue shortcuts without displaying windows.
|