1;; emms-streams.el -- interface to add and play streams
2
3;; Copyright (C) 2004, 2005, 2006, 2007, 2008,
4;;   2009 Free Software Foundation, Inc.
5
6;; Authors: Lucas Bonnet <lucas@rincevent.net>
7;;          Jose A Ortega Ruiz <jao@gnu.org>
8;;          Yoni Rabkin <yrk@gnu.org>
9;;          Michael Olson <mwolson@gnu.org>
10
11;; This file is part of EMMS.
12
13;; EMMS is free software; you can redistribute it and/or
14;; modify it under the terms of the GNU General Public License
15;; as published by the Free Software Foundation; either version 3
16;; of the License, or (at your option) any later version.
17
18;; EMMS is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with EMMS; if not, write to the Free Software Foundation,
25;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
26
27;;; Commentary:
28
29;; It is part of the EMMS package
30
31;; Heavily based on bmk-mgr.el by Jose A Ortega Ruiz <jao@gnu.org>
32;; thanks to you !
33
34;;; Code:
35
36(require 'emms)
37(require 'later-do)
38
39(defgroup emms-stream nil
40  "*Add and play streams with EMMS."
41  :group 'emms)
42
43(defcustom emms-stream-bookmarks-file (concat (file-name-as-directory emms-directory) "streams")
44  "*The file where you store your favorite emms streams."
45  :type 'file
46  :group 'emms-stream)
47
48(defcustom emms-stream-default-action "add"
49  "*The default action when you press RET in the EMMS Stream interface.
50Can be either \"add\" or \"play\". The default is \"add\"."
51  :type 'string
52  :group 'emms-stream)
53
54(defface emms-stream-name-face '((t (:bold t :weight bold)))
55  "Face for stream names."
56  :group 'emms-stream)
57
58(defface emms-stream-url-face
59  '((((class color) (background dark))
60     (:foreground "LightSteelBlue"))
61    (((class color) (background light))
62     (:foreground "Blue")))
63  "Face for stream URLs."
64  :group 'emms-stream)
65
66(defvar emms-stream-list nil
67  "The list that contains your current stream bookmarks.")
68
69(defvar emms-stream-buffer-name "*EMMS Streams*"
70  "The name of the buffer used by emms-stream interface.")
71
72(defvar emms-stream-play-hook nil
73  "*A hook run when you add or play an EMMS stream via the popup.")
74
75(defvar emms-stream-hook nil
76"*A hook run when you call emms-streams or emms-stream-popup.")
77
78(defvar emms-stream-current-stream nil
79  "The stream currently being played.
80Needed by the info method, as the track doesn't contain all the
81needed info.")
82
83(defvar emms-stream-popup-old-conf nil
84  "Old window configuration.")
85
86(defvar emms-stream-last-stream nil
87  "The last stream added/played by EMMS.")
88
89(defvar emms-stream-playlist-buffer nil
90  "The EMMS playlist buffer associated with emms-streams.")
91
92(defcustom emms-stream-repeat-p nil
93  "*If non-nil, try to repeat a streamlist if it gets disconnected."
94  :set (function
95        (lambda (sym val)
96          (when (buffer-live-p emms-stream-playlist-buffer)
97            (with-current-buffer emms-stream-playlist-buffer
98              (setq emms-repeat-playlist val)))
99          (set sym val)))
100  :type 'boolean
101  :group 'emms-stream)
102
103;; Format: (("descriptive name" url feed-number type))
104;;
105;; type could be either url, playlist, or lastfm. If url, then it
106;; represents a direct IP, if streamlist it's a stream playlist, if
107;; lastfm it's a lastfm station
108(defvar emms-stream-default-list
109  '(("SomaFM: Beatblender"
110     "http://www.somafm.com/beatblender.pls" 1 streamlist)
111    ("SomaFM: Secret Agent"
112     "http://www.somafm.com/secretagent.pls" 1 streamlist)
113    ("SomaFM: Groove Salad"
114     "http://www.somafm.com/groovesalad.pls" 1 streamlist)
115    ("SomaFM: Drone Zone"
116     "http://www.somafm.com/dronezone.pls" 1 streamlist)
117    ("SomaFM: Tag's Trance"
118     "http://www.somafm.com/tagstrance.pls" 1 streamlist)
119    ("SomaFM: Indie Pop Rocks"
120     "http://www.somafm.com/indiepop.pls" 1 streamlist)
121    ("SomaFM: Doomed"
122     "http://www.somafm.com/doomed.pls" 1 streamlist)
123    ("P H I L O S O M A T I K A - Progressive Psytrance"
124     "http://listen.radionomy.com:80/-PHILOSOMATIKAPROGRESSIVE-" 1 url)
125    ("P H I L O S O M A T I K A - Psytrance"
126     "http://listen.radionomy.com:80/-PHILOSOMATIKA-" 1 url)
127    ("Drum and Bass Radio, BassDrive"
128     "http://www.bassdrive.com/BassDrive.m3u" 1 streamlist)
129    ("WCPE, Classical Music"
130     "http://www.ibiblio.org/wcpe/wcpe.pls" 1 streamlist)
131    ("Kohina - Old school game and demo music"
132     "http://stream.nute.net/kohina/stream.ogg.m3u" 1 streamlist)
133    ("Nectarine, Demoscene Radio, DE Continuum's relay 192 mp3"
134     "http://privat.is-by.us:8000/necta192.mp3.m3u" 1 streamlist)
135    ("Nectarine, Demoscene Radio, DE stream (High Bitrate)"
136     "http://nectarine.from-de.com/necta192.m3u" 1 streamlist)
137    ("Nectarine, Demoscene Radio, FR stream (High Bitrate)"
138     "http://necta-relay.mnus.de:8000/necta192.mp3.m3u" 1 streamlist)
139    ("Nectarine, Demoscene Radio, Norwegian stream"
140     "http://pmaster.no:9000/necta.m3u" 1 streamlist)
141    ("Nectarine, Demoscene Radio, UK stream (High Bitrate)"
142     "http://necta.jansenit.com:8000/necta192.mp3.m3u" 1 streamlist)
143    ("idobi Radio"
144     "http://www.idobi.com/radio/iradio.pls" 1 streamlist)
145    ("radio.wazee - Modern Alternative Rock"
146     "http://www.wazee.org/128.pls" 1 streamlist)
147    ("WFMU, Freeform radio"
148     "http://www.wfmu.org/wfmu.pls" 1 streamlist)
149    ("WBCR-LP - Berkshire Community Radio"
150     "http://nyc01.egihosting.com:6232/listen.pls" 1 streamlist)))
151
152(defvar emms-stream-mode-map
153  (let ((map (make-keymap)))
154    (suppress-keymap map)
155    (define-key map (kbd "C-a") 'beginning-of-line)
156    (define-key map (kbd "C-e") 'end-of-line)
157    (define-key map (kbd "C-k") 'emms-stream-kill-bookmark)
158    (define-key map (kbd "C-y") 'emms-stream-yank-bookmark)
159    (define-key map (kbd "C-n") 'emms-stream-next-line)
160    (define-key map (kbd "C-p") 'emms-stream-previous-line)
161    (define-key map (kbd "Q") 'emms-stream-quit)
162    (define-key map (kbd "a") 'emms-stream-add-bookmark)
163    (define-key map (kbd "d") 'emms-stream-delete-bookmark)
164    (define-key map (kbd "e") 'emms-stream-edit-bookmark)
165    (define-key map (kbd "h") 'describe-mode)
166    (define-key map (kbd "n") 'emms-stream-next-line)
167    (define-key map (kbd "p") 'emms-stream-previous-line)
168    (define-key map (kbd "q") 'emms-stream-quit)
169    (define-key map (kbd "s") 'emms-stream-save-bookmarks-file)
170    (define-key map (kbd "t") 'emms-stream-toggle-default-action)
171;;    (define-key map (kbd "u") 'emms-stream-move-bookmark-up)
172    (define-key map (kbd "i") 'emms-stream-info-bookmark)
173    (define-key map (kbd "<up>") 'emms-stream-previous-line)
174    (define-key map (kbd "<down>") 'emms-stream-next-line)
175    (define-key map (kbd "<left>") 'beginning-of-line)
176    (define-key map (kbd "<right>") 'end-of-line)
177    (define-key map (kbd "RET") 'emms-stream-play)
178    map)
179  "Keymap for `emms-stream-menu'.")
180
181;;;###autoload
182(defun emms-streams ()
183  "Opens the EMMS Streams interface."
184  (interactive)
185  (kill-buffer (get-buffer-create emms-stream-buffer-name))
186  (set-buffer (get-buffer-create emms-stream-buffer-name))
187  (erase-buffer)
188  (when (string= emms-stream-default-action "play")
189    (emms-stream-create-playlist))
190  (emms-stream-mode)
191  (switch-to-buffer emms-stream-buffer-name))
192
193(defun emms-stream-mode ()
194  (kill-all-local-variables)
195  (buffer-disable-undo)
196  (setq major-mode 'emms-stream-mode)
197  (setq mode-name "EMMS Streams")
198  (use-local-map emms-stream-mode-map)
199  (emms-stream-init)
200  (set (make-local-variable 'truncate-lines) t)
201  (set (make-local-variable 'auto-hscroll-mode) t)
202  (set (make-local-variable 'kill-whole-line) t)
203  (set (make-local-variable 'next-line-add-newlines) nil)
204  (goto-char 1)
205  (emms-stream-display)
206  (read-only-mode 1)
207  (run-hooks 'emms-stream-hook)
208  (set-buffer-modified-p nil)
209  (message "EMMS Stream Menu"))
210
211(defun emms-stream-create-playlist ()
212  "Create a new EMMS playlist and associate it with emms-streams.
213This is used when `emms-stream-default-action' is \"play\"."
214  (save-excursion
215    (setq emms-stream-playlist-buffer
216          (emms-playlist-set-playlist-buffer (emms-playlist-new)))
217    (with-current-buffer emms-stream-playlist-buffer
218      ;; if emms-stream-repeat-p is non-nil, make sure that we
219      ;; continue to play the station, even if briefly disconnected
220      (set (make-local-variable 'emms-repeat-playlist)
221           emms-stream-repeat-p))))
222
223(defun emms-stream-kill-playlist ()
224  "Delete the EMMS playlist associated with emms-streams, if one exists."
225  (when (buffer-live-p emms-stream-playlist-buffer)
226    (save-excursion
227      (if (eq emms-stream-playlist-buffer emms-playlist-buffer)
228          (emms-playlist-current-kill)
229        (kill-buffer emms-stream-playlist-buffer)))
230    (setq emms-stream-playlist-buffer nil)))
231
232(defun emms-stream-popup-revert ()
233  "Revert to the window-configuration from before if there is one,
234otherwise just remove the special bindings from the stream menu."
235  (interactive)
236  (remove-hook 'emms-pbi-manually-change-song-hook 'emms-pbi-popup-revert)
237  (let ((streambuffer (get-buffer emms-stream-buffer-name)))
238    (when streambuffer
239      (with-current-buffer streambuffer
240	(local-unset-key (kbd "TAB")))))
241  (when emms-stream-popup-old-conf
242    (set-window-configuration emms-stream-popup-old-conf))
243  (remove-hook 'emms-stream-play-hook 'emms-stream-popup-revert)
244  (remove-hook 'emms-stream-quit-hook 'emms-stream-popup-revert))
245
246(defun emms-stream-popup (&optional popup-height)
247  "Pops up the stream Menu, for the new stream selection.
248
249POPUP-HEIGHT is the height of the new frame, defaulting to
250`emms-popup-default-height'."
251  (interactive)
252  (setq popup-height (or popup-height (/ (window-height) 2)))
253  ;; Split the current screen, and make the stream menu popup
254  (let ((new-window-height (- (window-height) popup-height)))
255    (if (not (> new-window-height 0))
256	(error "Current window too small to popup menu!"))
257    ;; Save the current window-configuration
258    (setq emms-stream-popup-old-conf (current-window-configuration))
259    ;; Split and select the menu
260    (let ((buffer-down
261           (split-window-vertically new-window-height)))
262      (select-window buffer-down))
263
264      (kill-buffer (get-buffer-create emms-stream-buffer-name))
265      (switch-to-buffer (get-buffer-create emms-stream-buffer-name))
266      (erase-buffer)
267      (emms-stream-mode)
268
269      (add-hook 'emms-stream-play-hook 'emms-stream-popup-revert)
270      (add-hook 'emms-stream-quit-hook 'emms-stream-popup-revert)
271      (local-set-key (kbd "TAB") 'emms-stream-popup-revert)
272      (local-set-key (kbd "RET") 'emms-stream-play)
273      ;; (local-set-key (kbd "q") 'delete-window)
274      ;; Also, forget about the whole thing if the user does something
275      ;; to the window-configuration
276      ;; (add-hook 'window-configuration-change-hook 'emms-stream-popup-forget-conf)))
277      ))
278
279(defun emms-stream-init ()
280  (setq emms-stream-list (emms-stream-read-file emms-stream-bookmarks-file)))
281
282(defun emms-stream-read-file (file)
283  "Returns a sexp."
284  (let ((file (expand-file-name file)))
285    (if (file-readable-p file)
286        (with-temp-buffer
287          (emms-insert-file-contents file)
288          (goto-char (point-min))
289          (read (current-buffer)))
290      emms-stream-default-list)))
291
292(defun emms-stream-save-bookmarks-file ()
293  (interactive)
294  (save-excursion
295    (let ((buffer (find-file-noselect emms-stream-bookmarks-file)))
296      (set-buffer buffer)
297      (erase-buffer)
298      (insert "(")
299      (let ((firstp t))
300        (dolist (stream emms-stream-list)
301          (if (not firstp)
302              (insert "\n ")
303            (setq firstp nil))
304          ;; make sure type identifier is a symbol, not a string
305          (when (stringp (nth 3 stream))
306            (setq stream (copy-alist stream))
307            (setcar (nthcdr 3 stream) (intern (nth 3 stream))))
308          (prin1 stream buffer)))
309      (insert ")\n")
310      (save-buffer)
311      (kill-buffer buffer)))
312  (set-buffer-modified-p nil))
313
314(defun emms-stream-display-line (line)
315  (insert (emms-stream-name line))
316  (add-text-properties (point-at-bol) (point-at-eol)
317                       '(face emms-stream-name-face))
318  (add-text-properties (point-at-bol) (point-at-eol) `(emms-stream ,line))
319  (insert "\n      ")
320  (insert (emms-stream-url  line))
321  (add-text-properties (point-at-bol) (point-at-eol)
322                       '(face emms-stream-url-face))
323  (insert "\n"))
324
325(defun emms-stream-display ()
326  "Displays the bookmark list in the current buffer, in a human
327  readable way."
328  (mapc 'emms-stream-display-line emms-stream-list)
329  (goto-char (point-min)))
330
331;; Helper functions
332(defun emms-stream-take (n list)
333  "Takes N elements from LIST."
334  (let ((idx  0)
335        (res '()))
336    (while (< idx n)
337      (setq res (append res (list (nth idx list))))
338      (setq idx (+ idx 1)))
339    res))
340
341(defun emms-stream-insert-at (n elt list)
342  "Inserts the element ELT in LIST, *before* position N.
343Positions are counted starting with 0."
344  (let* ((n-1     (- n 1))
345         (before (emms-stream-take n-1 list))
346         (after  (last list (- (length list) n-1))))
347    (append before (list elt) after)))
348
349(defun emms-stream-insert-several-at (n new-list list)
350  "Inserts the list NEW-LIST in LIST, *before* position N.
351Positions are counted starting with 0."
352  (let* ((n-1     (- n 1))
353         (before (emms-stream-take n-1 list))
354         (after  (last list (- (length list) n-1))))
355    (append before new-list after)))
356
357(defun emms-stream-look-behind ()
358  "Return non-nil if the position behind the point is an emms-stream."
359  (and (not (bobp))
360       (get-text-property (1- (point)) 'emms-stream)))
361
362(defun emms-stream-back-to-stream ()
363  "If we are not on a stream, move backwards to the nearest one."
364  (unless (get-text-property (point) 'emms-stream)
365    (unless (emms-stream-look-behind)
366      (goto-char (or (previous-single-property-change (point) 'emms-stream)
367                     (point-min))))
368    (goto-char (or (previous-single-property-change (point) 'emms-stream)
369                   (point-min)))))
370
371(defun emms-stream-get-bookmark-at-point ()
372  "Returns the bookmark under point."
373  (emms-stream-back-to-stream)
374  (get-text-property (point) 'emms-stream))
375
376(defun emms-stream-redisplay ()
377  (let ((inhibit-read-only t))
378    (erase-buffer)
379    (goto-char (point-min))
380    (emms-stream-display)))
381
382(defun emms-stream-determine-fd (name)
383  "Return a feed descriptor, given NAME.
384This is the count of the times NAME appears in the bookmark list,
385plus one."
386  (let ((count 1))
387    (dolist (feed emms-stream-list)
388      (when (string= (emms-stream-name feed) name)
389        (setq count (1+ count))))
390    count))
391
392(defun emms-stream-add-bookmark (name url fd type)
393  "Creates a new bookmark, and inserts it at point position.
394
395Don't forget to run `emms-stream-save-bookmarks-file' after !"
396  (interactive
397   (list
398    (read-string "Name of the bookmark: ")
399    (read-string "URL: ")
400    nil
401    (emms-completing-read
402     "Type (url, streamlist, or lastfm): "
403     (mapcar #'list '("url" "streamlist" "lastfm")))))
404  (unless fd (setq fd (emms-stream-determine-fd name)))
405  (when (stringp type) (setq type (intern type)))
406  (let* ((line     (emms-line-number-at-pos (point)))
407         (index    (+ (/ line 2) 1)))
408    (setq emms-stream-list (emms-stream-insert-at index (list name url fd type)
409                                                  emms-stream-list))
410    (emms-stream-redisplay)
411    (goto-char (point-min))
412    (forward-line (1- line))))
413
414(defun emms-stream-delete-bookmark ()
415  "Deletes the bookmark under the point.
416
417Don't forget to save your modifications !"
418  (interactive)
419  (let ((line (emms-line-number-at-pos (point))))
420    (setq emms-stream-list
421          (delete (emms-stream-get-bookmark-at-point) emms-stream-list))
422    (emms-stream-redisplay)
423    (goto-char (point-min))
424    (forward-line (1- line))))
425
426(defun emms-stream-edit-bookmark ()
427  "Change the information of current bookmark."
428  (interactive)
429  (let* ((bookmark (emms-stream-get-bookmark-at-point))
430         (name     (read-from-minibuffer "Description: "
431                                         (emms-stream-name bookmark)))
432         (url      (read-from-minibuffer "URL: "
433                                         (emms-stream-url bookmark)))
434         (fd       (read-from-minibuffer "Feed Descriptor: "
435                                         (int-to-string (emms-stream-fd bookmark))))
436         (type     (read-from-minibuffer "Type (url, streamlist, or lastfm): "
437                                         (format "%s" (emms-stream-type bookmark)))))
438    (emms-stream-delete-bookmark)
439    (emms-stream-add-bookmark name url (string-to-number fd) type)))
440
441(defun emms-stream-name (el)
442  (car el))
443(defun emms-stream-url (el)
444  (cadr el))
445(defun emms-stream-fd (el)
446  (car (cddr el)))
447(defun emms-stream-type (el)
448  (cadr (cddr el)))
449
450(defun emms-stream-play ()
451  (interactive)
452  (let* ((line  (or (get-text-property (point) 'emms-stream)
453                    (progn
454                      (goto-char (or (previous-single-property-change
455                                      (point) 'emms-stream)
456                                     (point-min)))
457                      (goto-char (or (previous-single-property-change
458                                      (point) 'emms-stream)
459                                     (point-min)))
460                      (get-text-property (point) 'emms-stream))
461                    (error "No stream found at point")))
462         (name  (emms-stream-name line))
463         (url   (emms-stream-url  line))
464         (fd    (emms-stream-fd   line))
465         (type  (emms-stream-type line))
466         (player (read (concat "emms-" emms-stream-default-action "-"
467                               (format "%s" type)))))
468    (setq emms-stream-last-stream line)
469;;    (funcall emms-stream-default-action url)
470    (funcall player url)
471    (if (string= emms-stream-default-action "add")
472        (message "URL added to playlist")))
473  (later-do 'emms-mode-line-alter)
474  (run-hooks 'emms-stream-play-hook))
475
476(defun emms-stream-info-bookmark ()
477  "Return the station and track information for the streaming audio station under point."
478  (interactive)
479  (if (fboundp 'emms-stream-info-message)
480      (let* ((line (get-text-property (point) 'emms-stream))
481	     (url (emms-stream-url line)))
482	(emms-stream-info-message url))
483    (message "Streaming media info not available.")))
484
485;; Killing and yanking
486(defvar emms-stream-killed-streams ()
487  "Bookmarks that have been killed.")
488
489(defun emms-stream-kill-bookmark ()
490  "Kill the current bookmark."
491  (interactive)
492  (let ((stream (emms-stream-get-bookmark-at-point)))
493    (setq emms-stream-list (delete stream emms-stream-list)
494          emms-stream-killed-streams (cons stream emms-stream-killed-streams)))
495  (let ((inhibit-read-only t))
496    (kill-line 2)))
497
498(defun emms-stream-yank-bookmark ()
499  "Yank bookmark into the streams buffer."
500  (interactive)
501  (emms-stream-back-to-stream)
502  (let ((inhibit-read-only t)
503        (streams nil))
504    ;; get all valid streams
505    (save-restriction
506      (narrow-to-region (point) (point))
507      (yank)
508      (goto-char (point-min))
509      (while (and (< (point) (point-max))
510                  (car emms-stream-killed-streams)
511                  (looking-at "^\\(.+\\)\n      \\(.+\\)\n"))
512        (setq streams (cons (car emms-stream-killed-streams) streams)
513              emms-stream-killed-streams (cdr emms-stream-killed-streams))
514        (goto-char (match-end 0)))
515      (delete-region (point-min) (point-max)))
516    ;; insert streams into list
517    (if streams
518        (let* ((line (emms-line-number-at-pos (point)))
519               (index (+ (/ line 2) 1)))
520          (setq emms-stream-list (emms-stream-insert-several-at
521                                  index streams emms-stream-list))
522          (setq line (+ line (* (length streams) 2)))
523          (emms-stream-redisplay)
524          (goto-char (point-min))
525          (forward-line (1- line)))
526      (message "Not yanking anything"))))
527
528;; Navigation
529(defun emms-stream-next-line ()
530  (interactive)
531  (when (get-text-property (point) 'emms-stream)
532    (goto-char (or (next-single-property-change (point) 'emms-stream)
533                   (point-max))))
534  (goto-char (or (next-single-property-change (point) 'emms-stream)
535                 (point-max)))
536  (forward-line 0))
537
538(defun emms-stream-previous-line ()
539  (interactive)
540  (emms-stream-back-to-stream)
541  (goto-char (or (previous-single-property-change (point) 'emms-stream)
542                   (point-min)))
543  (goto-char (or (previous-single-property-change (point) 'emms-stream)
544                 (point-min)))
545  (forward-line 0))
546
547(defun emms-stream-quit ()
548  (interactive)
549  (emms-stream-kill-playlist)
550  (kill-this-buffer)
551  (run-hooks 'emms-stream-quit-hook))
552
553(defun emms-stream-toggle-default-action ()
554"Toggle between adding to the current active playlist or play
555right now (and thus erase the current active playlist)."
556  (interactive)
557  (if (string= emms-stream-default-action "play")
558      (progn
559        (emms-stream-kill-playlist)
560        (setq emms-stream-default-action "add")
561        (message "Default action is now add"))
562    (emms-stream-create-playlist)
563    (setq emms-stream-default-action "play")
564    (message "Default action is now play")))
565
566;; info part
567; (define-emms-info-method emms-info-url
568;    :providep 'emms-info-url-providep
569;    :get 'emms-info-url-get)
570;;   :set 'emms-info-url-set)
571
572;; A way to get the last element.  it is either the only one, or the
573;; last one added by emms-add-url. so in both cases, that's what we
574;; want.
575;; FIXME : not working with the new design. Yrk ?
576; (defun emms-stream-last-element ()
577;  (elt emms-playlist (- (length emms-playlist) 1)))
578
579(defun emms-info-url-providep (track)
580  (if (eq (emms-track-type track) 'url)
581      t
582    nil))
583
584; (defun emms-info-url-get (track)
585;   (make-emms-info
586;    :title (emms-stream-url (emms-track-get track 'metadata))
587;    :artist (emms-stream-name (emms-track-get track 'metadata))
588;    :album " "
589;    :note " "
590;    :year " "
591;    :genre " "
592;    :file (emms-stream-url (emms-track-get track 'metadata))))
593
594;; Then you register it with emms-info, by adding it to
595;; `emms-info-methods-list'.
596
597; (add-to-list 'emms-info-methods-list 'emms-info-url)
598
599(defun emms-stream-add-data-to-track (track)
600  (emms-track-set track 'metadata emms-stream-last-stream))
601
602(add-to-list 'emms-track-initialize-functions
603             'emms-stream-add-data-to-track)
604
605; (when (featurep 'emms-info)
606;   (eval-when-compile (require 'emms-info)) ; appease byte-compiler
607;   (add-to-list 'emms-info-methods-list 'emms-info-streamlist)
608;   (defun emms-info-streamlist-providep (track)
609;     (if (eq (emms-track-type track) 'streamlist)
610;         t
611;       nil))
612;   (define-emms-info-method emms-info-streamlist  ;; FIXME-PLS ?
613;     :providep 'emms-info-streamlist-providep ;; FIXME-PLS ?
614;     :get 'emms-info-url-get))
615
616(provide 'emms-streams)
617;;; emms-streams.el ends here
618