diff options
author | forcer <forcer> | 2005-09-11 20:05:00 +0000 |
---|---|---|
committer | forcer <mwolson@gnu.org> | 2005-09-11 20:05:00 +0000 |
commit | bb65333ef00df02dbf6bd83294b4df49e64ea325 (patch) | |
tree | 5435715fe823d566ac5494bc672088522af5a763 /emms-streams.el |
Initial commit (CVS 2005-09-11)
darcs-hash:20050911200506-2189f-48a136015e33465c3cf09940ce935ec2203df463.gz
Diffstat (limited to 'emms-streams.el')
-rw-r--r-- | emms-streams.el | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/emms-streams.el b/emms-streams.el new file mode 100644 index 0000000..e879618 --- /dev/null +++ b/emms-streams.el @@ -0,0 +1,445 @@ +;; emms-streams.el -- interface to add and play streams + +;; 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 2 +;; 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, write to the Free Software +;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +;; 02110-1301 USA + +;; Commentary: + +;; It is part of the EMMS package + +;; Heavily based on bmk-mgr.el by Jose A Ortega Ruiz <jao@gnu.org> +;; thanks to you ! + +;; Code: + +(defvar emms-stream-bookmarks-file "~/.emacs.d/emms-streams" + "The file where you store your favorite emms streams") + +(defvar emms-stream-list nil + "The list that contains your current stream bookmarks.") + +(defvar emms-stream-buffer-name "*EMMS Streams*" + "The name of the buffer used by emms-stream interface.") + +(defvar emms-stream-play-hook nil + "*A hook run when you add or play an EMMS stream via the popup.") + +(defvar emms-stream-current-stream nil + "The stream currently being played. +Needed by the info method, as the track doesn't contain all the +needed info.") + +(defvar emms-stream-default-action "add" + "The default action when you press RET in the EMMS Stream interface. +Can be either \"add\" or \"play\". The default is \"add\".") + +(defvar emms-stream-last-stream nil + "The last stream added/played by EMMS.") + +(defface emms-stream-name-face '((t (:bold t :foreground nil :weight bold))) + "Face for stream names.") + +(defface emms-stream-url-face '((t (:foreground "LightSteelBlue"))) + "Face for stream URLs.") + +;; Format: (("descriptive name" url feed-number type)) +;; type could be either url or playlist. If url, then it represents a +;; direct IP, otherwite it's a stream playlist +(defvar emms-stream-default-list + '(("SomaFM: Beatblender" + "http://www.somafm.com/beatblender.pls" 1 playlist) + ("SomaFM: Secret Agent" + "http://www.somafm.com/secretagent.pls" 1 playlist) + ("SomaFM: Groove Salad" + "http://www.somafm.com/groovesalad.pls" 1 playlist) + ("SomaFM: Drone Zone" + "http://www.somafm.com/dronezone.pls" 1 playlist) + ("SomaFM: Tag's Trance" + "http://www.somafm.com/tagstrance.pls" 1 playlist) + ("Digitally Imported, Trance" + "http://www.digitallyimported.com/mp3/trance.pls" 1 playlist) + ("Digitally Imported, Deephouse" + "http://www.digitallyimported.com/mp3/deephouse.pls" 1 playlist) + ("Digitally Imported, Mostly Classical" + "http://www.digitallyimported.com/mp3/classical.pls" 1 playlist) + ("Digitally Imported, Chillout" + "http://www.digitallyimported.com/mp3/chillout.pls" 1 playlist) + ("Digitally Imported, Drum and Bass" + "http://www.digitallyimported.com/mp3/drumandbass.pls" 1 playlist) + ("Philosomatika, Goa-Trance" + "http://www.philosomatika.com/Philosomatika.pls" 1 playlist) + ("Drum and Bass Radio, BassDrive" + "http://www.bassdrive.com/BassDrive.m3u" 1 playlist) + ("Flaresound, Jazzmusique" + "http://64.236.34.196:80/stream/1016" 1 url) + ("Flaresound, Jazzmusique" + "http://205.188.234.4:8004" 2 url) + ("Flaresound, L'Electric" + "http://www.bp6.com:8002" 1 url) + ("Stangs Garage, Eclectic" + "http://www.stangsgarage.com/listen.pls" 1 playlist) + ("DNA Lounge, Live" + "http://www.dnalounge.com/audio/128.m3u" 1 playlist) + ("Virgin Radio, The Groove" + "http://www.smgradio.com/core/audio/ogg/live.pls?service=grbb" 1 playlist) + ("Virgin Radio, Virgin Classic" + "http://www.smgradio.com/core/audio/ogg/live.pls?service=vcbb" 1 playlist) + ("Virgin Radio, Virgin 1215AM" + "http://www.smgradio.com/core/audio/ogg/live.pls?service=vrbb" 1 playlist) + ("WCPE, Classical Music" + "http://www.ibiblio.org/wcpe/wcpe.pls" 1 playlist))) + +(defvar emms-stream-mode-map + (let ((map (make-keymap))) + (suppress-keymap map) + (define-key map [(control ?a)] 'beginning-of-line) + (define-key map [(control ?e)] 'end-of-line) + (define-key map [(control ?k)] 'emms-stream-kill-bookmark) + (define-key map [(control ?y)] 'emms-stream-yank-bookmark) + (define-key map [(control ?n)] 'emms-stream-next-line) + (define-key map [(control ?p)] 'emms-stream-previous-line) + (define-key map [?Q] 'emms-stream-quit) + (define-key map [?a] 'emms-stream-add-bookmark) + (define-key map [?d] 'emms-stream-delete-bookmark) + (define-key map [?e] 'emms-stream-edit-bookmark) + (define-key map [?h] 'describe-mode) + (define-key map [?n] 'emms-stream-next-line) + (define-key map [?p] 'emms-stream-previous-line) + (define-key map [?q] 'emms-stream-quit) + (define-key map [?s] 'emms-stream-save-bookmarks-file) +;; (define-key map [?u] 'emms-stream-move-bookmark-up) + (define-key map [?i] 'emms-stream-info-bookmark) + (define-key map (kbd "<up>") 'emms-stream-previous-line) + (define-key map (kbd "<down>") 'emms-stream-next-line) + (define-key map (kbd "<left>") 'beginning-of-line) + (define-key map (kbd "<right>") 'end-of-line) + (define-key map (kbd "RET") 'emms-stream-play) + map) + "Keymap for `emms-stream-menu'.") + +(defun emms-stream-line-number-at-pos (&optional pos) + "Return (narrowed) buffer line number at position POS. +If POS is nil, use current buffer location." + (let ((opoint (or pos (point))) start) + (save-excursion + (goto-char (point-min)) + (setq start (point)) + (goto-char opoint) + (forward-line 0) + (1+ (count-lines start (point)))))) + +(defun emms-streams () + "Opens the EMMS Streams interface." + (interactive) + (kill-buffer (get-buffer-create emms-stream-buffer-name)) + (set-buffer (get-buffer-create emms-stream-buffer-name)) + (erase-buffer) + (emms-stream-mode) + (switch-to-buffer emms-stream-buffer-name)) + +(defun emms-stream-mode () + (kill-all-local-variables) + (buffer-disable-undo) + (setq major-mode 'emms-stream-mode) + (setq mode-name "EMMS Streams") + (use-local-map emms-stream-mode-map) + (emms-stream-init) + (set (make-local-variable 'truncate-lines) t) + (set (make-local-variable 'automatic-hscrolling) t) + (set (make-local-variable 'kill-whole-line) t) + (set (make-local-variable 'next-line-add-newlines) nil) + (goto-char 1) + (emms-stream-display) + (toggle-read-only 1) + (message "EMMS Stream Menu")) + +(defun emms-stream-popup-revert () + "Revert to the window-configuration from before if there is one, +otherwise just remove the special bindings from the stream menu." + (interactive) + (remove-hook 'emms-pbi-manually-change-song-hook 'emms-pbi-popup-revert) + (let ((streambuffer (get-buffer emms-stream-buffer-name))) + (when streambuffer + (save-excursion + (set-buffer streambuffer) + ;; (local-unset-key (kbd "q")) + (local-unset-key (kbd "TAB"))))) + ;; (local-unset-key (kbd "RET"))))) + (when emms-stream-popup-old-conf + (set-window-configuration emms-stream-popup-old-conf)) + (remove-hook 'emms-stream-play-hook 'emms-stream-popup-revert) + (remove-hook 'emms-stream-quit-hook 'emms-stream-popup-revert)) + +(defun emms-stream-popup (&optional popup-height) + "Pops up the stream Menu, for the new stream selection. + +POPUP-HEIGHT is the height of the new frame, defaulting to +`emms-popup-default-height'." + (interactive) + (setq popup-height (or popup-height (/ (window-height) 2))) + ;; Split the current screen, and make the stream menu popup + (let ((new-window-height (- (window-height) popup-height))) + (if (not (> new-window-height 0)) + (error "Current window too small to popup menu!")) + ;; Save the current window-configuration + (setq emms-stream-popup-old-conf (current-window-configuration)) + ;; Split and select the menu + (let ((buffer-down + (split-window-vertically new-window-height))) + (select-window buffer-down)) + + (kill-buffer (get-buffer-create emms-stream-buffer-name)) + (switch-to-buffer (get-buffer-create emms-stream-buffer-name)) + (erase-buffer) + (emms-stream-mode) + + (add-hook 'emms-stream-play-hook 'emms-stream-popup-revert) + (add-hook 'emms-stream-quit-hook 'emms-stream-popup-revert) + (local-set-key (kbd "TAB") 'emms-stream-popup-revert) + (local-set-key (kbd "RET") 'emms-stream-play) + ;; (local-set-key (kbd "q") 'delete-window) + ;; Also, forget about the whole thing if the user does something + ;; to the window-configuration + ;; (add-hook 'window-configuration-change-hook 'emms-stream-popup-forget-conf))) + )) + +(defun emms-stream-init () + (setq emms-stream-list (emms-stream-read-file emms-stream-bookmarks-file))) + +(defun emms-stream-read-file (file) + "Returns a sexp." + (let ((file (expand-file-name file))) + (if (file-readable-p file) + (with-temp-buffer + (insert-file-contents-literally file) + (goto-char (point-min)) + (read (current-buffer))) + emms-stream-default-list))) + +(defun emms-stream-save-bookmarks-file () + (interactive) + (let ((buffer (find-file-noselect emms-stream-bookmarks-file))) + (set-buffer buffer) + (erase-buffer) + (prin1 emms-stream-list buffer) + (save-buffer) + (kill-buffer buffer))) + +(defun emms-stream-display-line (line) + (insert (emms-stream-name line)) + (add-text-properties (point-at-bol) (point-at-eol) '(face emms-stream-name-face)) + (add-text-properties (point-at-bol) (point-at-eol) `(emms-stream ,line)) + (insert "\n ") + (insert (emms-stream-url line)) + (add-text-properties (point-at-bol) (point-at-eol) '(face emms-stream-url-face)) + (insert "\n")) + +(defun emms-stream-display () + "Displays the bookmark list in the current buffer, in a human + readable way." + (mapc 'emms-stream-display-line emms-stream-list) + (goto-char (point-min))) + +;; Helper functions +(defun take (n list) + "Takes N elements from LIST." + (let ((idx 0) + (res '())) + (while (< idx n) + (setq res (append res (list (nth idx list)))) + (setq idx (+ idx 1))) + res)) + +(defun insert-at (n elt list) + "Inserts the element ELT in LIST, *before* position N. +Positions are counted starting with 0." + (let* ((n-1 (- n 1)) + (before (take n-1 list)) + (after (last list (- (length list) n-1)))) + (append before (list elt) after))) + +(defun emms-stream-get-bookmark-at-point () + "Returns the bookmark under point." + (get-text-property (point) 'emms-stream)) + + +(defun emms-stream-redisplay () + (let ((inhibit-read-only t)) + (erase-buffer) + (goto-char 1) + (emms-stream-display))) + +(defun emms-stream-add-bookmark (name url fd type) + "Creates a new bookmark, and inserts it at point position. + +Don't forget to run `emms-stream-save-bookmarks-file' after !" + (interactive "sName of the bookmark: +sURL: +nFeed descriptor: +SType (url or playlist): ") + (let* ((line (emms-stream-line-number-at-pos (point))) + (index (+ (/ line 2) 1))) + (setq emms-stream-list (insert-at index (list name url fd type) emms-stream-list)) + (emms-stream-redisplay) + (goto-line line))) + +(defun emms-stream-delete-bookmark () + "Deletes the bookmark under the point. + +Don't forget to save your modifications !" + (interactive) + (let ((line (emms-stream-line-number-at-pos (point)))) + (setq emms-stream-list + (remove (emms-stream-get-bookmark-at-point) emms-stream-list)) + (emms-stream-redisplay) + (goto-line line))) + +(defun emms-stream-edit-bookmark () + "Change the information of current bookmark." + (interactive) + (let* ((bookmark (emms-stream-get-bookmark-at-point)) + (name (read-from-minibuffer "Description: " + (emms-stream-name bookmark))) + (url (read-from-minibuffer "URL: " + (emms-stream-url bookmark))) + (fd (read-from-minibuffer "Feed Descriptor: " + (int-to-string (emms-stream-fd bookmark)))) + (type (read-from-minibuffer "Type (url or playlist): " + (format "%s" (emms-stream-type bookmark))))) + (emms-stream-delete-bookmark) + (emms-stream-add-bookmark name url (string-to-int fd) type))) + +(defun emms-stream-name (el) + (car el)) +(defun emms-stream-url (el) + (cadr el)) +(defun emms-stream-fd (el) + (caddr el)) +(defun emms-stream-type (el) + (cadddr el)) + +(defun emms-stream-play () + (interactive) + (let* ((line (get-text-property (point) 'emms-stream)) + (name (emms-stream-name line)) + (url (emms-stream-url line)) + (fd (emms-stream-fd line)) + (type (emms-stream-type line)) + (player (read (concat "emms-" emms-stream-default-action "-" (format "%s" type))))) + (setq emms-stream-last-stream line) +;; (funcall emms-stream-default-action url) + (funcall player url) + (if (string= emms-stream-default-action "add") + (message "URL added to playlist"))) + (later-do 'emms-mode-line-alter) + (run-hooks 'emms-stream-play-hook)) + +(defun emms-stream-info-bookmark () + "Return the station and track information for the streaming audio station under point." + (interactive) + (if (fboundp 'emms-stream-info-message) + (let* ((line (get-text-property (point) 'emms-stream)) + (url (emms-stream-url line))) + (emms-stream-info-message url)) + (message "Streaming media info not available."))) + +;; Navigation +(defun emms-stream-next-line () + (interactive) + (forward-line 2)) + +(defun emms-stream-previous-line () + (interactive) + (forward-line -2)) + +(defun emms-stream-quit () + (interactive) + (kill-this-buffer) + (run-hooks 'emms-stream-quit-hook)) + +(defun emms-stream-toggle-default-action () + (interactive) + (if (string= emms-stream-default-action "play") + (progn + (setq emms-stream-default-action "add") + (message "Default action is now add")) + (setq emms-stream-default-action "play") + (message "Default action is now play"))) + +;; info part +(define-emms-info-method emms-info-url + :providep 'emms-info-url-providep + :get 'emms-info-url-get) +;; :set 'emms-info-url-set) + +;; A way to get the last element. it is either the only one, or the +;; last one added by emms-add-url. so in both cases, that's what we +;; want. +(defun emms-stream-last-element () + (elt emms-playlist (- (length emms-playlist) 1))) + +(defun emms-info-url-providep (track) + (if (eq (emms-track-type track) 'url) + t + nil)) + +(defun emms-info-url-get (track) + (make-emms-info + :title (emms-stream-url (emms-track-get track 'metadata)) + :artist (emms-stream-name (emms-track-get track 'metadata)) + :album " " + :note " " + :year " " + :genre " " + :file (emms-stream-url (emms-track-get track 'metadata)))) + +;; Then you register it with emms-info, by adding it to +;; `emms-info-methods-list'. + +(add-to-list 'emms-info-methods-list 'emms-info-url) + +(defun emms-info-file-info-song-artist (track) + "Returns a description of TRACK, build from its comments. + +If `emms-info-methods-list' indicates how to retrieve special info +about it, use this. Otherwise returns the name alone." + (if (not (and track (emms-track-name track))) + "Invalid track!" + (let ((info (emms-info-get track))) + (if (eq (emms-info-method-for track) 'emms-info-url) + (progn + (concat (emms-info-artist info) " - " (emms-info-title info))) + (if (and info (not (string= (emms-info-artist info) "")) (not (string= (emms-info-title info) ""))) + (concat (emms-info-artist info) " - " (emms-info-title info)) + (file-name-sans-extension (file-name-nondirectory (emms-track-name track)))))))) + +(defun emms-stream-add-data-to-track (track) + (emms-track-set track 'metadata emms-stream-last-stream)) + +(setq emms-track-initialize-functions '(emms-stream-add-data-to-track)) + +(when (featurep 'emms-info) + (eval-when-compile (require 'emms-info)) ; appease byte-compiler + (add-to-list 'emms-info-methods-list 'emms-info-playlist) + (defun emms-info-playlist-providep (track) + (if (eq (emms-track-type track) 'playlist) + t + nil)) + (define-emms-info-method emms-info-playlist + :providep 'emms-info-playlist-providep + :get 'emms-info-url-get)) + +(provide 'emms-streams) +;;; emms-streams.el ends here |