add emms
[emacs.git] / .emacs.d / elisp / emms / lisp / emms-cache.el
1 ;;; emms-cache.el --- persistence for emms-track
2
3 ;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4
5 ;; Author: Damien Elmes <emacs@repose.cx>
6 ;; Keywords: emms, mp3, mpeg, multimedia
7
8 ;; This file is part of EMMS.
9
10 ;; EMMS is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 3, or (at your option)
13 ;; any later version.
14
15 ;; EMMS is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with EMMS; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
24
25 ;;; Commentary:
26
27 ;; The cache is a mapping of a full path name to information, and so
28 ;; it is invalidated when you rename or move files about. It also
29 ;; does not differentiate between file or uri tracks.
30
31 ;; Because cache lookups are much faster than disk access, this works
32 ;; much better with a later-do-interval of something like 0.001. Also
33 ;; consider using synchronous mode, as it's quite fast now.
34
35 ;; This code is activated by (emms-standard) and above.
36
37 ;; To activate it by hand, use:
38
39 ;; (emms-cache 1)
40
41 ;;; Code:
42
43 (require 'emms)
44 (require 'emms-info)
45
46 (when (fboundp 'define-hash-table-test)
47 (define-hash-table-test 'string-hash 'string= 'sxhash))
48
49 (defvar emms-cache-db (make-hash-table
50 :test (if (fboundp 'define-hash-table-test)
51 'string-hash
52 'equal))
53 "A mapping of paths to file info.
54 This is used to cache over emacs sessions.")
55
56 (defvar emms-cache-dirty nil
57 "True if the cache has been updated since init.")
58
59 (defcustom emms-cache-file (concat (file-name-as-directory emms-directory) "cache")
60 "A file used to store cached file information over sessions."
61 :group 'emms
62 :type 'file)
63
64 (defcustom emms-cache-file-coding-system 'utf-8
65 "Coding system used for saving `emms-cache-file'."
66 :group 'emms
67 :type 'coding-system)
68
69 (defun emms-cache (arg)
70 "Turn on Emms caching if ARG is positive, off otherwise."
71 (interactive "p")
72 (if (and arg (> arg 0))
73 (progn
74 (unless emms-cache-dirty
75 (emms-cache-restore))
76 (unless noninteractive
77 (add-hook 'kill-emacs-hook 'emms-cache-save))
78 (setq emms-cache-get-function 'emms-cache-get)
79 (setq emms-cache-set-function 'emms-cache-set)
80 (setq emms-cache-modified-function 'emms-cache-dirty))
81 (remove-hook 'kill-emacs-hook 'emms-cache-save)
82 (setq emms-cache-get-function nil)
83 (setq emms-cache-set-function nil)
84 (setq emms-cache-modified-function nil)))
85
86 ;;;###autoload
87 (defun emms-cache-enable ()
88 "Enable caching of Emms track data."
89 (interactive)
90 (emms-cache 1)
91 (message "Emms cache enabled"))
92
93 ;;;###autoload
94 (defun emms-cache-disable ()
95 "Disable caching of Emms track data."
96 (interactive)
97 (emms-cache -1)
98 (message "Emms cache disabled"))
99
100 ;;;###autoload
101 (defun emms-cache-toggle ()
102 "Toggle caching of Emms track data."
103 (interactive)
104 (if emms-cache-get-function
105 (emms-cache-disable)
106 (emms-cache-enable)))
107
108 (defsubst emms-cache-dirty (&rest ignored)
109 "Mark the cache as dirty."
110 (setq emms-cache-dirty t))
111
112 (defun emms-cache-get (type path)
113 "Return a cache element for PATH, or nil."
114 (gethash path emms-cache-db))
115
116 ;; Note we ignore TYPE, as it's stored in TRACK
117 (defun emms-cache-set (type path track)
118 "Set PATH to TRACK in the cache."
119 (puthash path track emms-cache-db)
120 (emms-cache-dirty))
121
122 (defun emms-cache-del (path)
123 "Remove a track from the cache, with key PATH."
124 (remhash path emms-cache-db)
125 (emms-cache-dirty))
126
127 (defun emms-cache-save ()
128 "Save the track cache to a file."
129 (interactive)
130 (when emms-cache-dirty
131 (message "Saving emms track cache...")
132 (set-buffer (get-buffer-create " emms-cache "))
133 (erase-buffer)
134 (insert
135 (concat ";;; .emms-cache -*- mode: emacs-lisp; coding: "
136 (symbol-name emms-cache-file-coding-system)
137 "; -*-\n"))
138 (maphash (lambda (k v)
139 (insert (format
140 "(puthash %S '%S emms-cache-db)\n" k v)))
141 emms-cache-db)
142 (when (fboundp 'set-buffer-file-coding-system)
143 (set-buffer-file-coding-system emms-cache-file-coding-system))
144 (unless (file-directory-p (file-name-directory emms-cache-file))
145 (make-directory (file-name-directory emms-cache-file)))
146 (write-region (point-min) (point-max) emms-cache-file)
147 (kill-buffer (current-buffer))
148 (message "Saving emms track cache...done")
149 (setq emms-cache-dirty nil)))
150
151 (defun emms-cache-restore ()
152 "Restore the track cache from a file."
153 (interactive)
154 (load emms-cache-file t nil t)
155 (setq emms-cache-dirty nil))
156
157 (defun emms-cache-sync ()
158 "Sync the cache with the data on disc.
159 Remove non-existent files, and update data for files which have
160 been modified."
161 (interactive)
162 (message "Syncing emms track cache...")
163 (let (removed)
164 (maphash (lambda (path track)
165 (when (eq (emms-track-get track 'type) 'file)
166 ;; if no longer here, remove
167 (if (not (file-exists-p path))
168 (progn
169 (remhash path emms-cache-db)
170 (setq removed t))
171 (let ((file-mtime (emms-info-track-file-mtime track))
172 (info-mtime (emms-track-get track 'info-mtime)))
173 (when (or (not info-mtime)
174 (emms-time-less-p
175 info-mtime file-mtime))
176 (run-hook-with-args 'emms-info-functions track))))))
177 emms-cache-db)
178 (when removed
179 (setq emms-cache-dirty t)))
180 (message "Syncing emms track cache...done"))
181
182 (provide 'emms-cache)
183 ;;; emms-cache.el ends here