aboutsummaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorWilliam Xu <william.xwl@gmail.com>2008-12-27 10:25:33 +0800
committerWilliam Xu <william.xwl@gmail.com>2008-12-27 10:25:33 +0800
commite315f293d7f075f4c6f38270a62cef22c88ec1a0 (patch)
tree3470eb798957c215276342d23cdbfd2ec26cea5b /lisp
parent0176b1afe505be41a2af7920aaa8c99dc3d5407d (diff)
parent1cb621334a33563996784b14eadc96f2126767f2 (diff)
Merge branch 'master' of ssh://xwl@git.sv.gnu.org/srv/git/emms
Diffstat (limited to 'lisp')
-rw-r--r--lisp/emms-stream-info.el788
1 files changed, 80 insertions, 708 deletions
diff --git a/lisp/emms-stream-info.el b/lisp/emms-stream-info.el
index 4f9c0c5..1683357 100644
--- a/lisp/emms-stream-info.el
+++ b/lisp/emms-stream-info.el
@@ -22,722 +22,94 @@
;;; Commentary:
;;
-;; 'emms-stream-info' establishes a TCP connection with the server and
-;; sends an HTTP request string. The server (hopefully) responds with
-;; some header information describing the streaming audio channel,
-;; some audio data and then the name of the song being played (usually
-;; in that order).
+;; Set `*emms-stream-info-backend*' to either 'vlc or 'mplayer, which
+;; are the two currently supported backends for retrieving stream
+;; information. You can then either call `emms-stream-info-message'
+;; directly or hit "i" in the `emms-streams' buffer over stream you
+;; want to investigate.
;;
-;; Some stations like WCPE [http://wcpe.org], while giving excellent
-;; broadcasts do not support title streaming over MP3 or Ogg. Using
-;; this software on such stations will only result in general station
-;; information and not the artist name or title of the track being
-;; played.
-
-;;; Functionality:
-;;
-;; Currently supports Icecast and Shoutcast servers with Ogg and MP3
-;; streams.
-
-;;; Use:
+;; Note that you do not have to be playing the stream in question in
+;; order to find out what is playing on it since this library will
+;; open its own connection to the streaming server.
;;
-;; Look at the documentation strings for the three interactive
-;; functions: 'emms-stream-info-get', 'emms-stream-info-message' and
-;; 'emms-stream-info-insert'.
+;; Please send bug reports and stations which do not work to the
+;; maintainer (email at the top of this file).
-;;; Important Notes:
-;;
-;; 1) This software does not parse, cache or save audio data at
-;; all. This software downloads a limited amount of data from a
-;; given streaming audio channel per call. This software is
-;; optimized to download as little as possible from a given
-;; streaming audio channel and then to immediately disconnect.
-;;
-;; 2) This software disregards and then discards all audio data
-;; automatically after each call.
+;;; History:
;;
-;; 3) This software connects for a maximum of 10 seconds and then
-;; immediately disconnects. Usually the software will disconnect
-;; long before the 10 second limit is reached.
-;;
-;; 4) It is the responsibility of the user to read the Terms of
-;; Service of the streaming audio channel before running this
-;; software on that channel's service. Some streaming audio
-;; channels explicitly request 3rd party applications not to
-;; connect to their service. This is their prerogative. Respect it.
-
-;; $Id: emms-stream-info.el,v 1.8 2005/07/09 11:56:00 forcer Exp $
+;; This library was re-implemented from scratch around January of
+;; 2009. If you are looking for the old code then grab source code
+;; older than that.
;;; Code:
-(require 'emms)
-
-;; A higher value for 'emms-stream-info-max' this gives us a
-;; correspondingly higher chance of grabbing the title information
-;; from a stream but incurs a price in the additional time it takes to
-;; download.
-;;
-;; This value is not relevant for Ogg streams since the title info in
-;; Ogg streams arrives almost immediately.
-;;
-;; Do not set under 30000 since the typical value of 'metaint' on most
-;; streaming audio servers is either 8192 or 24576
-(defconst emms-stream-info-max 120000
- "Byte limit for downloads.")
-
-(defconst emms-stream-info-timeout 10
- "Seconds to timeout connection (dead or alive).")
-
-(defconst emms-stream-info-verbose t
- "Output real-time information about the connection.")
-
-(defconst emms-stream-info-version
- "$Revision: 1.8 $"
- "Software version.")
-
-(defconst emms-stream-info-char-alter-regexp "[-,'=:%+&0-9A-Za-z\.()/ ]"
- "Unified character alternative clause for regular expressions.")
-
-(defconst emms-stream-info-shoutcast-regexp
- (concat emms-stream-info-char-alter-regexp ".*?")
- "Regular expression for Shoutcast.")
-
-(defconst emms-stream-info-icecast-regexp
- (concat emms-stream-info-char-alter-regexp "+")
- "Regular expression for Icecast.")
-
-(defconst emms-stream-info-shoutcast-title-regexp
- (concat "StreamTitle='\\(" emms-stream-info-shoutcast-regexp "\\)';")
- "Regular expression for Shoutcast.")
-
-;; Reference: http://www.xiph.org/ogg/vorbis/doc/framing.html
-(defconst emms-stream-info-icecast-capture-pattern "Oggs\\(.*\\)BCV"
- "Regular Expression for the beggining of an Ogg bitstream page.")
-
-;; For all servers
-(defconst emms-stream-info-stream-header-regexp
- (concat emms-stream-info-char-alter-regexp "+")
- "Regular expression for metainformation headers.")
-
-(defconst emms-stream-info-streamlist-regexp
- "\\(^http://.*\\)\\|^File.=\\(http://.*\\)"
- "Regular expression for streamlist URLs.")
-
-;; When t output debugging info
-(defconst emms-stream-info-debugging nil
- "If t then emms-stream-info will spill the stream into a buffer.
-Set to NIL unless you want a buffer filled with binary junk.")
-
-(defconst emms-stream-info-debug-buffer "*emms-stream-info-debug*"
- "Buffer for debugging information.")
-
-(defconst emms-stream-info-vocab (list "name"
- "genre"
- "pub"
- "metaint"
- "br"
- "bitrate"
- "description"
- "public"
- "audio-info")
- "List of header keys.")
-
-(defconst emms-stream-info-format-string
- "Now streaming:%s, %c %bKb/sec"
- "The following %-sequences are supported:
-
-%b Bitrate
-%s Song title and artist name
-%c Station/Channel name and short description
-%t Song title
-%g Station/Channel genre
-%a Artist name
-
-Note that some stations do not supply artist and song title
-information.")
-
-(defconst emms-stream-info-format-string-notitle
- "Now streaming: %c %bKb/sec %g"
- "Some streaming audio stations/channels do not provide artist
-and songtitle information. This string specifies an alternate
-format for those stations.")
-
-(defconst emms-stream-info-pls-regexp ".*\.pls"
- "Regular expression for a .pls streamlist file.")
-
-(defconst emms-stream-info-m3u-regexp ".*\.m3u"
- "Regular expression for a .m3u streamlist file.")
-
-(defvar emms-stream-info-url nil
- "Server URL.")
-
-(defvar emms-stream-info-port nil
- "Server port.")
-
-(defvar emms-stream-info-found nil
- "Results of our search.")
-
-(defvar emms-stream-info-streamlist-found nil
- "Results of our streamlist search.")
-
-(defvar emms-stream-info-procname "emms-stream-info-process"
- "Name of network connection process.")
-
-(defvar emms-stream-info-downloaded 0
- "Amount of stream data downloaded.")
-
-(defvar emms-stream-info-read-inhibit nil
- "When t do not attempt to read 'emms-stream-info-found'.")
-
-(defvar emms-stream-info-return-hook nil
- "Activated after the disconnection from the streaming audio server.")
-
-(defvar emms-stream-info-read-hook nil
- "Activated after the disconnection from the streaming audio
-server. This hook is for integration purposes, for general user
-functions use 'emms-stream-info-return-hook'.")
-
-(defvar emms-stream-info-header-flag nil
- "Non-nil means header information has been captured.")
-
-(defvar emms-stream-info-title-flag nil
- "Non-nil means title information has been captured.")
-
-(defvar emms-stream-info-streamlist-flag nil
- "Non-nil means streamlist information has been captured.")
-
-(defvar emms-stream-info-request-string nil
- "String sent to streaming audio server.")
-
-(defun emms-stream-info-decompose-url (urlstr)
- "Return a vector containing the elements of the URI URLSTR."
- (let ((host nil)
- (file nil)
- (port nil)
- (protocol nil)
- (user nil) ; nil
- (pass nil) ; nil
- (refs nil) ; nil
- (attr nil) ; nil
- (full nil)
- (pos 1))
+(defvar *emms-stream-info-backend* 'mplayer
+ "Symbol designating the backend program to use.")
+
+;; using unhygienic macros for good... or is it evil?
+(defmacro emms-stream-info-defreg (symname regexp)
+ "Set SYMNAME to be the match for REGEXP."
+ `(save-excursion
+ (goto-char (point-min))
+ (re-search-forward ,regexp (point-max) t)
+ (when (and (match-string-no-properties 1)
+ (> (length (match-string-no-properties 1)) 0))
+ (setq ,symname (match-string-no-properties 1)))))
+
+(defun emms-stream-info-mplayer-backend (url)
+ "Backend command for running mplayer on URL."
+ (condition-case excep
+ (call-process "mplayer" nil t nil
+ "-nocache" "-endpos" "0" "-vo" "null" "-ao" "null"
+ url)
+ (file-error
+ (error "Could not find the mplayer backend binary"))))
+
+(defun emms-stream-info-vlc-backend (url)
+ "Backend command for running VLC on URL."
+ (condition-case excep
+ (call-process "vlc" nil t nil
+ "-vvv" "--intf" "dummy" "--stop-time" "1" "--noaudio"
+ url "vlc:quit")
+ (file-error
+ (error "Could not find the VLC backend binary"))))
+
+(defun emms-stream-info-call-backend (url)
+ "Call backend and return a list of stream information for URL."
+ (let ((name "N/A")
+ (genre "N/A")
+ (bitrate "N/A")
+ (nowplaying "N/A"))
(with-temp-buffer
- (insert urlstr)
- (goto-char (point-min))
- (if (looking-at "http")
- (progn
- (forward-char 4)
- (setq protocol (buffer-substring-no-properties pos (point)))
- (setq pos (point))))
- (skip-chars-forward "://")
- (setq pos (point))
- (skip-chars-forward "^/")
- (setq host (buffer-substring pos (point)))
- (if (string-match ":\\([0-9+]+\\)" host)
- (setq port (string-to-number (match-string 1 host))
- host (substring host 0 (match-beginning 0))))
- (setq pos (point))
- (setq file (buffer-substring pos (point-max)))
- (setq full (buffer-substring (point-min) (point-max))))
- ;; Return in format compatible with 'url-generic-parse-url'.
- (vector protocol user pass host port file refs attr full)))
-
-;; This is our tiny state machine for keeping track across multiple
-;; connections.
-(defvar emms-stream-info-state-bv
- (if (fboundp 'make-bool-vector)
- (make-bool-vector 3 nil)
- (make-vector 3 nil))
- "State of sequential connections.
-true at index 0 means output formatted message.
-true at index 1 means insert formatted message.
-trye at index 2 means continue to next connection.")
-
-;; This bit is ugly and non-lispish, but asynchronous communications
-;; need a state machine. Better to do it with a macro. and once
-;; everything works I will too!
-(defun emms-stream-info-set-message ()
- (aset emms-stream-info-state-bv 0 t))
-(defun emms-stream-info-unset-message ()
- (aset emms-stream-info-state-bv 0 nil))
-(defun emms-stream-info-message-p ()
- (aref emms-stream-info-state-bv 0))
-
-(defun emms-stream-info-set-insert ()
- (aset emms-stream-info-state-bv 1 t))
-(defun emms-stream-info-unset-insert ()
- (aset emms-stream-info-state-bv 1 nil))
-(defun emms-stream-info-insert-p ()
- (aref emms-stream-info-state-bv 1))
-
-(defun emms-stream-info-set-continue ()
- (aset emms-stream-info-state-bv 2 t))
-(defun emms-stream-info-unset-continue ()
- (aset emms-stream-info-state-bv 2 nil))
-(defun emms-stream-info-continue-p ()
- (aref emms-stream-info-state-bv 2))
-
-(defun emms-stream-info-streamlist-type (str)
- (if (stringp str)
- (cond ((string-match emms-stream-info-pls-regexp str)
- 'pls)
- ((string-match emms-stream-info-m3u-regexp str)
- 'm3u)
- (t nil))
- nil))
-
-(defun emms-stream-info-format (str format-alist)
- (let ((key-list (mapcar 'car format-alist)))
- (setq key-list (mapcar 'car format-alist))
- (mapc (lambda (e)
- (setq str
- (emms-replace-regexp-in-string
- e
- (cdr (assoc e format-alist))
- str)))
- key-list))
- str)
-
-;; Output a human readable message
-(defun emms-stream-info-pretty-print (&optional string-out)
- "Output a human readable message. If STRING-OUT is non-nil, do
-not output a message and only return a string."
- (let (str
- (format-string emms-stream-info-format-string)
- (format-alist
- (list
- (cons "%b" (or (emms-stream-info-get-key "br")
- (emms-stream-info-get-key "bitrate")
- ""))
- (cons "%s" (or (emms-stream-info-get-key "songtitle") ""))
- (cons "%c" (or (emms-stream-info-get-key "name") ""))
- (cons "%t" (or (emms-stream-info-get-key "title") ""))
- (cons "%g" (or (emms-stream-info-get-key "genre") ""))
- (cons "%a" (or (emms-stream-info-get-key "artist") ""))
- (cons "%. " "")))) ; clean untreated tags
-
- ;; Choose alternate string format if necessary
- (unless (emms-stream-info-get-key "title")
- (setq format-string emms-stream-info-format-string-notitle))
-
- ;; format according to the format-string
- (setq str
- (emms-stream-info-format
- format-string
- format-alist))
-
- ;; Escape rougue percent signs hiding in our string.
- (setq str (emms-replace-regexp-in-string "%" "%%" str))
-
- ;; Either output a message or return a string. But only if it is
- ;; an identifiable station/channel
- (when (emms-stream-info-get-key "name")
- (if string-out
- str
- (message "%s" str)))))
-
-(defun emms-stream-info-pretty-print-insert ()
- "Insert the formatted output of 'emms-stream-info-get' at point."
- (insert (or (emms-stream-info-pretty-print t) "")))
-
-(defun emms-stream-info-continue ()
- (emms-stream-info-unset-continue)
- (if emms-stream-info-streamlist-found
- (emms-stream-info-get emms-stream-info-streamlist-found
- (emms-stream-info-message-p)
- (emms-stream-info-insert-p)
- nil)
- (error "No streamlist found at URL")))
-
-;; Useful
-(defun list-to-string (l)
- "Return a STRING which is the concatenation of the elements of
-L."
- (if (not l)
- nil
- (if (stringp (car l))
- (concat (car l) (list-to-string (cdr l)))
- (list-to-string (cdr l)))))
-
-(defun emms-stream-info-get-key (key)
- "Return STRING associated with KEY."
- (unless emms-stream-info-read-inhibit
- (cdr (assoc key emms-stream-info-found))))
-
-(defun emms-stream-info-get-keys (keys)
- "Return a list of strings associated with each key in
-KEYS. KEYS should be a list of strings."
- (mapcar (lambda (e)
- (emms-stream-info-get-key e))
- keys))
-
-;; BEGIN to END should typically be a segment of about 250 Bytes
-;; length for Ogg streams.
-(defun emms-stream-info-decode-ogg (begin end)
- "Parse Ogg stream segment from BEGIN to END."
- (let ((artist nil)
- (title nil))
-
- (goto-char begin)
- (re-search-forward (concat "artist=\\("
- emms-stream-info-icecast-regexp
- "\\)") end t)
- (setq artist (emms-match-string-no-properties 1))
-
- (goto-char begin)
- (re-search-forward (concat "title=\\("
- emms-stream-info-icecast-regexp
- "\\)") end t)
- (setq title (emms-match-string-no-properties 1))
-
- ;; ugh
- (if (or artist title)
- (list (cons "songtitle" (concat artist
- (if (and artist title)
- " - "
- " ")
- title))
- (cons "artist" artist)
- (cons "title" title))
- nil)))
-
-;; BEGIN to END should be about 20 Bytes long
-(defun emms-stream-info-decode-mp3 (begin end)
- "Parse Shoutcast/Icecast-MP3 segment from BEGIN to END."
- (let ((split nil)
- (songtitle nil)
- (artist nil)
- (title nil))
-
- (goto-char begin)
- (setq songtitle (buffer-substring begin end)
- split (split-string songtitle "-"))
-
- (if (cdr split)
- (setq artist (car split)
- title (list-to-string (cdr split))))
-
- (list (cons "songtitle" songtitle)
- (cons "artist" artist)
- (cons "title" title))))
-
-(defun emms-stream-info-filter (proc str)
- "Filter function for the network process.
-Argument PROC Process.
-Argument STR Quanta of data."
-
- ;; Debugging flag dependent
- (if emms-stream-info-debugging
- (with-current-buffer emms-stream-info-debug-buffer
- (insert str)))
-
- (with-temp-buffer
- (setq emms-stream-info-downloaded (+ emms-stream-info-downloaded
- (length str)))
-
- ;; Insert a quanta of data.
- (insert str)
-
- ;; Look for headers
- (unless emms-stream-info-header-flag
- (mapc (lambda (term)
- (goto-char (point-min))
- (if (re-search-forward
- (concat (regexp-opt
- (list "icy-" "ice-"))
- term
- ":\\("
- emms-stream-info-stream-header-regexp
- "\\)")
- (point-max) t)
- (progn
- (add-to-list 'emms-stream-info-found
- (cons term
- (emms-match-string-no-properties 1)))
- (setq emms-stream-info-header-flag t))))
- emms-stream-info-vocab))
-
- ;; Look for title
- (unless emms-stream-info-title-flag
- (goto-char (- (point)
- (length str)))
- (cond ((re-search-forward
- emms-stream-info-icecast-capture-pattern
- (point-max)
- t)
- (setq emms-stream-info-found
- (append
- emms-stream-info-found
- (emms-stream-info-decode-ogg
- (match-beginning 1)
- (match-end 1))))
- (setq emms-stream-info-title-flag t))
- ;; In retrospect this section mimics input_http.c from
- ;; the Xine project only that it uses buffer searching.
- ((re-search-forward
- emms-stream-info-shoutcast-title-regexp
- (point-max)
- t)
- (setq emms-stream-info-found
- (append emms-stream-info-found
- (emms-stream-info-decode-mp3
- (match-beginning 1)
- (match-end 1))))
- (setq emms-stream-info-title-flag t))))
-
- ;; Too many nested conditions
- (if (emms-stream-info-set-continue)
- (unless emms-stream-info-streamlist-flag
- (goto-char (point-min))
- (if (re-search-forward
- emms-stream-info-streamlist-regexp
- (point-max) t)
- (progn
- (setq emms-stream-info-streamlist-found
- (or (emms-match-string-no-properties 1)
- (emms-match-string-no-properties 2)))
- (setq emms-stream-info-streamlist-flag t))))))
-
- ;; Be chatty at the user
- (if emms-stream-info-verbose
- (message "Connection %s. Downloaded %d/%d bytes."
- (process-status proc)
- emms-stream-info-downloaded
- emms-stream-info-max))
-
- ;; Find out if we need to kill the connection
- (if (or (> emms-stream-info-downloaded emms-stream-info-max) ; maxed out?
- ;; Captured header and title info?
- (and emms-stream-info-header-flag emms-stream-info-title-flag)
- ;; Captured streamlist info?
- emms-stream-info-streamlist-flag)
- (emms-stream-info-kill-process proc)))
-
-;; Closing the connection proves to be the most difficult part of the
-;; program. There is a difference in the way emacs21 vs. emacs22
-;; behave.
-(defun emms-stream-info-kill-process (proc)
- "Hold Emacs while trying to close the connection.
-Argument PROC Process."
- (while (not (equal (process-status proc) 'closed))
- (delete-process proc))
- (if (process-filter proc)
- (set-process-filter proc nil))
- ;; Workaround Emacs 21 sentinel problems
- (when (= emacs-major-version 21)
- (emms-stream-info-after-function)))
-
-(defun emms-stream-info-after-function ()
- "Evalutated when the connection ends."
- (setq emms-stream-info-read-inhibit nil) ; allow reading
- (run-hooks 'emms-stream-info-read-hook)
- (run-hooks 'emms-stream-info-return-hook))
-
-(defun emms-stream-info-sentinel (proc ev)
- "Sentinel function for network process.
-Argument PROC Process.
-Argument EV Event string."
- ;; Workaround Emacs 21 sentinel problems
- (unless (= emacs-major-version 21)
- (emms-stream-info-after-function)))
-
-(defun emms-stream-info-make-request-string (file)
- "Return a valid HTTP request string with FILE as a URI."
- (concat "GET "
- (if (equal file "")
- "/"
- file)
- " HTTP/1.0\r\n"
- "User-Agent: Free software (see www.gnu.org), reads title of currently playing track (discards audio).\r\n"
- "Icy-MetaData:1\r\n"
- "\r\n"))
-
-(defun emms-stream-info-parse-url (urlstring)
- "Set the global variables for connecting to the streaming audio
-server at URLSTRING."
- (let* ((url (emms-stream-info-decompose-url urlstring))
- (hostname (elt url 3))
- (port (elt url 4))
- (file (elt url 5))
- (protocol (elt url 0)))
-
- (cond ((or (not (equal protocol "http"))
- (equal hostname ""))
- (error "Invalid URL"))
-
- ;; eg. "http://music.station.com:8014"
- ((and (empty-string-p file)
- port)
- (setq emms-stream-info-port port))
-
- ;; eg. "http://ogg.smgradio.com/vr96.ogg"
- ((and (not (empty-string-p file))
- (or (equal port "")
- (equal port nil)
- (equal port 0)))
- (setq emms-stream-info-port 80))
-
- ;; eg. "http://audio.ibiblio.org:8010/wcpe.ogg"
- ((and (not (empty-string-p file))
- port)
- (setq emms-stream-info-port port))
-
- (t (error "Invalid URL")))
-
- (setq emms-stream-info-url hostname
- emms-stream-info-request-string
- (emms-stream-info-make-request-string file))))
-
-(defun empty-string-p (str)
- "Return t if STR is equal to the empty string."
- (equal str ""))
-
-(defun emms-stream-info-reset-state ()
- (setq emms-stream-info-downloaded 0) ; restart fallback
- (setq emms-stream-info-title-flag nil) ; forget title flag
- (setq emms-stream-info-header-flag nil) ; forget header flag
- (setq emms-stream-info-found nil) ; forget output
- (setq emms-stream-info-streamlist-found nil) ; forget streamlist
- (setq emms-stream-info-streamlist-flag nil) ; forget streamlist
- (setq emms-stream-info-read-inhibit t) ; do not read output
-
- ;; Reset state machine
- (emms-stream-info-unset-message)
- (emms-stream-info-unset-insert)
- (emms-stream-info-unset-continue)
-
- ;; forget hooks
- (remove-hook 'emms-stream-info-return-hook
- 'emms-stream-info-pretty-print)
- (remove-hook 'emms-stream-info-return-hook
- 'emms-stream-info-continue)
- (remove-hook 'emms-stream-info-return-hook
- 'emms-stream-info-pretty-print-insert))
-
-;; -------------------------------------------------------------------
-;; Interactive functions
-;; -------------------------------------------------------------------
-
-(defun emms-stream-info-get (&optional urlstring say write cont)
- "Get streaming audio server header metadata and song title from stream at URL.
-Argument URLSTRING Address of streaming audio server as a string.
-If URLSTRING is nil then get the latest stream played via emms.
-Optional argument SAY boolean.
-Optional argument WRITE boolean.
-Optional argument CONT boolean."
- (interactive)
-
- (if urlstring
- (emms-stream-info-parse-url urlstring)
- (and (boundp 'emms-stream-last-stream)
- (fboundp 'emms-stream-url)
- emms-stream-last-stream
- (emms-stream-info-parse-url
- (emms-stream-url emms-stream-last-stream))))
-
- (emms-stream-info-reset-state)
-
- ;; Output formatted text as a message.
- (if say
- (progn
- (add-hook 'emms-stream-info-return-hook
- 'emms-stream-info-pretty-print)
- (emms-stream-info-set-message)))
- ;; Insert formatted text into the current buffer.
- (if write
- (progn
- (add-hook 'emms-stream-info-return-hook
- 'emms-stream-info-pretty-print-insert)
- (emms-stream-info-set-insert)))
- ;; Continue to the next connection after this one.
- (if cont
- (progn
- (add-hook 'emms-stream-info-return-hook
- 'emms-stream-info-continue)
- (emms-stream-info-set-continue)))
-
- ;; Debugging flag dependent
- (if emms-stream-info-debugging
- (progn
- (if (get-buffer emms-stream-info-debug-buffer)
- (kill-buffer emms-stream-info-debug-buffer))
- (get-buffer-create emms-stream-info-debug-buffer)))
-
- ;; Open connection
- (condition-case nil
- (if (fboundp 'make-network-process)
- (make-network-process :name emms-stream-info-procname
- :buffer nil
- :host emms-stream-info-url
- :service emms-stream-info-port)
- (open-network-stream emms-stream-info-procname
- nil
- emms-stream-info-url
- emms-stream-info-port))
- (error
- (emms-stream-info-reset-state)
- (message "Error connecting to streaming audio sever at %s"
- emms-stream-info-url)))
-
- (let ((proc (get-process emms-stream-info-procname)))
- (when proc
-
- ;; Connection timeone
- (run-at-time emms-stream-info-timeout
- nil
- 'emms-stream-info-kill-process
- proc)
-
- ;; Start download
- (process-send-string emms-stream-info-procname
- emms-stream-info-request-string)
- (set-process-sentinel proc
- 'emms-stream-info-sentinel)
- (set-process-filter proc
- 'emms-stream-info-filter)
- (unless (process-sentinel proc)
- (error "No process sentinel")))))
-
-;; Should be phased out.
-;; (defun emms-stream-info-input-sanity (&optional urlstring)
-;; (let ((type (emms-track-type (emms-playlist-selected-track))))
-;; (cond ((null urlstring)
-;; (if (or (equal type 'streamlist)
-;; (equal type 'url))
-;; (emms-track-name (emms-playlist-selected-track))))
-;; ((not (stringp urlstring))
-;; (error "URL must be in string format"))
-;; ((stringp url) urlstring))))
-
-(defun emms-stream-info-input-sanity (&optional urlstring)
- (if (stringp urlstring)
- urlstring
- (error "URL must be in string format")))
-
-(defun emms-stream-info-message (&optional urlstring)
- "Get information from streaming audio server at URLSTRING.
-Return a formatted message.
-URLSTRING should be a string."
- (interactive)
- (let ((url (emms-stream-info-input-sanity urlstring)))
- (cond ((equal (emms-stream-info-streamlist-type url) 'pls)
- (emms-stream-info-get url t nil t))
- ((equal (emms-stream-info-streamlist-type url) 'm3u)
- (emms-stream-info-get url t nil t))
- (t (emms-stream-info-get url t)))))
-
-;; Insertion does not work for sequential connections.
-(defun emms-stream-info-insert (&optional urlstring)
- "Get information from streaming audio server at URLSTRING.
-Insert a formatted message at point.
-URLSTRING should be a string."
- (interactive)
- (let ((url (emms-stream-info-input-sanity urlstring)))
- (cond ((equal (emms-stream-info-streamlist-type url) 'pls)
- (emms-stream-info-get url nil t t))
- ((equal (emms-stream-info-streamlist-type url) 'm3u)
- (emms-stream-info-get url nil t t))
- (t (emms-stream-info-get url nil t)))))
+ (message "querying stream...")
+ (cond
+ ((eq *emms-stream-info-backend* 'mplayer)
+ (emms-stream-info-mplayer-backend url)
+ (emms-stream-info-defreg name "^Name[ ]+:[ ]+\\(.*\\)$")
+ (emms-stream-info-defreg genre "^Genre[ ]+:[ ]+\\(.*\\)$")
+ (emms-stream-info-defreg bitrate "^Bitrate[ ]+:[ ]+\\(.*\\)$")
+ (emms-stream-info-defreg nowplaying "ICY Info: StreamTitle='\\(.+?\\)'"))
+ ((eq *emms-stream-info-backend* 'vlc)
+ (emms-stream-info-vlc-backend url)
+ (emms-stream-info-defreg name "'Title' = '\\(.*\\)'")
+ (emms-stream-info-defreg genre "Genre: \\(.*\\)")
+ (emms-stream-info-defreg bitrate "bitrate:\\([0-9].+\\)")
+ (emms-stream-info-defreg nowplaying "'Now Playing' = '\\(.+?\\)'"))
+ (t (error "Unknown backend"))))
+ (message "querying stream...done")
+ (list name genre bitrate nowplaying)))
+
+;; point of entry
+(defun emms-stream-info-message (url)
+ "Display a message with information about the stream at URL."
+ (interactive "Murl: ")
+ (let* ((stream-info (emms-stream-info-call-backend url))
+ (name (nth 0 stream-info))
+ (genre (nth 1 stream-info))
+ (bitrate (nth 2 stream-info))
+ (nowplaying (nth 3 stream-info)))
+ (message "now playing: %s on %s, genre: %s, bitrate: %s"
+ nowplaying name genre bitrate)))
(provide 'emms-stream-info)