aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--emms-history.el33
-rw-r--r--emms-i18n.el22
-rw-r--r--emms-info-ogginfo.el2
-rw-r--r--emms-lyrics.el4
-rw-r--r--emms-mark.el12
-rw-r--r--emms-mp3tag.el218
6 files changed, 187 insertions, 104 deletions
diff --git a/emms-history.el b/emms-history.el
index 3c1720a..cd74681 100644
--- a/emms-history.el
+++ b/emms-history.el
@@ -23,8 +23,7 @@
;;; Commentary:
;; Save playlists when exit emacs.
-;; Next time use M-x emms-playlist-load-saved-list to load saved
-;; playlist
+;; Next time use M-x emms-history-load to load saved playlist
;; Put this file into your load-path and the following into your ~/.emacs:
;; (require 'emms-history)
@@ -36,10 +35,14 @@
(eval-when-compile
(require 'cl))
-(defvar emms-history-saved-list-file "~/.emacs.d/.emms-history")
+(defvar emms-history-file "~/.emacs.d/.emms-history"
+ "File to save playlists")
-(defun emms-history-save-on-exit ()
- (when (stringp emms-history-saved-list-file)
+(defun emms-history-save ()
+ "Save all playlists that open in this emacs session when exit. Use
+`emms-history-load' to load saved playlists."
+ (interactive)
+ (when (stringp emms-history-file)
(let ((oldbuf emms-playlist-buffer)
emms-playlist-buffer playlists)
(save-excursion
@@ -71,17 +74,17 @@
(emms-repeat-playlist . ,emms-repeat-playlist))
(current-buffer))
(insert "\n)")
- (write-file emms-history-saved-list-file))))))
+ (write-file emms-history-file))))))
-(add-hook 'kill-emacs-hook 'emms-history-save-on-exit)
+(add-hook 'kill-emacs-hook 'emms-history-save)
-(defun emms-history-load-saved-list ()
+(defun emms-history-load ()
(interactive)
- (when (and (stringp emms-history-saved-list-file)
- (file-exists-p emms-history-saved-list-file))
+ (when (and (stringp emms-history-file)
+ (file-exists-p emms-history-file))
(let (history buf)
(with-temp-buffer
- (insert-file-contents emms-history-saved-list-file)
+ (insert-file-contents emms-history-file)
(setq history (read (current-buffer)))
(dolist (playlist (cadr history))
(with-current-buffer (emms-playlist-new (car playlist))
@@ -90,12 +93,12 @@
(setq buf (current-buffer)))
(mapc 'emms-playlist-insert-track
(nth 2 playlist))
- (condition-case nil
- (emms-playlist-select (cadr playlist))
- (error nil))))
+ (ignore-errors
+ (emms-playlist-select (cadr playlist)))))
(setq emms-playlist-buffer buf)
(dolist (method (nth 2 history))
(set (car method) (cdr method)))
- (emms-start)))))
+ (ignore-errors
+ (emms-start))))))
;;; emms-history.el ends here
diff --git a/emms-i18n.el b/emms-i18n.el
index 6aa9f6c..26ccbb4 100644
--- a/emms-i18n.el
+++ b/emms-i18n.el
@@ -1,4 +1,4 @@
-;;; emms-i18n.el ---
+;;; emms-i18n.el --- Function for handling coding system
;; Copyright 2006 Ye Wenbin
;;
@@ -63,7 +63,7 @@
(defun emms-iconv-buffer (from to &optional buf)
(save-excursion
(and buf (set-buffer buf))
- (emms-iconv-region-1 (point-min) (point-max) from to)))
+ (emms-iconv-region (point-min) (point-max) from to)))
(defun emms-set-default-coding-system (read-coding write-coding)
"Set `emms-default-coding-system'"
@@ -81,17 +81,31 @@
(cdr default-process-coding-system))))))
(defun emms-call-process-to-string (program &rest args)
+ "This function run program and return the program result. If the CAR
+part of `emms-default-coding-system' is non-nil, the program result will
+be decode use the CAR part of emms-default-coding-system. Otherwise,
+use `emms-coding-dectect-functions' to detect the coding system of the
+result. If the emms-coding-dectect-functions failed, use
+`emms-detect-coding-function' to detect coding system. If all the
+coding system is nil or in `emms-nerver-used-coding-system', decode
+the result using `emms-coding-system-for-read'.
+
+The result arguments ARGS is a list of string which pass to `call-process'."
(with-temp-buffer
(let ((default-process-coding-system (copy-tree default-process-coding-system))
(process-coding-system-alist nil) exit)
(setcar default-process-coding-system (car emms-default-coding-system))
(setq exit (apply 'call-process (append (list program nil t nil) args)))
(when (and (zerop exit) (null (car emms-default-coding-system)))
- (setq coding (emms-detect-buffer-coding-system))
- (decode-coding-region (point-min) (point-max) coding))
+ (decode-coding-region (point-min) (point-max) (emms-detect-buffer-coding-system)))
(and (zerop exit) (buffer-string)))))
+;; Is this function useful?
(defun emms-call-process (program &rest args)
+ "Run the program like `call-process'. If
+the cdr part `emms-default-coding-system' is non-nil, the string in
+ARGS will be encode by the CDR part of `emms-default-coding-system',
+otherwise, it is pass all parameter to `call-process'."
(with-temp-buffer
(if (cdr emms-default-coding-system)
(let ((default-process-coding-system emms-default-coding-system)
diff --git a/emms-info-ogginfo.el b/emms-info-ogginfo.el
index 9de34a9..d8ed2c7 100644
--- a/emms-info-ogginfo.el
+++ b/emms-info-ogginfo.el
@@ -71,7 +71,7 @@ This is a useful element for `emms-info-functions'."
(goto-char (point-min))
(when (re-search-forward "^.*\\.\\.\\.$" (point-max) t)
(while (zerop (forward-line 1))
- (when (looking-at "^\t\\(.*\\)=\\(.*\\)$")
+ (when (looking-at "^\t\\(.*?\\)=\\(.*\\)$") ; recognize the first '='
(let ((a (match-string 1))
(b (match-string 2)))
(when (and (< 0 (length a))
diff --git a/emms-lyrics.el b/emms-lyrics.el
index 54a7417..8013c9d 100644
--- a/emms-lyrics.el
+++ b/emms-lyrics.el
@@ -131,7 +131,9 @@ FILE should be under the same directory as the music file, or under
'type))
(unless (file-exists-p file)
(setq file (emms-lyrics-find-lyric file)))
- (setq file (funcall emms-lyrics-find-lyric-function file)))
+ (setq file
+ (and (functionp emms-lyrics-find-lyric-function)
+ (funcall emms-lyrics-find-lyric-function file))))
(when (and file (not (string= file "")) (file-exists-p file))
(with-temp-buffer
(let ((coding-system-for-read emms-lyrics-coding-system))
diff --git a/emms-mark.el b/emms-mark.el
index d4d917e..9d71cef 100644
--- a/emms-mark.el
+++ b/emms-mark.el
@@ -152,6 +152,7 @@ description function.")
(forward-line 1)))))
(defsubst emms-mark-has-markedp ()
+ "Predicate whether the playlist has marked line"
(save-excursion
(goto-char (point-min))
(re-search-forward (format "^[%c]" emms-mark-char) nil t)))
@@ -160,7 +161,13 @@ description function.")
;;{{{ functions to operate marked tracks
(defun emms-mark-do-with-marked-track (func &optional move)
- "If your function don't move forward, set move to non-nil."
+ "Call FUNC on every marked line in current playlist. The FUNC take
+no argument, so if need the track in marked line, should use
+`emms-playlist-track-at' to get it. The FUNC can also modify the
+playlist buffer, such as delete the line. It is import for who want to
+use this function, this function didn't move forward. So if FUNC don't
+move forward, set the third parameter MOVE to non-nil. Otherwise, the
+function will never exit the loop."
(let ((regexp (format "^[%c]" emms-mark-char))
(newfunc func))
(if move
@@ -172,6 +179,9 @@ description function.")
(funcall newfunc)))))
(defun emms-mark-mapcar-marked-track (func &optional move)
+ "This function does the same thing as
+`emms-mark-do-with-marked-track', the only difference is this function
+collect the result of FUNC."
(let ((regexp (format "^[%c]" emms-mark-char))
result (newfunc func))
(if move
diff --git a/emms-mp3tag.el b/emms-mp3tag.el
index 3e3fd98..1e8be5f 100644
--- a/emms-mp3tag.el
+++ b/emms-mp3tag.el
@@ -1,4 +1,4 @@
-;;; emms-mp3tag.el ---
+;;; emms-mp3tag.el --- Edit track tags.
;; Copyright 2006 Ye Wenbin
;;
@@ -45,29 +45,33 @@
(info-tracknumber . "n")
(info-year . "y")
(info-genre . "g")
- (info-note . "c")))
+ (info-date . "d")
+ (info-note . "c"))
+"A list to setup format.")
(defvar emms-mp3tag-edit-buffer "*EMMS-TAGS*"
"Buffer name to edit mp3 tags")
(defvar emms-mp3tag-log-buffer "*EMMS-LOG*"
"Buffer name of mp3tag edit log")
-(defvar emms-mp3tag-format
- `(("default"
- ,(format "%%m\n%s\n\n"
- (mapconcat
- (lambda (tag)
- (concat (propertize (format "%-16s = " (symbol-name (car tag)))
- 'read-only t 'rear-nonsticky t)
- "%" (cdr tag)))
- (append '((name . "f")) emms-mp3tag-tags) "\n"))
- emms-mp3tag-default-parser))
- "The contents of this variable should look like:
- ((NAME FORMATER PARSER) ...)
-
-The NAME is use to select proper format, and FORMATER should be a
-string or a function. When it is a string, it can use specification
-as:
+(defun emms-mp3tag-make-format (tags)
+ (format "%%m\n%-16s = %%f\n%s\n\n" "name"
+ (mapconcat
+ (lambda (tag)
+ (concat (propertize (format "%-16s = " (symbol-name tag))
+ 'read-only t 'rear-nonsticky t 'face 'bold)
+ "%" (cdr (assoc tag emms-mp3tag-tags))))
+ tags "\n")))
+
+(defvar emms-mp3tag-formats
+ (let* ((tags (mapcar 'car emms-mp3tag-tags))
+ (default (emms-mp3tag-make-format (remove 'info-date tags))))
+ `(("mp3" . ,default)
+ ("ogg" . ,(emms-mp3tag-make-format (remove 'info-year tags)))
+ ("default" . ,default)))
+ "Format to insert the track. The CAR part is the extension of the
+track name, and the CDR part is the format template. The format
+specification is like:
m -- Track description
f -- Track name
a -- Track info-artist
@@ -78,27 +82,79 @@ as:
g -- Track info-genre
c -- Track info-note
-When it is a function, it recept a parameter, the track, and should
-return a string that to insert to `emms-mp3tag-edit-buffer'.
+You can add new specification in `emms-mp3tag-tags' and use
+`emms-mp3tag-make-format' to help create a new format.
-The PARSER is a function to collect all track info in
-`emms-mp3tag-edit-buffer'. It should return the new tracks. If
-the track tag changed, it should add a new property tag-modified
-and set to non-nil. If the track name change, it should set new
-newname to the new file name.
+The CDR part also can be a function, which accept one parameter, the
+track, and should return a string to insert to `emms-mp3tag-edit-buffer'.
")
-(defvar emms-mp3tag-selected-format
- (assoc "default" emms-mp3tag-format))
-
-(defun emms-mp3tag-select-format (format)
- (interactive
- (list (completing-read "Set edit format to: "
- emms-mp3tag-format nil t)))
- (setq emms-mp3tag-select-format (assoc "default" emms-mp3tag-format)))
+(defvar emms-mp3tag-get-format-function 'emms-mp3tag-get-format
+ "Function to decide which format to use for format the track.")
+
+(defvar emms-mp3tag-parse-function 'emms-mp3tag-default-parser
+ "Function to parse tags in `emms-mp3tag-edit-buffer'. It should find
+all modified tags, and return all the tracks. The tracks which tag has
+been modified should set a property 'tag-modified to t, and if the
+track name have been change, the function should set a new property
+'newname instead set the 'name directly.
+
+See also `emms-mp3tag-default-parser'.")
+
+(defvar emms-mp3tag-tagfile-functions
+ '(("mp3" "mp3info"
+ ((info-artist . "a")
+ (info-title . "t")
+ (info-album . "l")
+ (info-tracknumber . "n")
+ (info-year . "y")
+ (info-genre . "g")
+ (info-note . "c")))
+ ("ogg" . emms-mp3tag-tag-ogg))
+ "A List for change tag in files. If the extern program set tag by
+command line options one by one such as mp3info, the list should like:
+ (EXTENSION PROGRAM COMMAND_LINE_OPTIONS)
+
+Otherwise, a function that accept a parameter, the track, should be
+given.
+
+See also `emms-mp3tag-tag-file' and `emms-mp3tag-tag-ogg'.
+")
-(defun emms-mp3tag-format-track (format track)
- (if (stringp format)
+(defun emms-mp3tag-tag-ogg (track)
+ (call-process "vorbiscomment" nil nil nil
+ "-w" "-t"
+ (mapconcat
+ (lambda (tag)
+ (concat tag "="
+ (emms-track-get track (intern (concat "info-" tag)))))
+ '("artist" "title" "album" "tracknumber" "date" "genre" "note")
+ "\n\t")
+ (emms-track-name track)))
+
+(defun emms-mp3tag-tag-file (track program tags)
+ "Change tag in FILE use PROGRAM. The TAGS is given in `emms-mp3tag-tagfile-functions'."
+ (let (args val)
+ (mapc (lambda (tag)
+ (when (> (length (setq val (emms-track-get track (car tag)))) 0)
+ (setq args (append args (list (concat "-" (cdr tag)) val)))))
+ tags)
+ (apply 'call-process program
+ nil nil nil
+ filename args)))
+
+(defun emms-mp3tag-get-format (track)
+ (let ((format
+ (assoc (file-name-extension (emms-track-name track))
+ emms-mp3tag-formats)))
+ (if format
+ (cdr format)
+ (cdr (assoc "default" emms-mp3tag-formats)))))
+
+(defun emms-mp3tag-format-track (track)
+ (let ((format (funcall emms-mp3tag-get-format-function track)))
+ (if (functionp format)
+ (funcall format track)
(format-spec
format
(apply 'format-spec-make
@@ -107,12 +163,10 @@ newname to the new file name.
'emms-track (copy-sequence track))
?f (emms-track-name track)
(apply 'append
- (mapcar
- (lambda (pair)
- (list (aref (cdr pair) 0)
- (or (emms-track-get track (car pair)) "")))
- emms-mp3tag-tags))))
- (funcall format track)))
+ (mapcar (lambda (tag)
+ (list (string-to-char (cdr tag))
+ (or (emms-track-get track (car tag)) "")))
+ emms-mp3tag-tags)))))))
(defun emms-mp3tag-track-at (&optional pos)
(let ((track (emms-playlist-track-at pos))
@@ -129,19 +183,9 @@ newname to the new file name.
(set-buffer (get-buffer-create buf))
(erase-buffer))))
-;; (defun emms-mp3tag-insert-track (track)
-;; (cond ((null track) nil)
-;; ((not (eq (emms-track-get track 'type) 'file))
-;; (emms-mp3tag-log "Track %s is not a local file!" (emms-track-name track)))
-;; ((not (file-writable-p (emms-track-name track)))
-;; (emms-mp3tag-log "The file %s is not writable" (emms-track-name track)))
-;; (t (insert (emms-mp3tag-format-track
-;; (cadr emms-mp3tag-selected-format) track)))))
-
(defsubst emms-mp3tag-insert-track (track)
(and track
- (insert (emms-mp3tag-format-track
- (cadr emms-mp3tag-selected-format) track))))
+ (insert (emms-mp3tag-format-track track))))
(defun emms-mp3tag-insert-tracks (tracks)
(save-excursion
@@ -149,7 +193,7 @@ newname to the new file name.
(emms-mp3tag-erase-buffer emms-mp3tag-edit-buffer)
(set-buffer (get-buffer emms-mp3tag-edit-buffer))
(mapc 'emms-mp3tag-insert-track tracks)
- (emms-mp3tag-mode 1)
+ (emms-mp3tag-mode)
(pop-to-buffer (current-buffer))
(goto-char (point-min))
(emms-mp3tag-display-log-buffer-maybe)))
@@ -168,6 +212,7 @@ newname to the new file name.
(emms-mp3tag-insert-tracks tracks))))
(defun emms-mp3tag-edit ()
+ "Edit tags of track at point or marked tracks"
(interactive)
(if (emms-mark-has-markedp)
(emms-mp3tag-edit-marked-tracks)
@@ -183,28 +228,32 @@ newname to the new file name.
(define-key map [backtab] 'emms-mp3tag-prev-field)
(define-key map "\C-c\C-n" 'emms-mp3tag-next-track)
(define-key map "\C-c\C-p" 'emms-mp3tag-prev-track)
- (define-key map "\C-c\C-c" 'emms-mp3tag-submit)
+ (define-key map "\C-c\C-c" 'emms-mp3tag-submit-and-exit)
+ (define-key map "\C-c\C-s" 'emms-mp3tag-submit)
(define-key map "\C-c\C-r" 'emms-mp3tag-replace-all)
map))
(define-key emms-playlist-mode-map "E" 'emms-mp3tag-edit)
-(define-minor-mode emms-mp3tag-mode
- "A minor mode to edit mp3tag.
-\\{emms-mp3tag-mode-map}"
- :lighter " MP3Tag"
- :keymap emms-mp3tag-mode-map)
+(define-derived-mode emms-mp3tag-mode text-mode "Mp3tag"
+ "Major mode to edit track tags.
+\\{emms-mp3tag-mode-map}")
(defun emms-mp3tag-replace-all (name value)
+ "Replace all track's NAME to VALUE. If turn transient-mark-mode on,
+you can apply the command to a selected region."
(interactive
(list (completing-read "Replace tag: "
emms-mp3tag-tags nil t)
(read-from-minibuffer "Set tag to: ")))
(save-excursion
- (goto-char (point-min))
- (while (re-search-forward (concat "^" (regexp-quote name)) nil t)
- (skip-chars-forward " \t=")
- (delete-region (point) (line-end-position))
- (insert value))))
+ (save-restriction
+ (if (and mark-active transient-mark-mode)
+ (narrow-to-region (region-beginning) (region-end)))
+ (goto-char (point-min))
+ (while (re-search-forward (concat "^" (regexp-quote name)) nil t)
+ (skip-chars-forward " \t=")
+ (delete-region (point) (line-end-position))
+ (insert value)))))
(defun emms-mp3tag-next-field (arg)
(interactive "p")
@@ -247,10 +296,12 @@ newname to the new file name.
(error "No next track"))
(goto-char next)))
-(defun emms-mp3tag-submit ()
- (interactive)
- (let ((tracks (funcall (nth 2 emms-mp3tag-selected-format)))
- filename exit old pos args val need-sync)
+(defun emms-mp3tag-submit (arg)
+ "Make modified tags take affect. With prefiex argument, bury tag
+edit buffer."
+ (interactive "P")
+ (let ((tracks (funcall emms-mp3tag-parse-function))
+ filename func exit old pos val need-sync)
(if (not (and tracks (y-or-n-p "Submit changes? ")))
(message "Nothing have to do!")
(emms-mp3tag-erase-buffer emms-mp3tag-log-buffer)
@@ -275,22 +326,20 @@ newname to the new file name.
(funcall emms-cache-modified-function)
(funcall emms-cache-set-function filename 'file old))
;; set tags to original track
- (setq args nil)
(dolist (tag emms-mp3tag-tags)
(when (setq val (emms-track-get track (car tag)))
- (emms-track-set old (car tag) val)
- (setq args (append args (list (concat "-" (cdr tag)) val)))))
+ (emms-track-set old (car tag) val)))
;; use mp3info to change tag in mp3 file
- (if (and (eq (emms-track-get track 'type) 'file)
- (file-writable-p (emms-track-name track))
- (string-match "\\.mp3\\'" filename))
- (if (zerop (setq exit
- (apply 'call-process emms-info-mp3info-program-name
- nil nil nil
- filename args)))
- ;; for `emms-cache-sync' not call `emms-info-functions' again
- (emms-track-get track 'info-mtime (butlast (current-time)))
- (emms-mp3tag-log "Change tags of %s failed with exit value %d" filename exit)))
+ (when (and (eq (emms-track-get track 'type) 'file)
+ (file-writable-p (emms-track-name track))
+ (setq func (assoc (file-name-extension filename) emms-mp3tag-tagfile-functions)))
+ (setq exit
+ (if (functionp (cdr func))
+ (funcall (cdr func) track)
+ (emms-mp3tag-tag-file track (cadr func) (nth 2 func))))
+ (if (zerop exit)
+ (emms-track-get track 'info-mtime (butlast (current-time)))
+ (emms-mp3tag-log "Change tags of %s failed with exit value %d" filename exit)))
;; update track in playlist
(when (and (setq pos (emms-track-get track 'position))
(marker-position pos))
@@ -302,7 +351,12 @@ newname to the new file name.
(if (and need-sync (y-or-n-p "You have change some track names, sync the cache? "))
(emms-cache-sync))
(emms-mp3tag-display-log-buffer-maybe)
- (message "Set all mp3 tag done!"))))
+ (message "Set all mp3 tag done!")))
+ (if arg (bury-buffer)))
+
+(defun emms-mp3tag-submit-and-exit ()
+ (interactive)
+ (emms-mp3tag-submit t))
(defun emms-mp3tag-default-parser ()
(let (next tracks track key val)