aboutsummaryrefslogtreecommitdiff
path: root/.config/emacs/lisp/evil-collection/modes/lms/evil-collection-lms.el
blob: 19ebf372cc34a64efa7f837dedebc217afbc8e3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
;;; evil-collection-lms.el --- Evil bindings for lms.el -*- lexical-binding: t -*-
;; Copyright (C) 2021-2023 Edgar Vincent

;; Author: Edgar Vincent <e-v@posteo.net>
;; URL: https://github.com/emacs-evil/evil-collection
;; Version: 0.0.1
;; Package-Requires: ((emacs "25.1"))
;; Keywords: evil, multimedia, music, logitechmediaserver, squeezebox

;; This file is not part of GNU Emacs.
;;
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation; either version 3, or (at your
;; option) any later version.
;;
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.

;;; Commentary:
;; Evil bindings for lms.el.
;;
;;; Code:
(require 'lms nil t)
(require 'evil-collection)

(defvar lms-ui-docs)
(defvar lms-ui-playing-now-mode-map)
(defvar lms-ui-players-mode-map)
(defvar lms-ui-playlist-mode-map)
(defvar lms-ui-track-info-mode-map)
(defvar lms-ui-tracks-list-mode-map)
(defvar lms--ui-editing-p)
(defvar lms--ui-pl-tracks)

(declare-function lms-ui-playing-now-refresh "lms")

(defconst evil-collection-lms-maps '(lms-ui-players-mode-map
                                     lms-ui-playing-now-mode-map
                                     lms-ui-playlist-mode-map
                                     lms-ui-track-info-mode-map
                                     lms-ui-tracks-list-mode-map
                                     lms-ui-year-album-artist-list-mode-map))

(defconst evil-collection-lms-modes '(lms-players-mode
                                      lms-ui-playing-now-mode
                                      lms-ui-track-info-mode
                                      lms-ui-players-mode
                                      lms-ui-playlist-mode
                                      lms-ui-tracks-list-mode
                                      lms-ui-year-album-artist-list-mode))

(defun evil-collection-lms-ui-track-info-mode-quit ()
  "Exit `lms-ui-track-info-mode'."
  (interactive)
  (kill-buffer "*LMS: Track Information*")
  (lms-ui-playing-now-refresh))

(defun evil-collection-lms-ui-players-mode-quit ()
  "Exit `lms-ui-players-mode'."
  (interactive)
  (kill-buffer (format "*LMS: Players*"))
  (lms-ui-playing-now-refresh))

(defun evil-collection-lms-ui-playlist-mode-quit ()
  "Exit `lms-ui-playlist-mode'."
  (interactive)
  (kill-buffer (format "*LMS: Playlist [%d tracks]*" (length lms--ui-pl-tracks)))
  (lms-ui-playing-now-refresh))

(defun evil-collection-lms-ui-tracks-list-mode-quit ()
  "Exit `lms-ui-tracks-list-mode'."
  (interactive)
  (kill-buffer)
  (lms-ui-playing-now-refresh))

(defalias 'evil-collection-lms-ui-year-album-artist-list-mode-quit
  'evil-collection-lms-ui-tracks-list-mode-quit
  "Exit lms-ui-tracks-list-mode.")

(defun evil-collection-lms-goto-line (count)
  "Move the point to line COUNT. By default the penultimate line."
  (interactive "P")
  (evil-goto-line count)
  (unless count
    (forward-line -1)))

(defun evil-collection-lms-next-line ()
  "Move the point to the next line, except if it is at the end of the buffer."
  (interactive)
  (forward-line 1)
  (when (eobp) (forward-line -1)))

(defun evil-collection-lms-ui-playing-now ()
  "Modify the *LMS: Playing Now* buffer to reflect evil keybinding changes."
  (setq-local buffer-read-only nil)
  (setq lms--ui-editing-p t)
  (while (search-forward-regexp "Press 'h' for help" nil 'noerror)
      (replace-match "")
      (insert (propertize "Press 'gh' or 'g?' for help" 'face '(variable-pitch (:height 0.85 :slant italic :foreground "gray40")))))
  (setq-local buffer-read-only t)
  (setq lms--ui-editing-p nil))

(defvar evil-collection-lms-ui-docs
  "#+TITLE: lms.el Documentation
#+AUTHOR: Iñigo Serna
#+DATE: 2020/06/14

* Introduction
This is an *emacs* frontend to interact with Squeezebox Server / Logitech Media Server.
Released under GPL version 3 license or later.

It requires emacs version 25 or higher.

More information on what a *squeezebox controller* is at https://inigo.katxi.org/blog/2017/07/31/lms_el.html.

Quick instructions: customize some basic parameters such as 'lms-url' and run it with *lms* or *lms-ui*.
From there, you could read complete documentation after pressing *gh* or *g?*.
You can also run 'emacsclient -e \"(lms-float)\"' to display an independent small frame.

Package should appear in [[https://melpa.org][MELPA repository]], and the code is in [[https://hg.serna.eu/emacs/lms][the code repository]] as well.

* Features
This is Squeezebox controller, i.e. a program which can handle your local music library.

Some of the features:
- Display song: title, artist, album, year, cover…
- Play, pause, stop, select next / previous song
- Control players: select player, power on/off, volume, repeat and shuffle modes
- Playlist control: list, select song, delete track, clear
- Show track information and change rating

It is not aimed to be a complete controller, as it can't - and won't - manage external sources such us BBC, Deezer, Pandora, Spotify, or TuneIn Radio.

* Configuration
There are some parameters you could customize:
|--------------------------+-----------------------------------------------+------------------------------------|
| Parameter                | Description                                   | Default                            |
|--------------------------+-----------------------------------------------+------------------------------------|
| lms-url                  | Logitech Media Server hostname or ip and port | http://lms_server:9000             |
| lms-default-player       | Name of default player                        | nil  (1)                           |
| lms-ui-cover-width       | Cover image width                             | 500  (2)                           |
| lms-ui-update-interval   | Time in seconds between UI updates            | 1    (3)                           |
| lms-number-recent-albums | Number of recent albums to show               | 25                                 |
| lms-number-random-albums | Number of random albums to show               | 25                                 |
| lms-number-random-songs  | Number of random songs to show                | 50                                 |
| lms-set-rating-function  | Function to use to set song rating            | lms--set-rating-with-trackstat (4) |
|--------------------------+-----------------------------------------------+------------------------------------|
Notes:
(1) If *lms-default-player* is not defined or a player with that name does not exist, it will ask for one at start.
(2) It's recomendable not to change *lms-ui-cover-width*.
(3) Note that small values in *lms-ui-update-interval* could freeze your Emacs use while refreshing window.
(4) LMS does not have any means to set the rating of a song by itself, so it depends on an external plugin.
    TrackStat (function *lms--set-rating-with-trackstat*) is a popular one, and RatingsLight (function *lms--set-rating-with-ratingslight*) is another option.
** Faces
The colors and font attributes of text can be customized in some views:
|----------------------------+-------------------------------+---------------------|
| Face name                  | Description                   | Default             |
|----------------------------+-------------------------------+---------------------|
| lms-playing-face           | Playing symbol                | DarkTurquoise, bold |
| lms-title-face             | Song title                    | SlateGray, italic   |
| lms-artist-face            | Artist                        | RosyBrown, bold     |
| lms-year-face              | Song year                     | SteelBlue           |
| lms-album-face             | Album                         | CadetBlue           |
| lms-tracknum-face          | Track number                  | gray40              |
| lms-duration-face          | Song duration                 | gray60              |
| lms-players-selected-face  | Selected icon in players list | SteelBlue           |
| lms-players-isplaying-face | Isplaying in players list     | RosyBrown           |
| lms-players-name-face      | Player name in players list   | CadetBlue           |
| lms-players-model-face     | Player model in players list  | SlateGray           |
| lms-players-playerid-face  | Player id in players list     | gray60              |
| lms-players-ip-face        | Player IP in players list     | gray40              |
| lms-players-power-face     | Ispower in players list       | Maroon              |
|----------------------------+-------------------------------+---------------------|

* Playing now
Main window showing information about current track and player status.
The actions triggered by pressing keys refer to the current track.
** Key bindings
|-----------------+--------------------------------|
| Ctrl-p          | select player                  |
| t               | change player power state      |
| R               | change track rating            |
| Ctrl-=          | set volume                     |
| x, <enter>      | toggle play/pause              |
| p               | play                           |
| s               | stop playing                   |
| Ctrl-k, <left>  | play previous song in playlist |
| Ctrl-j, <right> | play next song in playlist     |
| m               | toggle mute volume             |
| +, =            | volume up +5                   |
| -               | volume down -5                 |
| r               | cycle repeat mode              |
| S               | cycle shuffle mode             |
| gr              | update window contents         |
| i               | display track information      |
| P               | display playlist               |
| T               | show all albums by artist      |
| L               | show all tracks of album       |
| Y               | show all albums of this year   |
| M               | browse music libray            |
| gh, g?          | show this documentation        |
| q               | quit LMS                       |
|-----------------+--------------------------------|

* Track information
Display track information.
Previous/next track only works when *Track information* window was called from a list, but not from *Playing now*.
** Key bindings
|-----------------+-------------------------|
| R               | change track rating     |
| Ctrl-k, <left>  | show previous track     |
| Ctrl-j, <right> | show next track         |
| gh, g?          | show this documentation |
| q               | close window            |
|-----------------+-------------------------|

* Players list
Players list.
** Key bindings
|--------------------+--------------------------------|
| k, <up>, j, <down> | move cursor                    |
| <enter>            | select player and close window |
| x                  | toggle player play/pause       |
| t                  | toggle player power state      |
| gh, g?             | show this documentation        |
| q                  | close window                   |
|--------------------+--------------------------------|

* Playlist
Playlist view.
The actions triggered by pressing keys refer to the track under cursor.
** Key bindings
|--------------------+------------------------------------|
| k, <up>, j, <down> | move cursor                        |
| <enter>            | play track                         |
| i                  | show track information             |
| C                  | jump to current track              |
| d, <delete>        | remove track from playlist         |
| c c                | clear playlist                     |
| c u                | remove tracks from start to cursor |
| c f                | remove tracks from cursor to end   |
| u                  | update window contents             |
| A                  | show all albums by artist          |
| T                  | show all tracks of album           |
| Y                  | show all albums of this year       |
| gh, g?             | show this documentation            |
| q                  | close window                       |
|--------------------+------------------------------------|

* Year - Album - Artist list
View all albums of an artist, sorted by date/year.
The actions triggered by pressing keys refer to the album under cursor.
** Key bindings
|--------------------+------------------------------|
| k, <up>, j, <down> | move cursor                  |
| <enter>, a         | show all tracks of album     |
| A                  | show all albums by artist    |
| Y                  | show all albums of this year |
| p                  | add album to playlist        |
| gh, g?             | show this documentation      |
| q                  | close window                 |
|--------------------+------------------------------|

* Tracks list
View list of tracks.
The actions triggered by pressing keys refer to the track under cursor.
** Key bindings
|--------------------+------------------------------|
| j, <up>, k, <down> | move cursor                  |
| <enter>, i         | display track information    |
| A                  | show all albums by artist    |
| Y                  | show all albums of this year |
| p                  | add song to playlist         |
| P                  | add all songs to playlist    |
| gh, g?             | show this documentation      |
| q                  | close window                 |
|--------------------+------------------------------|
"
  "LMS documentation.")

;;;###autoload
(defun evil-collection-lms-setup ()
  "Set up `evil' bindings for `lms'."

  (dolist (map evil-collection-lms-maps)
    (evil-collection-inhibit-insert-state map))

  (dolist (mode evil-collection-lms-modes)
    (evil-set-initial-state mode 'normal))

  (evil-collection-define-key 'normal 'lms-ui-playing-now-mode-map
    "t"              'lms-ui-playing-now-change-player-power-state
    (kbd "C-p")      'lms-ui-playing-now-players-list
    "R"              'lms-ui-playing-now-change-rating
    (kbd  "C-=")     'lms-ui-playing-now-set-volume
    (kbd "RET")      'lms-ui-playing-now-play-pause
    "x"              'lms-ui-playing-now-play-pause
    "p"              'lms-ui-playing-now-play
    "s"              'lms-ui-playing-now-stop
    (kbd "C-j")      'lms-ui-playing-now-next
    (kbd  "<right>") 'lms-ui-playing-now-next
    (kbd "C-k")      'lms-ui-playing-now-prev
    (kbd  "<left>")  'lms-ui-playing-now-prev
    "+"              'lms-ui-playing-now-volume-up
    "="              'lms-ui-playing-now-volume-up
    "-"              'lms-ui-playing-now-volume-down
    "m"              'lms-ui-playing-now-volume-mute
    "r"              'lms-ui-playing-now-cycle-repeat
    "S"              'lms-ui-playing-now-cycle-shuffle
    "gr"             'lms-ui-playing-now-refresh
    "i"              'lms-ui-playing-now-show-track-info
    "P"              'lms-ui-playing-now-show-playlist
    "T"              'lms-ui-playing-now-album-tracks-list
    "A"              'lms-ui-playing-now-artist-albums-list
    "Y"              'lms-ui-playing-now-year-albums-list
    "M"              'lms-ui-playing-now-browse-music-library
    "g?"             'lms-ui-playing-now-help
    "gh"             'lms-ui-playing-now-help
    "q"              'lms-ui-playing-now-quit)

  (evil-collection-define-key 'normal 'lms-ui-track-info-mode-map
    "R"             'lms-ui-track-info-change-rating
    (kbd "C-k")     'lms-ui-track-info-prev
    (kbd "<left>")  'lms-ui-track-info-prev
    (kbd "C-j")     'lms-ui-track-info-next
    (kbd "<right>") 'lms-ui-track-info-next
    "g?"            'lms-ui-playing-now-help
    "gh"            'lms-ui-playing-now-help
    "q"             'evil-collection-lms-ui-track-info-mode-quit)

  (evil-collection-define-key 'normal 'lms-ui-players-mode-map
    [remap evil-goto-line] 'evil-collection-lms-goto-line
    [remap end-of-defun] 'evil-collection-lms-goto-line
    [remap evil-forward-paragraph] 'evil-collection-lms-goto-line
    [remap evil-next-line] 'evil-collection-lms-next-line
    (kbd "RET") 'lms-ui-players-select
    "x" 'lms-ui-players-playpause
    "t" 'lms-ui-players-toggle-power
    "g?" 'lms-ui-playing-now-help
    "gh" 'lms-ui-playing-now-help
    "q" 'evil-collection-lms-ui-players-mode-quit)

  (evil-collection-define-key 'normal 'lms-ui-playlist-mode-map
    [remap evil-goto-line] 'evil-collection-lms-goto-line
    [remap end-of-defun] 'evil-collection-lms-goto-line
    [remap evil-forward-paragraph] 'evil-collection-lms-goto-line
    [remap evil-next-line] 'evil-collection-lms-next-line
    (kbd "RET")      'lms-ui-playlist-play
    "i"              'lms-ui-playlist-track-info
    "C"              'lms-ui-playlist-jump-to-current
    "d"              'lms-ui-playlist-delete-track
    (kbd "<delete>") 'lms-ui-playlist-delete-track
    "cc"             'lms-ui-playlist-clear
    "ct"             'lms-ui-playlist-clear-until-track
    "cf"             'lms-ui-playlist-clear-from-track
    "u"              'lms-ui-playlist
    "A"              'lms-ui-playlist-artist-albums-list
    "T"              'lms-ui-playlist-album-tracks-list
    "Y"              'lms-ui-playlist-year-albums-list
    "g?"             'lms-ui-playing-now-help
    "gh"             'lms-ui-playing-now-help
    "q"              'evil-collection-lms-ui-playlist-mode-quit)

  (evil-collection-define-key 'normal 'lms-ui-tracks-list-mode-map
    [remap evil-goto-line] 'evil-collection-lms-goto-line
    [remap end-of-defun] 'evil-collection-lms-goto-line
    [remap evil-forward-paragraph] 'evil-collection-lms-goto-line
    [remap evil-next-line] 'evil-collection-lms-next-line
    "i"         'lms-ui-tl-track-info
    (kbd "RET") 'lms-ui-tl-track-info
    "p"         'lms-ui-tl-to-playlist
    "P"         'lms-ui-tl-all-to-playlist
    "Y"         'lms-ui-tl-by-year
    "A"         'lms-ui-tl-by-artist
    "g?"        'lms-ui-playing-now-help
    "gh"        'lms-ui-playing-now-help
    "q"         'evil-collection-lms-ui-tracks-list-mode-quit)

  (evil-collection-define-key 'normal 'lms-ui-year-album-artist-list-mode-map
    [remap evil-goto-line] 'evil-collection-lms-goto-line
    [remap end-of-defun] 'evil-collection-lms-goto-line
    [remap evil-forward-paragraph] 'evil-collection-lms-goto-line
    [remap evil-next-line] 'evil-collection-lms-next-line
    "Y"         'lms-ui-yaal-by-year
    "A"         'lms-ui-yaal-by-artist
    (kbd "RET") 'lms-ui-yaal-by-album
    "a"         'lms-ui-yaal-by-album
    "p"         'lms-ui-yaal-to-playlist
    "g?"        'lms-ui-playing-now-help
    "gh"        'lms-ui-playing-now-help
    "q"         'evil-collection-lms-ui-year-album-artist-list-mode-quit)

  ;; Reflect help keybinding changes in the lms.el UI.
  (advice-add 'lms-ui-playing-now :after 'evil-collection-lms-ui-playing-now)
  (setq lms-ui-docs evil-collection-lms-ui-docs))

(provide 'evil-collection-lms)
;;; evil-collection-lms.el ends here