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