v0.33.2 57f21d6

output.go RawHistoryFolder

1// Package factory provides audio backend selection with fallback support.
2package factory
3
4import (
5	"context"
6	"errors"
7	"fmt"
8
9	"github.com/bnema/dumber/internal/application/port"
10	"github.com/bnema/dumber/internal/infrastructure/audio/null"
11	"github.com/bnema/dumber/internal/infrastructure/audio/pipewire"
12)
13
14// Selector chooses between a primary and fallback audio backend.
15// If the primary backend fails to create a stream, it falls back to the fallback.
16type Selector struct {
17	Primary  port.AudioOutputFactory
18	Fallback port.AudioOutputFactory
19}
20
21// NewStream attempts to create a stream from the primary backend.
22// If that fails, it falls back to the fallback backend.
23// Returns an error only if both backends fail.
24func (s *Selector) NewStream(ctx context.Context, format port.AudioStreamFormat) (port.AudioOutputStream, error) {
25	if s.Primary != nil {
26		stream, err := s.Primary.NewStream(ctx, format)
27		if err == nil {
28			return stream, nil
29		}
30
31		// Primary failed, try fallback
32		if s.Fallback != nil {
33			fallbackStream, fallbackErr := s.Fallback.NewStream(ctx, format)
34			if fallbackErr == nil {
35				return fallbackStream, nil
36			}
37			return nil, fmt.Errorf("audio backends failed: %w", errors.Join(err, fallbackErr))
38		}
39		return nil, fmt.Errorf("primary failed: %w; no fallback configured", err)
40	}
41
42	// No primary, try fallback only
43	if s.Fallback != nil {
44		return s.Fallback.NewStream(ctx, format)
45	}
46
47	return nil, errors.New("no audio backend configured")
48}
49
50// NewAudioOutputFactory creates the primary audio output factory with PipeWire
51// as the primary backend and null as the fallback.
52// If PipeWire stream creation fails at runtime, the Selector falls back to the
53// null backend automatically.
54func NewAudioOutputFactory() port.AudioOutputFactory {
55	pwFactory, err := pipewire.NewFactory()
56	if err != nil {
57		// Unexpected failure; use null fallback only
58		return &null.Factory{}
59	}
60
61	return &Selector{
62		Primary:  pwFactory,
63		Fallback: &null.Factory{},
64	}
65}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close