aboutsummaryrefslogtreecommitdiff
path: root/emms-info.el
blob: b5148f38efb5952ae3b5fd8c15af6aad3a26bbbb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
;;; emms-info.el --- Info system for EMMS 

;; Copyright (C) 2003  Free Software Foundation, Inc.

;; Author: Ulrik Jensen <terryp@daimi.au.dk>
;; Keywords: 

;; This file 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, or (at your option)
;; any later version.

;; This file 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
;; Boston, MA 02110-1301 USA

;;; Commentary:

;; This file provides an interface for different methods of reading
;; info about the files that EMMS is playing, and displaying it.

;; To create a method for retrieving info about a file, you create an
;; object like this:

;; (define-emms-info-method emms-info-mp3info
;;   :providep 'emms-info-mp3info-providep
;;   :get 'emms-info-mp3info-get
;;   :set 'emms-info-mp3info-set)

;; Then you register it with emms-info, by adding it to
;; `emms-info-methods-list'.

;; (add-to-list 'emms-info-methods-list 'emms-info-ogg-comment)

;;; Code:
(require 'emms)

(eval-when-compile (require 'cl))

(defvar emms-info-version "0.2 $Revision: 1.16 $"
  "EMMS info version string.")
;; $Id: emms-info.el,v 1.16 2005/08/12 17:59:30 xwl Exp $

;; Customizations
(defgroup emms-info nil
  "*Info system for EMMS"
  :prefix "emms-info-"
  :group 'emms)

(defgroup emms-info-methods nil
  "*Methods to get info for EMMS-info"
  :group 'emms-info
  :prefix "emms-info-")

(defcustom emms-info-methods-list nil
  "List of info-methods. You need to set this."
  :group 'emms-info
  :type '(repeat function))

;; Caching
(defcustom emms-info-cache t
  "Boolean value, indicating whether or not to use a cache for
info-structures."
  :group 'emms-info
  :type 'boolean)

(defcustom emms-info-format '("%s - %s" (emms-info-artist emms-info-title))
  "Format the info string.
The first element of the list is a string with typical format
instructions, the cdr is a list of functions that get called with
the struct as argument."
  :type '(list string (repeat sexp))
  :group 'emms-pbi)

(defvar emms-info-cache-hash-table nil
  "A hash-table storing the cached info.

Uses tracks as keys and the emms-info structures as
values.")

 ;; The structure for info about files:
(defstruct emms-info title artist album note year genre file
  playing-time playing-time-min playing-time-sec)

;; Interface
(defmacro define-emms-info-method (name &rest alist)
  `(defun ,name (action)
     (plist-get ',(mapcar (lambda (keyword)
                            (if (not (keywordp keyword))
                                (cadr keyword)
                              (intern (substring (symbol-name keyword) 1))))
                          alist)
                action)))

;; Methods for the cache
(defun emms-info-get-cached (track)
  "Return cached info for the track TRACK, nil of no cache."
  (if emms-info-cache-hash-table
      (gethash track emms-info-cache-hash-table nil)
    nil))

(defun emms-info-set-cached (track info)
  "Set cached info for TRACK to INFO"
  (unless emms-info-cache-hash-table
    ;; No hash-table yet, create one
    (setq emms-info-cache-hash-table (make-hash-table :test 'equal)))
  (puthash track info emms-info-cache-hash-table))

;; Retrieve 
(defun emms-info-method-for (track)
  "Return an info-method suitable for TRACK."
  (unless emms-info-methods-list 
    (error "There are no info-methods defined at all. You should customize `emms-info-methods-alist'."))
  ;; find an info-method capable of providing info for this file
  (let ((curmethod emms-info-methods-list))
    (while (and curmethod
		(not (funcall (funcall (car curmethod) 'providep) track)))
      (setq curmethod (cdr curmethod)))
    (when curmethod
      (car curmethod))))

(defun emms-info-get (track &optional dont-use-cached)
  "Return an emms-info structure representing the track TRACK.
if DONT-USE-CACHED is non-nil, then always read from the file."
  ;; extend with methods for caching
  (let ((method (emms-info-method-for track))
	(cached (emms-info-get-cached track)))
    (if (or dont-use-cached (not emms-info-cache) (not cached))
	;; read from the file
	(when method
	  (let ((readinfo (funcall (funcall method 'get) track)))
	    (when emms-info-cache
	      ;; save the cache
	      (emms-info-set-cached track readinfo))
	    ;; return the read version
	    readinfo))
      ;; else just use the cached
      cached)))

(defun emms-info-set (track info)
  "Set the info of the file TRACK to the emms-info structure INFO."
  (let ((method (emms-info-method-for track)))
    (when method
      (when emms-info-cache
	(emms-info-set-cached track info))
      (funcall (funcall method 'set) track info))))

(defun emms-info-format-info (format struct)
  "Take FORMAT and format it with STRUCT.
For the formaz of FORMAT see `emms-info-format')"
  (apply 'format (car format) 
	 (mapcar (lambda (func) 
		   (funcall func struct)) 
		 (cadr format))))

;; Functions suitable as values of
;; `emms-playlist-get-file-name-function':

(defun emms-info-file-info-song-artist (track)
  "Returns a description of TRACK, build from it's 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!"
    (if (emms-info-method-for track)
	;; read the info
	(let ((info (emms-info-get track)))
	  (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)))))
      ;; we can't read info for this file, default to the name
      (file-name-sans-extension (file-name-nondirectory (emms-track-name track))))))
    
(provide 'emms-info)
;;; emms-info.el ends here