[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [bongo-devel] Re: Stream metadata
From: |
Daniel Brockman |
Subject: |
Re: [bongo-devel] Re: Stream metadata |
Date: |
Sun, 08 Apr 2007 18:26:03 +0200 |
User-agent: |
Gnus/5.11 (Gnus v5.11) Emacs/22.0.92 (gnu/linux) |
address@hidden (Daniel Jensen) writes:
> Daniel Brockman <address@hidden> writes:
>
>> Here are my new suggestions:
>>
>> - `stream-genre'
>> - `stream-title'
>> - `stream-part-title'
>
> Okay. For the record, I still prefer stream "name"!
> It sounds more natural to me.
Okay, let's go with that. I changed that one back to
`stream-name', and kept the other two as above.
I have been massaging this code for a while now, trying to
make it fit nicely into Bongo. I believe I've come up with
something reasonably clean (but the process has certainly
reminded me of why I started to consider deeper changes).
>> Thanks. I should read it. I want to understand Common Lisp.
>
> I'll warn you that the risk of becoming frustrated with Emacs
> Lisp in the future is high.
Bah. I was in love with Scheme before I dug into Emacs Lisp. :-)
Anyway, please consider the following patch. I believe it
is fit for installation, but you may want to make changes.
It is a move away from treating infosets as data stores,
and towards treating them as a means of data presentation.
That's not the way I originally thought of them, --- quite
the opposite, in fact, --- but it appears to be more natural
given the skew and evolution that the code has gone through.
It is also a move towards recognizing a special kind of
track for streams. This also appears to be a more natural
way of meeting the goals we have for this feature.
Here's a brief description of how the code works now:
* Players set their `stream-name', `stream-part-title'
and `stream-genre' properties and notify Bongo by
calling `bongo-player-metadata-changed'.
* The `stream-name' and `stream-genre' properties are
propagated (i.e., duplicated) to the track line.
(This is because they should accompany the track wherever
it goes --- it could be copied, enqueued, saved, etc.)
They are stored in properties called `bongo-stream-name'
and `bongo-stream-genre'.
* The infoset for a URI track line that has at least one
stream property is built (on demand) like so:
`((artist . unknown)
(album . unknown)
(stream (uri . ,(bongo-line-file-name))
(uri-title
. ,(bongo-line-get-property 'bongo-uri-title))
(name
. ,(bongo-line-get-property 'bongo-stream-name))
(genre
. ,(bongo-line-get-property 'bongo-stream-genre))
(part-title . ,stream-part-title)))
(As the stream part title is not stored in a track
line property, it is taken from the player property.)
The URI title is the user-specified title for the URI,
which used to be stored in the infoset. In case there's
no URI title or stream name, the URI itself is included.
* I don't know where I'm going with this and why I made
this into a bulleted list so I'll just stop here.
diff -rN -u old-bongo/bongo.el new-bongo/bongo.el
--- old-bongo/bongo.el 2007-04-08 14:33:05.000000000 +0200
+++ new-bongo/bongo.el 2007-04-08 14:33:05.000000000 +0200
@@ -658,7 +658,27 @@
When the expressions are evaluated,
- `bongo-action-description' is bound to the action description;
- `bongo-action-expression' is bound to the action expression;
- - `bongo-target' is short for `bongo-infoset-formattnig-target';
+ - `bongo-target' is short for `bongo-infoset-formatting-target';
+ - `bongo-line' is short for `bongo-infoset-formatting-target-line'."
+ :type '(repeat sexp)
+ :group 'bongo-display)
+
+(defcustom bongo-stream-format
+ '((or bongo-uri-title bongo-stream-name bongo-uri)
+ (when bongo-stream-genre
+ (concat " (" bongo-stream-genre ")"))
+ (when bongo-stream-part-title
+ (concat ": " bongo-stream-part-title)))
+ "Template for displaying stream tracks in Bongo.
+Value is a list of expressions, each evaluating to a string or nil.
+The values of the expressions are concatenated.
+When the expressions are evaluated,
+ - `bongo-uri' is bound to the URI of the stream;
+ - `bongo-uri-title' is bound to the URI title or nil;
+ - `bongo-stream-name' is bound to the stream name or nil;
+ - `bongo-stream-genre' is bound to the stream genre or nil;
+ - `bongo-stream-part-title' is bound to the stream part title;
+ - `bongo-target' is short for `bongo-infoset-formatting-target';
- `bongo-line' is short for `bongo-infoset-formatting-target-line'."
:type '(repeat sexp)
:group 'bongo-display)
@@ -1896,7 +1921,31 @@
(require 'format-spec)
(format-spec bongo-track-format `((?t . ,bongo-title)
(?i . ,bongo-index)))))))
+ ((stream)
+ ;; These variables are used in `bongo-stream-format',
+ ;; so their names are significant.
+ (let ((bongo-uri
+ (propertize (bongo-alist-get data 'uri)
+ 'face 'bongo-album-title))
+ (bongo-uri-title
+ (when (bongo-alist-get data 'uri-title)
+ (propertize (bongo-alist-get data 'uri-title)
+ 'face 'bongo-album-title)))
+ (bongo-stream-name
+ (when (bongo-alist-get data 'name)
+ (propertize (bongo-alist-get data 'name)
+ 'face 'bongo-album-title)))
+ (bongo-stream-genre
+ (when (bongo-alist-get data 'genre)
+ (bongo-alist-get data 'genre)))
+ (bongo-stream-part-title
+ (when (bongo-alist-get data 'part-title)
+ (propertize (bongo-alist-get data 'part-title)
+ 'face 'bongo-track-title))))
+ (bongo-format-string bongo-stream-format)))
((action)
+ ;; These variables are used in `bongo-action-format',
+ ;; so their names are significant.
(let ((bongo-action-expression data)
(bongo-action-description
(let ((description-specifier
@@ -2596,8 +2645,40 @@
(bongo-point-at-bol)
(bongo-point-at-previous-track-line))))
-(defun bongo-infoset-from-action (action)
- `((action . ,action)))
+(defun bongo-uri-track-infoset (&optional point)
+ "Return the infoset for the URI track at POINT.
+You should use `bongo-line-infoset' most of the time."
+ (let ((file-name
+ (bongo-line-file-name point))
+ (uri-title
+ (bongo-line-get-property 'bongo-uri-title point))
+ (stream-name
+ (bongo-line-get-property 'bongo-stream-name point))
+ (stream-genre
+ (bongo-line-get-property 'bongo-stream-genre point))
+ (stream-part-title
+ (let ((player (bongo-line-get-property 'bongo-player point)))
+ (and player (bongo-player-running-p player)
+ (bongo-player-get player 'stream-part-title)))))
+ (cond ((or stream-name stream-genre stream-part-title)
+ `((artist . unknown)
+ (album . unknown)
+ (stream (uri . ,file-name)
+ (uri-title . ,uri-title)
+ (name . ,stream-name)
+ (genre . ,stream-genre)
+ (part-title . ,stream-part-title))))
+ (uri-title
+ `((artist . unknown)
+ (album . unknown)
+ (track (title . ,(or uri-title stream-name)))))
+ (t
+ (bongo-infoset-from-file-name file-name)))))
+
+(defun bongo-action-track-infoset (&optional point)
+ "Return the infoset for the action track at POINT.
+You should use `bongo-line-infoset' most of the time."
+ `((action . ,(bongo-line-action point))))
(defun bongo-track-infoset (&optional point)
"Return the infoset for the track at POINT.
@@ -2605,10 +2686,13 @@
(unless (bongo-track-line-p point)
(error "Point is not on a track line"))
(or (bongo-line-get-property 'bongo-infoset point)
- (cond ((bongo-line-file-name point)
- (bongo-infoset-from-file-name (bongo-line-file-name point)))
- ((bongo-line-action point)
- (bongo-infoset-from-action (bongo-line-action point))))))
+ (let (file-name)
+ (cond ((setq file-name (bongo-line-file-name point))
+ (if (bongo-uri-p file-name)
+ (bongo-uri-track-infoset point)
+ (bongo-infoset-from-file-name file-name)))
+ ((bongo-line-action point)
+ (bongo-action-track-infoset))))))
(defun bongo-header-infoset (&optional point)
"Return the infoset for the header at POINT.
@@ -3075,8 +3159,9 @@
(defvar bongo-line-semantic-properties
;; When changing this, consider also changing
;; `bongo-line-serializable-properties'.
- (list 'bongo-file-name 'bongo-action
- 'bongo-infoset 'bongo-backend
+ (list 'bongo-file-name 'bongo-action 'bongo-backend
+ 'bongo-infoset 'bongo-uri-title
+ 'bongo-stream-name 'bongo-stream-genre
'bongo-fields 'bongo-external-fields
'bongo-header 'bongo-collapsed
'bongo-marked 'bongo-reference-counted-marker
@@ -3101,6 +3186,7 @@
(position (bongo-point-at-eol point)))
(bongo-ensure-final-newline)
(put-text-property position (1+ position) name value)))
+(put 'bongo-line-set-property 'lisp-indent-function 1)
(defun bongo-line-set-properties (properties &optional point)
"Set the text properties PROPERTIES on the line at POINT.
@@ -4524,6 +4610,44 @@
(when (bufferp bongo-seek-buffer)
(bongo-seek-redisplay))))
+(defcustom bongo-player-metadata-changed-hook '(bongo-show)
+ "Normal hook run when a Bongo player receives new metadata."
+ :options '(bongo-show)
+ :type 'hook
+ :group 'bongo)
+
+(defvar bongo-player-metadata-changed-functions nil
+ "Abnormal hook run when a Bongo player receives new metadata.")
+
+(defun bongo-player-metadata-changed (player)
+ "Take actions appropriate for when PLAYER's metadata changed.
+Changing metadata is provided by some Internet radio streams.
+This function runs the hooks `bongo-player-metadata-changed-hook'
+ and `bongo-player-metadata-changed-functions'.
+The following metadata properties are currently used:
+ `stream-name' - The name of the stream.
+ `stream-genre' - The genre of the stream.
+ `stream-part-title' - The title of the part that is
+ currently being streamed."
+ (save-current-buffer
+ (when (buffer-live-p (bongo-player-buffer player))
+ (set-buffer (bongo-player-buffer player)))
+ (run-hook-with-args 'bongo-stream-metadata-changed-functions player)
+ (when (bongo-buffer-p)
+ (save-excursion
+ (goto-char (bongo-point-at-current-track-line))
+ (bongo-line-set-property 'bongo-stream-name
+ (bongo-player-get player 'stream-name))
+ (bongo-line-set-property 'bongo-stream-genre
+ (bongo-player-get player 'stream-genre))
+ (bongo-player-put player 'infoset (bongo-line-infoset))
+ (when bongo-header-line-mode
+ (bongo-update-header-line-string))
+ (when bongo-mode-line-indicator-mode
+ (bongo-update-mode-line-indicator-string))
+ (bongo-redisplay-line))
+ (run-hooks 'bongo-stream-metadata-changed-hook))))
+
(defun bongo-player-backend-name (player)
"Return the name of PLAYER's backend."
(car player))
@@ -5244,49 +5368,99 @@
(with-temp-buffer
(insert string)
(goto-char (point-min))
- (while (not (eobp))
- (cond
- ((looking-at (eval-when-compile
- (rx (and line-start
- "status change:"
- (zero-or-more (or space "("))
- "play state:"
- (zero-or-more space)
- (submatch (one-or-more digit))
- (zero-or-more (or space ")"))
- line-end))))
- (case (string-to-number (match-string 1))
- ((1 3)
- (bongo-player-put player 'paused nil)
- (bongo-player-paused/resumed player)
- (when (null (bongo-player-get player 'timer))
- (bongo-vlc-player-start-timer player)))
- ((2 4)
- (bongo-player-put player 'paused t)
- (bongo-player-paused/resumed player))))
- ((looking-at (eval-when-compile
- (rx (and line-start
- (optional
- (and "[" (zero-or-more digit) "]"))
- (zero-or-more space)
- "main playlist: nothing to play"
- line-end))))
- (process-send-string process "quit\n"))
- ((looking-at (eval-when-compile
- (rx (and line-start
- (submatch (one-or-more digit))
- (zero-or-more space)
- line-end))))
- (when (bongo-player-get player 'pending-queries)
- (let ((value (string-to-number (match-string 1))))
- (ecase (bongo-player-shift player 'pending-queries)
- (time
- (bongo-player-update-elapsed-time player value)
- (bongo-player-times-changed player))
- (length
- (bongo-player-update-total-time player value)
- (bongo-player-times-changed player)))))))
- (forward-line))))
+ (let (stream-name stream-genre stream-part-title)
+ (while (not (eobp))
+ (cond ((looking-at
+ (eval-when-compile
+ (rx (and line-start
+ "status change:"
+ (zero-or-more (or space "("))
+ "play state:"
+ (zero-or-more space)
+ (submatch (one-or-more digit))
+ (zero-or-more (or space ")"))
+ line-end))))
+ (case (string-to-number (match-string 1))
+ ((1 3)
+ (bongo-player-put player 'paused nil)
+ (bongo-player-paused/resumed player)
+ (when (null (bongo-player-get player 'timer))
+ (bongo-vlc-player-start-timer player)))
+ ((2 4)
+ (bongo-player-put player 'paused t)
+ (bongo-player-paused/resumed player))))
+ ((looking-at
+ (eval-when-compile
+ (rx (and line-start
+ (optional
+ (and "[" (zero-or-more digit) "]"))
+ (zero-or-more space)
+ "main input debug:"
+ (zero-or-more space)
+ "- 'Title' = '"
+ (submatch (zero-or-more not-newline))
+ "'"
+ line-end))))
+ (setq stream-name (match-string 1)))
+ ((looking-at
+ (eval-when-compile
+ (rx (and line-start
+ (optional
+ (and "[" (zero-or-more digit) "]"))
+ (zero-or-more space)
+ "main input debug:"
+ (zero-or-more space)
+ "- 'Genre' = '"
+ (submatch (zero-or-more not-newline))
+ "'"
+ line-end))))
+ (setq stream-genre (match-string 1)))
+ ((looking-at
+ (eval-when-compile
+ (rx (and line-start
+ (optional
+ (and "[" (zero-or-more digit) "]"))
+ (zero-or-more space)
+ "main input debug:"
+ (zero-or-more space)
+ "- 'Now Playing' = '"
+ (submatch (zero-or-more not-newline))
+ "'"
+ line-end))))
+ (setq stream-part-title (match-string 1)))
+ ((looking-at
+ (eval-when-compile
+ (rx (and line-start
+ (optional
+ (and "[" (zero-or-more digit) "]"))
+ (zero-or-more space)
+ "main playlist: nothing to play"
+ line-end))))
+ (process-send-string process "quit\n"))
+ ((looking-at
+ (eval-when-compile
+ (rx (and line-start
+ (submatch (one-or-more digit))
+ (zero-or-more space)
+ line-end))))
+ (when (bongo-player-get player 'pending-queries)
+ (let ((value (string-to-number (match-string 1))))
+ (ecase (bongo-player-shift player 'pending-queries)
+ (time
+ (bongo-player-update-elapsed-time player value)
+ (bongo-player-times-changed player))
+ (length
+ (bongo-player-update-total-time player value)
+ (bongo-player-times-changed player)))))))
+ (forward-line))
+ (when stream-name
+ (bongo-player-put player 'stream-name stream-name))
+ (when stream-genre
+ (bongo-player-put player 'stream-genre stream-genre))
+ (when stream-part-title
+ (bongo-player-put player 'stream-part-title stream-part-title))
+ (when (or stream-name stream-genre stream-part-title)
+ (bongo-stream-metadata-changed player)))))
;; Getting errors in process filters is not fun, so stop.
(error (bongo-stop)
(signal (car condition) (cdr condition)))))
@@ -5296,6 +5470,8 @@
(arguments (append
(when bongo-vlc-interactive
(append (list "-I" "rc" "--rc-fake-tty")
+ (when (bongo-uri-p file-name)
+ (list "-vv"))
(when (eq window-system 'w32)
(list "--rc-quiet"))))
(bongo-evaluate-program-arguments
@@ -7039,11 +7215,7 @@
nil nil uri)))
(list uri title)))
(with-bongo-buffer
- (apply 'bongo-insert-line 'bongo-file-name uri
- (when title
- (list 'bongo-infoset `((artist . unknown)
- (album . unknown)
- (track (title . ,title)))))))
+ (bongo-insert-line 'bongo-file-name uri))
(when (and (interactive-p) (not (bongo-buffer-p)))
(message "Inserted URI: %s"
(bongo-format-infoset
@@ -8333,21 +8505,20 @@
NEW-URI is the new URI; NEW-TITLE, if non-nil, is the new title."
(interactive
(when (bongo-uri-track-line-p)
- (list (read-from-minibuffer "Change URI to: " (bongo-line-file-name))
- (let ((old-title
- (cdr (assq 'title
- (cdr (assq 'track
- (bongo-line-infoset)))))))
- (read-from-minibuffer "Change URI title to: " old-title)))))
+ (list (read-from-minibuffer
+ "Change URI to: " (bongo-line-file-name))
+ (read-from-minibuffer
+ "Change URI title to: "
+ (or (bongo-line-get-property 'bongo-uri-title)
+ (bongo-line-get-property 'bongo-stream-name))))))
(with-point-at-bongo-track point
(when (not (bongo-uri-track-line-p))
(error "No URI track at point"))
(bongo-line-set-property 'bongo-file-name new-uri)
(when new-title
- (bongo-line-set-property 'bongo-infoset
- `((artist . unknown)
- (album . unknown)
- (track (title . ,new-title)))))
+ (bongo-line-set-property 'bongo-uri-title
+ (and (not (equal new-title ""))
+ new-title)))
(bongo-redisplay-line)))
(defun bongo-rename-action-track (new-action &optional point)
@@ -8452,8 +8623,9 @@
(defvar bongo-line-serializable-properties
;; When changing this, consider also changing
;; `bongo-line-semantic-properties'.
- (list 'bongo-file-name 'bongo-action
- 'bongo-infoset 'bongo-backend
+ (list 'bongo-file-name 'bongo-action 'bongo-backend
+ 'bongo-infoset 'bongo-uri-title
+ 'bongo-stream-name 'bongo-stream-genre
'bongo-fields 'bongo-external-fields
'bongo-header 'bongo-collapsed)
"List of serializable text properties used in Bongo buffers.
--
Daniel Brockman <address@hidden>
- [bongo-devel] Re: Stream metadata, Daniel Jensen, 2007/04/01
- Re: [bongo-devel] Re: Stream metadata, Daniel Brockman, 2007/04/01
- [bongo-devel] Re: Stream metadata, Daniel Jensen, 2007/04/02
- Re: [bongo-devel] Re: Stream metadata, Daniel Brockman, 2007/04/02
- [bongo-devel] Re: Stream metadata, Daniel Jensen, 2007/04/03
- Re: [bongo-devel] Re: Stream metadata, Daniel Brockman, 2007/04/03
- [bongo-devel] Re: Stream metadata, Daniel Jensen, 2007/04/04
- Re: [bongo-devel] Re: Stream metadata,
Daniel Brockman <=
- [bongo-devel] Re: Stream metadata, Daniel Jensen, 2007/04/09
- Re: [bongo-devel] Re: Stream metadata, Daniel Brockman, 2007/04/09