Skip to content

Commit 13e42cb

Browse files
committed
Replace * binding with Ctrl+B and rename favorite to bookmark
Layout-unstable * is remapped to Ctrl+B (layout-stable Ctrl+letter). Playlist-track favorites are renamed to bookmarks throughout: struct field, playlist/provider APIs, CLI subcommands (playlist bookmark/ bookmarks), TOML key, JSON output. The TOML reader still accepts the legacy favorite key for backward compatibility with existing playlists. The unrelated radio-station FavoriteToggler is left untouched.
1 parent 3cad406 commit 13e42cb

17 files changed

Lines changed: 117 additions & 117 deletions

cmd/playlist.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func PlaylistShow(name string, jsonOutput bool) error {
156156
Year int `json:"year,omitempty"`
157157
TrackNumber int `json:"track_number,omitempty"`
158158
DurationSecs int `json:"duration_secs,omitempty"`
159-
Favorite bool `json:"favorite,omitempty"`
159+
Bookmark bool `json:"bookmark,omitempty"`
160160
}
161161
out := make([]jsonTrack, len(tracks))
162162
for i, t := range tracks {
@@ -169,7 +169,7 @@ func PlaylistShow(name string, jsonOutput bool) error {
169169
Year: t.Year,
170170
TrackNumber: t.TrackNumber,
171171
DurationSecs: t.DurationSecs,
172-
Favorite: t.Favorite,
172+
Bookmark: t.Bookmark,
173173
}
174174
}
175175
enc := json.NewEncoder(os.Stdout)
@@ -219,15 +219,15 @@ func PlaylistDelete(name string) error {
219219
return nil
220220
}
221221

222-
// PlaylistFavorite toggles the favorite flag on a track by index.
223-
func PlaylistFavorite(name string, index int) error {
222+
// PlaylistBookmark toggles the bookmark flag on a track by index.
223+
func PlaylistBookmark(name string, index int) error {
224224
prov, err := newProvider()
225225
if err != nil {
226226
return err
227227
}
228228

229-
if err := prov.SetFavorite(name, index-1); err != nil {
230-
return fmt.Errorf("toggling favorite: %w", err)
229+
if err := prov.SetBookmark(name, index-1); err != nil {
230+
return fmt.Errorf("toggling bookmark: %w", err)
231231
}
232232

233233
tracks, err := prov.Tracks(name)
@@ -238,16 +238,16 @@ func PlaylistFavorite(name string, index int) error {
238238
return fmt.Errorf("track %d no longer exists in playlist (now has %d tracks)", index, len(tracks))
239239
}
240240
t := tracks[index-1]
241-
if t.Favorite {
241+
if t.Bookmark {
242242
fmt.Printf("★ %s\n", t.DisplayName())
243243
} else {
244244
fmt.Printf("☆ %s\n", t.DisplayName())
245245
}
246246
return nil
247247
}
248248

249-
// PlaylistFavorites lists all favorited tracks across all playlists.
250-
func PlaylistFavorites() error {
249+
// PlaylistBookmarks lists all bookmarked tracks across all playlists.
250+
func PlaylistBookmarks() error {
251251
prov, err := newProvider()
252252
if err != nil {
253253
return err
@@ -265,17 +265,17 @@ func PlaylistFavorites() error {
265265
continue
266266
}
267267
for i, t := range tracks {
268-
if t.Favorite {
268+
if t.Bookmark {
269269
fmt.Printf(" ★ [%s] %d. %s\n", pl.Name, i+1, t.DisplayName())
270270
total++
271271
}
272272
}
273273
}
274274

275275
if total == 0 {
276-
fmt.Println("No favorites yet. Press * on a track to favorite it.")
276+
fmt.Println("No bookmarks yet. Press Ctrl+B on a track to bookmark it.")
277277
} else {
278-
fmt.Printf("\n %d favorites across %d playlists.\n", total, len(lists))
278+
fmt.Printf("\n %d bookmarks across %d playlists.\n", total, len(lists))
279279
}
280280
return nil
281281
}

commands.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -315,24 +315,24 @@ func playlistCommand() *cli.Command {
315315
},
316316
},
317317
{
318-
Name: "favorite",
319-
Usage: "toggle favorite on a track by index",
318+
Name: "bookmark",
319+
Usage: "toggle bookmark on a track by index",
320320
ArgsUsage: "\"Name\"",
321321
Flags: []cli.Flag{
322322
&cli.IntFlag{Name: "index", Usage: "track index (1-based)", Required: true},
323323
},
324324
Action: func(ctx context.Context, c *cli.Command) error {
325325
if c.Args().Len() == 0 {
326-
return fmt.Errorf("usage: cliamp playlist favorite \"Name\" --index N")
326+
return fmt.Errorf("usage: cliamp playlist bookmark \"Name\" --index N")
327327
}
328-
return cmd.PlaylistFavorite(c.Args().First(), int(c.Int("index")))
328+
return cmd.PlaylistBookmark(c.Args().First(), int(c.Int("index")))
329329
},
330330
},
331331
{
332-
Name: "favorites",
333-
Usage: "list all favorited tracks across playlists",
332+
Name: "bookmarks",
333+
Usage: "list all bookmarked tracks across playlists",
334334
Action: func(ctx context.Context, c *cli.Command) error {
335-
return cmd.PlaylistFavorites()
335+
return cmd.PlaylistBookmarks()
336336
},
337337
},
338338
{

docs/keybindings.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Press `Ctrl+K` in the player to see all keybindings.
7070
| `p` | Playlist manager |
7171
| `r` | Cycle repeat (Off / All / One) |
7272
| `z` | Toggle shuffle |
73+
| `Ctrl+B` | Toggle bookmark ★ on selected track |
7374

7475
## General
7576

external/local/provider.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -192,16 +192,16 @@ func (p *Provider) savePlaylist(name string, tracks []playlist.Track) error {
192192
return os.Rename(tmp, path)
193193
}
194194

195-
// SetFavorite toggles the favorite flag on a track and rewrites the playlist.
196-
func (p *Provider) SetFavorite(playlistName string, idx int) error {
195+
// SetBookmark toggles the bookmark flag on a track and rewrites the playlist.
196+
func (p *Provider) SetBookmark(playlistName string, idx int) error {
197197
tracks, err := p.loadTOMLByName(playlistName)
198198
if err != nil {
199199
return err
200200
}
201201
if idx < 0 || idx >= len(tracks) {
202202
return fmt.Errorf("index %d out of range (playlist has %d tracks)", idx, len(tracks))
203203
}
204-
tracks[idx].Favorite = !tracks[idx].Favorite
204+
tracks[idx].Bookmark = !tracks[idx].Bookmark
205205
return p.savePlaylist(playlistName, tracks)
206206
}
207207

@@ -277,8 +277,8 @@ func writeTrack(w io.Writer, t playlist.Track) {
277277
if t.DurationSecs != 0 {
278278
fmt.Fprintf(w, "duration_secs = %d\n", t.DurationSecs)
279279
}
280-
if t.Favorite {
281-
fmt.Fprintln(w, "favorite = true")
280+
if t.Bookmark {
281+
fmt.Fprintln(w, "bookmark = true")
282282
}
283283
}
284284

@@ -349,8 +349,9 @@ func (p *Provider) loadTOML(path string) ([]playlist.Track, error) {
349349
if n, err := strconv.Atoi(val); err == nil {
350350
current.DurationSecs = n
351351
}
352-
case "favorite":
353-
current.Favorite = val == "true"
352+
case "bookmark", "favorite":
353+
// "favorite" accepted for backward compatibility with playlists saved before the rename.
354+
current.Bookmark = val == "true"
354355
}
355356
}
356357
if current != nil {

external/local/provider_test.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ func TestWriteTrackMinimal(t *testing.T) {
7979
if strings.Contains(got, "artist") {
8080
t.Fatal("empty artist should not be written")
8181
}
82-
if strings.Contains(got, "favorite") {
83-
t.Fatal("false favorite should not be written")
82+
if strings.Contains(got, "bookmark") {
83+
t.Fatal("false bookmark should not be written")
8484
}
8585
}
8686

@@ -95,7 +95,7 @@ func TestWriteTrackAllFields(t *testing.T) {
9595
Year: 2024,
9696
TrackNumber: 3,
9797
DurationSecs: 240,
98-
Favorite: true,
98+
Bookmark: true,
9999
Feed: true,
100100
})
101101
got := buf.String()
@@ -109,7 +109,7 @@ func TestWriteTrackAllFields(t *testing.T) {
109109
"year = 2024",
110110
"track_number = 3",
111111
"duration_secs = 240",
112-
"favorite = true",
112+
"bookmark = true",
113113
"feed = true",
114114
} {
115115
if !strings.Contains(got, want) {
@@ -125,7 +125,7 @@ func TestLoadTOMLRoundTrip(t *testing.T) {
125125
os.MkdirAll(p.dir, 0o755)
126126

127127
tracks := []playlist.Track{
128-
{Path: "/a.mp3", Title: "A", Artist: "Art1", Album: "Alb", Year: 2020, TrackNumber: 1, DurationSecs: 180, Favorite: true},
128+
{Path: "/a.mp3", Title: "A", Artist: "Art1", Album: "Alb", Year: 2020, TrackNumber: 1, DurationSecs: 180, Bookmark: true},
129129
{Path: "/b.flac", Title: "B", Genre: "Jazz", Feed: true},
130130
}
131131

@@ -144,8 +144,8 @@ func TestLoadTOMLRoundTrip(t *testing.T) {
144144
if loaded[0].Path != "/a.mp3" || loaded[0].Title != "A" || loaded[0].Artist != "Art1" {
145145
t.Fatalf("track 0 mismatch: %+v", loaded[0])
146146
}
147-
if !loaded[0].Favorite {
148-
t.Fatal("track 0 should be favorite")
147+
if !loaded[0].Bookmark {
148+
t.Fatal("track 0 should be bookmarked")
149149
}
150150
if loaded[0].Year != 2020 || loaded[0].TrackNumber != 1 || loaded[0].DurationSecs != 180 {
151151
t.Fatalf("track 0 numeric fields mismatch: %+v", loaded[0])
@@ -267,37 +267,37 @@ func TestExists(t *testing.T) {
267267
}
268268
}
269269

270-
// --- SetFavorite ---
270+
// --- SetBookmark ---
271271

272-
func TestSetFavorite(t *testing.T) {
272+
func TestSetBookmark(t *testing.T) {
273273
p := newTestProvider(t)
274-
p.AddTrack("favs", playlist.Track{Path: "/a.mp3", Title: "A"})
274+
p.AddTrack("marks", playlist.Track{Path: "/a.mp3", Title: "A"})
275275

276-
if err := p.SetFavorite("favs", 0); err != nil {
277-
t.Fatalf("SetFavorite: %v", err)
276+
if err := p.SetBookmark("marks", 0); err != nil {
277+
t.Fatalf("SetBookmark: %v", err)
278278
}
279279

280-
tracks, _ := p.Tracks("favs")
281-
if !tracks[0].Favorite {
282-
t.Fatal("track should be favorite after toggle")
280+
tracks, _ := p.Tracks("marks")
281+
if !tracks[0].Bookmark {
282+
t.Fatal("track should be bookmarked after toggle")
283283
}
284284

285285
// Toggle off.
286-
p.SetFavorite("favs", 0)
287-
tracks, _ = p.Tracks("favs")
288-
if tracks[0].Favorite {
289-
t.Fatal("track should not be favorite after second toggle")
286+
p.SetBookmark("marks", 0)
287+
tracks, _ = p.Tracks("marks")
288+
if tracks[0].Bookmark {
289+
t.Fatal("track should not be bookmarked after second toggle")
290290
}
291291
}
292292

293-
func TestSetFavoriteOutOfRange(t *testing.T) {
293+
func TestSetBookmarkOutOfRange(t *testing.T) {
294294
p := newTestProvider(t)
295295
p.AddTrack("one", playlist.Track{Path: "/a.mp3", Title: "A"})
296296

297-
if err := p.SetFavorite("one", 5); err == nil {
297+
if err := p.SetBookmark("one", 5); err == nil {
298298
t.Fatal("expected error for out-of-range index")
299299
}
300-
if err := p.SetFavorite("one", -1); err == nil {
300+
if err := p.SetBookmark("one", -1); err == nil {
301301
t.Fatal("expected error for negative index")
302302
}
303303
}

playlist/playlist.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type Track struct {
4242
Realtime bool // true for real-time/live streams (e.g. radio)
4343
Feed bool // true for RSS/podcast feed URLs (resolved before playback)
4444
DurationSecs int // known duration in seconds (0 = unknown)
45-
Favorite bool // user-favorited track
45+
Bookmark bool // user-bookmarked track
4646

4747
Unplayable bool // true when the track is known not playable in the current playback context
4848

@@ -699,18 +699,18 @@ func (p *Playlist) SetTrack(i int, t Track) {
699699
// Tracks returns all tracks in the playlist.
700700
func (p *Playlist) Tracks() []Track { return p.tracks }
701701

702-
// ToggleFavorite flips the Favorite flag on the track at the given index.
703-
func (p *Playlist) ToggleFavorite(idx int) {
702+
// ToggleBookmark flips the Bookmark flag on the track at the given index.
703+
func (p *Playlist) ToggleBookmark(idx int) {
704704
if idx >= 0 && idx < len(p.tracks) {
705-
p.tracks[idx].Favorite = !p.tracks[idx].Favorite
705+
p.tracks[idx].Bookmark = !p.tracks[idx].Bookmark
706706
}
707707
}
708708

709-
// FavoriteCount returns the number of favorited tracks.
710-
func (p *Playlist) FavoriteCount() int {
709+
// BookmarkCount returns the number of bookmarked tracks.
710+
func (p *Playlist) BookmarkCount() int {
711711
n := 0
712712
for _, t := range p.tracks {
713-
if t.Favorite {
713+
if t.Bookmark {
714714
n++
715715
}
716716
}

playlist/shuffle_repeat_test.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -141,46 +141,46 @@ func TestSetTrackOutOfBounds(t *testing.T) {
141141
}
142142
}
143143

144-
func TestToggleFavorite(t *testing.T) {
144+
func TestToggleBookmark(t *testing.T) {
145145
p := makePlaylist(3, false)
146146

147-
p.ToggleFavorite(0)
148-
if !p.Tracks()[0].Favorite {
149-
t.Fatal("track 0 should be favorited")
147+
p.ToggleBookmark(0)
148+
if !p.Tracks()[0].Bookmark {
149+
t.Fatal("track 0 should be bookmarked")
150150
}
151-
if p.FavoriteCount() != 1 {
152-
t.Fatalf("FavoriteCount() = %d, want 1", p.FavoriteCount())
151+
if p.BookmarkCount() != 1 {
152+
t.Fatalf("BookmarkCount() = %d, want 1", p.BookmarkCount())
153153
}
154154

155-
p.ToggleFavorite(0) // toggle off
156-
if p.Tracks()[0].Favorite {
157-
t.Fatal("track 0 should be unfavorited")
155+
p.ToggleBookmark(0) // toggle off
156+
if p.Tracks()[0].Bookmark {
157+
t.Fatal("track 0 should be unbookmarked")
158158
}
159-
if p.FavoriteCount() != 0 {
160-
t.Fatalf("FavoriteCount() = %d, want 0", p.FavoriteCount())
159+
if p.BookmarkCount() != 0 {
160+
t.Fatalf("BookmarkCount() = %d, want 0", p.BookmarkCount())
161161
}
162162
}
163163

164-
func TestToggleFavoriteOutOfBounds(t *testing.T) {
164+
func TestToggleBookmarkOutOfBounds(t *testing.T) {
165165
p := makePlaylist(3, false)
166166

167167
// Should be no-op, not panic
168-
p.ToggleFavorite(-1)
169-
p.ToggleFavorite(5)
168+
p.ToggleBookmark(-1)
169+
p.ToggleBookmark(5)
170170

171-
if p.FavoriteCount() != 0 {
172-
t.Fatal("favorites were modified by out-of-bounds ToggleFavorite")
171+
if p.BookmarkCount() != 0 {
172+
t.Fatal("bookmarks were modified by out-of-bounds ToggleBookmark")
173173
}
174174
}
175175

176-
func TestFavoriteCount(t *testing.T) {
176+
func TestBookmarkCount(t *testing.T) {
177177
p := makePlaylist(5, false)
178178

179-
p.ToggleFavorite(0)
180-
p.ToggleFavorite(2)
181-
p.ToggleFavorite(4)
179+
p.ToggleBookmark(0)
180+
p.ToggleBookmark(2)
181+
p.ToggleBookmark(4)
182182

183-
if got := p.FavoriteCount(); got != 3 {
184-
t.Fatalf("FavoriteCount() = %d, want 3", got)
183+
if got := p.BookmarkCount(); got != 3 {
184+
t.Fatalf("BookmarkCount() = %d, want 3", got)
185185
}
186186
}

provider/interfaces.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ type PlaylistDeleter interface {
6767
RemoveTrack(name string, index int) error
6868
}
6969

70-
// FavoriteSetter is implemented by providers that support toggling
71-
// track favorites and persisting them.
72-
type FavoriteSetter interface {
73-
SetFavorite(playlistName string, idx int) error
70+
// BookmarkSetter is implemented by providers that support toggling
71+
// track bookmarks and persisting them.
72+
type BookmarkSetter interface {
73+
SetBookmark(playlistName string, idx int) error
7474
}
7575

7676
// CustomStreamer is implemented by providers that need a custom audio

site/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,7 @@
18661866
<div class="key-row"><kbd>o</kbd><span>Open file browser</span></div>
18671867
<div class="key-row"><kbd>a / A</kbd><span>Queue (play next) / Queue manager</span></div>
18681868
<div class="key-row"><kbd>p</kbd><span>Playlist manager</span></div>
1869+
<div class="key-row"><kbd>Ctrl+B</kbd><span>Toggle bookmark &#9733;</span></div>
18691870
<div class="key-row"><kbd>L</kbd><span>Browse local playlists</span></div>
18701871
<div class="key-row"><kbd>Ctrl+X</kbd><span>Expand playlist</span></div>
18711872
</div>

ui/model/audio.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"strconv"
66
"strings"
77
"time"
8-
98
)
109

1110
const speedSaveDebounce = time.Second

0 commit comments

Comments
 (0)