Documentation
¶
Overview ¶
Package player is pixeltui's headless audio engine: it resolves a track to a playable stream and drives mpv (with ffplay/afplay fallbacks) over IPC. It has no dependency on the terminal UI, so any front-end — the TUI, the pocket hardware client, or the server — can reuse it. The TUI wraps these calls in tea.Cmds; pocket consumes Watch()/Media() directly.
Index ¶
- func CleanupCovers()
- func CoverFor(artURL string) string
- func EnsureVideoID(c engine.Candidate) engine.Candidate
- func MPVAvailable() bool
- func Offline() bool
- func OutputRegistry() *output.Registry
- func Resolve(videoID string) (string, error)
- func SetAudioDevice(dev string)
- func SetCache(c Cache)
- func SetOffline(b bool)
- func SetOutputRegistry(r *output.Registry)
- func YtdlpPath() string
- type Cache
- type MediaCmd
- type State
- type Stream
- func (s *Stream) CanControl() bool
- func (s *Stream) CurrentEntryID() int
- func (s *Stream) Duration() float64
- func (s *Stream) Ended() bool
- func (s *Stream) Gapless(removeID int, url, title, cover string) (int, error)
- func (s *Stream) IsPaused() bool
- func (s *Stream) Media() <-chan MediaCmd
- func (s *Stream) Pause()
- func (s *Stream) Position() float64
- func (s *Stream) Restart()
- func (s *Stream) Seek(sec float64)
- func (s *Stream) SetTitle(title string)
- func (s *Stream) SetVolume(v int)
- func (s *Stream) Stop()
- func (s *Stream) Volume() int
- func (s *Stream) Watch(ctx context.Context, every time.Duration) <-chan State
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CleanupCovers ¶
func CleanupCovers()
CleanupCovers removes all generated cover PNGs (call on exit).
func CoverFor ¶
CoverFor returns a cached pixelated cover PNG for artURL, generating it on first use. Returns "" if unavailable. Safe for concurrent calls.
func EnsureVideoID ¶
EnsureVideoID enriches a candidate with a YouTube Music video id (+ duration and art) if it doesn't already have one. Recommender candidates arrive bare; ytmusic search results already carry these.
func MPVAvailable ¶
func MPVAvailable() bool
MPVAvailable reports whether mpv is installed (gates playback controls).
func Offline ¶
func Offline() bool
Offline reports whether network resolution is currently gated off.
func OutputRegistry ¶
OutputRegistry returns the active sink registry, creating a default one if needed. Useful for menus that list available sinks.
func Resolve ¶
Resolve turns a video id into a direct CDN audio URL (InnerTube first, yt-dlp fallback), caching the result by video id. Convenience wrapper that resolves the yt-dlp path itself.
func SetAudioDevice ¶
func SetAudioDevice(dev string)
SetAudioDevice pins the mpv --audio-device for subsequently started streams. Empty (the default) uses mpv's default output device. It also updates the "mpv-device" sink in the output registry, so capability-driven menus see it.
func SetCache ¶
func SetCache(c Cache)
SetCache installs the resolved-URL disk cache (nil disables caching).
func SetOutputRegistry ¶
SetOutputRegistry replaces the active sink registry. Callers that want a custom sink list (e.g. a Bluetooth or AirPlay renderer) use this; the registry is still consulted in mpvBaseArgs.
Types ¶
type Cache ¶
type Cache interface {
GetStreamURL(videoID string) (string, bool)
PutStreamURL(videoID, url string, expire int64)
}
Cache caches resolved CDN URLs to disk (implemented by store.Cache).
type MediaCmd ¶
type MediaCmd int
MediaCmd is an OS / hardware transport command observed from mpv. On the desktop these come from OS media keys / the Now Playing widget; on pocket hardware the GPIO buttons feed this same channel.
type State ¶
State is a snapshot of playback for headless consumers (pocket, serve) that can't use the TUI's tea-driven poll loop.
type Stream ¶
type Stream struct {
// contains filtered or unexported fields
}
Stream holds one active audio stream.
func Attach ¶
Attach wraps an already-running mpv IPC socket as a controllable Stream without spawning a process — for front-ends that drive a player they didn't start (and for tests). ended is closed when the underlying player exits; an open channel means "still playing".
func Start ¶
Start begins streaming a candidate. We ALWAYS resolve the direct CDN URL ourselves (fast android_vr client) and hand it to the player — mpv's internal ytdl hook is slow/fragile (it hangs on music.youtube URLs), so we never rely on it. Resolution order:
- resolve CDN URL (preloaded if available, else InnerTube/yt-dlp)
- play it: mpv (IPC controls) → ffplay (opus-capable)
- fallback: yt-dlp | ffplay pipe, then afplay proxy (m4a) — for odd cases
Returns the (possibly enriched) candidate so the UI gets duration/art.
func (*Stream) CanControl ¶
CanControl reports whether IPC control (pause/seek/volume) is available.
func (*Stream) CurrentEntryID ¶
CurrentEntryID reports the playlist entry id mpv is currently on (0 if unknown) — how a poll loop notices a gapless auto-advance.
func (*Stream) Gapless ¶
Gapless reconciles mpv's playlist with the queue head: it drops a stale previously-appended entry (removeID; 0 = none) and, if url != "", appends the next track right after the current one so the natural end-of-track boundary plays on inside the running mpv (no respawn). Returns the new entry id.
func (*Stream) Media ¶
Media returns the channel of OS/hardware transport commands (nil for a non-mpv fallback player). On pocket hardware the GPIO buttons feed this same channel; re-read it after each command to keep listening.
func (*Stream) Restart ¶
func (s *Stream) Restart()
Restart seeks the current track back to the beginning (OS "previous" → restart).
func (*Stream) Stop ¶
func (s *Stream) Stop()
Stop kills the player (and any yt-dlp feeder) and cleans up the IPC socket.