-
Notifications
You must be signed in to change notification settings - Fork 2
/
helm-rhythmbox.el
171 lines (142 loc) · 6.12 KB
/
helm-rhythmbox.el
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
;;; helm-rhythmbox.el --- control Rhythmbox's play queue via Helm -*-lexical-binding: t-*-
;; Copyright (C) 2015 by Thomas Winant
;; Author: Thomas Winant <dewinant@gmail.com>
;; URL: https://github.com/mrBliss/helm-rhythmbox
;; Version: 0.1
;; Package-Requires: ((helm "1.5.0") (cl-lib "0.5"))
;; Created: Mar 13 2015
;; This program 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 of the License, or
;; (at your option) any later version.
;; This program 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.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Control Rhythmbox's play queue via Helm.
;;
;; Start by calling `helm-rhythmbox' to browse the library retrieved from a
;; running Rhythmbox instance via D-Bus. The default action is to play the
;; selected song. There is also the option to enqueue the selected song, this
;; also works for a selection.
;;
;; The whole library is retrieved on first use and can be reloaded
;; with `helm-rhythmbox-reload-library'.
;;
;; Note that candidates formatted with `helm-rhythmbox-candidate-format' are
;; cached, so to see the effect of changing `helm-rhythmbox-candidate-format'
;; (after already having loaded the library) requires reloading the library to
;; reset the cache.
;;; Code:
(require 'dbus)
(require 'cl-lib)
(require 'cl-macs)
(require 'helm)
(defvar helm-rhythmbox-candidate-format
#'helm-rhythmbox-candidate-default-format
"The function to format a candidate.
Will get a `helm-rhythmbox-song' struct as input and must output
a string. Defaults to `helm-rhythmbox-candidate-format'.")
(defvar helm-rhythmbox--cache nil
"Store a list of cached candidates for `helm-rhythmbox'.
A candidate is of the format (DISPLAY . SONG), where SONG is a
`helm-rhythmbox-song' structure, and DISPLAY is the result
of (funcall helm-rhythmbox-candidate-format SONG).")
(cl-defstruct (helm-rhythmbox-song
(:constructor helm-rhythmbox-song-new
(artist album title uri)))
"Structure representing a song retrieved from Rhythmbox.
Slots:
`artist'
The artist of the song.
`album'
The album containing the song.
`title'
The title of the song.
`uri'
The URI of the song, used by Rhythmbox as identifier."
artist album title uri)
(defun helm-rhythmbox-candidate-default-format (song)
"Default candidate format function for `helm-rhythmbox'.
Formats the SONG as \"ARTIST - ALBUM - TITLE\"."
(format "%s - %s - %s"
(helm-rhythmbox-song-artist song)
(helm-rhythmbox-song-album song)
(helm-rhythmbox-song-title song)))
(defun helm-rhythmbox-song-from-dbus-item (dbus-item)
"Make a `helm-rhythmbox-song' from DBUS-ITEM.
DBUS-ITEM is a song retrieved via D-Bus."
(helm-rhythmbox-song-new
(cl-caadr (assoc "Artist" dbus-item))
(cl-caadr (assoc "Album" dbus-item))
(cl-caadr (assoc "DisplayName" dbus-item))
(cl-caaadr (assoc "URLs" dbus-item))))
(defun helm-rhythmbox-load-callback (dbus-items)
"Callback for `helm-rhythmbox-load-library'.
Will populate `helm-rhythmbox--cache' with DBUS-ITEMS using
`helm-rhythmbox-song-from-dbus-item' and
`helm-rhythmbox-candidate-format'."
(setq helm-rhythmbox--cache
(mapcar (lambda (dbus-item)
(let ((song (helm-rhythmbox-song-from-dbus-item dbus-item)))
(cons (funcall helm-rhythmbox-candidate-format song)
song)))
dbus-items)))
(defun helm-rhythmbox-load-library ()
"Load the Rhythmbox library via D-Bus."
(let* ((service "org.gnome.Rhythmbox3")
(path "/org/gnome/UPnP/MediaServer2/Library/all")
(interface "org.gnome.UPnP.MediaContainer2")
(nb-songs (dbus-get-property
:session service path interface "ChildCount")))
(if (not nb-songs)
(error "Couldn't connect to Rhythmbox")
(dbus-call-method-asynchronously
:session service path interface "ListChildren" #'helm-rhythmbox-load-callback
0 nb-songs '("*")))))
(defun helm-rhythmbox-reload-library ()
"Reload the Rhythmbox library."
(interactive)
(helm-rhythmbox-load-library))
(defun helm-rhythmbox-play-song (song)
"Let Rhythmbox play the given SONG."
(let ((service "org.gnome.Rhythmbox3")
(path "/org/mpris/MediaPlayer2")
(interface "org.mpris.MediaPlayer2.Player"))
(dbus-call-method :session service path interface
"OpenUri" (helm-rhythmbox-song-uri song))))
(defun helm-rhythmbox-enqueue-song (_)
"Let Rhythmbox enqueue the marked songs."
(let ((service "org.gnome.Rhythmbox3")
(path "/org/gnome/Rhythmbox3/PlayQueue")
(interface "org.gnome.Rhythmbox3.PlayQueue"))
(dolist (song (helm-marked-candidates))
(dbus-call-method :session service path interface
"AddToQueue" (helm-rhythmbox-song-uri song)))))
(defun helm-rhythmbox-playpause-song ()
"Play/pause the selected song."
(interactive)
(let ((service "org.gnome.Rhythmbox3")
(path "/org/mpris/MediaPlayer2")
(interface "org.mpris.MediaPlayer2.Player"))
(dbus-call-method :session service path interface
"PlayPause")))
(defvar helm-source-rhythmbox-track-search
(helm-build-sync-source "Rhythmbox"
:candidates 'helm-rhythmbox--cache
:action '(("Play song" . helm-rhythmbox-play-song)
("Enqueue song" . helm-rhythmbox-enqueue-song))
:init (lambda () (unless helm-rhythmbox--cache
(helm-rhythmbox-load-library))))
"Helm source for searching Rhythmbox tracks.")
;;;###autoload
(defun helm-rhythmbox ()
"Choose a song from the Rhythmbox library to play or enqueue."
(interactive)
(helm :sources '(helm-source-rhythmbox-track-search)
:buffer "*helm-rhythmbox*"))
(provide 'helm-rhythmbox)
;;; helm-rhythmbox.el ends here