aboutsummaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
authorYoni Rabkin <yoni@rabkins.net>2020-06-03 11:52:04 -0400
committerYoni Rabkin <yoni@rabkins.net>2020-06-03 11:52:04 -0400
commite102891fb3bbb3fec134b5c678a0dd2306b9beaf (patch)
treef69de3d75b8ccbc1719d1a60a86823e530f57300 /lisp
parentf177bf33cd8dac05908b19ae2c5c33ffbb5eeacf (diff)
move all files to top-level
Diffstat (limited to 'lisp')
-rw-r--r--lisp/Makefile28
-rw-r--r--lisp/emms-auto.in17
-rw-r--r--lisp/emms-bookmarks.el153
-rw-r--r--lisp/emms-browser.el2254
-rw-r--r--lisp/emms-cache.el195
-rw-r--r--lisp/emms-compat.el185
-rw-r--r--lisp/emms-cue.el120
-rw-r--r--lisp/emms-history.el134
-rw-r--r--lisp/emms-i18n.el180
-rw-r--r--lisp/emms-info-libtag.el116
-rw-r--r--lisp/emms-info-metaflac.el107
-rw-r--r--lisp/emms-info-mp3info.el104
-rw-r--r--lisp/emms-info-ogginfo.el85
-rw-r--r--lisp/emms-info-opusinfo.el85
-rw-r--r--lisp/emms-info-tinytag.el119
-rw-r--r--lisp/emms-info.el140
-rw-r--r--lisp/emms-last-played.el123
-rw-r--r--lisp/emms-librefm-scrobbler.el327
-rw-r--r--lisp/emms-librefm-stream.el393
-rw-r--r--lisp/emms-lyrics.el585
-rw-r--r--lisp/emms-maint.el3
-rw-r--r--lisp/emms-mark.el295
-rw-r--r--lisp/emms-metaplaylist-mode.el246
-rw-r--r--lisp/emms-mode-line-icon.el80
-rw-r--r--lisp/emms-mode-line.el158
-rw-r--r--lisp/emms-player-mpd.el1320
-rw-r--r--lisp/emms-player-mpg321-remote.el223
-rw-r--r--lisp/emms-player-mplayer.el81
-rw-r--r--lisp/emms-player-mpv.el847
-rw-r--r--lisp/emms-player-simple.el210
-rw-r--r--lisp/emms-player-vlc.el85
-rw-r--r--lisp/emms-player-xine.el92
-rw-r--r--lisp/emms-playing-time.el239
-rw-r--r--lisp/emms-playlist-limit.el224
-rw-r--r--lisp/emms-playlist-mode.el614
-rw-r--r--lisp/emms-playlist-sort.el228
-rw-r--r--lisp/emms-score.el272
-rw-r--r--lisp/emms-setup.el156
-rw-r--r--lisp/emms-show-all.el125
-rw-r--r--lisp/emms-source-file.el314
-rw-r--r--lisp/emms-source-playlist.el494
-rw-r--r--lisp/emms-stream-info.el30
-rw-r--r--lisp/emms-streams.el179
-rw-r--r--lisp/emms-tag-editor.el775
-rw-r--r--lisp/emms-url.el114
-rw-r--r--lisp/emms-volume-amixer.el76
-rw-r--r--lisp/emms-volume-mixerctl.el80
-rw-r--r--lisp/emms-volume-pulse.el110
-rw-r--r--lisp/emms-volume.el154
-rw-r--r--lisp/emms.el1539
-rw-r--r--lisp/jack.el368
-rw-r--r--lisp/later-do.el86
52 files changed, 0 insertions, 15267 deletions
diff --git a/lisp/Makefile b/lisp/Makefile
deleted file mode 100644
index 85ff3e1..0000000
--- a/lisp/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-EMACS=emacs
-SITEFLAG=--no-site-file
-ALLSOURCE=$(wildcard *.el)
-ALLCOMPILED=$(wildcard *.elc)
-SPECIAL=emms-auto.el emms-maint.el
-SOURCE=$(filter-out $(SPECIAL),$(ALLSOURCE))
-TARGET=$(patsubst %.el,%.elc,$(SOURCE))
-
-.PHONY: all clean
-.PRECIOUS: %.elc
-all: emms-auto.el $(TARGET)
-
-emms-auto.el: emms-auto.in $(SOURCE)
- cp emms-auto.in emms-auto.el
- -rm -f emms-auto.elc
- @$(EMACS) -q $(SITEFLAG) -batch \
- -l emms-maint.el \
- -l emms-auto.el \
- -f emms-generate-autoloads \
- $(shell pwd)/emms-auto.el .
-
-%.elc: %.el
- @$(EMACS) -q $(SITEFLAG) -batch \
- -l emms-maint.el \
- -f batch-byte-compile $<
-
-clean:
- -rm -f *~ *.elc emms-auto.el
diff --git a/lisp/emms-auto.in b/lisp/emms-auto.in
deleted file mode 100644
index d799e4a..0000000
--- a/lisp/emms-auto.in
+++ /dev/null
@@ -1,17 +0,0 @@
-;;; -*-emacs-lisp-*-
-
-(defvar generated-autoload-file)
-(defvar command-line-args-left)
-(defun emms-generate-autoloads ()
- (interactive)
- (require 'autoload)
- (setq generated-autoload-file (car command-line-args-left))
- (setq command-line-args-left (cdr command-line-args-left))
- (batch-update-autoloads))
-
-(add-to-list 'load-path (directory-file-name
- (or (file-name-directory load-file-name)
- (car load-path))))
-
-(provide 'emms-auto)
-;;; Generated autoloads follow (made by autoload.el).
diff --git a/lisp/emms-bookmarks.el b/lisp/emms-bookmarks.el
deleted file mode 100644
index b579ca3..0000000
--- a/lisp/emms-bookmarks.el
+++ /dev/null
@@ -1,153 +0,0 @@
-;;; emms-bookmarks.el --- Bookmarks for Emms.
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-;; Keywords: emms, bookmark
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-;;
-;; You can use this to add ``temporal bookmarks'' (term by Lucas
-;; Bonnet) to your media files. The interesting functions here are
-;; `emms-bookmarks-next', `emms-bookmarks-prev', `emms-bookmarks-add'
-;; (which pauses the player while you describe the bookmark) and
-;; `emms-bookmarks-clear'. All of which do exactly what you think
-;; they do.
-
-;;; Code:
-
-
-;; dependencies
-(require 'emms)
-(require 'emms-playing-time)
-
-(defvar emms-bookmarks-prev-overshoot 5
- "Time in seconds for skipping a previous bookmark.")
-
-(defun emms-bookmarks-reset (track)
- "Remove all the bookmarks from TRACK."
- (emms-track-set track 'bookmarks nil))
-
-(defun emms-bookmarks-straight-insertion-sort (item l acc)
- "Insert ITEM into the already sorted L, ACC should be nil."
- (if (null l)
- (append acc (list item))
- (cond ((< (cdr item) (cdr (car l))) (append acc (list item (car l)) (cdr l)))
- (t (emms-bookmarks-straight-insertion-sort item (cdr l) (append acc (list (car l))))))))
-
-(defun emms-bookmarks-get (track)
- "Return the bookmark property from TRACK."
- (emms-track-get track 'bookmarks))
-
-(defun emms-bookmarks-set (track desc time)
- "Set bookmark property for TRACK, text DESC at TIME seconds."
- (let ((old-bookmarks (emms-track-get track 'bookmarks))
- (new-bookmarks nil))
- (setq new-bookmarks (emms-bookmarks-straight-insertion-sort (cons desc time) old-bookmarks nil))
- (emms-track-set track 'bookmarks new-bookmarks)))
-
-(defun emms-bookmarks-set-current (desc)
- "Set bookmark property for the current track with text DESC."
- (emms-bookmarks-set (emms-playlist-current-selected-track) desc emms-playing-time))
-
-(defun emms-bookmarks-search (time track test)
- "Return a bookmark based on heuristics.
-
-TIME should be a reference point in seconds.
-TRACK should be an Emms track.
-TEST should be a numerical comparator predicate."
- (let ((s (append (list (cons "time" time)) (copy-sequence (emms-bookmarks-get track)))))
- (sort s #'(lambda (a b) (funcall test (cdr a) (cdr b))))
- (while (not (= time (cdar s)))
- (setq s (cdr s)))
- (when (cdr s)
- (car (cdr s)))))
-
-(defun emms-bookmarks-next-1 (time track)
- "Return the bookmark after TIME for TRACK, otherwise return nil."
- (emms-bookmarks-search time track #'<))
-
-(defun emms-bookmarks-prev-1 (time track)
- "Return the bookmark before TIME for TRACK, otherwise return nil."
- (emms-bookmarks-search (- time emms-bookmarks-prev-overshoot) track #'>))
-
-(defun emms-bookmarks-goto (search-f track failure-message)
- "Seek the player to a bookmark.
-
-SEARCH-F should be a function which returns a bookmark.
-TRACK should be an Emms track.
-FAILURE-MESSAGE should be a string."
- ;; note that when emms is paused then `emms-player-playing-p' => t
- (when (not emms-player-playing-p)
- (emms-start))
- (let ((m (funcall search-f emms-playing-time track)))
- (if m
- (progn
- (emms-player-seek-to (cdr m))
- (message "%s" (car m)))
- (message "%s" failure-message))))
-
-
-;; entry points
-
-(defun emms-bookmarks-next ()
- "Seek to the next bookmark in the current track."
- (interactive)
- (emms-bookmarks-goto #'emms-bookmarks-next-1
- (emms-playlist-current-selected-track)
- "No next bookmark"))
-
-(defun emms-bookmarks-prev ()
- "Seek to the previous bookmark in the current track."
- (interactive)
- (emms-bookmarks-goto #'emms-bookmarks-prev-1
- (emms-playlist-current-selected-track)
- "No previous bookmark"))
-
-(defmacro emms-bookmarks-with-paused-player (&rest body)
- "Eval BODY with player paused."
- `(progn
- (when (not emms-player-paused-p) (emms-pause))
- ,@body
- (when emms-player-paused-p (emms-pause))))
-
-;; can't use `interactive' to promt the user here because we want to
-;; pause the player before the prompt appears.
-(defun emms-bookmarks-add ()
- "Add a new bookmark to the current track.
-
-This function pauses the player while prompting the user for a
-description of the bookmark. The function resumes the player
-after the prompt."
- (interactive)
- (emms-bookmarks-with-paused-player
- (let ((desc (read-string "Description: ")))
- (if (emms-playlist-current-selected-track)
- (emms-bookmarks-set-current desc)
- (error "No current track to bookmark")))))
-
-(defun emms-bookmarks-clear ()
- "Remove all the bookmarks from the current track."
- (interactive)
- (let ((this (emms-playlist-current-selected-track)))
- (when this (emms-bookmarks-reset this))))
-
-(provide 'emms-bookmarks)
-
-;;; emms-bookmarks.el ends here
diff --git a/lisp/emms-browser.el b/lisp/emms-browser.el
deleted file mode 100644
index f805b3b..0000000
--- a/lisp/emms-browser.el
+++ /dev/null
@@ -1,2254 +0,0 @@
-;;; emms-browser.el --- a track browser supporting covers and filtering
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Damien Elmes <emacs@repose.cx>
-;; Keywords: emms, mp3, mpeg, multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; This code allows you to browse the metadata cache and add tracks to
-;; your playlist. To be properly useful, you should M-x
-;; emms-add-directory-tree to all the files you own at least once so
-;; that the cache is fully populated.
-
-;; Usage
-;; -------------------------------------------------------------------
-
-;; To use, run (emms-all) and then bind `emms-smart-browse' to a key,
-;; like:
-
-;; (global-set-key (kbd "<f2>") 'emms-smart-browse)
-
-;; The 'smart browsing' code attempts to link the browser and playlist
-;; windows together, so that closing one will close both. Activating
-;; it will toggle between three states:
-
-;; a) both windows displayed, with the browser focused
-;; b) focus switched to the playlist window
-;; c) the extra window closed, and both buffers buried
-
-;; If you just want access to the browser, try M-x
-;; emms-browse-by-TYPE, where TYPE is one of artist, album, composer,
-;; genre or year. These commands can also be used while smart browsing to
-;; change the browsing category.
-
-;; If you don't want to activate the code with (emms-devel), you can
-;; activate it manually with:
-
-;; (require 'emms-browser)
-
-;; Key bindings
-;; -------------------------------------------------------------------
-
-;; C-j emms-browser-add-tracks-and-play
-;; RET emms-browser-add-tracks
-;; SPC emms-browser-toggle-subitems
-;; ^ emms-browser-move-up-level
-;; / emms-isearch-buffer
-;; 1 emms-browser-collapse-all
-;; 2 emms-browser-expand-to-level-2
-;; 3 emms-browser-expand-to-level-3
-;; 4 emms-browser-expand-to-level-4
-;; < emms-browser-previous-filter
-;; > emms-browser-next-filter
-;; ? describe-mode
-;; C emms-browser-clear-playlist
-;; E emms-browser-expand-all
-;; d emms-browser-view-in-dired
-;; D emms-browser-delete-files
-;; q emms-browser-bury-buffer
-;; r emms-browser-goto-random
-;; n next-line
-;; p previous-line
-;; C-/ emms-playlist-mode-undo
-;; <C-return> emms-browser-add-tracks-and-play
-;; <backtab> emms-browser-prev-non-track
-;; <tab> emms-browser-next-non-track
-
-;; s A emms-browser-search-by-album
-;; s a emms-browser-search-by-artist
-;; s c emms-browser-search-by-composer
-;; s s emms-browser-search-by-names
-;; s t emms-browser-search-by-title
-;; s p emms-browser-search-by-performer
-
-;; b 1 emms-browse-by-artist
-;; b 2 emms-browse-by-album
-;; b 3 emms-browse-by-genre
-;; b 4 emms-browse-by-year
-;; b 5 emms-browse-by-composer
-;; b 6 emms-browse-by-performer
-
-;; W a w emms-browser-lookup-album-on-wikipedia
-
-;; W A w emms-browser-lookup-artist-on-wikipedia
-
-;; W C w emms-browser-lookup-composer-on-wikipedia
-
-;; W P w emms-browser-lookup-performer-on-wikipedia
-
-;; Displaying covers
-;; -------------------------------------------------------------------
-
-;; The browser will attempt to display cover images if they're
-;; available. By default it looks for images cover_small.jpg,
-;; cover_med.jpg, etc. Customize emms-browser-covers to use your own
-;; covers. Note that you'll probably want to resize your existing
-;; covers to particular sizes. Suggested sizes are 100x100 for small,
-;; and 200x200 for medium.
-
-;; Also emacs by default will jump around a lot when scrolling a
-;; buffer with images. Set the following variables to prevent that:
-
-;; scroll-up-aggressively 0.0
-;; scroll-down-aggressively 0.0
-
-;; To show a 'no cover' image for albums which don't have a cover, add
-;; the following code to your .emacs:
-
-;; (setq emms-browser-default-covers
-;; (list "/path/to/cover_small.jpg" nil nil)
-
-;; (the medium and large images can be set too, if you want)
-
-;; You can download an example 'no cover' image from:
-;; http://repose.cx/cover_small.jpg
-
-;; Filtering tracks
-;; -------------------------------------------------------------------
-
-;; If you want to display a subset of your collection (such as a
-;; directory of 80s music, only avi files, etc), then you can make
-;; some filters using code like this:
-
-;; ;; show everything
-;; (emms-browser-make-filter "all" 'ignore)
-
-;; ;; Set "all" as the default filter
-;; (emms-browser-set-filter (assoc "all" emms-browser-filters))
-
-;; ;; show all files (no streamlists, etc)
-;; (emms-browser-make-filter
-;; "all-files" (emms-browser-filter-only-type 'file))
-
-;; ;; show only tracks in one folder
-;; (emms-browser-make-filter
-;; "80s" (emms-browser-filter-only-dir "~/Mp3s/80s"))
-
-;; ;; show all tracks played in the last month
-;; (emms-browser-make-filter
-;; "last-month" (emms-browser-filter-only-recent 30))
-
-;; After executing the above commands, you can use M-x
-;; emms-browser-show-all, emms-browser-show-80s, etc to toggle
-;; between different collections. Alternatively you can use '<' and
-;; '>' to cycle through the available filters.
-
-;; The second argument to make-filter is a function which returns t if
-;; a single track should be filtered. You can write your own filter
-;; functions to check the type of a file, etc.
-
-;; Some more examples:
-
-;; ;; show only tracks not played in the last year
-;; (emms-browser-make-filter "not-played"
-;; (lambda (track)
-;; (not (funcall (emms-browser-filter-only-recent 365) track))))
-
-;; ;; show all files that are not in the pending directory
-;; (emms-browser-make-filter
-;; "all"
-;; (lambda (track)
-;; (or
-;; (funcall (emms-browser-filter-only-type 'file) track)
-;; (not (funcall
-;; (emms-browser-filter-only-dir "~/Media/pending") track)))))
-
-;; Changing tree structure
-;; -------------------------------------------------------------------
-
-;; You can change the way the tree is displayed by modifying
-;; `emms-browser-next-mapping-type'. The following code displays
-;; artist->track instead of artist->album->track when you switch to
-;; the 'singles' filter.
-
-;; (defadvice emms-browser-next-mapping-type
-;; (after no-album (current-mapping))
-;; (when (eq ad-return-value 'info-album)
-;; (setq ad-return-value 'info-title)))
-
-;; (defun toggle-album-display ()
-;; (if (string= emms-browser-current-filter-name "singles")
-;; (ad-activate 'emms-browser-next-mapping-type)
-;; (ad-deactivate 'emms-browser-next-mapping-type)))
-
-;; (add-hook 'emms-browser-filter-changed-hook 'toggle-album-display)
-
-;; Changing display format
-;; -------------------------------------------------------------------
-
-;; Format strings govern the way items are displayed in the browser
-;; and playlist. You can customize these if you wish.
-
-;; `emms-browser-default-format' controls the format to use when no
-;; other format has been explicitly defined. By default, only track and
-;; albums deviate from the default.
-
-;; To customise the format of a particular type, find the name of the
-;; field you want to use (eg `info-artist', `info-title', etc), and
-;; insert that into emms-browser-<type>-format or
-;; emms-browser-playlist-<type>-format. For example, if you wanted to
-;; remove track numbers from tracks in both the browser and playlist,
-;; you could do:
-
-;; (defvar emms-browser-info-title-format "%i%n")
-;; (defvar emms-browser-playlist-info-title-format
-;; emms-browser-info-title-format)
-
-;; The format specifiers available include:
-
-;; %i indent relative to the current level
-;; %n the value of the item - eg -info-artist might be "pink floyd"
-;; %y the album year
-;; %A the album name
-;; %a the artist name of the track
-;; %C the composer name of the track
-;; %p the performer name of the track
-;; %t the title of the track
-;; %T the track number
-;; %cS a small album cover
-;; %cM a medium album cover
-;; %cL a big album cover
-
-;; Note that if you use track-related items like %t, it will take the
-;; data from the first track.
-
-;; Changing display faces
-;; -------------------------------------------------------------------
-
-;; The faces used to display the various fields are also customizable.
-;; They are in the format emms-browser-<type>-face, where type is one
-;; of "year/genre", "artist", "composer", "performer", "album" or
-;; "track". Note that faces lack the initial "info-" part. For example,
-;; to change the artist face, type
-;; M-x customize-face emms-browser-artist-face.
-
-;; Deleting files
-;; -------------------------------------------------------------------
-
-;; You can use the browser to delete tracks from your hard disk.
-;; Because this is dangerous, it is disabled by default.
-
-;; The following code will delete covers at the same time, and remove
-;; parent directories if they're now empty.
-
-;; (defun de-kill-covers-and-parents (dir tracks)
-;; (when (> (length tracks) 1)
-;; ;; if we're not deleting an individual file, delete covers too
-;; (dolist (cover '("cover.jpg"
-;; "cover_med.jpg"
-;; "cover_small.jpg"
-;; "folder.jpg"))
-;; (condition-case nil
-;; (delete-file (concat dir cover))
-;; (error nil)))
-;; ;; try and delete empty parents - we actually do the work of the
-;; ;; calling function here, too
-;; (let (failed)
-;; (while (and (not (string= dir "/"))
-;; (not failed))
-;; (condition-case nil
-;; (delete-directory dir)
-;; (error (setq failed t)))
-;; (setq dir (file-name-directory (directory-file-name dir)))))))
-;; (add-hook 'emms-browser-delete-files-hook 'de-kill-covers-and-parents)
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'emms)
-(require 'emms-cache)
-(require 'emms-source-file)
-(require 'emms-playlist-sort)
-(require 'sort)
-(require 'seq)
-
-
-;; --------------------------------------------------
-;; Variables and configuration
-;; --------------------------------------------------
-
-(defvar emms-browser-mode-hook nil
- "Emms browser mode hook.")
-
-(defgroup emms-browser nil
- "*The Emacs Multimedia System browser"
- :prefix "emms-browser-"
- :group 'multimedia
- :group 'applications)
-
-(defcustom emms-browser-default-browse-type
- 'info-artist
- "*The default browsing mode."
- :group 'emms-browser
- :type 'function)
-
-(defcustom emms-browser-make-name-function
- 'emms-browser-make-name-standard
- "*A function to make names for entries and subentries.
-Overriding this function allows you to customise how various elements
-are displayed. It is called with two arguments - track and type."
- :group 'emms-browser
- :type 'function)
-
-(defcustom emms-browser-get-track-field-function
- 'emms-browser-get-track-field-albumartist
- "*A function to get an element from a track.
-Change this to customize the way data is organized in the
-browser. For example,
-`emms-browser-get-track-field-use-directory-name' uses the
-directory name to determine the artist. This means that
-soundtracks, compilations and so on don't populate the artist
-view with lots of 1-track elements."
- :group 'emms-browser
- :type '(choice (function :tag "Sort by album-artist" emms-browser-get-track-field-albumartist)
- (function :tag "Simple" emms-browser-get-track-field-simple)))
-
-(defcustom emms-browser-covers
- '("cover_small" "cover_med" "cover_large")
- "*Control how cover images are found.
-Can be either a list of small, medium and large images (large
-currently not used), a function which takes a directory and one
-of the symbols `small', `medium' or `large', and should return a
-path to the cover, or nil to turn off cover loading."
- :group 'emms-browser
- :type '(choice list function boolean))
-
-(defcustom emms-browser-covers-file-extensions
- '("jpg" "jpeg" "png" "gif" "bmp")
- "*File extensions accepted for `emms-browser-covers'.
-Should be a list of extensions as strings. Should be set before
-emms-browser is required."
- :group 'emms-browser
- :type '(repeat (string :tag "Extension")))
-
-(defconst emms-browser--covers-filename nil
- "*List of potential cover art names.")
-
-(defcustom emms-browser-default-covers nil
- "*A list of default images to use if a cover isn't found."
- :group 'emms-browser
- :type 'list)
-
-(defcustom emms-browser-comparison-test
- (if (fboundp 'define-hash-table-test)
- 'case-fold
- 'equal)
- "*A method for comparing entries in the cache.
-The default is to compare case-insensitively."
- :group 'emms-browser
- :type 'symbol)
-
-(defcustom emms-browser-track-sort-function
- 'emms-sort-natural-order-less-p
- "*How to sort tracks in the browser.
-Ues nil for no sorting."
- :group 'emms-browser
- :type 'function)
-
-(defcustom emms-browser-alpha-sort-function
- (if (functionp 'string-collate-lessp) 'string-collate-lessp 'string<)
- "*How to sort artists/albums/etc. in the browser.
-Use nil for no sorting."
- :group 'emms-browser
- :type 'function)
-
-(defcustom emms-browser-album-sort-function
- 'emms-browser-sort-by-year-or-name
- "*How to sort artists/albums/etc. in the browser.
-Use nil for no sorting."
- :group 'emms-browser
- :type 'function)
-
-(defcustom emms-browser-show-display-hook nil
- "*Hooks to run when starting or switching to a browser buffer."
- :group 'emms-browser
- :type 'hook)
-
-(defcustom emms-browser-hide-display-hook nil
- "*Hooks to run when burying or removing a browser buffer."
- :group 'emms-browser
- :type 'hook)
-
-(defcustom emms-browser-tracks-added-hook nil
- "*Hooks to run when tracks are added to the playlist."
- :group 'emms-browser
- :type 'hook)
-
-(defcustom emms-browser-filter-tracks-hook nil
- "*Given a track, return t if the track should be ignored."
- :group 'emms-browser
- :type 'hook)
-
-(defcustom emms-browser-filter-changed-hook nil
- "*Hook run after the filter has changed."
- :group 'emms-browser
- :type 'hook)
-
-(defcustom emms-browser-delete-files-hook nil
- "*Hook run after files have been deleted.
-This hook can be used to clean up extra files, such as album covers.
-Called once for each directory."
- :group 'emms-browser
- :type 'hook)
-
-(defvar emms-browser-buffer nil
- "The current browser buffer, if any.")
-
-(defvar emms-browser-buffer-name "*EMMS Browser*"
- "The default buffer name.")
-
-(defvar emms-browser-search-buffer-name "*emms-browser-search*"
- "The search buffer name.")
-
-(defvar emms-browser-top-level-hash nil
- "The current mapping db, eg. artist -> track.")
-(make-variable-buffer-local 'emms-browser-top-level-hash)
-
-(defvar emms-browser-top-level-type nil
- "The current mapping type, eg. 'info-artist.")
-(make-variable-buffer-local 'emms-browser-top-level-type)
-
-(defvar emms-browser-current-indent nil
- "Used to override the current indent, for the playlist, etc.")
-
-(defvar emms-browser-current-filter-name nil
- "The name of the current filter in place, if any.")
-
-(defvar emms-browser-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "q") 'emms-browser-bury-buffer)
- (define-key map (kbd "/") 'emms-isearch-buffer)
- (define-key map (kbd "r") 'emms-browser-goto-random)
- (define-key map (kbd "n") 'next-line)
- (define-key map (kbd "p") 'previous-line)
- (define-key map (kbd "C") 'emms-browser-clear-playlist)
- (define-key map (kbd "?") 'describe-mode)
- (define-key map (kbd "C-/") 'emms-playlist-mode-undo)
- (define-key map (kbd "SPC") 'emms-browser-toggle-subitems)
- (define-key map (kbd "^") 'emms-browser-move-up-level)
- (define-key map (kbd "RET") 'emms-browser-add-tracks)
- (define-key map (kbd "<C-return>") 'emms-browser-add-tracks-and-play)
- (define-key map (kbd "C-j") 'emms-browser-add-tracks-and-play)
- (define-key map (kbd "<tab>") 'emms-browser-next-non-track)
- (define-key map (kbd "<backtab>") 'emms-browser-prev-non-track)
- (define-key map (kbd "d") 'emms-browser-view-in-dired)
- (define-key map (kbd "D") 'emms-browser-delete-files)
- (define-key map (kbd "E") 'emms-browser-expand-all)
- (define-key map (kbd "1") 'emms-browser-collapse-all)
- (define-key map (kbd "2") 'emms-browser-expand-to-level-2)
- (define-key map (kbd "3") 'emms-browser-expand-to-level-3)
- (define-key map (kbd "4") 'emms-browser-expand-to-level-4)
- (define-key map (kbd "b 1") 'emms-browse-by-artist)
- (define-key map (kbd "b 2") 'emms-browse-by-album)
- (define-key map (kbd "b 3") 'emms-browse-by-genre)
- (define-key map (kbd "b 4") 'emms-browse-by-year)
- (define-key map (kbd "b 5") 'emms-browse-by-composer)
- (define-key map (kbd "b 6") 'emms-browse-by-performer)
- (define-key map (kbd "s a") 'emms-browser-search-by-artist)
- (define-key map (kbd "s c") 'emms-browser-search-by-composer)
- (define-key map (kbd "s p") 'emms-browser-search-by-performer)
- (define-key map (kbd "s A") 'emms-browser-search-by-album)
- (define-key map (kbd "s t") 'emms-browser-search-by-title)
- (define-key map (kbd "s s") 'emms-browser-search-by-names)
- (define-key map (kbd "W A w") 'emms-browser-lookup-artist-on-wikipedia)
- (define-key map (kbd "W C w") 'emms-browser-lookup-composer-on-wikipedia)
- (define-key map (kbd "W P w") 'emms-browser-lookup-performer-on-wikipedia)
- (define-key map (kbd "W a w") 'emms-browser-lookup-album-on-wikipedia)
- (define-key map (kbd ">") 'emms-browser-next-filter)
- (define-key map (kbd "<") 'emms-browser-previous-filter)
- (define-key map (kbd "+") 'emms-volume-raise)
- (define-key map (kbd "-") 'emms-volume-lower)
- map)
- "Keymap for `emms-browser-mode'.")
-
-(defvar emms-browser-search-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map emms-browser-mode-map)
- (define-key map (kbd "q") 'emms-browser-kill-search)
- map)
- "Keymap for `emms-browser-mode'.")
-
-;; --------------------------------------------------
-;; Compatability functions
-;; --------------------------------------------------
-
-(eval-and-compile
- (if (fboundp 'with-selected-window)
- (defalias 'emms-browser-with-selected-window 'with-selected-window)
- (defmacro emms-browser-with-selected-window (window &rest body)
- ;; this emulates the behavior introduced earlier, though it
- ;; might be best to do something with `window'
- `(save-selected-window ,body)))
- (put 'emms-browser-with-selected-window 'lisp-indent-function 1)
- (put 'emms-browser-with-selected-window 'edebug-form-spec '(form body))
-
- (if (fboundp 'run-mode-hooks)
- (defalias 'emms-browser-run-mode-hooks 'run-mode-hooks)
- (defalias 'emms-browser-run-mode-hooks 'run-hooks)))
-
-;; --------------------------------------------------
-;; General mode setup
-;; --------------------------------------------------
-
-;;;###autoload
-(defun emms-browser ()
- "Launch or switch to the EMMS Browser."
- (interactive)
- (emms-browser-create-or-focus
- emms-browser-default-browse-type))
-
-(defun emms-browser-create-or-focus (type)
- "Create a new browser buffer with BROWSE-FUNC, or switch.
-BROWSE-FUNC should fill the buffer with something of interest. An
-example function is `emms-browse-by-artist'."
- (let ((buf (emms-browser-get-buffer))
- wind)
- (if buf
- ;; if the buffer is displayed, switch the window instead
- (progn
- (setq wind (get-buffer-window buf))
- (if wind
- (select-window wind)
- (switch-to-buffer buf))
- (emms-browser-run-mode-hooks 'emms-browser-show-display-hook))
- ;; if there's no buffer, create a new window
- (emms-browser-create)
- (emms-browse-by type))))
-
-(defun emms-browser-create ()
- "Create a new emms-browser buffer and start emms-browser-mode."
- (emms-browser-new-buffer)
- (emms-browser-mode)
- (emms-browser-run-mode-hooks 'emms-browser-show-display-hook))
-
-(defun emms-browser-mode (&optional no-update)
- "A major mode for the Emms browser.
-\\{emms-browser-mode-map}"
- ;; create a new buffer
- (interactive)
-
- (use-local-map emms-browser-mode-map)
- (setq major-mode 'emms-browser-mode
- mode-name "Emms-Browser")
-
- (setq buffer-read-only t)
- (unless no-update
- (setq emms-browser-buffer (current-buffer)))
-
- (run-hooks 'emms-browser-mode-hook))
-
-(defun emms-browser-new-buffer ()
- "Create a new browser buffer, and switch to it."
- (switch-to-buffer (generate-new-buffer
- emms-browser-buffer-name)))
-
-(defun emms-browser-clear ()
- "Create or switch to a browser buffer, clearing it."
- (let ((buf (emms-browser-get-buffer)))
- (if buf
- (progn
- (switch-to-buffer buf)
- (emms-with-inhibit-read-only-t
- (delete-region (point-min) (point-max))))
- (emms-browser-create))))
-
-(defun emms-browser-get-buffer ()
- "Return the current buffer if it exists, or nil.
-If a browser search exists, return it."
- (or (get-buffer emms-browser-search-buffer-name)
- (unless (or (null emms-browser-buffer)
- (not (buffer-live-p emms-browser-buffer)))
- emms-browser-buffer)))
-
-(defun emms-browser-ensure-browser-buffer ()
- (unless (eq major-mode 'emms-browser-mode)
- (error "Current buffer is not an emms-browser buffer")))
-
-(defun emms-browser-bury-buffer ()
- "Bury the browser buffer, running hooks."
- (interactive)
- (emms-browser-run-mode-hooks 'emms-browser-hide-display-hook)
- (bury-buffer))
-
-;; --------------------------------------------------
-;; Top-level browsing methods - by artist/album/etc
-;; --------------------------------------------------
-
-;; Since the number of tracks may be rather large, we use a hash to
-;; sort the top level elements into various categories. All
-;; subelements will be stored in a bdata alist structure.
-
-(defmacro emms-browser-add-category (name type)
- "Create an interactive function emms-browse-by-NAME."
- (let ((funname (intern (concat "emms-browse-by-" name)))
- (funcdesc (concat "Browse by " name ".")))
- `(defun ,funname ()
- ,funcdesc
- (interactive)
- (emms-browse-by ,type))))
-
-(defun emms-browse-by (type)
- "Render a top level buffer based on TYPE."
- ;; FIXME: assumes we only browse by info-*
- (let* ((name (substring (symbol-name type) 5))
- (modedesc (concat "Browsing by: " name))
- (hash (emms-browser-make-hash-by type)))
- (when emms-browser-current-filter-name
- (setq modedesc (concat modedesc
- " [" emms-browser-current-filter-name "]")))
- (emms-browser-clear)
- (rename-buffer modedesc)
- (emms-browser-render-hash hash type)
- (setq emms-browser-top-level-hash hash)
- (setq emms-browser-top-level-type type)
- (unless (> (hash-table-count hash) 0)
- (emms-browser-show-empty-cache-message))
- (goto-char (point-min))))
-
-(emms-browser-add-category "artist" 'info-artist)
-(emms-browser-add-category "composer" 'info-composer)
-(emms-browser-add-category "performer" 'info-performer)
-(emms-browser-add-category "album" 'info-album)
-(emms-browser-add-category "genre" 'info-genre)
-(emms-browser-add-category "year" 'info-year)
-
-(defun emms-browser-get-track-field (track type)
- "Return TYPE from TRACK.
-This can be customized to group different artists into one for
-compilations, etc."
- (funcall emms-browser-get-track-field-function track type))
-
-(defun emms-browser-get-track-field-simple (track type)
- "Return TYPE from TRACK without any heuristic.
-This function can be used as
-`emms-browser-get-track-field-function'."
- (emms-track-get track type "misc"))
-
-(defun emms-browser-get-track-field-albumartist (track type)
- "Return TYPE from TRACK with an albumartist-oriented heuristic.
-For 'info-artist TYPE, use 'info-albumartistsort, 'info-albumartist,
-'info-artistsort.
-For 'info-year TYPE, use 'info-originalyear, 'info-originaldate and
-'info-date symbols."
- (cond ((eq type 'info-artist)
- (or (emms-track-get track 'info-albumartist)
- (emms-track-get track 'info-albumartistsort)
- (emms-track-get track 'info-artist)
- (emms-track-get track 'info-artistsort "<unknown artist>")))
- ((eq type 'info-year)
- (let ((date (or (emms-track-get track 'info-originaldate)
- (emms-track-get track 'info-originalyear)
- (emms-track-get track 'info-date)
- (emms-track-get track 'info-year "<unknown year>"))))
- (emms-format-date-to-year date)))
- (t (emms-track-get track type "misc"))))
-
-(defun emms-browser-get-track-field-use-directory-name (track type)
- (if (eq type 'info-artist)
- (emms-browser-get-artist-from-path
- track)
- (emms-track-get track type "misc")))
-
-(defun emms-browser-get-artist-from-path (track)
- (let* ((path (emms-track-get track 'name))
- (dir (file-name-directory path))
- (basedir
- (file-name-nondirectory
- (directory-file-name
- (file-name-directory dir)))))
- (car (split-string basedir " - "))))
-
-(defun emms-browser-make-hash-by (type)
- "Make a hash, mapping with TYPE, eg artist -> tracks."
- (let ((hash (make-hash-table
- :test emms-browser-comparison-test))
- field existing-entry)
- (maphash (lambda (path track)
- (unless (run-hook-with-args-until-success
- 'emms-browser-filter-tracks-hook track)
- (setq field
- (emms-browser-get-track-field track type))
- (when field
- (setq existing-entry (gethash field hash))
- (if existing-entry
- (puthash field (cons track existing-entry) hash)
- (puthash field (list track) hash)))))
- emms-cache-db)
- hash))
-
-(defun emms-browser-render-hash (db type)
- "Render a mapping (DB) into a browser buffer."
- (maphash (lambda (desc data)
- (emms-browser-insert-top-level-entry desc data type))
- db)
- (emms-with-inhibit-read-only-t
- (let ((sort-fold-case t))
- (if emms-browser-alpha-sort-function
- (progn
- (goto-char (point-min))
- (sort-subr nil
- #'forward-line #'end-of-line
- (lambda () (buffer-substring-no-properties
- (line-beginning-position) (line-end-position)))
- nil
- emms-browser-alpha-sort-function))
- (sort-lines nil (point-min) (point-max))))))
-
-(defun case-fold-string= (a b)
- (eq t (compare-strings a nil nil b nil nil t)))
-
-(defun case-fold-string-hash (a)
- (sxhash (upcase a)))
-
-(when (fboundp 'define-hash-table-test)
- (define-hash-table-test 'case-fold
- 'case-fold-string= 'case-fold-string-hash))
-
-(defun emms-browser-insert-top-level-entry (name tracks type)
- "Insert a single top level entry into the buffer."
- (emms-browser-ensure-browser-buffer)
- (let ((bdata (emms-browser-make-bdata-tree type 1 tracks name)))
- (emms-browser-insert-format bdata)))
-
-(defun emms-browser-show-empty-cache-message ()
- "Display some help if the cache is empty."
- (emms-with-inhibit-read-only-t
- (insert "
-Welcome to EMMS.
-
-There are currently no files in the EMMS database.
-To browse music, you need to tell EMMS where your
-files are.
-
-Try the following commands:
-
- M-x emms-add-directory-tree:
- Add all music in a directory and its subdirectories.
-
- M-x emms-add-directory:
- Add all music in a directory
-
- M-x emms-add-file: Add a single music file.
-
-After you have added some files, wait for EMMS to say
-'all track information loaded,' then return to the
-browser, and hit 'b 1' to refresh.")))
-
-;; --------------------------------------------------
-;; Building a subitem tree
-;; --------------------------------------------------
-
-(defun emms-browser-next-mapping-type (current-mapping)
- "Return the next sensible mapping.
-Eg. if CURRENT-MAPPING is currently 'info-artist, return 'info-album."
- (cond
- ((eq current-mapping 'info-artist) 'info-album)
- ((eq current-mapping 'info-composer) 'info-album)
- ((eq current-mapping 'info-performer) 'info-album)
- ((eq current-mapping 'info-album) 'info-title)
- ((eq current-mapping 'info-genre) 'info-artist)
- ((eq current-mapping 'info-year) 'info-artist)))
-
-(defun emms-browser-make-bdata-tree (type level tracks name)
- "Build a tree of browser DB elements for tracks."
- (emms-browser-make-bdata
- (emms-browser-make-bdata-tree-recurse
- type level tracks)
- name
- type level))
-
-(defun emms-browser-make-bdata-tree-recurse (type level tracks)
- "Build a tree of alists based on a list of tracks, TRACKS.
-For example, if TYPE is 'info-year, return an alist like:
-artist1 -> album1 -> *track* 1.."
- (let* ((next-type (emms-browser-next-mapping-type type))
- (next-level (1+ level))
- alist name new-db new-tracks)
- ;; if we're at a leaf, the db data is a list of tracks
- (if (eq type 'info-title)
- tracks
- ;; otherwise, make DBs from the sub elements
- (setq alist
- (emms-browser-make-sorted-alist
- next-type tracks))
- (mapcar (lambda (entry)
- (setq name (emms-browser-make-name
- entry next-type))
- (setq new-tracks (cdr entry))
- (emms-browser-make-bdata
- (emms-browser-make-bdata-tree-recurse
- next-type next-level new-tracks)
- name next-type next-level))
- alist))))
-
-(defun emms-browser-make-name (entry type)
- "Return a name for ENTRY, used for making a bdata object."
- (let ((key (car entry))
- (track (cadr entry))
- artist title) ;; only the first track
- (cond
- ((eq type 'info-title)
- (setq artist (emms-track-get track 'info-artist))
- (setq title (emms-track-get track 'info-title))
- (if (not (and artist title))
- key
- (concat artist " - " title)))
- (t key))))
-
-(defun emms-browser-track-number (track)
- "Return a string representation of a track number.
-The string will end in a space. If no track number is available,
-return an empty string."
- (let ((tracknum (emms-track-get track 'info-tracknumber)))
- (if (or (not (stringp tracknum)) (string= tracknum "0"))
- ""
- (concat
- (if (eq (length tracknum) 1)
- (concat "0" tracknum)
- tracknum)))))
-
-(defun emms-browser-disc-number (track)
- "Return a string representation of a track number.
-The string will end in a space. If no track number is available,
-return an empty string."
- (let ((discnum (emms-track-get track 'info-discnumber)))
- (if (or (not (stringp discnum)) (string= discnum "0"))
- ""
- discnum)))
-
-(defun emms-browser-year-number (track)
- "Return a string representation of a track's year.
-This will be in the form '(1998) '."
- (let ((year (emms-track-get-year track)))
- (if (or (not (stringp year)) (string= year "0"))
- ""
- (concat
- "(" year ") "))))
-
-(defun emms-browser-track-duration (track)
- "Return a string representation of a track duration.
-If no duration is available, return an empty string."
- (let ((pmin (emms-track-get track 'info-playing-time-min))
- (psec (emms-track-get track 'info-playing-time-sec))
- (ptot (emms-track-get track 'info-playing-time)))
- (cond ((and pmin psec) (format "%02d:%02d" pmin psec))
- (ptot (format "%02d:%02d" (/ ptot 60) (% ptot 60)))
- (t ""))))
-
-(defun emms-browser-make-bdata (data name type level)
- "Return a browser data item from ALIST.
-DATA should be a list of DB items, or a list of tracks.
-NAME is a name for the DB item.
-TYPE is a category the data is organised by, such as 'info-artist.
-LEVEL is the number of the sublevel the db item will be placed in."
- (list (cons 'type type)
- (cons 'level level)
- (cons 'name name)
- (cons 'data data)))
-
-(defun emms-browser-make-alist (type tracks)
- "Make an alist mapping of TYPE -> TRACKS.
-Items with no metadata for TYPE will be placed in 'misc'"
- (let (db key existing tracknum)
- (dolist (track tracks)
- (setq key (emms-browser-get-track-field track type))
- (when (eq type 'info-title)
- ;; try and make every track unique
- (setq tracknum (emms-browser-track-number track))
- (if (string= tracknum "")
- (setq key (file-name-nondirectory
- (emms-track-get track 'name)))
- (setq key (concat tracknum key))))
- (setq existing (assoc key db))
- (if existing
- (setcdr existing (cons track (cdr existing)))
- (push (cons key (list track)) db)))
- ;; sort the entries we've built
- (dolist (item db)
- (setcdr item (nreverse (cdr item))))
- db))
-
-(defun emms-browser-make-sorted-alist (type tracks)
- "Return a sorted alist of TRACKS.
-TYPE is the metadata to make the alist by - eg. if it's
-'info-artist, an alist of artists will be made."
- (emms-browser-sort-alist
- (emms-browser-make-alist type tracks)
- type))
-
-;; --------------------------------------------------
-;; BDATA accessors and predicates
-;; --------------------------------------------------
-
-(defun emms-browser-bdata-level (bdata)
- (cdr (assq 'level bdata)))
-
-(defun emms-browser-bdata-name (bdata)
- (cdr (assq 'name bdata)))
-
-(defun emms-browser-bdata-type (bdata)
- (cdr (assq 'type bdata)))
-
-(defun emms-browser-bdata-data (bdata)
- (cdr (assq 'data bdata)))
-
-(defun emms-browser-bdata-p (obj)
- "True if obj is a BDATA object."
- (consp (assq 'data obj)))
-
-;; --------------------------------------------------
-;; Sorting expanded entries
-;; --------------------------------------------------
-
-(defmacro emms-browser-sort-cadr (sort-func)
- "Return a function to sort an alist using SORT-FUNC.
-This sorting predicate will compare the cadr of each entry.
-SORT-FUNC should be a playlist sorting predicate like
-`emms-playlist-sort-by-natural-order'."
- `(lambda (a b)
- (funcall ,sort-func (cadr a) (cadr b))))
-
-(defmacro emms-browser-sort-car (sort-func)
- "Return a function to sort an alist using SORT-FUNC.
-This sorting predicate will compare the car of each entry.
-SORT-FUNC should be a playlist sorting predicate like
-`emms-playlist-sort-by-natural-order'."
- `(lambda (a b)
- (funcall ,sort-func (car a) (car b))))
-
-(defun emms-browser-sort-by-track (alist)
- "Sort an ALIST by the tracks in each entry.
-Uses `emms-browser-track-sort-function'."
- (if emms-browser-track-sort-function
- (sort alist (emms-browser-sort-cadr
- emms-browser-track-sort-function))
- alist))
-
-(defun emms-browser-sort-by-name (alist)
- "Sort ALIST by keys alphabetically.
-Uses `emms-browser-alpha-sort-function'."
- (if emms-browser-alpha-sort-function
- (sort alist (emms-browser-sort-car
- emms-browser-alpha-sort-function))
- alist))
-
-(defun emms-browser-sort-by-year-or-name (alist)
- "Sort based on year or name."
- (sort alist (emms-browser-sort-cadr
- 'emms-browser-sort-by-year-or-name-p)))
-
-(defun emms-browser-sort-by-year-or-name-p (a b)
- ;; FIXME: this is a bit of a hack
- (let ((a-desc (concat
- (emms-browser-year-number a)
- (emms-track-get a 'info-album "misc")))
- (b-desc (concat
- (emms-browser-year-number b)
- (emms-track-get b 'info-album "misc"))))
- (string< a-desc b-desc)))
-
-(defun emms-browser-sort-alist (alist type)
- "Sort ALIST using the sorting function for TYPE."
- (let ((sort-func
- (cond
- ((or
- (eq type 'info-artist)
- (eq type 'info-composer)
- (eq type 'info-performer)
- (eq type 'info-year)
- (eq type 'info-genre))
- 'emms-browser-sort-by-name)
- ((eq type 'info-album)
- emms-browser-album-sort-function)
- ((eq type 'info-title)
- 'emms-browser-sort-by-track)
- (t (message "Can't sort unknown mapping!")))))
- (funcall sort-func alist)))
-
-;; --------------------------------------------------
-;; Subitem operations on the buffer
-;; --------------------------------------------------
-
-(defun emms-browser-bdata-at-point ()
- "Return the bdata object at point.
-Includes information at point (such as album name), and metadata."
- (get-text-property (point-at-bol)
- 'emms-browser-bdata))
-
-(defun emms-browser-data-at-point ()
- "Return the data stored under point.
-This will be a list of DB items."
- (emms-browser-bdata-data (emms-browser-bdata-at-point)))
-
-(defun emms-browser-level-at-point ()
- "Return the current level at point."
- (emms-browser-bdata-level (emms-browser-bdata-at-point)))
-
-(defun emms-browser-tracks-at-point (&optional node)
- "Return a list of tracks at point."
- (let (tracks)
- (dolist (node (if node
- node
- (emms-browser-data-at-point)))
- (if (not (emms-browser-bdata-p node))
- (setq tracks (cons node tracks))
- (setq tracks
- (append tracks
- (emms-browser-tracks-at-point
- (emms-browser-bdata-data node))))))
- tracks))
-
-(defun emms-browser-expand-one-level ()
- "Expand the current line by one sublevel."
- (interactive)
- (let* ((data (emms-browser-data-at-point)))
- (save-excursion
- (forward-line 1)
- (beginning-of-line)
- (dolist (data-item data)
- (emms-browser-insert-data-item data-item)))))
-
-(defun emms-browser-insert-data-item (data-item)
- "Insert DATA-ITEM into the buffer.
-This checks DATA-ITEM's level to determine how much to indent.
-The line will have a property emms-browser-bdata storing subitem
-information."
- (emms-browser-insert-format data-item))
-
-(defun emms-browser-find-entry-more-than-level (level)
- "Move point to next entry more than LEVEL and return point.
-If no entry exits, return nil.
-Returns point if currently on a an entry more than LEVEL."
- (let ((old-pos (point))
- level-at-point)
- (forward-line 1)
- (setq level-at-point (emms-browser-level-at-point))
- (if (and level-at-point
- (> level-at-point level))
- (point)
- (goto-char old-pos)
- nil)))
-
-(defun emms-browser-subitems-visible ()
- "True if there are any subentries visible point."
- (let ((current-level (emms-browser-level-at-point))
- new-level)
- (save-excursion
- (re-search-forward "\n" nil t)
- (when (setq new-level (emms-browser-level-at-point))
- (> new-level current-level)))))
-
-(defun emms-browser-subitems-exist ()
- "True if it's possible to expand the current line."
- (not (eq (emms-browser-bdata-type
- (emms-browser-bdata-at-point))
- 'info-title)))
-
-(defun emms-browser-move-up-level (&optional direction)
- "Move up one level if possible.
-Return true if we were able to move up.
-If DIRECTION is 1, move forward, otherwise move backwards."
- (interactive "P")
- (let ((moved nil)
- (continue t)
- (current-level (emms-browser-level-at-point)))
- (while (and
- continue
- (zerop (forward-line
- (or (and (numberp direction) direction) -1))))
- (when (> current-level (or (emms-browser-level-at-point) 0))
- (setq moved t)
- (setq continue nil)))
- moved))
-
-(defun emms-browser-toggle-subitems ()
- "Show or hide (kill) subitems under the current line."
- (interactive)
- (if (emms-browser-subitems-visible)
- (emms-browser-kill-subitems)
- (if (emms-browser-subitems-exist)
- (emms-browser-show-subitems)
- (cl-assert (emms-browser-move-up-level))
- (emms-browser-kill-subitems))))
-
-(defun emms-browser-toggle-subitems-recursively ()
- "Recursively toggle all subitems under the current line.
-If there is no more subitems to expand, collapse the current node."
- (interactive)
- (let ((current-level (emms-browser-level-at-point))
- first-expandable-level)
- (save-excursion
- (while (or (and (emms-browser-subitems-exist)
- (not (emms-browser-subitems-visible))
- (or (and (not first-expandable-level)
- (setq first-expandable-level (emms-browser-level-at-point)))
- (= first-expandable-level (emms-browser-level-at-point)))
- (emms-browser-show-subitems))
- (emms-browser-find-entry-more-than-level current-level))))
- (unless first-expandable-level
- (emms-browser-kill-subitems))))
-
-(defun emms-browser-show-subitems ()
- "Show subitems under the current line."
- (unless (emms-browser-subitems-visible)
- (if (emms-browser-subitems-exist)
- (emms-browser-expand-one-level))))
-
-(defun emms-browser-kill-subitems ()
- "Remove all subitems under the current line.
-Stops at the next line at the same level, or EOF."
- (when (emms-browser-subitems-visible)
- (let ((current-level (emms-browser-level-at-point))
- (next-line (point-at-bol 2)))
- (emms-with-inhibit-read-only-t
- (delete-region next-line
- (save-excursion
- (while
- (emms-browser-find-entry-more-than-level
- current-level))
- (point-at-bol 2)))))))
-
-;; --------------------------------------------------
-;; Dealing with the playlist (queuing songs, etc)
-;; --------------------------------------------------
-
-(defun emms-browser-playlist-insert-group (bdata)
- "Insert a group description into the playlist buffer."
- (let* ((type (emms-browser-bdata-type bdata))
- (short-type (substring (symbol-name type) 5))
- (name (emms-browser-format-line bdata 'playlist)))
- (with-current-emms-playlist
- (goto-char (point-max))
- (insert name "\n"))))
-
-(defun emms-browser-playlist-insert-track (bdata)
- "Insert a track into the playlist buffer."
- (let ((name (emms-browser-format-line bdata 'playlist))
- (track (car (emms-browser-bdata-data bdata))))
- (with-current-emms-playlist
- (goto-char (point-max))
- (insert name "\n"))))
-
-(defun emms-browser-playlist-insert-bdata (bdata starting-level)
- "Add all tracks in BDATA to the playlist."
- (let ((type (emms-browser-bdata-type bdata))
- (name (emms-browser-bdata-name bdata))
- (level (emms-browser-bdata-level bdata))
- emms-browser-current-indent)
-
- ;; adjust the indentation relative to the starting level
- (when starting-level
- (setq level (- level (1- starting-level))))
- ;; we temporarily rebind the current indent to the relative indent
- (setq emms-browser-current-indent
- (emms-browser-make-indent level))
-
- ;; add a group heading?
- (unless (eq type 'info-title)
- (emms-browser-playlist-insert-group bdata))
-
- ;; recurse or add tracks
- (dolist (item (emms-browser-bdata-data bdata))
- (if (not (eq type 'info-title))
- (emms-browser-playlist-insert-bdata item starting-level)
- (emms-browser-playlist-insert-track bdata)))))
-
-;; --------------------------------------------------
-;; Expanding/contracting
-;; --------------------------------------------------
-
-(defun emms-browser-expand-to-level (level)
- "Expand to a depth specified by LEVEL.
-After expanding, jump to the currently marked entry."
- (let ((count 1)
- (total 0)
- progress-reporter)
- (goto-char (point-min))
- (while (not (eq (buffer-end 1) (point)))
- (when (= (emms-browser-level-at-point) 1)
- (setq total (1+ total)))
- (emms-browser-next-non-track))
- (goto-char (point-min))
- (setq progress-reporter
- (make-progress-reporter "Expanding EMMS browser entries..."
- 0 total))
- (while (not (eq (buffer-end 1) (point)))
- (when (= (emms-browser-level-at-point) 1)
- (progress-reporter-update progress-reporter count)
- (setq count (1+ count)))
- (if (< (emms-browser-level-at-point) level)
- (emms-browser-show-subitems))
- (emms-browser-next-non-track))
- (progress-reporter-done progress-reporter)
- (emms-browser-pop-mark)
- (recenter '(4))))
-
-(defun emms-browser-mark-and-collapse ()
- "Save the current top level element, and collapse."
- (emms-browser-mark-entry)
- (goto-char (point-max))
- (while (not (eq (buffer-end -1) (point)))
- (emms-browser-prev-non-track)
- (emms-browser-kill-subitems)))
-
-(defun emms-browser-find-top-level ()
- "Move up until reaching a top-level element."
- (while (not (eq (emms-browser-level-at-point) 1))
- (forward-line -1)))
-
-(defun emms-browser-mark-entry ()
- "Mark the current top level entry."
- (save-excursion
- (emms-browser-find-top-level)
- (emms-with-inhibit-read-only-t
- (add-text-properties (point-at-bol)
- (point-at-eol)
- (list 'emms-browser-mark t)))))
-
-(defun emms-browser-pop-mark ()
- "Return to the last marked entry, and remove the mark."
- (goto-char (point-min))
- (let ((pos (text-property-any (point-min) (point-max)
- 'emms-browser-mark t)))
- (if pos
- (progn
- (goto-char pos)
- (emms-with-inhibit-read-only-t
- (remove-text-properties (point-at-bol)
- (point-at-eol)
- (list 'emms-browser-mark))))
- (message "No mark saved!"))))
-
-(defun emms-browser-go-to-parent ()
- "Move point to the parent of the current node.
-Return point. If at level one, return the current point."
- (let ((current-level (emms-browser-level-at-point)))
- (unless (eq current-level 1)
- (while (<= current-level (emms-browser-level-at-point))
- (forward-line -1)))
- (point)))
-
-(defun emms-browser-delete-current-node ()
- "Remove the current node, and empty parents."
- ;; set the data to empty
- (setcdr (assq 'data (emms-browser-bdata-at-point)) nil)
- (emms-browser-delete-node-if-empty))
-
-(defun emms-browser-delete-node-if-empty ()
- "If empty, remove node and empty parents."
- (when (zerop (length (emms-browser-data-at-point)))
- (save-excursion
- (let ((child-bdata (emms-browser-bdata-at-point))
- parent-bdata parent-point)
- ;; record the parent's position before we delete anything
- (save-excursion
- (setq parent-point (emms-browser-go-to-parent)))
- ;; delete the current line
- (when (emms-browser-subitems-visible)
- (emms-browser-kill-subitems))
- (emms-with-inhibit-read-only-t
- (goto-char (point-at-bol))
- (kill-line 1))
- (unless (eq (emms-browser-bdata-level child-bdata) 1)
- ;; remove the node from the parent, and recurse
- (goto-char parent-point)
- (setq parent-bdata (emms-browser-bdata-at-point))
- (setcdr (assq 'data parent-bdata)
- (delq child-bdata
- (emms-browser-bdata-data parent-bdata)))
- (emms-browser-delete-node-if-empty))))))
-
-;; --------------------------------------------------
-;; User-visible commands
-;; --------------------------------------------------
-
-(defun emms-browser-add-tracks ()
- "Add all tracks at point or in region if active.
-When the region is not active, a numeric prefix argument inserts that many
-tracks from point.
-Return the playlist buffer point-max before adding."
- (interactive)
- (let ((count (cond
- ((use-region-p)
- (1+ (- (line-number-at-pos (region-end)) (line-number-at-pos (region-beginning)))))
- ((numberp current-prefix-arg)
- current-prefix-arg)
- (t 1)))
- (first-new-track (with-current-emms-playlist (point-max))))
- (when (use-region-p) (goto-char (region-beginning)))
- (dotimes (_ count first-new-track)
- (let ((bdata (emms-browser-bdata-at-point)))
- (when bdata
- (emms-browser-playlist-insert-bdata
- bdata (emms-browser-bdata-level bdata))
- (forward-line))))
- (run-hook-with-args 'emms-browser-tracks-added-hook
- first-new-track)
- (deactivate-mark)
- first-new-track))
-
-(defun emms-browser-add-tracks-and-play ()
- "Add all tracks at point, and play the first added track."
- (interactive)
- (let ((old-pos (emms-browser-add-tracks)))
- (with-current-emms-playlist
- (goto-char old-pos)
- ;; if we're sitting on a group name, move forward
- (unless (emms-playlist-track-at (point))
- (emms-playlist-next))
- (emms-playlist-select (point)))
- ;; FIXME: is there a better way of doing this?
- (emms-stop)
- (emms-start)))
-
-(defun emms-isearch-buffer ()
- "Isearch through the buffer."
- (interactive)
- (goto-char (point-min))
- (when (isearch-forward)
- (unless (emms-browser-subitems-visible)
- (emms-browser-show-subitems))))
-
-(defun emms-browser-next-non-track (&optional direction)
- "Jump to the next non-track element."
- (interactive)
- (let ((continue t))
- (while (and continue
- (forward-line (or direction 1)))
- (unless (eq (emms-browser-bdata-type
- (emms-browser-bdata-at-point)) 'info-title)
- (setq continue nil)))))
-
-(defun emms-browser-prev-non-track ()
- "Jump to the previous non-track element."
- (interactive)
- (emms-browser-next-non-track -1))
-
-(defun emms-browser-expand-all ()
- "Expand everything."
- (interactive)
- (emms-browser-expand-to-level 99))
-
-(defun emms-browser-expand-to-level-2 ()
- "Expand all top level items one level."
- (interactive)
- (emms-browser-mark-and-collapse)
- (emms-browser-expand-to-level 2))
-
-(defun emms-browser-expand-to-level-3 ()
- "Expand all top level items two levels."
- (interactive)
- (emms-browser-mark-and-collapse)
- (emms-browser-expand-to-level 3))
-
-(defun emms-browser-expand-to-level-4 ()
- "Expand all top level items three levels."
- (interactive)
- (emms-browser-mark-and-collapse)
- (emms-browser-expand-to-level 4))
-
-(defun emms-browser-collapse-all ()
- "Collapse everything, saving and restoring the mark."
- (interactive)
- (emms-browser-mark-and-collapse)
- (emms-browser-pop-mark)
- (recenter '(4)))
-
-(defvar emms-browser-seed-pending t
- "Do we need to seed (random)?")
-
-(defun emms-browser-goto-random ()
- "Move cursor to random item with the lowest visible level."
- (interactive)
- (when emms-browser-seed-pending
- (random t)
- (setq emms-browser-seed-pending nil))
- (while (progn (goto-char (point-min))
- (forward-line (1- (random (count-lines (point-min) (point-max)))))
- (emms-browser-subitems-visible))))
-
-(defun emms-browser-view-in-dired (&optional bdata)
- "View the current directory in dired."
- ;; FIXME: currently just grabs the directory from the first track
- (interactive)
- (if bdata
- (if (eq (emms-browser-bdata-type bdata) 'info-title)
- (let* ((track (car (emms-browser-bdata-data bdata)))
- (path (emms-track-get track 'name))
- (dir (file-name-directory path)))
- (find-file dir))
- (emms-browser-view-in-dired (car (emms-browser-bdata-data bdata))))
- (emms-browser-view-in-dired (emms-browser-bdata-at-point))))
-
-(defun emms-browser-remove-tracks (&optional delete start end)
- "Remove all tracks at point or in region if active.
-Unless DELETE is non-nil or with prefix argument, this only acts on the browser,
-files are untouched.
-If caching is enabled, files are removed from the cache as well.
-When the region is not active, a numeric prefix argument remove that many
-tracks from point, it does not delete files."
- (interactive "P\nr")
- (let ((count (cond
- ((use-region-p)
- (1+ (- (line-number-at-pos end) (line-number-at-pos start))))
- ((numberp current-prefix-arg)
- current-prefix-arg)
- (t 1)))
- dirs path tracks)
- ;; If numeric prefix argument, never delete files.
- (when (numberp delete) (setq delete nil))
- (when delete
- (save-mark-and-excursion
- (when (use-region-p) (goto-char start))
- (let ((lines (min count (- (line-number-at-pos (point-max)) (line-number-at-pos (point))))))
- (dotimes (_ lines)
- ;; TODO: Test this!
- (setq tracks (append tracks (emms-browser-tracks-at-point)))
- (forward-line))))
- (unless (yes-or-no-p
- (format "Really permanently delete these %d tracks? " (length tracks)))
- (error "Cancelled!"))
- (message "Deleting files..."))
- (when (use-region-p) (goto-char start))
- (dotimes (_ count)
- (dolist (track (emms-browser-tracks-at-point))
- (setq path (emms-track-get track 'name))
- (when delete
- (delete-file path))
- (add-to-list 'dirs (file-name-directory path))
- (emms-cache-del path))
- ;; remove the item from the browser
- (when (emms-browser-tracks-at-point)
- (emms-browser-delete-current-node)))
- (deactivate-mark)
- ;; remove empty dirs
- (when delete
- (dolist (dir dirs)
- (run-hook-with-args 'emms-browser-delete-files-hook dir tracks)
- (condition-case nil
- (delete-directory dir)
- (error nil))))
- (when delete
- (message "Deleting files...done"))))
-
-(defalias 'emms-browser-delete-files 'emms-browser-remove-tracks)
-(put 'emms-browser-delete-files 'disabled t)
-
-(defun emms-browser-clear-playlist ()
- (interactive)
- (with-current-emms-playlist
- (emms-playlist-clear)))
-
-(defun emms-browser-lookup (field url)
- (let ((data
- (emms-track-get (emms-browser-bdata-first-track
- (emms-browser-bdata-at-point))
- field)))
- (when data
- (browse-url
- (concat url data)))))
-
-(defun emms-browser-lookup-wikipedia (field)
- (emms-browser-lookup
- field "http://en.wikipedia.org/wiki/Special:Search?search="))
-
-(defun emms-browser-lookup-artist-on-wikipedia ()
- (interactive)
- (emms-browser-lookup-wikipedia 'info-artist))
-
-(defun emms-browser-lookup-composer-on-wikipedia ()
- (interactive)
- (emms-browser-lookup-wikipedia 'info-composer))
-
-(defun emms-browser-lookup-performer-on-wikipedia ()
- (interactive)
- (emms-browser-lookup-wikipedia 'info-performer))
-
-(defun emms-browser-lookup-album-on-wikipedia ()
- (interactive)
- (emms-browser-lookup-wikipedia 'info-album))
-
-
-;; --------------------------------------------------
-;; Linked browser and playlist windows
-;; --------------------------------------------------
-
-(defcustom emms-browser-switch-to-playlist-on-add
- nil
- "Whether to switch to to the playlist after adding files."
- :group 'emms-browser
- :type 'boolean)
-
-;;;###autoload
-(defun emms-smart-browse ()
- "Display browser and playlist.
-Toggle between selecting browser, playlist or hiding both. Tries
-to behave sanely if the user has manually changed the window
-configuration."
- (interactive)
- (add-to-list 'emms-browser-show-display-hook
- 'emms-browser-display-playlist)
- (add-to-list 'emms-browser-hide-display-hook
- 'emms-browser-hide-linked-window)
- ;; switch to the playlist window when adding tracks?
- (add-to-list 'emms-browser-tracks-added-hook
- (lambda (start-of-tracks) (interactive)
- (let (playlist-window)
- (when emms-browser-switch-to-playlist-on-add
- (emms-smart-browse))
- ;; center on the first added track/group name
- (when
- (setq playlist-window
- (emms-browser-get-linked-window))
- (emms-browser-with-selected-window
- playlist-window
- (goto-char start-of-tracks)
- (recenter '(4)))))))
- (let (wind buf)
- (cond
- ((eq major-mode 'emms-browser-mode)
- (setq buf (emms-browser-get-linked-buffer))
- (setq wind (emms-browser-get-linked-window))
- ;; if the playlist window is visible, select it
- (if wind
- (select-window wind)
- ;; otherwise display and select it
- (select-window (emms-browser-display-playlist))))
- ((eq major-mode 'emms-playlist-mode)
- (setq wind (emms-browser-get-linked-window))
- ;; if the playlist window is selected, and the browser is visible,
- ;; hide both
- (if wind
- (progn
- (select-window wind)
- (emms-browser-bury-buffer)
- ;; After a browser search, the following buffer could be the
- ;; unfiltered browser, which we want to bury as well. We don't want
- ;; to call `emms-browser-hide-display-hook' for this one so we bury it
- ;; directly.
- (when (eq major-mode 'emms-browser-mode)
- (bury-buffer)))
- ;; otherwise bury both
- (bury-buffer)
- (emms-browser-hide-linked-window)))
- (t
- ;; show both
- (emms-browser)))))
-
-(defun emms-browser-get-linked-buffer ()
- "Return linked buffer (eg browser if playlist is selected."
- (cond
- ((eq major-mode 'emms-browser-mode)
- (car (emms-playlist-buffer-list)))
- ((eq major-mode 'emms-playlist-mode)
- (emms-browser-get-buffer))))
-
-(defun emms-browser-get-linked-window ()
- "Return linked window (eg browser if playlist is selected."
- (let ((buf (emms-browser-get-linked-buffer)))
- (when buf
- (get-buffer-window buf))))
-
-(defun emms-browser-display-playlist ()
- "A hook to show the playlist when the browser is displayed.
-Returns the playlist window."
- (interactive)
- (let ((pbuf (emms-browser-get-linked-buffer))
- (pwin (emms-browser-get-linked-window)))
- ;; if the window isn't alive..
- (unless (window-live-p pwin)
- (save-selected-window
- (split-window-horizontally)
- (other-window 1)
- (if pbuf
- (switch-to-buffer pbuf)
- ;; there's no playlist - create one
- (setq pbuf (emms-playlist-current-clear))
- (switch-to-buffer pbuf))
- ;; make q in the playlist window hide the linked browser
- (when (boundp 'emms-playlist-mode-map)
- (define-key emms-playlist-mode-map (kbd "q")
- (lambda ()
- (interactive)
- (emms-browser-hide-linked-window)
- (bury-buffer))))
- (setq pwin (get-buffer-window pbuf))))
- pwin))
-
-(defun emms-browser-hide-linked-window ()
- "Delete a playlist or browser window when the other is hidden."
- (interactive)
- (let ((other-buf (emms-browser-get-linked-buffer))
- (other-win (emms-browser-get-linked-window)))
- (when (and other-win
- (window-live-p other-win))
- (delete-window other-win))
- ;; bury the buffer, or it becomes visible when we hide the
- ;; linked buffer
- (bury-buffer other-buf)))
-
-;; --------------------------------------------------
-;; Searching
-;; --------------------------------------------------
-
-(defun emms-browser-filter-cache (search-list)
- "Return a list of tracks that match SEARCH-LIST.
-SEARCH-LIST is a list of cons pairs, in the form:
-
- ((field1 field2) string)
-
-If string matches any of the fields in a cons pair, it will be
-included."
-
- (let (tracks)
- (maphash (lambda (k track)
- (when (emms-browser-matches-p track search-list)
- (push track tracks)))
- emms-cache-db)
- tracks))
-
-(defun emms-browser-matches-p (track search-list)
- (let (no-match matched)
- (dolist (item search-list)
- (setq matched nil)
- (dolist (field (car item))
- (let ((track-field (emms-track-get track field "")))
- (when (and track-field (string-match (cadr item) track-field))
- (setq matched t))))
- (unless matched
- (setq no-match t)))
- (not no-match)))
-
-(defun emms-browser-search-buffer-go ()
- "Create a new search buffer, or clean the existing one."
- (switch-to-buffer
- (get-buffer-create emms-browser-search-buffer-name))
- (emms-browser-mode t)
- (use-local-map emms-browser-search-mode-map)
- (emms-with-inhibit-read-only-t
- (delete-region (point-min) (point-max))))
-
-(defun emms-browser-search (fields)
- "Search for STR using FIELDS."
- (let* ((prompt (format "Searching with %S: " fields))
- (str (read-string prompt)))
- (emms-browser-search-buffer-go)
- (emms-with-inhibit-read-only-t
- (emms-browser-render-search
- (emms-browser-filter-cache
- (list (list fields str)))))
- (emms-browser-expand-all)
- (goto-char (point-min))))
-
-(defun emms-browser-render-search (tracks)
- (let ((entries
- (emms-browser-make-sorted-alist 'info-artist tracks)))
- (dolist (entry entries)
- (emms-browser-insert-top-level-entry (car entry)
- (cdr entry)
- 'info-artist))))
-
-;; hmm - should we be doing this?
-(defun emms-browser-kill-search ()
- "Kill the buffer when q is hit."
- (interactive)
- (kill-buffer (current-buffer)))
-
-(defun emms-browser-search-by-artist ()
- (interactive)
- (emms-browser-search '(info-artist)))
-
-(defun emms-browser-search-by-composer ()
- (interactive)
- (emms-browser-search '(info-composer)))
-
-(defun emms-browser-search-by-performer ()
- (interactive)
- (emms-browser-search '(info-performer)))
-
-(defun emms-browser-search-by-title ()
- (interactive)
- (emms-browser-search '(info-title)))
-
-(defun emms-browser-search-by-album ()
- (interactive)
- (emms-browser-search '(info-album)))
-
-(defun emms-browser-search-by-names ()
- (interactive)
- (emms-browser-search '(info-artist info-composer info-performer info-title info-album)))
-
-;; --------------------------------------------------
-;; Album covers
-;; --------------------------------------------------
-
-(defun emms-browser--build-cover-filename ()
- "Build `emms-browser--covers-filename'.
-
-Based on from `emms-browser-covers' (when a list) and
-`emms-browser-covers-file-extensions'."
- (setq emms-browser--covers-filename
- (mapcar (lambda (cover)
- (if (file-name-extension cover)
- (list cover)
- (mapcar (lambda (ext) (concat cover "." ext))
- emms-browser-covers-file-extensions)))
- emms-browser-covers)))
-
-(defun emms-browser-get-cover-from-album (bdata &optional size)
- (cl-assert (eq (emms-browser-bdata-type bdata) 'info-album))
- (let* ((track1data (emms-browser-bdata-data bdata))
- (track1 (car (emms-browser-bdata-data (car track1data))))
- (path (emms-track-get track1 'name)))
- (emms-browser-get-cover-from-path path size)))
-
-(defun emms-browser-get-cover-from-path (path &optional size)
- "Return a cover filename, if it exists."
- (unless size
- (setq size 'medium))
- (let* ((size-idx (cond
- ((eq size 'small) 0)
- ((eq size 'medium) 1)
- ((eq size 'large) 2)))
- (cover
- (cond
- ((functionp emms-browser-covers)
- (funcall emms-browser-covers (file-name-directory path) size))
- ((and (listp emms-browser-covers)
- (nth size-idx emms-browser-covers))
- (unless emms-browser--covers-filename
- (emms-browser--build-cover-filename))
- (car (delq nil
- (mapcar (lambda (cover)
- (let ((coverpath
- (concat (file-name-directory path) cover)))
- (and (file-exists-p coverpath) coverpath)))
- (nth size-idx emms-browser--covers-filename))))))))
- (if (and cover (file-readable-p cover))
- cover
- ;; no cover found, use default
- (when emms-browser-default-covers
- (nth size-idx emms-browser-default-covers)))))
-
-(defun emms-browser-insert-cover (path)
- (insert (emms-browser-make-cover path)))
-
-(defun emms-browser-make-cover (path)
- (let* ((ext (file-name-extension path))
- (type (cond
- ((string= ext "png") 'png)
- ((string= ext "xbm") 'xbm)
- ((string= ext "xpm") 'xpm)
- ((string= ext "pbm") 'pbm)
- ((string-match "e?ps"
- ext) 'postscript)
- ((string= ext "gif") 'gif)
- ((string= ext "tiff") 'tiff)
- (t 'jpeg))))
- (emms-propertize " "
- 'display `(image
- :type ,type
- :margin 5
- :file ,path)
- 'rear-nonsticky '(display))))
-
-(defun emms-browser-get-cover-str (path size)
- (let ((cover (emms-browser-get-cover-from-path path size)))
- (if cover
- (emms-browser-make-cover cover)
- ;; we use a single space so that cover & no cover tracks line up
- ;; in a terminal
- " ")))
-
-;; --------------------------------------------------
-;; Display formats
-;; --------------------------------------------------
-
-(defun emms-browser-bdata-first-track (bdata)
- "Return the first track from a given bdata.
-If > album level, most of the track data will not make sense."
- (let ((type (emms-browser-bdata-type bdata)))
- (if (eq type 'info-title)
- (car (emms-browser-bdata-data bdata))
- ;; recurse
- (emms-browser-bdata-first-track
- (car (emms-browser-bdata-data bdata))))))
-
-(defun emms-browser-insert-format (bdata)
- (emms-with-inhibit-read-only-t
- (insert
- (emms-browser-format-line bdata)
- "\n")))
-
-(defun emms-browser-make-indent (level)
- (or
- emms-browser-current-indent
- (make-string (* 1 (1- level)) ?\s)))
-
-(defun emms-browser-format-elem (format-string elem)
- (cdr (assoc elem format-string)))
-
-(defun emms-browser-format-line (bdata &optional target)
- "Return a propertized string to be inserted in the buffer."
- (unless target
- (setq target 'browser))
- (let* ((name (or (emms-browser-bdata-name bdata) "misc"))
- (level (emms-browser-bdata-level bdata))
- (type (emms-browser-bdata-type bdata))
- (indent (emms-browser-make-indent level))
- (track (emms-browser-bdata-first-track bdata))
- (path (emms-track-get track 'name))
- (face (emms-browser-get-face bdata))
- (format (emms-browser-get-format bdata target))
- (props (list 'emms-browser-bdata bdata))
- (format-choices
- `(("i" . ,indent)
- ("n" . ,name)
- ("y" . ,(emms-track-get-year track))
- ("A" . ,(emms-track-get track 'info-album))
- ("a" . ,(emms-track-get track 'info-artist))
- ("C" . ,(emms-track-get track 'info-composer))
- ("p" . ,(emms-track-get track 'info-performer))
- ("t" . ,(emms-track-get track 'info-title))
- ("D" . ,(emms-browser-disc-number track))
- ("T" . ,(emms-browser-track-number track))
- ("d" . ,(emms-browser-track-duration track))))
- str)
- (when (equal type 'info-album)
- (setq format-choices (append format-choices
- `(("cS" . ,(emms-browser-get-cover-str path 'small))
- ("cM" . ,(emms-browser-get-cover-str path 'medium))
- ("cL" . ,(emms-browser-get-cover-str path 'large))))))
-
-
- (when (functionp format)
- (setq format (funcall format bdata format-choices)))
-
- (setq str
- (with-temp-buffer
- (insert format)
- (goto-char (point-min))
- (let ((start (point-min)))
- ;; jump over any image
- (when (re-search-forward "%c[SML]" nil t)
- (setq start (point)))
- ;; jump over the indent
- (when (re-search-forward "%i" nil t)
- (setq start (point)))
- (add-text-properties start (point-max)
- (list 'face face)))
- (buffer-string)))
-
- (setq str (emms-browser-format-spec str format-choices))
-
- ;; give tracks a 'boost' if they're not top-level
- ;; (covers take up an extra space)
- (when (and (eq type 'info-title)
- (not (string= indent "")))
- (setq str (concat " " str)))
-
- ;; if we're in playlist mode, add a track
- (when (and (eq target 'playlist)
- (eq type 'info-title))
- (setq props
- (append props `(emms-track ,track))))
-
- ;; add properties to the whole string
- (add-text-properties 0 (length str) props str)
- str))
-
-(defun emms-browser-get-face (bdata)
- "Return a suitable face for BDATA."
- (let* ((type (emms-browser-bdata-type bdata))
- (name (cond
- ((or (eq type 'info-year)
- (eq type 'info-genre)) "year/genre")
- ((eq type 'info-artist) "artist")
- ((eq type 'info-composer) "composer")
- ((eq type 'info-performer) "performer")
- ((eq type 'info-album) "album")
- ((eq type 'info-title) "track"))))
- (intern
- (concat "emms-browser-" name "-face"))))
-
-;; based on gnus code
-(defun emms-browser-format-spec (format specification)
- "Return a string based on FORMAT and SPECIFICATION.
-FORMAT is a string containing `format'-like specs like \"bash %u %k\",
-while SPECIFICATION is an alist mapping from format spec characters
-to values. Any text properties on a %-spec itself are propagated to
-the text that it generates."
- (with-temp-buffer
- (insert format)
- (goto-char (point-min))
- (while (search-forward "%" nil t)
- (cond
- ;; Quoted percent sign.
- ((eq (char-after) ?%)
- (delete-char 1))
- ;; Valid format spec.
- ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]+\\)")
- (let* ((num (match-string 1))
- (spec (match-string 2))
- (val (cdr (assoc spec specification))))
- (unless val
- (error "Invalid format character: %s" spec))
- ;; Pad result to desired length.
- (let ((text (format (concat "%" num "s") val)))
- ;; Insert first, to preserve text properties.
- (insert-and-inherit text)
- ;; Delete the specifier body.
- (delete-region (+ (match-beginning 0) (length text))
- (+ (match-end 0) (length text)))
- ;; Delete the percent sign.
- (delete-region (1- (match-beginning 0)) (match-beginning 0)))))
- ;; Signal an error on bogus format strings.
- (t
- (error "Invalid format string"))))
- (buffer-string)))
-
-;; --------------------------------------------------
-;; Display formats - defaults
-;; --------------------------------------------------
-
-;; FIXME: optional format strings would avoid having to define a
-;; function for specifiers which may be empty.
-
-(defvar emms-browser-default-format "%i%n"
- "indent + name")
-
-;; tracks
-(defvar emms-browser-info-title-format
- 'emms-browser-track-artist-and-title-format)
-(defvar emms-browser-playlist-info-title-format
- 'emms-browser-track-artist-and-title-format)
-
-(defun emms-browser-get-format (bdata target)
- (let* ((type (emms-browser-bdata-type bdata))
- (target-str (or
- (and (eq target 'browser) "")
- (concat (symbol-name target) "-")))
- (sym
- (intern
- (concat "emms-browser-"
- target-str
- (symbol-name type)
- "-format"))))
- (if (boundp sym)
- (symbol-value sym)
- emms-browser-default-format)))
-
-(defun emms-browser-track-artist-and-title-format (bdata fmt)
- (concat
- "%i"
- (let ((track (emms-browser-format-elem fmt "T")))
- (if (and track (not (string= track "0")))
- "%T. "
- ""))
- "%n"))
-
-;; albums - we define two formats, one for a small cover (browser),
-;; and one for a medium sized cover (playlist).
-(defvar emms-browser-info-album-format
- 'emms-browser-year-and-album-fmt)
-(defvar emms-browser-playlist-info-album-format
- 'emms-browser-year-and-album-fmt-med)
-
-(defun emms-browser-year-and-album-fmt (bdata fmt)
- (concat
- "%i%cS"
- (let ((year (emms-browser-format-elem fmt "y")))
- (if (and year (not (string= year "0")))
- "(%y) "
- ""))
- "%n"))
-
-(defun emms-browser-year-and-album-fmt-med (bdata fmt)
- (concat
- "%i%cM"
- (let ((year (emms-browser-format-elem fmt "y")))
- (if (and year (not (string= year "0")))
- "(%y) "
- ""))
- "%n"))
-
-;; --------------------------------------------------
-;; Display faces
-;; --------------------------------------------------
-
-(defmacro emms-browser-make-face (name dark-col light-col height)
- (let ((face-name (intern (concat "emms-browser-" name "-face"))))
- `(defface ,face-name
- '((((class color) (background dark))
- (:foreground ,dark-col
- :height ,height))
- (((class color) (background light))
- (:foreground ,light-col
- :height ,height))
- (((type tty) (class mono))
- (:inverse-video t))
- (t (:background ,dark-col)))
- ,(concat "Face for "
- name
- " in a browser/playlist buffer.")
- :group 'emms-browser-mode)))
-
-(emms-browser-make-face "year/genre" "#aaaaff" "#444477" 1.5)
-(emms-browser-make-face "artist" "#aaaaff" "#444477" 1.3)
-(emms-browser-make-face "composer" "#aaaaff" "#444477" 1.3)
-(emms-browser-make-face "performer" "#aaaaff" "#444477" 1.3)
-(emms-browser-make-face "album" "#aaaaff" "#444477" 1.1)
-(emms-browser-make-face "track" "#aaaaff" "#444477" 1.0)
-
-;; --------------------------------------------------
-;; Filtering
-;; --------------------------------------------------
-
-(defvar emms-browser-filters nil
- "A list of available filters.")
-
-(defmacro emms-browser-make-filter (name func)
- "Make a user-level function for filtering tracks.
-This:
- - defines an interactive function M-x emms-browser-show-NAME.
- - defines a variable emms-browser-filter-NAME of (name . func).
- - adds the filter to emms-browser-filters."
- (let ((funcnam (intern (concat "emms-browser-show-" name)))
- (var (intern (concat "emms-browser-filter-" name)))
- (desc (concat "Filter the cache using rule '"
- name "'")))
- `(progn
- (defvar ,var nil ,desc)
- (setq ,var (cons ,name ,func))
- (add-to-list 'emms-browser-filters ,var)
- (defun ,funcnam ()
- ,desc
- (interactive)
- (emms-browser-refilter ,var)))))
-
-(defun emms-browser-set-filter (filter)
- "Set the current filter to be used on next update.
-This does not refresh the current buffer."
- (setq emms-browser-filter-tracks-hook (cdr filter))
- (setq emms-browser-current-filter-name (car filter))
- (run-hooks 'emms-browser-filter-changed-hook))
-
-(defun emms-browser-refilter (filter)
- "Filter and render the top-level tracks."
- (emms-browser-set-filter filter)
- (emms-browse-by (or emms-browser-top-level-type
- emms-browser-default-browse-type)))
-
-(defun emms-browser-next-filter (&optional reverse)
- "Redisplay with the next filter."
- (interactive)
- (let* ((list (if reverse
- (reverse emms-browser-filters)
- emms-browser-filters))
- (key emms-browser-current-filter-name)
- (next (cadr (member (assoc key list) list))))
- ;; wrapped
- (unless next
- (setq next (car list)))
- (emms-browser-refilter next)))
-
-(defun emms-browser-previous-filter ()
- "Redisplay with the previous filter."
- (interactive)
- (emms-browser-next-filter t))
-
-(defun emms-browser-filter-only-dir (path)
- "Generate a function which checks if a track is in path.
-If the track is not in path, return t."
- `(lambda (track)
- (not (string-match ,(concat "^" (expand-file-name path))
- (emms-track-get track 'name)))))
-
-(defun emms-browser-filter-only-type (type)
- "Generate a function which checks a track's type.
-If the track is not of TYPE, return t."
- `(lambda (track)
- (not (eq (quote ,type) (emms-track-get track 'type)))))
-
-;; seconds in a day (* 60 60 24) = 86400
-(defun emms-browser-filter-only-recent (days)
- "Show only tracks played within the last number of DAYS."
- `(lambda (track)
- (let ((min-date (time-subtract
- (current-time)
- (seconds-to-time (* ,days 86400))))
- last-played)
- (not (and (setq last-played
- (emms-track-get track 'last-played nil))
- (time-less-p min-date last-played))))))
-
-;; TODO: Add function to clear the cache from thumbnails that have no associated
-;; cover folders. This is especially useful in case the music library path
-;; changes: currently, all covers will have to be re-cached while the old ones
-;; are left as is, useless.
-
-;; TODO: `emms-browser-expand-all' is slow because of all the covers (about 30
-;; sec fot 1500 covers in my case). Try to profile & optimize. It will
-;; probably not be enough and we might need to run emms-browser-expand-all
-;; asynchronously.
-
-
-(defvar emms-browser-thumbnail-directory (expand-file-name "thumbnails" emms-directory)
- "Directory where to store cover thumbnails.")
-
-(defvar emms-browser-thumbnail-small-size 128
- "Cover thumbnail will be resized if necessary so that neither width nor height exceed this dimension.")
-(defvar emms-browser-thumbnail-medium-size 256
- "Cover thumbnail will be resized if necessary so that neither width nor height exceed this dimension.")
-(defvar emms-browser-thumbnail-large-size 1024 ; Emms does not use large covers as of 2017-11-26.
- "Cover thumbnail will be resized if necessary so that neither width nor height exceed this dimension.")
-
-(defun emms-browser-thumbnail-filter-default (dir)
- "Select covers containing 'front' or 'cover' in DIR.
-If none was found, fallback on `emms-browser-thumbnail-filter-all'.
-
-See `emms-browser-thumbnail-filter'."
- (when (file-directory-p dir)
- (let ((ls (directory-files dir t nil t))
- (case-fold-search t)
- covers)
- (dolist (ext emms-browser-covers-file-extensions)
- (setq covers (append (seq-filter (lambda (c) (string-match (concat "\\(front\\|cover\\).*\\." ext) c)) ls) covers)))
- (unless covers
- (setq covers (emms-browser-thumbnail-filter-all dir)))
- covers)))
-
-(defun emms-browser-thumbnail-filter-all (dir)
- "Return the list of all files with `emms-browser-covers-file-extensions' in DIR.
-
-See `emms-browser-thumbnail-filter'."
- (let (covers)
- (dolist (ext emms-browser-covers-file-extensions covers)
- (setq covers (append (file-expand-wildcards (expand-file-name (concat "*." ext) dir)) covers)))))
-
-(defvar emms-browser-thumbnail-filter 'emms-browser-thumbnail-filter-default
- "This filter must hold a function that takes a directory argument and returns a list of cover file names.
-The list will be processed by `emms-browser-cache-thumbnail'.
-See also `emms-browser-thumbnail-filter-default'.")
-
-(defvar emms-browser-thumbnail-convert-program (executable-find "convert")
- "The ImageMagick's `convert' program.")
-
-(defun emms-browser-cache-thumbnail (dir size)
- "Return cached cover SIZE for album in DIR.
-
-SIZE must be 'small, 'medium or 'large. It will determine the
-resolution of the cached file. See the variables
-`emms-browser-thumbnail-SIZE-size'.
-
-If cover is not cached or if cache is out-of-date, re-cache it.
-If both the width and the height of the cover are smaller than
-`emms-browser-thumbnail-SIZE-size', it need not be cached and
-will be used directly.
-
-Emms assumes that you have one album per folder. This function
-will always use the same cover per folder.
-
-`emms-browser-covers' can be `fset' to this function."
- (if (eq size 'large)
- ;; 'large is unused for now. Return empty.
- nil
- (let (covers
- cover
- (cover-width 0) (cover-height 0)
- (size-value (symbol-value (intern (concat "emms-browser-thumbnail-" (symbol-name size) "-size"))))
- cache-dest-file)
- (setq covers (funcall emms-browser-thumbnail-filter dir))
- (if (not covers)
- nil
- ;; Find best quality cover.
- (let (res)
- (dolist (c covers)
- (setq res (image-size (create-image c) t))
- ;; image-size does not error, it returns (30 . 30) instead.
- (and (> (car res) 30) (> (cdr res) 30)
- (< cover-width (car res)) (< cover-height (cdr res))
- (setq cover-width (car res) cover-height (cdr res) cover c))))
- (if (and (>= size-value cover-width) (>= size-value cover-height))
- ;; No need to resize and cache.
- cover
- (let ((cache-dest (concat emms-browser-thumbnail-directory (file-name-directory cover))))
- (mkdir cache-dest t)
- (setq cache-dest-file (concat
- (expand-file-name "cover_" cache-dest)
- (symbol-name size)
- "." (file-name-extension cover))))
- (and emms-browser-thumbnail-convert-program
- (or (not (file-exists-p cache-dest-file))
- (time-less-p (nth 5 (file-attributes cache-dest-file))
- (nth 5 (file-attributes cover)) ))
- (let (err msg)
- ;; An Elisp function would be faster, but Emacs does not seem be be
- ;; able to resize image files. It can resize image displays though.
- ;; TODO: Add image resizing support to Emacs.
- (setq msg (with-output-to-string
- (with-current-buffer standard-output
- (setq err (call-process (executable-find "convert") nil '(t t) nil
- "-resize" (format "%sx%s" size-value size-value)
- cover
- cache-dest-file)))))
- (when (/= err 0)
- (warn "%s" msg)
- (setq cache-dest-file nil))))
- cache-dest-file)))))
-
-(defvar emms-browser--cache-hash nil
- "Cache for `emms-browser-cache-thumbnail-async'.")
-
-(defun emms-browser-cache-thumbnail-async (dir size)
- "Like `emms-browser-cache-thumbnail' but caches queries for faster lookups.
-The drawback is that if changes are made to the covers in DIR
-after `emms-browser-cache-thumbnail-async' queried them, it won't
-be taken into account. Call `emms-browser-clear-cache-hash' to
-refresh the cache."
- (unless emms-browser--cache-hash
- (setq emms-browser--cache-hash (make-hash-table :test 'equal)))
- (let* ((key (cons dir size))
- (val (gethash key emms-browser--cache-hash)))
- (or val
- (puthash key (emms-browser-cache-thumbnail dir size)
- emms-browser--cache-hash))))
-
-(defun emms-browser-clear-cache-hash ()
- "Resets `emms-browser-cache-thumbnail-async' cache.
-This is useful if there were changes on disk after
-`emms-browser-cache-thumbnail-async' first cached them."
- (interactive)
- (clrhash emms-browser--cache-hash))
-
-(provide 'emms-browser)
-;;; emms-browser.el ends here
diff --git a/lisp/emms-cache.el b/lisp/emms-cache.el
deleted file mode 100644
index 792b1b8..0000000
--- a/lisp/emms-cache.el
+++ /dev/null
@@ -1,195 +0,0 @@
-;;; emms-cache.el --- persistence for emms-track
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Damien Elmes <emacs@repose.cx>
-;; Keywords: emms, mp3, mpeg, multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; The cache is a mapping of a full path name to information, and so
-;; it is invalidated when you rename or move files about. It also
-;; does not differentiate between file or uri tracks.
-
-;; Because cache lookups are much faster than disk access, this works
-;; much better with a later-do-interval of something like 0.001. Also
-;; consider using synchronous mode, as it's quite fast now.
-
-;; This code is activated by (emms-standard) and above.
-
-;; To activate it by hand, use:
-
-;; (emms-cache 1)
-
-;;; Code:
-
-(require 'emms)
-(require 'emms-info)
-
-(when (fboundp 'define-hash-table-test)
- (define-hash-table-test 'string-hash 'string= 'sxhash))
-
-(defvar emms-cache-db (make-hash-table
- :test (if (fboundp 'define-hash-table-test)
- 'string-hash
- 'equal))
- "A mapping of paths to file info.
-This is used to cache over emacs sessions.")
-
-(defvar emms-cache-dirty nil
- "True if the cache has been updated since init.")
-
-(defcustom emms-cache-file (concat (file-name-as-directory emms-directory) "cache")
- "A file used to store cached file information over sessions."
- :group 'emms
- :type 'file)
-
-(defcustom emms-cache-file-coding-system 'utf-8
- "Coding system used for saving `emms-cache-file'."
- :group 'emms
- :type 'coding-system)
-
-(defun emms-cache (arg)
- "Turn on Emms caching if ARG is positive, off otherwise."
- (interactive "p")
- (if (and arg (> arg 0))
- (progn
- (unless emms-cache-dirty
- (emms-cache-restore))
- (unless noninteractive
- (add-hook 'kill-emacs-hook 'emms-cache-save))
- (setq emms-cache-get-function 'emms-cache-get)
- (setq emms-cache-set-function 'emms-cache-set)
- (setq emms-cache-modified-function 'emms-cache-dirty))
- (remove-hook 'kill-emacs-hook 'emms-cache-save)
- (setq emms-cache-get-function nil)
- (setq emms-cache-set-function nil)
- (setq emms-cache-modified-function nil)))
-
-;;;###autoload
-(defun emms-cache-enable ()
- "Enable caching of Emms track data."
- (interactive)
- (emms-cache 1)
- (message "Emms cache enabled"))
-
-;;;###autoload
-(defun emms-cache-disable ()
- "Disable caching of Emms track data."
- (interactive)
- (emms-cache -1)
- (message "Emms cache disabled"))
-
-;;;###autoload
-(defun emms-cache-toggle ()
- "Toggle caching of Emms track data."
- (interactive)
- (if emms-cache-get-function
- (emms-cache-disable)
- (emms-cache-enable)))
-
-(defsubst emms-cache-dirty (&rest ignored)
- "Mark the cache as dirty."
- (setq emms-cache-dirty t))
-
-(defun emms-cache-get (type path)
- "Return a cache element for PATH, or nil."
- (gethash path emms-cache-db))
-
-;; Note we ignore TYPE, as it's stored in TRACK
-(defun emms-cache-set (type path track)
- "Set PATH to TRACK in the cache."
- (puthash path track emms-cache-db)
- (emms-cache-dirty))
-
-(defun emms-cache-del (path)
- "Remove a track from the cache, with key PATH."
- (remhash path emms-cache-db)
- (emms-cache-dirty))
-
-(defun emms-cache-save ()
- "Save the track cache to a file."
- (interactive)
- (when emms-cache-dirty
- (message "Saving emms track cache...")
- (set-buffer (get-buffer-create " emms-cache "))
- (erase-buffer)
- (insert
- (concat ";;; .emms-cache -*- mode: emacs-lisp; coding: "
- (symbol-name emms-cache-file-coding-system)
- "; -*-\n"))
- (maphash (lambda (k v)
- (insert (format
- "(puthash %S '%S emms-cache-db)\n" k v)))
- emms-cache-db)
- (when (fboundp 'set-buffer-file-coding-system)
- (set-buffer-file-coding-system emms-cache-file-coding-system))
- (unless (file-directory-p (file-name-directory emms-cache-file))
- (make-directory (file-name-directory emms-cache-file)))
- (write-region (point-min) (point-max) emms-cache-file)
- (kill-buffer (current-buffer))
- (message "Saving emms track cache...done")
- (setq emms-cache-dirty nil)))
-
-(defun emms-cache-restore ()
- "Restore the track cache from a file."
- (interactive)
- (load emms-cache-file t nil t)
- (setq emms-cache-dirty nil))
-
-(defun emms-cache-sync ()
- "Sync the cache with the data on disc.
-Remove non-existent files, and update data for files which have
-been modified."
- (interactive)
- (message "Syncing emms track cache...")
- (let (removed)
- (maphash (lambda (path track)
- (when (eq (emms-track-get track 'type) 'file)
- ;; if no longer here, remove
- (if (not (file-exists-p path))
- (progn
- (remhash path emms-cache-db)
- (setq removed t))
- (let ((file-mtime (emms-info-track-file-mtime track))
- (info-mtime (emms-track-get track 'info-mtime)))
- (when (or (not info-mtime)
- (emms-time-less-p
- info-mtime file-mtime))
- (run-hook-with-args 'emms-info-functions track))))))
- emms-cache-db)
- (when removed
- (setq emms-cache-dirty t)))
- (message "Syncing emms track cache...done"))
-
-(defun emms-cache-reset ()
- "Reset the cache."
- (interactive)
- (when (yes-or-no-p "Really reset the cache?")
- (setq emms-cache-db
- (make-hash-table
- :test (if (fboundp 'define-hash-table-test)
- 'string-hash
- 'equal)))
- (setq emms-cache-dirty t)
- (emms-cache-save)))
-
-(provide 'emms-cache)
-;;; emms-cache.el ends here
diff --git a/lisp/emms-compat.el b/lisp/emms-compat.el
deleted file mode 100644
index 94f9b45..0000000
--- a/lisp/emms-compat.el
+++ /dev/null
@@ -1,185 +0,0 @@
-;;; emms-compat.el --- Compatibility routines for EMMS
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Michael Olson <mwolson@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; These are functions and macros that EMMS needs in order to be
-;; compatible with various Emacs and XEmacs versions.
-
-;;; Code:
-
-
-;;; Miscellaneous
-
-(defun emms-propertize (string &rest properties)
- (if (fboundp 'propertize)
- (apply #'propertize string properties)
- (set-text-properties 0 (length string) properties string)
- string))
-
-;; Emacs accepts three arguments to `make-obsolete', but the XEmacs
-;; version only takes two arguments
-(defun emms-make-obsolete (old-name new-name when)
- "Make the byte-compiler warn that OLD-NAME is obsolete.
-The warning will say that NEW-NAME should be used instead.
-WHEN should be a string indicating when the function was
-first made obsolete, either the file's revision number or an
-EMMS release version number."
- (if (featurep 'xemacs)
- (make-obsolete old-name new-name)
- (make-obsolete old-name new-name when)))
-
-
-;;; Time and timers
-
-(defun emms-cancel-timer (timer)
- "Cancel the given TIMER."
- (when timer
- (cond ((fboundp 'cancel-timer)
- (cancel-timer timer))
- ((fboundp 'delete-itimer)
- (delete-itimer timer)))))
-
-(defun emms-time-less-p (t1 t2)
- "Say whether time T1 is less than time T2."
- (or (< (car t1) (car t2))
- (and (= (car t1) (car t2))
- (< (nth 1 t1) (nth 1 t2)))))
-
-
-;;; Highline
-
-(defun emms-activate-highlighting-mode ()
- "Activate highline mode."
- (if (featurep 'xemacs)
- (progn
- (require 'highline)
- (highline-local-mode 1))
- (progn
- (require 'hl-line)
- (hl-line-mode 1))))
-
-(declare-function hl-line-highlight "" nil)
-
-;; called from emms-lyrics
-(defun emms-line-highlight ()
- "Highlight the current line. You must call
-emms-activate-highlighting-mode beforehand."
- (if (featurep 'xemacs)
- (highline-highlight-current-line)
- (hl-line-highlight)))
-
-
-;;; Movement and position
-
-(defun emms-move-beginning-of-line (arg)
- "Move point to beginning of current line as displayed.
-If there's an image in the line, this disregards newlines
-which are part of the text that the image rests on."
- (if (fboundp 'move-beginning-of-line)
- (move-beginning-of-line arg)
- (if (numberp arg)
- (forward-line (1- arg))
- (forward-line 0))))
-
-(defun emms-line-number-at-pos (&optional pos)
- "Return (narrowed) buffer line number at position POS.
-If POS is nil, use current buffer location."
- (if (fboundp 'line-number-at-pos)
- (line-number-at-pos pos)
- (let ((opoint (or pos (point))) start)
- (save-excursion
- (goto-char (point-min))
- (setq start (point))
- (goto-char opoint)
- (forward-line 0)
- (1+ (count-lines start (point)))))))
-
-
-;;; Regular expression matching
-
-(defun emms-replace-regexp-in-string (regexp replacement text
- &optional fixedcase literal)
- "Replace REGEXP with REPLACEMENT in TEXT.
-If fourth arg FIXEDCASE is non-nil, do not alter case of replacement text.
-If fifth arg LITERAL is non-nil, insert REPLACEMENT literally."
- (cond
- ((fboundp 'replace-regexp-in-string)
- (replace-regexp-in-string regexp replacement text fixedcase literal))
- ((and (featurep 'xemacs) (fboundp 'replace-in-string))
- (replace-in-string text regexp replacement literal))
- (t (let ((repl-len (length replacement))
- start)
- (save-match-data
- (while (setq start (string-match regexp text start))
- (setq start (+ start repl-len)
- text (replace-match replacement fixedcase literal text)))))
- text)))
-
-(defun emms-match-string-no-properties (num &optional string)
- (if (fboundp 'match-string-no-properties)
- (match-string-no-properties num string)
- (match-string num string)))
-
-
-;;; Common Lisp
-
-(defun emms-delete-if (predicate seq)
- "Remove all items satisfying PREDICATE in SEQ.
-This is a destructive function: it reuses the storage of SEQ
-whenever possible."
- ;; remove from car
- (while (when (funcall predicate (car seq))
- (setq seq (cdr seq))))
- ;; remove from cdr
- (let ((ptr seq)
- (next (cdr seq)))
- (while next
- (when (funcall predicate (car next))
- (setcdr ptr (if (consp next)
- (cdr next)
- nil)))
- (setq ptr (cdr ptr))
- (setq next (cdr ptr))))
- seq)
-
-(defun emms-find-if (predicate seq)
- "Find the first item satisfying PREDICATE in SEQ.
-Return the matching item, or nil if not found."
- (catch 'found
- (dolist (el seq)
- (when (funcall predicate el)
- (throw 'found el)))))
-
-(defun emms-remove-if-not (predicate seq)
- "Remove all items not satisfying PREDICATE in SEQ.
-This is a non-destructive function; it makes a copy of SEQ to
-avoid corrupting the original SEQ."
- (let (newseq)
- (dolist (el seq)
- (when (funcall predicate el)
- (setq newseq (cons el newseq))))
- (nreverse newseq)))
-
-(provide 'emms-compat)
-;;; emms-compat.el ends here
diff --git a/lisp/emms-cue.el b/lisp/emms-cue.el
deleted file mode 100644
index aefcafd..0000000
--- a/lisp/emms-cue.el
+++ /dev/null
@@ -1,120 +0,0 @@
-;;; emms-cue.el --- Recognize cue sheet file
-
-;; Copyright (C) 2009 Free Software Foundation, Inc.
-
-;; Author: William Xu <william.xwl@gmail.com>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; By parsing cue file, we will be able to play next/previous track from a
-;; single .ape or .flac file.
-
-;;; Code:
-
-(require 'emms-playing-time)
-(require 'emms-info)
-
-(defun emms-cue-next ()
- "Play next track from .cue file."
- (interactive)
- (let ((cue-track (emms-cue-next-track)))
- (if (cdr cue-track)
- (progn
- (emms-seek-to (cdr cue-track))
- (message "Will play: %s" (car cue-track)))
- (message "Nothing to seek or missing .cue file?"))))
-
-(defun emms-cue-previous ()
- "Play previous track from .cue file."
- (interactive)
- (let ((cue-track (emms-cue-previous-track)))
- (if (cdr cue-track)
- (progn
- (emms-seek-to (cdr cue-track))
- (message "Will play: %s" (car cue-track)))
- (message "Nothing to seek or missing .cue file?"))))
-
-(defun emms-cue-next-track (&optional previous-p)
- "Get title and offset of next track from .cue file.
-
-When PREVIOUS-P is t, get previous track info instead."
- (let* ((track (emms-playlist-current-selected-track))
- (name (emms-track-get track 'name))
- (cue (concat (file-name-sans-extension name)".cue")))
- (when (file-exists-p cue)
- (with-temp-buffer
- (emms-insert-file-contents cue)
- (save-excursion
- (if previous-p
- (goto-char (point-max))
- (goto-char (point-min)))
- (let ((offset nil)
- (title "")
- ;; We should search one more track far when getting previous
- ;; track.
- (one-more-track previous-p))
- (while (and (not offset)
- (funcall
- (if previous-p 'search-backward-regexp 'search-forward-regexp)
- "INDEX 01 \\([0-9][0-9]\\):\\([0-9][0-9]\\):\\([0-9][0-9]\\)" nil t 1))
- (let* ((min (string-to-number (match-string-no-properties 1)))
- (sec (string-to-number (match-string-no-properties 2)))
- (msec (string-to-number (match-string-no-properties 3)))
- (total-sec (+ (* min 60) sec (/ msec 100.0))))
- (when (funcall (if previous-p '> '<) emms-playing-time total-sec)
- (if (not one-more-track)
- (progn
- (setq offset total-sec)
- (when (search-backward-regexp "TITLE \"\\(.*\\)\"" nil t 1)
- (setq title (match-string-no-properties 1))))
- (setq one-more-track nil)))))
- (cons title offset)))))))
-
-(defun emms-cue-previous-track ()
- "See `emms-cue-next-track'."
- (emms-cue-next-track t))
-
-(defun emms-info-cueinfo (track)
- "Add track information to TRACK.
-This is a useful element for `emms-info-functions'."
- (when (and (eq 'file (emms-track-type track))
- (string-match "\\.\\(ape\\|flac\\)\\'" (emms-track-name track)))
- (let ((cue (concat (file-name-sans-extension (emms-track-name track))
- ".cue")))
- (when (file-exists-p cue)
- (with-temp-buffer
- (emms-insert-file-contents cue)
- (save-excursion
- (mapc (lambda (i)
- (goto-char (point-min))
- (when (let ((case-fold-search t))
- (search-forward-regexp
- (concat (car i) " \\(.*\\)") nil t 1))
- (emms-track-set track
- (cdr i)
- (replace-regexp-in-string
- "\\`\"\\|\"\\'" "" (match-string 1)))))
- '(("performer" . info-artist)
- ("title" . info-album)
- ("title" . info-title)
- ("rem date" . info-year)))))))))
-
-
-(provide 'emms-cue)
-;;; emms-cue.el ends here
diff --git a/lisp/emms-history.el b/lisp/emms-history.el
deleted file mode 100644
index 2f75571..0000000
--- a/lisp/emms-history.el
+++ /dev/null
@@ -1,134 +0,0 @@
-;;; emms-history.el -- save all playlists when exiting emacs
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-;;
-;; Author: Ye Wenbin <wenbinye@163.com>
-
-;; This file is part of EMMS.
-
-;; This program 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 3, or (at your option)
-;; any later version.
-;;
-;; This program 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 this program; if not, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-;;; Commentary:
-
-;; Saves all playlists when you close emacs. When you start it up again use
-;; M-x emms-history-load to restore all saved playlists.
-
-;; To use it put the following into your ~/.emacs:
-;;
-;; (require 'emms-history)
-;;
-;; If all playlists should be restored on startup add this, too:
-;;
-;; (emms-history-load)
-
-;;; Code:
-
-(require 'emms)
-
-(defgroup emms-history nil
- "Saving and restoring all playlists when closing/restarting
-Emacs."
- :prefix "emms-history-"
- :group 'emms)
-
-(defcustom emms-history-file (concat (file-name-as-directory emms-directory) "history")
- "The file to save playlists in."
- :type 'string
- :group 'emms-history)
-
-(defcustom emms-history-start-playing nil
- "If non-nil emms starts playing the current track after
-`emms-history-load' was invoked."
- :type 'boolean
- :group 'emms-history)
-
-(defcustom emms-history-file-coding-system 'utf-8
- "Coding system used for saving `emms-history-file'."
- :type 'coding-system
- :group 'emms-history)
-
-(defun emms-history-save ()
- "Save all playlists that are open in this Emacs session."
- (interactive)
- (when (stringp emms-history-file)
- (let ((oldbuf emms-playlist-buffer)
- ;; print with no limit
- print-length print-level
- emms-playlist-buffer playlists)
- (save-excursion
- (dolist (buf (emms-playlist-buffer-list))
- (set-buffer buf)
- (when (> (buffer-size) 0) ; make sure there is track in the buffer
- (setq emms-playlist-buffer buf
- playlists
- (cons
- (list (buffer-name)
- (or
- (and emms-playlist-selected-marker
- (marker-position emms-playlist-selected-marker))
- (point-min))
- (save-restriction
- (widen)
- (nreverse
- (emms-playlist-tracks-in-region (point-min)
- (point-max)))))
- playlists))))
- (with-temp-buffer
- (insert
- (concat ";;; emms history -*- mode: emacs-lisp; coding: "
- (symbol-name emms-history-file-coding-system)
- "; -*-\n"))
- (insert "(\n;; active playlist\n")
- (prin1 (buffer-name oldbuf) (current-buffer))
- (insert "\n;; playlists: ((BUFFER_NAME SELECT_POSITION TRACKS) ...)\n")
- (prin1 playlists (current-buffer))
- (insert "\n;; play method\n")
- (prin1 `((emms-repeat-track . ,emms-repeat-track)
- (emms-repeat-playlist . ,emms-repeat-playlist))
- (current-buffer))
- (insert "\n)")
- (write-file emms-history-file))))))
-
-(unless noninteractive
- (add-hook 'kill-emacs-hook 'emms-history-save))
-
-(defun emms-history-load ()
- "Restore all playlists in `emms-history-file'."
- (interactive)
- (when (and (stringp emms-history-file)
- (file-exists-p emms-history-file))
- (let (history buf)
- (with-temp-buffer
- (emms-insert-file-contents emms-history-file)
- (setq history (read (current-buffer)))
- (dolist (playlist (cadr history))
- (with-current-buffer (emms-playlist-new (car playlist))
- (setq emms-playlist-buffer (current-buffer))
- (if (string= (car playlist) (car history))
- (setq buf (current-buffer)))
- (mapc 'emms-playlist-insert-track
- (nth 2 playlist))
- (run-hooks 'emms-playlist-source-inserted-hook)
- (ignore-errors
- (emms-playlist-select (cadr playlist)))))
- (setq emms-playlist-buffer buf)
- (dolist (method (nth 2 history))
- (set (car method) (cdr method)))
- (ignore-errors
- (when emms-history-start-playing
- (emms-start)))))))
-
-(provide 'emms-history)
-;;; emms-history.el ends here
diff --git a/lisp/emms-i18n.el b/lisp/emms-i18n.el
deleted file mode 100644
index 66a5eeb..0000000
--- a/lisp/emms-i18n.el
+++ /dev/null
@@ -1,180 +0,0 @@
-;;; emms-i18n.el --- functions for handling coding systems
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Ye Wenbin <wenbinye@163.com>
-
-;; This file is part of EMMS.
-
-;; This program 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 3, or (at
-;; your option) any later version.
-
-;; This program 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 this program; if not, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-;;; Commentary:
-
-;; When reading from process, first check the car part of
-;; `emms-i18n-default-coding-system'; if non-nil, use this for
-;; decoding, and never detect coding system; if nil, first call
-;; `emms-i18n-coding-detect-functions' to get coding system, if
-;; success, decode the result, otherwise, use
-;; `emms-i18n-detect-coding-function', the Emacs detect coding
-;; function, if the coding detected is not in
-;; `emms-i18n-never-used-coding-system', decode it, otherwise use
-;; locale-coding-system.
-
-;; When writing/sending data to process, first check the cdr part of
-;; `emms-i18n-default-coding-system', if non-nil, use this to encode
-;; data, otherwise do nothing, that means use
-;; `default-process-coding-system' or `process-coding-system-alist' to
-;; encode data.
-
-;; Put this file into your load-path and the following into your
-;; ~/.emacs:
-
-;; (require 'emms-i18n)
-
-;;; Code:
-
-(provide 'emms-i18n)
-
-;; TODO: Use defcustom.
-(defvar emms-i18n-never-used-coding-system
- '(raw-text undecided)
- "If the `emms-i18n-coding-detect-functions' return a coding
-system in this list, use `emms-i18n-default-coding-system'
-instead.")
-
-;; TODO: Use defcustom.
-(defvar emms-i18n-coding-system-for-read
- 'utf-8
- "If coding detect fails, use this for decoding.")
-
-;; TODO: Use defcustom.
-(defvar emms-i18n-default-coding-system
- '(no-conversion . no-conversion)
- "If non-nil, use this for decoding and encoding.")
-
-;; TODO: Use defcustom.
-(defvar emms-i18n-coding-detect-functions
- nil
- "A list of functions to call to detect codings.")
-
-;; TODO: Use defcustom.
-(defvar emms-i18n-detect-max-size
- 10000
- "Maximum amount of bytes to detect the coding system. nil
-means to scan the whole buffer.")
-
-(defun emms-i18n-iconv (from to str)
- "Convert string STR from FROM coding to TO coding."
- (if (and from to)
- (decode-coding-string
- (encode-coding-string str to)
- from)
- str))
-
-(defun emms-i18n-iconv-region (beg end from to)
- (when (and from to)
- (save-restriction
- (narrow-to-region beg end)
- (encode-coding-region (point-min) (point-max) to)
- (decode-coding-region (point-min) (point-max) from))))
-
-(defun emms-i18n-iconv-buffer (from to &optional buf)
- "Convert buffer BUF from FROM coding to TO coding. BUF
-defaults to the current buffer."
- (save-excursion
- (and buf (set-buffer buf))
- (emms-i18n-iconv-region (point-min) (point-max) from to)))
-
-(defun emms-i18n-set-default-coding-system (read-coding write-coding)
- "Set `emms-i18n-default-coding-system'."
- (interactive "zSet coding system for read: \nzSet coding system for write: ")
- (setq emms-i18n-default-coding-system
- (cons
- (and (coding-system-p read-coding) read-coding)
- (and (coding-system-p write-coding) write-coding)))
- (message (concat
- (if (car emms-i18n-default-coding-system)
- (format "The coding system for reading is %S." (car emms-i18n-default-coding-system))
- "Good, you want me to detect the coding system!")
- (format " The coding system for writing is %S."
- (or (cdr emms-i18n-default-coding-system)
- (cdr default-process-coding-system))))))
-
-(defun emms-i18n-call-process-simple (&rest args)
- "Run a program and return the program result.
-If the car part of `emms-i18n-default-coding-system' is non-nil,
-the program result will be decoded using the car part of
-`emms-i18n-default-coding-system'. Otherwise, use
-`emms-i18n-coding-detect-functions' to detect the coding system
-of the result. If the `emms-i18n-coding-detect-functions'
-failed, use `emms-i18n-detect-coding-function' to detect coding
-system. If all the coding systems are nil or in
-`emms-i18n-never-used-coding-system', decode the result using
-`emms-i18n-coding-system-for-read'.
-
-ARGS are the same as in `call-process', except BUFFER should
-always have the value t. Otherwise the coding detection will not
-be performed."
- (let ((default-process-coding-system (copy-tree default-process-coding-system))
- (process-coding-system-alist nil) exit pos)
- (when (eq (nth 2 args) 't)
- (setcar default-process-coding-system (car emms-i18n-default-coding-system))
- (setq pos (point)))
- (setq exit (apply 'call-process args))
- (when (and (eq (nth 2 args) 't)
- (eq (car emms-i18n-default-coding-system) 'no-conversion))
- (save-restriction
- (narrow-to-region pos (point))
- (decode-coding-region (point-min) (point-max) (emms-i18n-detect-buffer-coding-system))))
- exit))
-
-;; TODO: Is this function useful?
-(defun emms-i18n-call-process (&rest args)
- "Run the program like `call-process'. If the cdr part of
-`emms-i18n-default-coding-system' is non-nil, the string in ARGS
-will be encoded by the cdr part of
-`emms-i18n-default-coding-system'; otherwise, all parameters are
-simply passed to `call-process'."
- (with-temp-buffer
- (if (cdr emms-i18n-default-coding-system)
- (let ((default-process-coding-system emms-i18n-default-coding-system)
- (process-coding-system-alist nil))
- (apply 'call-process args))
- (apply 'call-process args))))
-
-(defun emms-i18n-detect-coding-function (size)
- (detect-coding-region (point)
- (+ (if (null emms-i18n-detect-max-size)
- size
- (min size emms-i18n-detect-max-size))
- (point)) t))
-
-(defun emms-i18n-detect-buffer-coding-system (&optional buf)
- "Before calling this function, make sure the buffer is literal."
- (let ((size (- (point-max) (point-min)))
- (func (append emms-i18n-coding-detect-functions 'emms-i18n-detect-coding-function))
- coding)
- (save-excursion
- (and buf (set-buffer buf))
- (goto-char (point-min))
- (when (> size 0)
- (setq coding (run-hook-with-args-until-success 'func size))
- (if (member (coding-system-base coding) emms-i18n-never-used-coding-system)
- (setq coding (emms-i18n-detect-coding-function size))))
- (if (or (null coding) (member (coding-system-base coding) emms-i18n-never-used-coding-system))
- emms-i18n-coding-system-for-read
- coding))))
-
-;;; emms-i18n.el ends here
diff --git a/lisp/emms-info-libtag.el b/lisp/emms-info-libtag.el
deleted file mode 100644
index 7954ab2..0000000
--- a/lisp/emms-info-libtag.el
+++ /dev/null
@@ -1,116 +0,0 @@
-;;; emms-info-libtag.el --- Info-method for EMMS using libtag
-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-;; 2009 Free Software Foundation, Inc.
-
-;; Authors: Ulrik Jensen <terryp@daimi.au.dk>
-;; Jorgen Schäfer <forcer@forcix.cx>
-;; Keywords:
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; This code has been adapted from code found in mp3player.el, written
-;; by Jean-Philippe Theberge (jphiltheberge@videotron.ca), Mario
-;; Domgoergen (kanaldrache@gmx.de) and Jorgen Schäfer
-;; <forcer@forcix.cx>
-
-;; To activate this method for getting info, use something like:
-
-;; (require 'emms-info-libtag)
-;; (add-to-list 'emms-info-functions 'emms-info-libtag)
-
-;; Note that you should remove emms-info-mp3info and emms-info-ogginfo
-;; from the emms-info-functions list if you want to avoid
-;; conflicts. For example, to set libtag as your exclusive info
-;; provider:
-
-;; (setq emms-info-functions '(emms-info-libtag))
-
-;; You may have to compile the program from source.
-;; Make sure that you have libtag installed.
-;; In the EMMS source directory do
-;;
-;; make emms-print-metadata
-;;
-;; and copy src/emms-print-metadata to your PATH.
-
-;; If compilation fails and libtag is installed, you may have to
-;; change the line
-;;
-;; #include <tag_c.h>
-;;
-;; to the correction location, e.g.
-;;
-;; #include <taglib/tag_c.h>
-
-;;; Code:
-
-(require 'emms-info)
-
-(defgroup emms-info-libtag nil
- "Options for EMMS."
- :group 'emms-info)
-
-(defvar emms-info-libtag-coding-system 'utf-8)
-
-(defcustom emms-info-libtag-program-name "emms-print-metadata"
- "Name of emms-info-libtag program."
- :type '(string)
- :group 'emms-info-libtag)
-
-(defcustom emms-info-libtag-known-extensions
- (regexp-opt '("mp3" "mp4" "m4a" "ogg" "flac" "spx" "wma"))
- "Regexp of known extensions compatible with `emms-info-libtag-program-name'.
-
-Case is irrelevant."
- :type '(string)
- :group 'emms-info-libtag)
-
-(defun emms-info-libtag (track)
- (when (and (eq 'file (emms-track-type track))
- (let ((case-fold-search t))
- (string-match
- emms-info-libtag-known-extensions
- (emms-track-name track))))
- (with-temp-buffer
- (when (zerop
- (let ((coding-system-for-read 'utf-8))
- (call-process emms-info-libtag-program-name
- nil '(t nil) nil
- (emms-track-name track))))
- (goto-char (point-min))
- ;; Crush the trailing whitespace
- (while (re-search-forward "[[:space:]]+$" nil t)
- (replace-match "" nil nil))
- (goto-char (point-min))
- (while (looking-at "^\\([^=\n]+\\)=\\(.*\\)$")
- (let ((name (intern-soft (match-string 1)))
- (value (match-string 2)))
- (when (> (length value)
- 0)
- (emms-track-set track
- name
- (if (eq name 'info-playing-time)
- (string-to-number value)
- value))))
- (forward-line 1))))))
-
-(provide 'emms-info-libtag)
-;;; emms-info-libtag.el ends here
diff --git a/lisp/emms-info-metaflac.el b/lisp/emms-info-metaflac.el
deleted file mode 100644
index 5a9f517..0000000
--- a/lisp/emms-info-metaflac.el
+++ /dev/null
@@ -1,107 +0,0 @@
-;;; emms-info-metaflac.el --- Info-method for EMMS using metaflac
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Matthew Kennedy <mkennedy@gentoo.org>
-;; 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 code has been adapted from code found in emms-info-mp3info.el
-;; written by Ulrik Jensen <terryp@daimi.au.dk> which contains the
-;; following attribution:
-
-;; This code has been adapted from code found in mp3player.el, written
-;; by Jean-Philippe Theberge (jphiltheberge@videotron.ca), Mario
-;; Domgoergen (kanaldrache@gmx.de) and Jorgen Schäfer
-;; <forcer@forcix.cx>
-
-;; To activate this method for getting info, use something like:
-
-;; (require 'emms-info-metaflac)
-;; (add-to-list 'emms-info-methods-list 'emms-info-metaflac)
-
-;;; Code:
-
-(require 'emms-info)
-
-(defvar emms-info-metaflac-version "0.1 $Revision: 1.10 $"
- "EMMS info metaflac version string.")
-
-;; $Id: emms-info-mp3info.el,v 1.10 2005/08/12 18:01:16 xwl Exp $
-
-(defgroup emms-info-metaflac nil
- "An EMMS-info method for getting/setting FLAC tags, using the
-external metaflac program"
- :group 'emms-info)
-
-(defcustom emms-info-metaflac-program-name "metaflac"
- "*The name/path of the metaflac program."
- :type 'string
- :group 'emms-info-metaflac)
-
-(defcustom emms-info-metaflac-options
- '("--no-utf8-convert"
- "--show-tag=TITLE"
- "--show-tag=ARTIST"
- "--show-tag=ALBUM"
- "--show-tag=NOTE"
- "--show-tag=YEAR"
- "--show-tag=TRACKNUMBER"
- "--show-tag=DISCNUMBER"
- "--show-tag=GENRE")
- "The argument to pass to `emms-info-metaflac-program-name'."
- :type '(repeat string)
- :group 'emms-info-metaflac)
-
-(defun emms-info-metaflac (track)
- "Get the FLAC tag of file TRACK, using `emms-info-metaflac-program'
-and return an emms-info structure representing it."
- (when (and (eq 'file (emms-track-type track))
- (string-match "\\.\\(flac\\|FLAC\\)\\'" (emms-track-name track)))
- (with-temp-buffer
- (when (zerop
- (apply 'call-process
- emms-info-metaflac-program-name
- nil t nil
- "--show-total-samples"
- "--show-sample-rate"
- (append emms-info-metaflac-options
- (list (emms-track-name track)))))
- (goto-char (point-min))
- (emms-track-set track 'info-playing-time
- (/ (string-to-number (buffer-substring (point) (line-end-position)))
- (progn
- (forward-line 1)
- (string-to-number (buffer-substring (point) (line-end-position))))))
- (forward-line 1)
- (while (looking-at "^\\([^=\n]+\\)=\\(.*\\)$")
- (let ((name (intern (concat "info-" (downcase (match-string 1)))))
- (value (match-string 2)))
- (when (> (length value)
- 0)
- (emms-track-set track
- name
- (if (eq name 'info-playing-time)
- (string-to-number value)
- value))))
- (forward-line 1))))))
-
-(provide 'emms-info-metaflac)
-
-;;; emms-info-metaflac.el ends here
diff --git a/lisp/emms-info-mp3info.el b/lisp/emms-info-mp3info.el
deleted file mode 100644
index b01217e..0000000
--- a/lisp/emms-info-mp3info.el
+++ /dev/null
@@ -1,104 +0,0 @@
-;;; emms-info-mp3info.el --- Info-method for EMMS using mp3info
-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-;; 2009 Free Software Foundation, Inc.
-
-;; Authors: Ulrik Jensen <terryp@daimi.au.dk>
-;; Jorgen Schäfer <forcer@forcix.cx>
-;; Keywords:
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; 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 code has been adapted from code found in mp3player.el, written
-;; by Jean-Philippe Theberge (jphiltheberge@videotron.ca), Mario
-;; Domgoergen (kanaldrache@gmx.de) and Jorgen Schäfer
-;; <forcer@forcix.cx>
-
-;; To activate this method for getting info, use something like:
-
-;; (require 'emms-info-mp3info)
-;; (add-to-list 'emms-info-functions 'emms-info-mp3info)
-
-;;; Code:
-
-(require 'emms-info)
-
-(defvar emms-info-mp3info-version "0.2 $Revision: 1.10 $"
- "EMMS info mp3info version string.")
-;; $Id: emms-info-mp3info.el,v 1.10 2005/08/12 18:01:16 xwl Exp $
-
-(defgroup emms-info-mp3info nil
- "An EMMS-info method for getting/setting ID3v1 tags, using the
-external mp3info program"
- :group 'emms-info)
-
-(defcustom emms-info-mp3info-coding-system 'utf-8
- "*Coding system used in the output of mp3info."
- :type 'coding-system
- :group 'emms-info-mp3info)
-
-(defcustom emms-info-mp3info-program-name "mp3info"
- "*The name/path of the mp3info tag program."
- :type 'string
- :group 'emms-info-mp3info)
-
-(defcustom emms-info-mp3find-arguments
- `("-p" ,(concat "info-artist=%a\\n"
- "info-title=%t\\n"
- "info-album=%l\\n"
- "info-tracknumber=%n\\n"
- "info-year=%y\\n"
- "info-genre=%g\\n"
- "info-note=%c\\n"
- "info-playing-time=%S\\n"))
- "The argument to pass to `emms-info-mp3info-program-name'.
-This should be a list of info-flag=value lines."
- :type '(repeat string)
- :group 'emms-info-mp3info)
-
-(defun emms-info-mp3info (track)
- "Add track information to TRACK.
-This is a useful element for `emms-info-functions'."
- (when (and (eq 'file (emms-track-type track))
- (string-match "\\.[Mm][Pp]3\\'" (emms-track-name track)))
- (with-temp-buffer
- (when (zerop
- (apply (if (fboundp 'emms-i18n-call-process-simple)
- 'emms-i18n-call-process-simple
- 'call-process)
- emms-info-mp3info-program-name
- nil t nil
- (append emms-info-mp3find-arguments
- (list (emms-track-name track)))))
- (goto-char (point-min))
- (while (looking-at "^\\([^=\n]+\\)=\\(.*\\)$")
- (let ((name (intern (match-string 1)))
- (value (match-string 2)))
- (when (> (length value)
- 0)
- (emms-track-set track
- name
- (if (eq name 'info-playing-time)
- (string-to-number value)
- value))))
- (forward-line 1))))))
-
-(provide 'emms-info-mp3info)
-;;; emms-info-mp3info.el ends here
diff --git a/lisp/emms-info-ogginfo.el b/lisp/emms-info-ogginfo.el
deleted file mode 100644
index 2d8412f..0000000
--- a/lisp/emms-info-ogginfo.el
+++ /dev/null
@@ -1,85 +0,0 @@
-;;; emms-info-ogginfo.el --- Emms information from Ogg Vorbis files.
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Jorgen Schaefer <forcer@forcix.cx>
-;; Yoni Rabkin <yrk@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3 of the License, or
-;; (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-;;
-
-;;; Code:
-
-(require 'emms-info)
-
-(defgroup emms-info-ogginfo nil
- "An EMMS-info method for getting, using the external ogginfo
-program"
- :group 'emms-info)
-
-(defcustom emms-info-ogginfo-coding-system 'utf-8
- "*Coding system used in the output of ogginfo."
- :type 'coding-system
- :group 'emms-info-ogginfo)
-
-(defcustom emms-info-ogginfo-program-name "ogginfo"
- "*The name/path of the ogginfo tag program."
- :type 'string
- :group 'emms-info-ogginfo)
-
-(defun emms-info-ogginfo (track)
- "Add track information to TRACK.
-This is a useful element for `emms-info-functions'."
- (when (and (eq 'file (emms-track-type track))
- (string-match "\\.[Oo][Gg][Gg]\\'" (emms-track-name track)))
-
- (with-temp-buffer
- (call-process emms-info-ogginfo-program-name
- nil t nil (emms-track-name track))
-
- ;; play time, emms-info-ogg.el [U. Jensen]
- (goto-char (point-min))
- (when (re-search-forward
- "Playback length: \\([0-9]*\\)m:\\([0-9]*\\)" nil t)
- (let* ((minutes (string-to-number (match-string 1)))
- (seconds (string-to-number (match-string 2)))
- (ptime-total (+ (* minutes 60) seconds))
- (ptime-min minutes)
- (ptime-sec seconds))
- (emms-track-set track 'info-playing-time ptime-total)
- (emms-track-set track 'info-playing-time-min ptime-min)
- (emms-track-set track 'info-playing-time-sec ptime-sec)
- (emms-track-set track 'info-file (emms-track-name track))))
-
- ;; all the rest of the info available
- (goto-char (point-min))
- (when (re-search-forward "^.*\\.\\.\\.$" (point-max) t)
- (while (zerop (forward-line 1))
- (when (looking-at "^\t\\(.*?\\)=\\(.*\\)$") ; recognize the first '='
- (let ((a (match-string 1))
- (b (match-string 2)))
- (when (and (< 0 (length a))
- (< 0 (length b)))
- (emms-track-set track
- (intern (downcase (concat "info-" (match-string 1))))
- (match-string 2))))))))))
-
-(provide 'emms-info-ogginfo)
-
-;;; emms-info-ogginfo.el ends here
diff --git a/lisp/emms-info-opusinfo.el b/lisp/emms-info-opusinfo.el
deleted file mode 100644
index d636f7b..0000000
--- a/lisp/emms-info-opusinfo.el
+++ /dev/null
@@ -1,85 +0,0 @@
-;;; emms-info-opusinfo.el --- Emms information from Ogg Opus files.
-
-;; Copyright (C) 2018 Free Software Foundation, Inc.
-
-;; Author: Pierre Neidhardt <mail@ambrevar.xyz>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3 of the License, or
-;; (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-;;
-
-;;; Code:
-
-(require 'emms-info)
-
-(defgroup emms-info-opusinfo nil
- "An EMMS-info method for getting, using the external opusinfo
-program"
- :group 'emms-info)
-
-(defcustom emms-info-opusinfo-coding-system 'utf-8
- "*Coding system used in the output of opusinfo."
- :type 'coding-system
- :group 'emms-info-opusinfo)
-
-(defcustom emms-info-opusinfo-program-name "opusinfo"
- "*The name/path of the opusinfo tag program."
- :type 'string
- :group 'emms-info-opusinfo)
-
-(defun emms-info-opusinfo (track)
- "Add track information to TRACK.
-This is a useful element for `emms-info-functions'."
- (when (and (eq 'file (emms-track-type track))
- (or (string-match "\\.[Oo][Gg][Gg]\\'" (emms-track-name track))
- (string-match "\\.[Oo][Pp][Uu][Ss]\\'" (emms-track-name track))))
-
- (with-temp-buffer
- (call-process emms-info-opusinfo-program-name
- nil t nil (emms-track-name track))
-
- ;; play time
- (goto-char (point-min))
- (when (re-search-forward
- "Playback length: \\([0-9]*\\)m:\\([0-9]*\\)" nil t)
- (let* ((minutes (string-to-number (match-string 1)))
- (seconds (string-to-number (match-string 2)))
- (ptime-total (+ (* minutes 60) seconds))
- (ptime-min minutes)
- (ptime-sec seconds))
- (emms-track-set track 'info-playing-time ptime-total)
- (emms-track-set track 'info-playing-time-min ptime-min)
- (emms-track-set track 'info-playing-time-sec ptime-sec)
- (emms-track-set track 'info-file (emms-track-name track))))
-
- ;; all the rest of the info available
- (goto-char (point-min))
- (when (re-search-forward "^.*\\.\\.\\.$" (point-max) t)
- (while (zerop (forward-line 1))
- (when (looking-at "^\t\\(.*?\\)=\\(.*\\)$") ; recognize the first '='
- (let ((a (match-string 1))
- (b (match-string 2)))
- (when (and (< 0 (length a))
- (< 0 (length b)))
- (emms-track-set track
- (intern (downcase (concat "info-" (match-string 1))))
- (match-string 2))))))))))
-
-(provide 'emms-info-opusinfo)
-
-;;; emms-info-opusinfo.el ends here
diff --git a/lisp/emms-info-tinytag.el b/lisp/emms-info-tinytag.el
deleted file mode 100644
index fe21653..0000000
--- a/lisp/emms-info-tinytag.el
+++ /dev/null
@@ -1,119 +0,0 @@
-;;; emms-info-tinytag.el --- Info-method for EMMS using tinytag -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2020 Free Software Foundation, Inc.
-
-;; Author: Fran Burstall <fran.burstall@gmail.com>
-;; Keywords: multimedia
-
-;; EMMS 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 3 of the License, or
-;; (at your option) any later version.
-
-;; EMMS 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 EMMS; see the file COPYING.. If not, see
-;; <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This code has been adapted from code found in emms-info-libtag.el,
-;; written by Ulrik Jensen <terryp@daimi.au.dk> and Jorgen Schäfer
-;; <forcer@forcix.cx>.
-
-;; To activate this method for getting info, use:
-
-;; (require 'emms-info-tinytag)
-;; (add-to-list 'emms-info-functions 'emms-info-tinytag)
-
-;; Note that you should remove emms-info-mp3info and emms-info-ogginfo
-;; from the emms-info-functions list if you want to avoid
-;; conflicts. For example, to set tinytag as your exclusive info
-;; provider:
-
-;; (setq emms-info-functions '(emms-info-tinytag))
-
-;; To use this provider, you need to install the tinytag python module
-;; with something like:
-
-;; pip install tinytag
-
-;;; Code:
-
-(require 'emms-info)
-(require 'json) ;see below
-
-(defgroup emms-info-tinytag nil
- "Options for EMMS."
- :group 'emms-info)
-
-(defvar emms-info-tinytag-coding-system 'utf-8) ;is this used anywhere?
-
-(defcustom emms-info-tinytag-python-name "python"
- "Name of python we use."
- :type '(string)
- :group 'emms-info-tinytag)
-
-(defcustom emms-info-tinytag-known-extensions
- (regexp-opt '("mp3" "mp4" "m4a" "m4b" "ogg" "opus" "flac" "wma" "wav"))
- "Regexp of known extensions that `emms-info-tinytag' can handle.
-
-Case is irrelevant."
- :type '(string)
- :group 'emms-info-tinytag)
-
-(defvar emms-info-tinytag--info-fields
- '((info-album . album)
- (info-albumartist . albumartist)
- (info-artist . artist)
- (info-composer . composer)
- (info-year . year)
- (info-discnumber . disc)
- (info-genre . genre)
- (info-note . comment)
- (info-playing-time . duration)
- (info-title . title)
- (info-tracknumber . track))
- "An alist mapping info-* fields to tinytag fields.")
-
-(defun emms-info-tinytag (track)
- "Set tags for TRACK using tinytag."
- (when (and (eq 'file (emms-track-type track))
- (let ((case-fold-search t))
- (string-match
- emms-info-tinytag-known-extensions
- (emms-track-name track))))
- (with-temp-buffer
- (when (zerop
- (let ((coding-system-for-read 'utf-8))
- (call-process emms-info-tinytag-python-name
- nil '(t nil) nil
- "-m" "tinytag" (emms-track-name track))))
- (goto-char (point-min))
- ;; tinytag can output json or [ct]sv. Sadly, in the latter
- ;; case, null values are unhelpfully represented by the string
- ;; "None" so we parse the json.
- (let ((track-info (json-read)))
- (dolist (field emms-info-tinytag--info-fields)
- (let ((name (car field))
- (value (alist-get (cdr field) track-info)))
- (when (and value (or (numberp value) (> (length value)
- 0)))
- (emms-track-set track
- name
- (cond ((eq name 'info-playing-time)
- (round value))
- ;; for m4a, disc or track is an int: issue raised upstream
- ((and (or (eq name 'info-discnumber)
- (eq name 'info-tracknumber))
- (numberp value))
- (number-to-string value))
- (t value)))))))))))
-
-(provide 'emms-info-tinytag)
-
-;;; emms-info-tinytag.el ends here
diff --git a/lisp/emms-info.el b/lisp/emms-info.el
deleted file mode 100644
index 5e8fae2..0000000
--- a/lisp/emms-info.el
+++ /dev/null
@@ -1,140 +0,0 @@
-;;; emms-info.el --- Retrieving track information
-
-;; Copyright (C) 2005-2020 Free Software Foundation, Inc.
-
-;; Author: Jorgen Schaefer <forcer@forcix.cx>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software
-;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-;; 02110-1301, USA.
-
-;;; Commentary:
-
-;; This EMMS module provides a way to add information for a track.
-;; This can use an ID3 or OGG comment like syntax.
-
-;; The code will add info symbols to the track. The following symbols
-;; are defined:
-
-;; info-artist - string naming the artist
-;; info-composer - string naming the composer
-;; info-performer - string naming the performer
-;; info-title - string naming the title of the song
-;; info-album - string naming the album
-;; info-tracknumber - string(?) naming the track number
-;; info-discnumber - string naming the disc number
-;; info-year - string naming the year
-;; info-note - string of free-form entry
-;; info-genre - string naming the genre
-;; info-playing-time - number giving the seconds of playtime
-
-;;; Code:
-
-(require 'emms)
-(require 'later-do)
-
-(defgroup emms-info nil
- "*Track information. ID3, OGG, etc."
- :group 'emms)
-
-(defcustom emms-info-auto-update t
- "*Non-nil when EMMS should update track information if the file changes.
-This will cause hard drive activity on track loading. If this is
-too annoying for you, set this variable to nil."
- :type 'boolean
- :group 'emms-info)
-
-(defcustom emms-info-asynchronously t
- "*Non-nil when track information should be loaded asynchronously.
-This requires `later-do', which should come with EMMS."
- :type 'boolean
- :group 'emms-info)
-
-(defcustom emms-info-report-each-num-tracks 200
- "*Non-zero will report progress information every number of tracks.
-The default is to display a message every 200 tracks.
-This variable is only used when adding tracks asynchronously."
- :type 'integer
- :group 'emms-info)
-
-(defcustom emms-info-functions nil
- "*Functions which add information to tracks.
-Each is called with a track as argument."
- :type 'hook
- :group 'emms-info)
-
-(defvar emms-info-asynchronous-tracks 0
- "Number of tracks we're waiting for to be done.")
-
-(defun emms-info-initialize-track (track)
- "Initialize TRACK with emms-info information.
-This is a suitable value for `emms-track-initialize-functions'."
- (if (not emms-info-asynchronously)
- (emms-info-really-initialize-track track)
- (setq emms-info-asynchronous-tracks (1+ emms-info-asynchronous-tracks))
- (later-do 'emms-info-really-initialize-track track)))
-
-(defun emms-info-really-initialize-track (track)
- "Really initialize TRACK.
-Return t when the track got changed."
- (let ((file-mtime (when emms-info-auto-update
- (emms-info-track-file-mtime track)))
- (info-mtime (emms-track-get track 'info-mtime))
- (name (emms-track-get track 'name)))
-
- ;; if the file's been modified or is new
- (when (or (not file-mtime)
- (not info-mtime)
- (emms-time-less-p info-mtime file-mtime))
- (run-hook-with-args 'emms-info-functions track)
- ;; not set by info functions
- (when file-mtime
- (emms-track-set track 'info-mtime file-mtime))
- (emms-track-updated track))
-
- (when emms-info-asynchronously
- (setq emms-info-asynchronous-tracks (1- emms-info-asynchronous-tracks))
- (if (zerop emms-info-asynchronous-tracks)
- (message "EMMS: All track information loaded.")
- (unless (zerop emms-info-report-each-num-tracks)
- (if (zerop
- (mod emms-info-asynchronous-tracks
- emms-info-report-each-num-tracks))
- (message "EMMS: %d tracks to go.."
- emms-info-asynchronous-tracks)))))))
-
-(defun emms-info-track-file-mtime (track)
- "Return the mtime of the file of TRACK, if any.
-Return nil otherwise."
- (if (eq (emms-track-type track)
- 'file)
- (nth 5 (file-attributes (emms-track-name track)))
- nil))
-
-(defun emms-info-track-description (track)
- "Return a description of TRACK."
- (let ((artist (emms-track-get track 'info-artist))
- (title (emms-track-get track 'info-title)))
- (cond
- ((and artist title)
- (concat artist " - " title))
- (title
- title)
- (t
- (emms-track-simple-description track)))))
-
-(provide 'emms-info)
-;;; emms-info.el ends here
diff --git a/lisp/emms-last-played.el b/lisp/emms-last-played.el
deleted file mode 100644
index 529869a..0000000
--- a/lisp/emms-last-played.el
+++ /dev/null
@@ -1,123 +0,0 @@
-;;; emms-last-played.el --- Support for last-played-time of a track
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Lucas Bonnet <lucas@rincevent.net>
-;; Keywords: emms, mp3, mpeg, multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; Records when the track was last played.
-;; Big portions of the time handling fuctions are copied from
-;; gnus-util.el, and slightly adapted.
-
-;;; Code:
-
-(require 'emms)
-
-(defvar emms-last-played-keep-count t
- "Specifies if EMMS should record the number of times you play a track.
-Set it to t if you want such a feature, and to nil if you don't.")
-
-(defvar emms-last-played-format-alist
- '(((emms-last-played-seconds-today) . "%k:%M")
- (604800 . "%a %k:%M") ;;that's one week
- ((emms-last-played-seconds-month) . "%a %d")
- ((emms-last-played-seconds-year) . "%b %d")
- (t . "%b %d '%y")) ;;this one is used when no
- ;;other does match
- "Specifies date format depending on when a track was last played.
-This is an alist of items (AGE . FORMAT). AGE can be a number (of
-seconds) or a Lisp expression evaluating to a number. When the age of
-the track is less than this number, then use `format-time-string'
-with the corresponding FORMAT for displaying the date of the track.
-If AGE is not a number or a Lisp expression evaluating to a
-non-number, then the corresponding FORMAT is used as a default value.
-
-Note that the list is processed from the beginning, so it should be
-sorted by ascending AGE. Also note that items following the first
-non-number AGE will be ignored.
-
-You can use the functions `emms-last-played-seconds-today',
-`emms-last-played-seconds-month' and
-`emms-last-played-seconds-year' in the AGE spec. They return the
-number of seconds passed since the start of today, of this month,
-of this year, respectively.")
-
-
-(defun emms-last-played-update-track (track)
- "Updates the last-played time of TRACK."
- (emms-track-set track 'last-played (current-time)))
-
-(defun emms-last-played-increment-count (track)
- "Increments the play-count property of TRACK.
-If non-existent, it is set to 1."
- (let ((play-count (emms-track-get track 'play-count)))
- (if play-count
- (emms-track-set track 'play-count (1+ play-count))
- (emms-track-set track 'play-count 1))))
-
-(defun emms-last-played-update-current ()
- "Updates the current track."
- (emms-last-played-update-track (emms-playlist-current-selected-track))
- (if emms-last-played-keep-count
- (emms-last-played-increment-count (emms-playlist-current-selected-track))))
-
-(defun emms-last-played-seconds-today ()
- "Return the number of seconds passed today."
- (let ((now (decode-time (current-time))))
- (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600))))
-
-(defun emms-last-played-seconds-month ()
- "Return the number of seconds passed this month."
- (let ((now (decode-time (current-time))))
- (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
- (* (- (car (nthcdr 3 now)) 1) 3600 24))))
-
-(defun emms-last-played-seconds-year ()
- "Return the number of seconds passed this year."
- (let ((now (decode-time (current-time)))
- (days (format-time-string "%j" (current-time))))
- (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
- (* (- (string-to-number days) 1) 3600 24))))
-
-(defun emms-last-played-format-date (messy-date)
- "Format the messy-date according to emms-last-played-format-alist.
-Returns \" ? \" if there's bad input or if an other error occurs.
-Input should look like this: \"Sun, 14 Oct 2001 13:34:39 +0200\"."
- (condition-case ()
- (let* ((messy-date (float-time messy-date))
- (now (float-time (current-time)))
- ;;If we don't find something suitable we'll use this one
- (my-format "%b %d '%y"))
- (let* ((difference (- now messy-date))
- (templist emms-last-played-format-alist)
- (top (eval (caar templist))))
- (while (if (numberp top) (< top difference) (not top))
- (progn
- (setq templist (cdr templist))
- (setq top (eval (caar templist)))))
- (if (stringp (cdr (car templist)))
- (setq my-format (cdr (car templist)))))
- (format-time-string (eval my-format) (seconds-to-time messy-date)))
- (error "Never.")))
-
-(provide 'emms-last-played)
-;;; emms-last-played.el ends here
diff --git a/lisp/emms-librefm-scrobbler.el b/lisp/emms-librefm-scrobbler.el
deleted file mode 100644
index a49a458..0000000
--- a/lisp/emms-librefm-scrobbler.el
+++ /dev/null
@@ -1,327 +0,0 @@
-;;; emms-librefm-scrobbler.el --- Libre.FM Scrobbing API
-
-;; Copyright (C) 2014 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-
-;; Keywords: emms, libre.fm, GNU FM
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the Free
-;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-;; MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; To use libre.fm you need to add username and password to
-;; ~/.authinfo.gpg or an equivalent file understood by auth-source.
-;; To enable scrobbling call (emms-librefm-scrobbler-enable).
-
-;;; Code:
-
-(require 'emms-playing-time)
-(require 'auth-source)
-
-
-(defvar emms-librefm-scrobbler-handshake-url
- "turtle.libre.fm"
- "Endpoint for client handshake.")
-
-(defvar emms-librefm-scrobbler-method
- "https"
- "Transfer method.")
-
-(defvar emms-librefm-scrobbler-username nil
- "Libre.fm username.
-
-Note that the preferred way of authenticating is using authinfo
-and only setting `emms-librefm-scrobbler-handshake-url'. See the
-manual for details.")
-
-(defvar emms-librefm-scrobbler-password nil
- "Libre.fm user password.
-
-Note that the preferred way of authenticating is using authinfo.
-See also `emms-librefm-scrobbler-username'.")
-
-(defvar emms-librefm-scrobbler-debug
- ""
- "Debugging variable to store communication.")
-
-(defvar emms-librefm-scrobbler-session-id
- nil
- "Session ID for Libre.fm.")
-
-(defvar emms-librefm-scrobbler-now-playing-url
- ""
- "URL for getting the track playing.")
-
-(defvar emms-librefm-scrobbler-submission-url
- ""
- "URL for submissions.")
-
-(defvar emms-librefm-scrobbler-track-play-start-timestamp
- nil
- "Time when a track started playing.")
-
-(defvar emms-librefm-scrobbler-display-submissions
- t
- "Whether to display a user message on every submission.")
-
-
-;;; ------------------------------------------------------------------
-;;; authenticate
-;;; ------------------------------------------------------------------
-(defun emms-librefm-scrobbler--get-auth-detail (token)
- "Return TOKEN from auth-source.
-TOKEN is :user of :secret."
- ;; TODO: Maybe we should enable :create t here. But it could be
- ;; kind of annoying as it makes a pop-up when no name is present.
- (plist-get
- (car (auth-source-search :host (list emms-librefm-scrobbler-handshake-url "libre.fm")
- :user (unless (equal emms-librefm-scrobbler-username "")
- emms-librefm-scrobbler-username)
- :max 1 :require '(:user :secret)))
- token))
-
-(defun emms-librefm-scrobbler--username ()
- "Return username for libre.fm."
- (or (emms-librefm-scrobbler--get-auth-detail :user)
- emms-librefm-scrobbler-username))
-
-(defun emms-librefm-scrobbler--password ()
- "Return password for libre.fm."
- (let ((token (emms-librefm-scrobbler--get-auth-detail :secret)))
- (cond ((functionp token) (funcall token))
- ((characterp token) token)
- (t emms-librefm-scrobbler-password))))
-
-;;; ------------------------------------------------------------------
-;;; handshake
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-scrobbler-handshake-string (url username password)
- "Return the client handshake string."
- (when (= 0 (length url))
- (error "bad url"))
- (when (= 0 (length username))
- (error "bad username"))
- (when (= 0 (length password))
- (error "bad password"))
- (let ((timestamp (format-time-string "%s")))
- (concat emms-librefm-scrobbler-method
- "://"
- url "/?"
- "hs=true" "&"
- "p=1.2" "&"
- "c=emm" "&"
- "v=1.0" "&"
- "u=" (url-encode-url username) "&"
- "t=" timestamp "&"
- "a=" (md5 (concat (md5 password) timestamp)))))
-
-(defun emms-librefm-scrobbler-handshake-call (url username password)
- "Perform client handshake and return a response in a buffer."
- (let ((url-request-method "POST"))
- (let ((response
- (url-retrieve-synchronously
- (emms-librefm-scrobbler-handshake-string
- url username password))))
- (setq emms-librefm-scrobbler-debug
- (with-current-buffer response
- (buffer-substring-no-properties (point-min)
- (point-max))))
- response)))
-
-(defun emms-librefm-scrobbler-handle-handshake-response (resbuf)
- "Handle the client handshake server response."
- (when (not (bufferp resbuf))
- (error "response not a buffer"))
- (with-current-buffer resbuf
- (goto-char (point-min))
- (when (not (re-search-forward "^.*200 OK$" (point-at-eol) t))
- (error "bad HTTP server response"))
- ;; go to the start of the FM response
- (when (not (re-search-forward "\n\n" (point-max) t))
- (error "bad FM server response"))
- (let ((status (buffer-substring (point-at-bol)
- (point-at-eol))))
- (when (not (string= status "OK"))
- (error "FM server returned: %s" status))
- (let (session-id
- now-playing-url
- submission-url)
- (forward-line 1)
- (setq session-id (buffer-substring (point-at-bol)
- (point-at-eol)))
- (forward-line 1)
- (setq now-playing-url (buffer-substring (point-at-bol)
- (point-at-eol)))
- (forward-line 1)
- (setq submission-url (buffer-substring (point-at-bol)
- (point-at-eol)))
- (when (or (= 0 (length session-id))
- (= 0 (length now-playing-url))
- (= 0 (length submission-url)))
- (error "couldn't parse FM server response"))
- (setq emms-librefm-scrobbler-session-id session-id
- emms-librefm-scrobbler-now-playing-url now-playing-url
- emms-librefm-scrobbler-submission-url submission-url)
- (message "handshake successful")))))
-
-(defun emms-librefm-scrobbler-handshake ()
- "Perform client handshake call and handle response."
- (emms-librefm-scrobbler-handle-handshake-response
- (emms-librefm-scrobbler-handshake-call
- emms-librefm-scrobbler-handshake-url
- (emms-librefm-scrobbler--username)
- (emms-librefm-scrobbler--password))))
-
-
-;;; ------------------------------------------------------------------
-;;; submission
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-scrobbler-make-query (track rating)
- "Format the url parameters for scrobbling."
- (setq rating
- (cond ((equal 'love rating) "L")
- ((equal 'ban rating) "B")
- ((equal 'skip rating) "S")
- (t "")))
- (let ((artist (emms-track-get track 'info-artist))
- (title (emms-track-get track 'info-title))
- (album (or (emms-track-get track 'info-album) ""))
- (track-number (emms-track-get track 'info-tracknumber))
- (musicbrainz-id "")
- (track-length (number-to-string
- (or (emms-track-get track
- 'info-playing-time)
- 0))))
- (if (and artist title)
- (concat
- "s=" emms-librefm-scrobbler-session-id
- "&a[0]=" (url-encode-url artist)
- "&t[0]=" (url-encode-url title)
- "&i[0]=" (url-encode-url
- (or emms-librefm-scrobbler-track-play-start-timestamp
- (format-time-string "%s")))
- "&o[0]=" "P"
- "&r[0]=" (url-encode-url rating)
- "&l[0]=" track-length
- "&b[0]=" (url-encode-url album)
- "&n[0]=" track-number
- "&m[0]=" musicbrainz-id)
- (error "Track title and artist must be known."))))
-
-
-;;; ------------------------------------------------------------------
-;;; asynchronous submission
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-scrobbler-get-response-status ()
- "Check the HTTP header and return the body."
- (let ((ok200 "HTTP/1.1 200 OK"))
- (if (< (point-max) 1)
- (error "No response from submission server"))
- (if (not (string= ok200 (buffer-substring-no-properties (point-min) 16)))
- (error "submission server not responding correctly"))
- (goto-char (point-min))
- (re-search-forward "\n\n")
- (buffer-substring-no-properties
- (point-at-bol) (point-at-eol))))
-
-(defun emms-librefm-scrobbler-make-async-submission-call (track rating)
- "Make asynchronous submission call."
- (let ((flarb (emms-librefm-scrobbler-make-query track rating)))
- (let* ((url-request-method "POST")
- (url-request-data flarb)
- (url-request-extra-headers
- `(("Content-type" . "application/x-www-form-urlencoded"))))
- (url-retrieve emms-librefm-scrobbler-submission-url
- #'emms-librefm-scrobbler-async-submission-callback
- (list (cons track rating))))))
-
-(defun emms-librefm-scrobbler-async-submission-callback (status &optional cbargs)
- "Pass response of asynchronous submission call to handler."
- (let ((response (emms-librefm-scrobbler-get-response-status)))
- ;; From the API docs: This indicates that the
- ;; submission request was accepted for processing. It
- ;; does not mean that the submission was valid, but
- ;; only that the authentication and the form of the
- ;; submission was validated.
- (let ((track (car cbargs)))
- (cond ((string= response "OK")
- (when emms-librefm-scrobbler-display-submissions
- (message "Libre.fm: Submitted %s"
- (emms-track-get track 'info-title))))
- ((string= response "BADSESSION")
- (emms-librefm-scrobbler-handshake)
- (emms-librefm-scrobbler-make-async-submission-call (car cbargs) (cdr cbargs)))
- (t
- (error "unhandled submission failure"))))))
-
-
-;;; ------------------------------------------------------------------
-;;; hooks
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-scrobbler-start-hook ()
- (setq emms-librefm-scrobbler-track-play-start-timestamp
- (format-time-string "%s")))
-
-(defun emms-librefm-scrobbler-stop-hook ()
- "Submit the track to libre.fm if it has been played for 240
-seconds or half the length of the track."
- (let ((current-track (emms-playlist-current-selected-track)))
- (let ((track-length (emms-track-get current-track 'info-playing-time)))
- (when (and track-length
- ;; only submit files
- (eq (emms-track-type current-track) 'file))
- (when (and
- ;; track must be longer than 30 secs
- (> track-length 30)
- ;; track must be played for more than 240 secs or
- ;; half the tracks length, whichever comes first.
- (> emms-playing-time (min 240 (/ track-length 2))))
- (emms-librefm-scrobbler-make-async-submission-call
- current-track nil))))))
-
-(defun emms-librefm-scrobbler-enable ()
- "Enable the scrobbler and submit played tracks."
- (interactive)
- (when (not emms-librefm-scrobbler-session-id)
- (emms-librefm-scrobbler-handshake))
- (add-hook 'emms-player-started-hook
- 'emms-librefm-scrobbler-start-hook t)
- (add-hook 'emms-player-stopped-hook
- 'emms-librefm-scrobbler-stop-hook)
- (add-hook 'emms-player-finished-hook
- 'emms-librefm-scrobbler-stop-hook))
-
-(defun emms-librefm-scrobbler-disable ()
- "Disable the scrobbler and don't submit played tracks."
- (interactive)
- (setq emms-librefm-scrobbler-session-id nil)
- (remove-hook 'emms-player-started-hook
- 'emms-librefm-scrobbler-start-hook)
- (remove-hook 'emms-player-stopped-hook
- 'emms-librefm-scrobbler-stop-hook)
- (remove-hook 'emms-player-finished-hook
- 'emms-librefm-scrobbler-stop-hook))
-
-
-(provide 'emms-librefm-scrobbler)
-
-
-;;; emms-librefm-scrobbler.el ends here
diff --git a/lisp/emms-librefm-stream.el b/lisp/emms-librefm-stream.el
deleted file mode 100644
index 7df67cb..0000000
--- a/lisp/emms-librefm-stream.el
+++ /dev/null
@@ -1,393 +0,0 @@
-;;; emms-librefm-stream.el --- Libre.FM streaming
-
-;; Copyright (C) 2014 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-
-;; Keywords: emms, libre.fm, GNU FM
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the Free
-;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-;; MA 02110-1301, USA.
-
-
-;;; Code:
-
-(require 'xml)
-(require 'emms-playlist-mode)
-(require 'emms-librefm-scrobbler)
-
-
-(defvar emms-librefm-stream-host-url
- "alpha.libre.fm"
- "URL for the streaming host")
-
-(defvar emms-librefm-stream-host-base-path
- ""
- "URL for the streaming host base path")
-
-(defvar emms-librefm-stream-session-id
- ""
- "Session ID for radio.")
-
-(defvar emms-librefm-stream-debug
- ""
- "Temporary debug information.")
-
-(defvar emms-librefm-stream-station-name
- ""
- "Last station name tuned to.")
-
-(defvar emms-librefm-stream-emms-tracklist
- ""
- "List of tracks for streaming.")
-
-(defvar emms-librefm-stream-playlist-buffer-name
- "*Emms GNU FM*"
- "Name for non-interactive Emms GNU FM buffer.")
-
-(defvar emms-librefm-stream-playlist-buffer nil
- "Non-interactive Emms GNU FM buffer.")
-
-(defvar emms-librefm-stream-connect-method "https://"
- "Method of connecting to server.")
-
-
-;;; ------------------------------------------------------------------
-;;; HTTP
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-stream-assert-http ()
- "Assert a sane HTTP response from the server.
-
-This function must be called inside the response buffer. Leaves
-point after the HTTP headers."
- (goto-char (point-min))
- (when (not (re-search-forward "^.*200 OK$" (point-at-eol) t))
- (error "bad HTTP server response"))
- ;; go to the start of the FM response
- (when (not (re-search-forward "\n\n" (point-max) t))
- (error "bad FM server response")))
-
-
-;;; ------------------------------------------------------------------
-;;; radio handshake
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-stream-tune-handshake-string ()
- "Create the tune handshake string."
- (when (not emms-librefm-scrobbler-username)
- (error "null username"))
- (when (not emms-librefm-scrobbler-password)
- (error "null password"))
- (let ((url (concat emms-librefm-stream-connect-method
- emms-librefm-stream-host-url
- "/radio/handshake.php?"
- "version=1.3.0.58" "&"
- "platform=linux" "&"
- "username=" (url-encode-url emms-librefm-scrobbler-username) "&"
- "passwordmd5=" (md5 emms-librefm-scrobbler-password) "&"
- "language=en")))
- url))
-
-(defun emms-librefm-stream-tune-handshake-call ()
- "Make the tune handshake call."
- (let ((url-request-method "POST"))
- (let ((response
- (url-retrieve-synchronously
- (emms-librefm-stream-tune-handshake-string))))
- (setq emms-librefm-stream-debug
- (with-current-buffer response
- (buffer-substring-no-properties (point-min)
- (point-max))))
- response)))
-
-(defun emms-librefm-stream-handle-tune-handshake-response (resbuf)
- "Handle the tune handshake server response."
- (when (not (bufferp resbuf))
- (error "response not a buffer"))
- (with-current-buffer resbuf
- (emms-librefm-stream-assert-http)
- (let (radio-session-id
- base-url
- base-path
- (start (point)))
-
- (if (re-search-forward "^session=\\(.*\\)$" (point-max) t)
- (setq radio-session-id (match-string-no-properties 1))
- (error "no radio session ID from server"))
-
- (goto-char start)
- (if (re-search-forward "^base_url=\\(.*\\)$" (point-max) t)
- (setq base-url (match-string-no-properties 1))
- (error "no base url from server"))
-
- (goto-char start)
- (if (re-search-forward "^base_path=\\(.*\\)$" (point-max) t)
- (setq base-path (match-string-no-properties 1))
- (error "no base path from server"))
-
- (setq emms-librefm-stream-session-id radio-session-id
- emms-librefm-stream-host-url base-url
- emms-librefm-stream-host-base-path base-path))
-
- (message "radio handshake successful")))
-
-(defun emms-librefm-stream-tune-handshake ()
- "Make and handle the tune handshake."
- (emms-librefm-stream-handle-tune-handshake-response
- (emms-librefm-stream-tune-handshake-call)))
-
-
-;;; ------------------------------------------------------------------
-;;; tuning
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-stream-tune-string (session-id station)
- "Create the tune string."
- (when (not session-id)
- (error "null session id"))
- (when (not station)
- (error "null station"))
- (let ((url (concat emms-librefm-stream-connect-method
- emms-librefm-stream-host-url
- emms-librefm-stream-host-base-path
- "/adjust.php?"
- "session=" session-id "&"
- "url=" (url-encode-url station))))
- url))
-
-(defun emms-librefm-stream-tune-call (session-id station)
- "Make the tune call."
- (let ((url-request-method "POST"))
- (let ((response
- (url-retrieve-synchronously
- (emms-librefm-stream-tune-string
- session-id station))))
- (setq emms-librefm-stream-debug
- (with-current-buffer response
- (buffer-substring-no-properties (point-min)
- (point-max))))
- response)))
-
-(defun emms-librefm-stream-handle-tune-response (resbuf)
- "Handle the tune server response."
- (when (not (bufferp resbuf))
- (error "response not a buffer"))
- (with-current-buffer resbuf
- (emms-librefm-stream-assert-http)
- (let ((status (buffer-substring (point-at-bol)
- (point-at-eol))))
- (let (response
- url
- stationname
- (start (point)))
-
- (if (re-search-forward "^response=\\(.*\\)$" (point-max) t)
- (setq response (match-string-no-properties 1))
- (error "no response status code"))
- (when (not (string= response "OK"))
- (error "tune response not OK"))
-
- (goto-char start)
- (if (re-search-forward "^url=\\(.*\\)$" (point-max) t)
- (setq url (match-string-no-properties 1))
- (error "no url from server"))
-
- (goto-char start)
- (if (re-search-forward "^stationname=\\(.*\\)$" (point-max) t)
- (setq stationname (match-string-no-properties 1))
- (error "no stationname from server"))
-
- (setq emms-librefm-stream-station-name stationname)
-
- (message "successfully tuned to: %s" stationname)))))
-
-(defun emms-librefm-stream-tune (station)
- "Make and handle tune call."
- (emms-librefm-stream-handle-tune-response
- (emms-librefm-stream-tune-call
- emms-librefm-stream-session-id
- station)))
-
-
-;;; ------------------------------------------------------------------
-;;; radio.getPlaylist
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-stream-getplaylist-string (radio-session-id)
- "Create the getplaylist string."
- (when (not radio-session-id)
- (error "null radio session id"))
- (let ((url (concat emms-librefm-stream-connect-method
- emms-librefm-stream-host-url
- emms-librefm-stream-host-base-path
- "/xspf.php?"
- "sk=" radio-session-id "&"
- "discovery=0" "&"
- "desktop=1.3.0.58")))
- url))
-
-(defun emms-librefm-stream-getplaylist-call (session-id)
- "Make the getplaylist call."
- (let ((url-request-method "POST"))
- (let ((response
- (url-retrieve-synchronously
- (emms-librefm-stream-getplaylist-string session-id))))
- (setq emms-librefm-stream-debug
- (with-current-buffer response
- (buffer-substring-no-properties (point-min)
- (point-max))))
- response)))
-
-(defun emms-librefm-stream-handle-getplaylist-response (resbuf)
- "Handle the getplaylist server response."
- (when (not (bufferp resbuf))
- (error "response not a buffer"))
- (with-current-buffer resbuf
- (emms-librefm-stream-assert-http)
- (xml-parse-region (point) (point-max))))
-
-(defun emms-librefm-stream-getplaylist ()
- "Make and handle radio.getPlaylist."
- (emms-librefm-stream-handle-getplaylist-response
- (emms-librefm-stream-getplaylist-call
- emms-librefm-stream-session-id)))
-
-
-;;; ------------------------------------------------------------------
-;;; XSPF
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-stream-xspf-find (tag data)
- "Return the tracklist portion of PLAYLIST or nil."
- (let ((tree (copy-tree data))
- result)
- (while (and tree (not result))
- (let ((this (car tree)))
- (when (and (listp this)
- (eq (car this) tag))
- (setq result this)))
- (setq tree (cdr tree)))
- result))
-
-(defun emms-librefm-stream-xspf-tracklist (playlist)
- "Return the tracklist portion of PLAYLIST or nil."
- (emms-librefm-stream-xspf-find 'trackList (car playlist)))
-
-(defun emms-librefm-stream-xspf-get (tag track)
- "Return the data associated with TAG in TRACK."
- (nth 2 (emms-librefm-stream-xspf-find tag track)))
-
-(defun emms-librefm-stream-xspf-convert-track (track)
- "Convert TRACK to an Emms track."
- (let ((location (emms-librefm-stream-xspf-get 'location track))
- (title (emms-librefm-stream-xspf-get 'title track))
- (album (emms-librefm-stream-xspf-get 'album track))
- (creator (emms-librefm-stream-xspf-get 'creator track))
- (duration (emms-librefm-stream-xspf-get 'duration track))
- (image (emms-librefm-stream-xspf-get 'image track)))
- (let ((emms-track (emms-dictionary '*track*)))
- (emms-track-set emms-track 'name location)
- (emms-track-set emms-track 'info-artist creator)
- (emms-track-set emms-track 'info-title title)
- (emms-track-set emms-track 'info-album album)
- (emms-track-set emms-track 'info-playing-time
- (/ (string-to-number duration)
- 1000))
- (emms-track-set emms-track 'type 'url)
- emms-track)))
-
-(defun emms-librefm-stream-xspf-convert-tracklist (tracklist)
- "Convert TRACKLIST to a list of Emms tracks."
- (let (tracks)
- (mapc
- #'(lambda (e)
- (when (and (listp e)
- (eq 'track (car e)))
- (setq tracks
- (append tracks
- `(,(emms-librefm-stream-xspf-convert-track e))))))
- tracklist)
- tracks))
-
-
-;;; ------------------------------------------------------------------
-;;; stream
-;;; ------------------------------------------------------------------
-
-(defun emms-librefm-stream-set-librefm-playlist-buffer ()
- "Setup the GNU FM buffer and make it `emms-playlist-buffer'."
- (when (not (buffer-live-p emms-librefm-stream-playlist-buffer))
- (setq emms-librefm-stream-playlist-buffer
- (emms-playlist-new
- emms-librefm-stream-playlist-buffer-name)))
- (setq emms-playlist-buffer emms-librefm-stream-playlist-buffer))
-
-(defun emms-librefm-stream-queue ()
- "Queue streaming tracks."
- (let ((tracklist
- (emms-librefm-stream-xspf-tracklist
- (emms-librefm-stream-getplaylist))))
- (when (not tracklist)
- (setq emms-librefm-stream-emms-tracklist nil)
- (error "could not find tracklist"))
- (setq emms-librefm-stream-emms-tracklist
- (emms-librefm-stream-xspf-convert-tracklist tracklist))
-
- (emms-librefm-stream-set-librefm-playlist-buffer)
-
- (with-current-emms-playlist
- (goto-char (point-max))
- (save-excursion
- (mapc
- #'(lambda (track)
- (emms-playlist-insert-track track))
- emms-librefm-stream-emms-tracklist)))))
-
-(defun emms-librefm-stream-queue-loader ()
- "Queue more streaming music if needed."
- (with-current-emms-playlist
- (goto-char (if emms-playlist-mode-selected-overlay
- (overlay-start emms-playlist-mode-selected-overlay)
- (point-min)))
- (when (and (eq (current-buffer)
- emms-librefm-stream-playlist-buffer)
- (not (next-single-property-change (point-at-eol)
- 'emms-track)))
- (emms-librefm-stream-queue))))
-
-(defun emms-librefm-stream (station)
- "Stream STATION from a GNU FM server."
- (interactive "sEnter station URL: ")
- (when (not (stringp station))
- (error "bad argument"))
-
- (add-hook 'emms-player-finished-hook
- 'emms-librefm-stream-queue-loader)
-
- (emms-librefm-stream-tune-handshake)
- (emms-librefm-stream-tune station)
-
- (message "tuned to %s, getting playlist..."
- emms-librefm-stream-station-name)
-
- (emms-librefm-stream-queue)
- (with-current-emms-playlist
- (emms-playlist-mode-play-current-track)))
-
-
-(provide 'emms-librefm-stream)
-
-;;; emms-librefm-stream.el ends here
diff --git a/lisp/emms-lyrics.el b/lisp/emms-lyrics.el
deleted file mode 100644
index 95b8e29..0000000
--- a/lisp/emms-lyrics.el
+++ /dev/null
@@ -1,585 +0,0 @@
-;;; emms-lyrics.el --- Display lyrics synchronically
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2013 Free Software Foundation, Inc.
-
-;; Author: William Xu <william.xwl@gmail.com>
-;; Keywords: emms music lyrics
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; This package enables you to play music files and display lyrics
-;; synchronically! :-) Plus, it provides a `emms-lyrics-mode' for
-;; making lyric files.
-
-;; Put this file into your load-path and the following into your
-;; ~/.emacs:
-;; (require 'emms-lyrics)
-;;
-;; Then either `M-x emms-lyrics-enable' or add (emms-lyrics 1) in
-;; your .emacs to enable.
-
-;;; TODO:
-
-;; 1. Maybe the lyric setup should run before `emms-start'.
-;; 2. Give a user a chance to choose when finding out multiple lyrics.
-;; 3. Search .lrc format lyrics from internet ?
-
-;;; Code:
-
-(require 'emms)
-(require 'emms-player-simple)
-(require 'emms-source-file)
-(require 'time-date)
-(require 'emms-url)
-(require 'emms-compat)
-
-;;; User Customization
-
-(defgroup emms-lyrics nil
- "Lyrics module for EMMS."
- :group 'emms)
-
-(defcustom emms-lyrics-display-on-modeline t
- "If non-nil, display lyrics on mode line."
- :type 'boolean
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-display-on-minibuffer nil
- "If non-nil, display lyrics on minibuffer."
- :type 'boolean
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-display-buffer nil
- "Non-nil will create deciated `emms-lyrics-buffer' to display lyrics."
- :type 'boolean
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-dir "~/music/lyrics"
- "Local lyrics repository.
-`emms-lyrics-find-lyric' will look for lyrics in current directory(i.e.,
-same as the music file) and this directory."
- :type 'string
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-display-format " %s "
- "Format for displaying lyrics."
- :type 'string
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-coding-system nil
- "Coding system for reading lyrics files.
-
-If all your lyrics use the same coding system, you can set this
-variable to that value; else you'd better leave it to nil, and
-rely on `prefer-coding-system', `file-coding-system-alist' or
-\(info \"(emacs)File Variables\"), sorted by priority
-increasingly."
- :type 'coding-system
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-mode-hook nil
- "Normal hook run after entering Emms Lyric mode."
- :type 'hook
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-find-lyric-function 'emms-lyrics-find-lyric
- "Function for finding lyric files."
- :type 'symbol
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-scroll-p t
- "Non-nil value will enable lyrics scrolling on mode line.
-
-Note: Even if this is set to t, it also depends on
-`emms-lyrics-display-on-modeline' to be t."
- :type 'boolean
- :group 'emms-lyrics)
-
-(defcustom emms-lyrics-scroll-timer-interval 0.4
- "Interval between scroller timers. The shorter, the faster."
- :type 'number
- :group 'emms-lyrics)
-
-
-;;; User Interfaces
-
-(defvar emms-lyrics-display-p t
- "If non-nil, will diplay lyrics.")
-
-(defvar emms-lyrics-mode-line-string ""
- "Current lyric.")
-
-(defvar emms-lyrics-buffer nil
- "Buffer to show lyrics.")
-
-(defvar emms-lyrics-chinese-url "http://mp3.baidu.com/m?f=ms&rn=10&tn=baidump3lyric&ct=150994944&word=%s&lm=-1"
- "URL used to find Chinese lyrics.
-Should contain one %s which is replaced with the filename.")
-
-(defvar emms-lyrics-latin-url "http://lyrics.wikia.com/%s%s"
- "URL used to find Latin lyrics.
-Should contain two %s-expressions. The first is replaced with
-the artist and second with the title.")
-
-;;;###autoload
-(defun emms-lyrics-enable ()
- "Enable displaying emms lyrics."
- (interactive)
- (emms-lyrics 1)
- (message "emms lyrics enabled."))
-
-;;;###autoload
-(defun emms-lyrics-disable ()
- "Disable displaying emms lyrics."
- (interactive)
- (emms-lyrics -1)
- (message "EMMS lyrics disabled"))
-
-;;;###autoload
-(defun emms-lyrics-toggle ()
- "Toggle displaying emms lyrics."
- (interactive)
- (if emms-lyrics-display-p
- (emms-lyrics-disable)
- (emms-lyrics-enable)))
-
-(defun emms-lyrics-toggle-display-on-minibuffer ()
- "Toggle display lyrics on minibbufer."
- (interactive)
- (if emms-lyrics-display-on-minibuffer
- (progn
- (setq emms-lyrics-display-on-minibuffer nil)
- (message "Disable lyrics on minibufer"))
- (setq emms-lyrics-display-on-minibuffer t)
- (message "Enable lyrics on minibufer")))
-
-(defun emms-lyrics-toggle-display-on-modeline ()
- "Toggle display lyrics on mode line."
- (interactive)
- (if emms-lyrics-display-on-modeline
- (progn
- (setq emms-lyrics-display-on-modeline nil
- emms-lyrics-mode-line-string "")
- (message "Disable lyrics on mode line"))
- (setq emms-lyrics-display-on-modeline t)
- (message "Enable lyrics on mode line")))
-
-(defun emms-lyrics-toggle-display-buffer ()
- "Toggle showing/hiding `emms-lyrics-buffer'."
- (interactive)
- (let ((w (get-buffer-window emms-lyrics-buffer)))
- (if w
- (delete-window w)
- (save-selected-window
- (pop-to-buffer emms-lyrics-buffer)
- (set-window-dedicated-p w t)))))
-
-(defun emms-lyrics (arg)
- "Turn on emms lyrics display if ARG is positive, off otherwise."
- (interactive "p")
- (if (and arg (> arg 0))
- (progn
- (setq emms-lyrics-display-p t)
- (add-hook 'emms-player-started-hook 'emms-lyrics-start)
- (add-hook 'emms-player-stopped-hook 'emms-lyrics-stop)
- (add-hook 'emms-player-finished-hook 'emms-lyrics-stop)
- (add-hook 'emms-player-paused-hook 'emms-lyrics-pause)
- (add-hook 'emms-player-seeked-functions 'emms-lyrics-seek)
- (add-hook 'emms-player-time-set-functions 'emms-lyrics-sync))
- (emms-lyrics-stop)
- (setq emms-lyrics-display-p nil)
- (emms-lyrics-restore-mode-line)
- (remove-hook 'emms-player-started-hook 'emms-lyrics-start)
- (remove-hook 'emms-player-stopped-hook 'emms-lyrics-stop)
- (remove-hook 'emms-player-finished-hook 'emms-lyrics-stop)
- (remove-hook 'emms-player-paused-hook 'emms-lyrics-pause)
- (remove-hook 'emms-player-seeked-functions 'emms-lyrics-seek)
- (remove-hook 'emms-player-time-set-functions 'emms-lyrics-sync)))
-
-(defun emms-lyrics-visit-lyric ()
- "Visit playing track's lyric file.
-If we can't find it from local disk, then search it from internet."
- (interactive)
- (let* ((track (emms-playlist-current-selected-track))
- (name (emms-track-get track 'name))
- (lrc (funcall emms-lyrics-find-lyric-function
- (emms-replace-regexp-in-string
- (concat "\\." (file-name-extension name) "\\'")
- ".lrc"
- (file-name-nondirectory name)))))
- (if (and lrc (file-exists-p lrc) (not (string= lrc "")))
- (find-file lrc)
- (message "Lyric file does not exist on file-system. Searching online...")
- (let* ((title (or (emms-track-get track 'info-title)
- (file-name-sans-extension
- (file-name-nondirectory name))))
- (artist (when (emms-track-get track 'info-title)
- (emms-track-get track 'info-artist)))
- (url
- (cond ((string-match "\\cc" title) ; Chinese lyrics.
- ;; Since tag info might be encoded using various coding
- ;; systems, we'd better fall back on filename.
- (format emms-lyrics-chinese-url
- (emms-url-quote-plus
- (encode-coding-string name 'gb2312))))
- (t ; English lyrics.g
- (format emms-lyrics-latin-url
- (if artist (concat (emms-url-quote-underscore artist) ":") "")
- (emms-url-quote-underscore title))))))
- (if (fboundp 'eww)
- (progn (require 'eww)
- (let ((readable-hook (when (fboundp 'eww-readable)
- (add-hook 'eww-after-render-hook 'eww-readable))))
- (eww url)
- (when readable-hook
- (remove-hook 'eww-after-render-hook 'eww-readable))))
- (browse-url url))
- (message "Lyric file does not exist on file-system. Searching online...")))))
-
-
-;;; EMMS Lyrics
-
-(defvar emms-lyrics-alist nil
- "a list of the form: '((time0 . lyric0) (time1 . lyric1)...)). In
-short, at time-i, display lyric-i.")
-
-(defvar emms-lyrics-timers nil
- "timers for displaying lyric.")
-
-(defvar emms-lyrics-start-time nil
- "emms lyric start time.")
-
-(defvar emms-lyrics-pause-time nil
- "emms lyric pause time.")
-
-(defvar emms-lyrics-elapsed-time 0
- "How long time has emms lyric played.")
-
-(defvar emms-lyrics-scroll-timers nil
- "Lyrics scroller timers.")
-
-(defun emms-lyrics-read-file (file &optional catchup)
- "Read a lyric file(LRC format).
-Optional CATCHUP is for recognizing `emms-lyrics-catchup'.
-FILE should end up with \".lrc\", its content looks like one of the
-following:
-
- [1:39]I love you, Emacs!
- [00:39]I love you, Emacs!
- [00:39.67]I love you, Emacs!
-
-FILE should be under the same directory as the music file, or under
-`emms-lyrics-dir'."
- (or catchup
- (setq file (funcall emms-lyrics-find-lyric-function file)))
- (when (and file (file-exists-p file))
- (with-temp-buffer
- (let ((coding-system-for-read emms-lyrics-coding-system))
- (emms-insert-file-contents file)
- (while (search-forward-regexp "\\[[0-9:.]+\\].*" nil t)
- (let ((lyric-string (match-string 0))
- (time 0)
- (lyric ""))
- (setq lyric
- (emms-replace-regexp-in-string ".*\\]" "" lyric-string))
- (while (string-match "\\[[0-9:.]+\\]" lyric-string)
- (let* ((time-string (match-string 0 lyric-string))
- (semi-pos (string-match ":" time-string)))
- (setq time
- (+ (* (string-to-number
- (substring time-string 1 semi-pos))
- 60)
- (string-to-number
- (substring time-string
- (1+ semi-pos)
- (1- (length time-string))))))
- (setq lyric-string
- (substring lyric-string (length time-string)))
- (setq emms-lyrics-alist
- (append emms-lyrics-alist `((,time . ,lyric))))
- (setq time 0)))))
- (setq emms-lyrics-alist
- (sort emms-lyrics-alist (lambda (a b) (< (car a) (car b))))))
- t)))
-
-(defun emms-lyrics-create-buffer ()
- "Create `emms-lyrics-buffer' dedicated to lyrics. "
- ;; leading white space in buffer name to hide the buffer
- (setq emms-lyrics-buffer (get-buffer-create " *EMMS Lyrics*"))
- (set-buffer emms-lyrics-buffer)
- (setq buffer-read-only nil
- cursor-type nil)
- (erase-buffer)
- (mapc (lambda (time-lyric) (insert (cdr time-lyric) "\n"))
- emms-lyrics-alist)
- (goto-char (point-min))
- (emms-activate-highlighting-mode)
- (setq buffer-read-only t))
-
-(defun emms-lyrics-start ()
- "Start displaying lryics."
- (setq emms-lyrics-start-time (current-time)
- emms-lyrics-pause-time nil
- emms-lyrics-elapsed-time 0)
- (when (let ((file
- (emms-track-get
- (emms-playlist-current-selected-track)
- 'name)))
- (emms-lyrics-read-file
- (emms-replace-regexp-in-string
- (concat "\\." (file-name-extension file) "\\'")
- ".lrc"
- (file-name-nondirectory file))))
- (when emms-lyrics-display-buffer
- (emms-lyrics-create-buffer))
- (emms-lyrics-set-timer)))
-
-(defun emms-lyrics-catchup (lrc)
- "Catchup with later downloaded LRC file(full path).
-If you write some lyrics crawler, which is running asynchronically,
-then this function would be useful to call when the crawler finishes its
-job."
- (let ((old-start emms-lyrics-start-time))
- (setq emms-lyrics-start-time (current-time)
- emms-lyrics-pause-time nil
- emms-lyrics-elapsed-time 0)
- (emms-lyrics-read-file lrc t)
- (emms-lyrics-set-timer)
- (emms-lyrics-seek (float-time (time-since old-start)))))
-
-(defun emms-lyrics-stop ()
- "Stop displaying lyrics."
- (interactive)
- (when emms-lyrics-alist
- (mapc #'emms-cancel-timer emms-lyrics-timers)
- (if (or (not emms-player-paused-p)
- emms-player-stopped-p)
- (setq emms-lyrics-alist nil
- emms-lyrics-timers nil
- emms-lyrics-mode-line-string ""))))
-
-(defun emms-lyrics-pause ()
- "Pause displaying lyrics."
- (if emms-player-paused-p
- (setq emms-lyrics-pause-time (current-time))
- (when emms-lyrics-pause-time
- (setq emms-lyrics-elapsed-time
- (+ (float-time
- (time-subtract emms-lyrics-pause-time
- emms-lyrics-start-time))
- emms-lyrics-elapsed-time)))
- (setq emms-lyrics-start-time (current-time)))
- (when emms-lyrics-alist
- (if emms-player-paused-p
- (emms-lyrics-stop)
- (emms-lyrics-set-timer))))
-
-(defun emms-lyrics-seek (sec)
- "Seek forward or backward SEC seconds lyrics."
- (setq emms-lyrics-elapsed-time
- (+ emms-lyrics-elapsed-time
- (float-time (time-since emms-lyrics-start-time))
- sec))
- (when (< emms-lyrics-elapsed-time 0) ; back to start point
- (setq emms-lyrics-elapsed-time 0))
- (setq emms-lyrics-start-time (current-time))
- (when emms-lyrics-alist
- (let ((paused-orig emms-player-paused-p))
- (setq emms-player-paused-p t)
- (emms-lyrics-stop)
- (setq emms-player-paused-p paused-orig))
- (emms-lyrics-set-timer)))
-
-(defun emms-lyrics-sync (sec)
- "Synchronize the lyric display at SEC seconds."
- (setq emms-lyrics-start-time (current-time)
- emms-lyrics-elapsed-time 0)
- (emms-lyrics-seek sec))
-
-(defun emms-lyrics-set-timer ()
- "Set timers for displaying lyrics."
- (setq emms-lyrics-timers '())
- (let ((lyrics-alist emms-lyrics-alist)
- (line 0))
- (while lyrics-alist
- (let ((time (- (caar lyrics-alist) emms-lyrics-elapsed-time))
- (lyric (cdar lyrics-alist))
- (next-time (and (cdr lyrics-alist)
- (- (car (cadr lyrics-alist))
- emms-lyrics-elapsed-time)))
- (next-lyric (and (cdr lyrics-alist)
- (cdr (cadr lyrics-alist)))))
- (setq line (1+ line))
- (when (> time 0)
- (setq emms-lyrics-timers
- (append emms-lyrics-timers
- (list
- (run-at-time (format "%d sec" time)
- nil
- 'emms-lyrics-display-handler
- lyric
- next-lyric
- line
- (and next-time (- next-time time)))))))
- (setq lyrics-alist (cdr lyrics-alist))))))
-
-(defun emms-lyrics-mode-line ()
- "Add lyric to the mode line."
- (or global-mode-string (setq global-mode-string '("")))
- (unless (member 'emms-lyrics-mode-line-string
- global-mode-string)
- (setq global-mode-string
- (append global-mode-string
- '(emms-lyrics-mode-line-string)))))
-
-(defun emms-lyrics-restore-mode-line ()
- "Restore the mode line."
- (setq global-mode-string
- (remove 'emms-lyrics-mode-line-string global-mode-string))
- (force-mode-line-update))
-
-(defun emms-lyrics-display-handler (lyric next-lyric line diff)
- "DIFF is the timestamp differences between current LYRIC and
-NEXT-LYRIC; LINE corresponds line number for LYRIC in `emms-lyrics-buffer'."
- (emms-lyrics-display (format emms-lyrics-display-format lyric) line)
- (when (and emms-lyrics-display-on-modeline emms-lyrics-scroll-p)
- (emms-lyrics-scroll lyric next-lyric diff)))
-
-(defun emms-lyrics-display (lyric line)
- "Display LYRIC now.
-See `emms-lyrics-display-on-modeline' and
-`emms-lyrics-display-on-minibuffer' on how to config where to
-display."
- (when emms-lyrics-alist
- (when emms-lyrics-display-on-modeline
- (emms-lyrics-mode-line)
- (setq emms-lyrics-mode-line-string lyric)
- ;; (setq emms-lyrics-mode-line-string ; make it fit scroller width
- ;; (concat emms-lyrics-mode-line-string
- ;; (make-string
- ;; (abs (- emms-lyrics-scroll-width (length lyric)))
- ;; (string-to-char " "))))
- (force-mode-line-update))
-
- (when emms-lyrics-display-on-minibuffer
- (unless (minibuffer-window-active-p (selected-window))
- (message lyric)))
-
- (when emms-lyrics-display-buffer
- (with-current-buffer emms-lyrics-buffer
- (when line
- (goto-char (point-min))
- (forward-line (1- line))
- (emms-line-highlight))))))
-
-(defun emms-lyrics-find-lyric (file)
- "Return full path of found lrc FILE, or nil if not found.
-Use `emms-source-file-directory-tree-function' to find lrc FILE under
-current directory and `emms-lyrics-dir'.
-e.g., (emms-lyrics-find-lyric \"abc.lrc\")"
- (let* ((track (emms-playlist-current-selected-track))
- (lyric-under-curr-dir
- (concat (file-name-directory (emms-track-get track 'name))
- file)))
- (or (and (eq (emms-track-type track) 'file)
- (file-exists-p lyric-under-curr-dir)
- lyric-under-curr-dir)
- (car (funcall emms-source-file-directory-tree-function
- emms-lyrics-dir
- file)))))
-
-;; (setq emms-lyrics-scroll-width 20)
-
-(defun emms-lyrics-scroll (lyric next-lyric diff)
- "Scroll LYRIC to left smoothly in DIFF seconds.
-DIFF is the timestamp differences between current LYRIC and
-NEXT-LYRIC."
- (setq diff (floor diff))
- (setq emms-lyrics-scroll-timers '())
- (let ((scrolled-lyric (concat lyric " " next-lyric))
- (time 0)
- (pos 0))
- (catch 'return
- (while (< time diff)
- (setq emms-lyrics-scroll-timers
- (append emms-lyrics-scroll-timers
- (list
- (run-at-time time
- nil
- 'emms-lyrics-display
- (if (>= (length lyric) pos)
- (substring scrolled-lyric pos)
- (throw 'return t))
- nil))))
- (setq time (+ time emms-lyrics-scroll-timer-interval))
- (setq pos (1+ pos))))))
-
-
-;;; emms-lyrics-mode
-
-(defvar emms-lyrics-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "p" 'emms-lyrics-previous-line)
- (define-key map "n" 'emms-lyrics-next-line)
- (define-key map "i" 'emms-lyrics-insert-time)
- map)
- "Keymap for `emms-lyrics-mode'.")
-
-(defun emms-lyrics-rem* (x y)
- "The remainder of X divided by Y, with the same sign as X."
- (let* ((q (floor x y))
- (rem (- x (* y q))))
- (if (= rem 0)
- 0
- (if (eq (>= x 0) (>= y 0))
- rem
- (- rem y)))))
-
-(defun emms-lyrics-insert-time ()
- "Insert lyric time in the form: [01:23.21], then goto the
-beginning of next line."
- (interactive)
- (let* ((total (+ (float-time
- (time-subtract (current-time)
- emms-lyrics-start-time))
- emms-lyrics-elapsed-time))
- (min (/ (* (floor (/ total 60)) 100) 100))
- (sec (/ (floor (* (emms-lyrics-rem* total 60) 100)) 100.0)))
- (insert (emms-replace-regexp-in-string
- " " "0" (format "[%2d:%2d]" min sec))))
- (emms-lyrics-next-line))
-
-(defun emms-lyrics-next-line ()
- "Goto the beginning of next line."
- (interactive)
- (forward-line 1))
-
-(defun emms-lyrics-previous-line ()
- "Goto the beginning of previous line."
- (interactive)
- (forward-line -1))
-
-(define-derived-mode emms-lyrics-mode nil "Emms Lyric"
- "Major mode for creating lyric files.
-\\{emms-lyrics-mode-map}"
- (run-hooks 'emms-lyrics-mode-hook))
-
-(provide 'emms-lyrics)
-
-;;; emms-lyrics.el ends here
diff --git a/lisp/emms-maint.el b/lisp/emms-maint.el
deleted file mode 100644
index fd5c4a4..0000000
--- a/lisp/emms-maint.el
+++ /dev/null
@@ -1,3 +0,0 @@
-;; Copyright (C) 2003-2020 Free Software Foundation, Inc.
-
-(add-to-list 'load-path ".")
diff --git a/lisp/emms-mark.el b/lisp/emms-mark.el
deleted file mode 100644
index b7d2558..0000000
--- a/lisp/emms-mark.el
+++ /dev/null
@@ -1,295 +0,0 @@
-;;; emms-mark.el --- mark track like dired
-
-;; Copyright (C) 2006, 2007, 2008, 2009, 2018 Free Software Foundation, Inc.
-;;
-;; Author: Ye Wenbin <wenbinye@163.com>
-
-;; This file is part of EMMS.
-
-;; This program 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 3, or (at your option)
-;; any later version.
-;;
-;; This program 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 this program; if not, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-;;; Commentary:
-
-;; Provide mark operation to tracks
-
-;; Put this file into your load-path and the following into your ~/.emacs:
-;; (require 'emms-mark)
-
-;; To activate it for the current buffer only, do:
-;; (emms-mark-mode)
-
-;; To make this the default EMMS mode, do:
-;; (setq emms-playlist-default-major-mode 'emms-mark-mode)
-
-;;; Code:
-
-(provide 'emms-mark)
-(require 'cl-lib)
-(require 'emms)
-(require 'emms-playlist-mode)
-
-;;{{{ set new description-function
-(defun emms-mark-track-description (track)
- "Return a description of the current track."
- (cl-assert (not (eq (default-value 'emms-track-description-function)
- 'emms-mark-track-description))
- nil (concat "Do not set `emms-track-selection-function' to be"
- " emms-mark-track-description."))
- (concat " " (funcall (default-value 'emms-track-description-function)
- track)))
-
-(defun emms-mark-update-descriptions ()
- "Update the track descriptions in the current buffer."
- (emms-with-inhibit-read-only-t
- (save-excursion
- (goto-char (point-min))
- (emms-walk-tracks
- (emms-playlist-update-track)))))
-;;}}}
-
-;;{{{ functions to mark tracks
-(defvar emms-mark-char ?*)
-(defvar emms-mark-face-alist
- '((?* . font-lock-warning-face)
- (?\040 . emms-playlist-track-face)))
-
-(defun emms-mark-track (&optional arg)
- "Mark the current track.
-If ARG is positive, also mark the next ARG-1 tracks as well.
-If ARG is negative, also mark the previous ARG-1 tracks."
- (interactive "p")
- (or arg (setq arg 1))
- (let ((face (assoc-default emms-mark-char emms-mark-face-alist))
- buffer-read-only track)
- (save-excursion
- (beginning-of-line)
- (while (and (not (eobp))
- (/= arg 0))
- (setq track (get-text-property (point) 'emms-track))
- (delete-char 1)
- (insert (emms-propertize (string emms-mark-char)
- 'emms-track track))
- (backward-char 1)
- (if (> arg 0)
- ;; Propertizing forward...
- (put-text-property (point)
- (progn (forward-line 1) (point))
- 'face face)
- ;; ... and backward
- (let ((start (save-excursion (end-of-line) (point))))
- (put-text-property (progn (beginning-of-line) (point))
- start
- 'face face))
- (forward-line -1))
- (setq arg (if (> arg 0)
- (1- arg)
- (1+ arg)))))))
-
-(defun emms-mark-unmark-track (&optional arg)
- "Unmark the current track.
-If ARG is positive, also unmark the next ARG-1 tracks as well.
-If ARG is negative, also unmark the previous ARG-1 tracks."
- (interactive "p")
- (let ((emms-mark-char ?\040))
- (emms-mark-track arg)))
-
-(defun emms-mark-forward (arg)
- "Mark one or more tracks and move the point past the newly-marked tracks.
-See `emms-mark-track' for further details."
- (interactive "p")
- (emms-mark-track arg)
- (forward-line arg))
-
-(defun emms-mark-unmark-forward (arg)
- "Unmark one or more tracks and move the point past the tracks.
-See `emms-mark-unmark-track' for further details."
- (interactive "p")
- (emms-mark-unmark-track arg)
- (forward-line arg))
-
-(defun emms-mark-all ()
- "Mark all tracks in the current buffer."
- (interactive)
- (save-excursion
- (goto-char (point-min))
- (emms-mark-track (count-lines (point-min) (point-max)))))
-
-(defun emms-mark-unmark-all ()
- "Unmark all tracks in the current buffer."
- (interactive)
- (emms-mark-do-with-marked-track 'emms-mark-unmark-track))
-
-(defun emms-mark-regexp (regexp arg)
- "Mark all tracks matching REGEXP. A prefix argument means to
-unmark them instead."
- (interactive
- (list
- (read-from-minibuffer (if current-prefix-arg
- "Unmark tracks matching: "
- "Mark tracks matching: "))
- current-prefix-arg))
- (let ((emms-mark-char (if arg ?\040 ?*)))
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward regexp nil t)
- (emms-mark-track 1)
- (forward-line 1)))))
-
-(defun emms-mark-toggle ()
- "Toggle all marks in the current buffer."
- (interactive)
- (save-excursion
- (goto-char (point-min))
- (let (buffer-read-only)
- (while (not (eobp))
- (if (eq ?\040 (following-char))
- (emms-mark-track)
- (emms-mark-unmark-track))
- (forward-line 1)))))
-
-(defsubst emms-mark-has-markedp ()
- "Return non-nil if the playlist has a marked line, nil otherwise."
- (save-excursion
- (goto-char (point-min))
- (re-search-forward (format "^[%c]" emms-mark-char) nil t)))
-
-;;}}}
-
-;;{{{ functions to operate marked tracks
-(defun emms-mark-do-with-marked-track (func &optional move)
- "Call FUNC on every marked line in current playlist.
-The function specified by FUNC takes no argument, so if the track
-on the marked line is needed, use `emms-playlist-track-at' to get
-it.
-
-The function can also modify the playlist buffer, such as
-deleting the current line. If the function doesn't move forward,
-be sure to set the second parameter MOVE to non-nil. Otherwise
-the function will never exit the loop."
- (let ((regexp (format "^[%c]" emms-mark-char))
- (newfunc func))
- (if move
- (setq newfunc (lambda () (funcall func) (forward-line 1))))
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward regexp nil t)
- (backward-char 1) ; move to beginning of line
- (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 being that
-this function collects the result of FUNC."
- (let ((regexp (format "^[%c]" emms-mark-char))
- result (newfunc func))
- (if move
- (setq newfunc (lambda () (let ((res (funcall func)))
- (forward-line 1) res))))
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward regexp nil t)
- (backward-char 1) ; move to beginning of line
- (setq result (cons (funcall newfunc) result)))
- (nreverse result))))
-
-(defun emms-mark-delete-marked-tracks ()
- "Delete all tracks that have been marked in the current buffer."
- (interactive)
- (emms-with-inhibit-read-only-t
- (emms-mark-do-with-marked-track
- (lambda nil (delete-region (point)
- (progn (forward-line 1) (point)))))))
-
-(defun emms-mark-kill-marked-tracks ()
- "Kill all tracks that have been marked in the current buffer."
- (interactive)
- (let (tracks buffer-read-only)
- (emms-mark-do-with-marked-track
- (lambda nil
- (setq tracks
- (concat tracks
- (delete-and-extract-region (point)
- (progn (forward-line 1) (point)))))))
- (kill-new tracks)))
-
-(defun emms-mark-copy-marked-tracks ()
- "Copy all tracks that have been marked in the current buffer."
- (interactive)
- (let (tracks)
- (emms-mark-do-with-marked-track
- (lambda nil
- (setq tracks
- (concat tracks
- (buffer-substring (point)
- (progn (forward-line 1) (point)))))))
- (kill-new tracks)))
-;;}}}
-
-;;{{{ mode stuff
-(defvar emms-mark-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "W" 'emms-mark-copy-marked-tracks)
- (define-key map "K" 'emms-mark-kill-marked-tracks)
- (define-key map "D" 'emms-mark-delete-marked-tracks)
- (define-key map "m" 'emms-mark-forward)
- (define-key map "u" 'emms-mark-unmark-forward)
- (define-key map "U" 'emms-mark-unmark-all)
- (define-key map "t" 'emms-mark-toggle)
- (define-key map "%m" 'emms-mark-regexp)
- map)
- "Keymap for `emms-mark-mode'.")
-
-(defun emms-mark-mode ()
- "An EMMS major mode that allows tracks to be marked like dired.
-\\{emms-mark-mode-map}"
- (interactive)
- (if (eq major-mode 'emms-mark-mode)
- ;; do nothing if we're already in emms-mark-mode
- nil
-
- ;; start emms-playlist-mode exactly once
- (setq emms-playlist-buffer-p t)
- (unless (eq major-mode 'emms-playlist-mode)
- (emms-playlist-mode))
-
- ;; use inherited keymap
- (set-keymap-parent emms-mark-mode-map (current-local-map))
- (use-local-map emms-mark-mode-map)
- (setq major-mode 'emms-mark-mode
- mode-name "Emms-Mark")
-
- ;; show a blank space at beginning of each line
- (set (make-local-variable 'emms-track-description-function)
- 'emms-mark-track-description)
- (emms-mark-update-descriptions)))
-
-(defun emms-mark-mode-disable ()
- "Disable `emms-mark-mode' and return to `emms-playlist-mode'."
- (interactive)
- (if (not (eq major-mode 'emms-mark-mode))
- ;; do nothing if we're not in emms-mark-mode
- nil
-
- ;; call emms-playlist-mode, saving important variables
- (let ((selected emms-playlist-selected-marker))
- (emms-playlist-mode)
- (setq emms-playlist-selected-marker selected)
- (emms-playlist-mode-overlay-selected))
-
- ;; update display
- (emms-mark-update-descriptions)))
-;;}}}
-
-;;; emms-mark.el ends here
diff --git a/lisp/emms-metaplaylist-mode.el b/lisp/emms-metaplaylist-mode.el
deleted file mode 100644
index d4616f0..0000000
--- a/lisp/emms-metaplaylist-mode.el
+++ /dev/null
@@ -1,246 +0,0 @@
-;;; emms-metaplaylist-mode.el --- A major mode for lists of Emms playlists
-
-;; Copyright (C) 2006, 2007, 2008, 2009, 2017-2018 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software
-;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-;; 02110-1301, USA.
-
-;;; Commentary:
-;;
-;; `emms-metaplaylist-mode' creates an interactive list of all the
-;; Emms playlist buffers. The currently active buffer is
-;; highlighted. You can choose a buffer from the list with RET and get
-;; taken there.
-
-;;; Code:
-
-(require 'emms)
-(require 'emms-playlist-mode)
-
-;;; --------------------------------------------------------
-;;; Variables, customisation and faces
-;;; --------------------------------------------------------
-
-(defgroup emms-metaplaylist-mode nil
- "*The Emacs Multimedia System meta-playlist mode."
- :prefix "emms-metaplaylist-mode-"
- :group 'multimedia)
-
-(defcustom emms-metaplaylist-mode-buffer-name "*Emms Playlist Buffers*"
- "*Name of the buffer in which Emms playlists will be listed."
- :type 'string
- :group 'emms-metaplaylist-mode)
-
-(defcustom emms-metaplaylist-mode-hooks nil
- "*List of hooks to run on entry to emms-metaplaylist-mode."
- :type 'list
- :group 'emms-metaplaylist-mode)
-
-(defface emms-metaplaylist-mode-face
- '((((class color) (background dark))
- (:foreground "AntiqueWhite3"))
- (((class color) (background light))
- (:foreground "red3"))
- (((type tty) (class mono))
- (:inverse-video t))
- (t (:background "WhiteSmoke")))
- "Face for the buffer names in the playlists buffer."
- :group 'emms-metaplaylist-mode)
-
-(defface emms-metaplaylist-mode-current-face
- '((((class color) (background dark))
- (:foreground "red2"))
- (((class color) (background light))
- (:background "red3" :foreground "white"))
- (((type tty) (class mono))
- (:inverse-video t))
- (t (:background "red3")))
- "Face for the current buffer name in the playlists buffer."
- :group 'emms-metaplaylist-mode)
-
-;;; --------------------------------------------------------
-;;; Keymap
-;;; --------------------------------------------------------
-
-(defvar emms-metaplaylist-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map text-mode-map)
- (define-key map (kbd "n") 'next-line)
- (define-key map (kbd "p") 'previous-line)
- (define-key map (kbd "RET") 'emms-metaplaylist-mode-goto-current)
- (define-key map (kbd "SPC") 'emms-metaplaylist-mode-set-active)
- (define-key map (kbd "g") 'emms-metaplaylist-mode-update)
- (define-key map (kbd "C") 'emms-metaplaylist-mode-new-buffer)
- (define-key map (kbd "C-k") 'emms-metaplaylist-mode-kill-buffer)
- (define-key map (kbd "c") 'emms-metaplaylist-mode-center-current)
- (define-key map (kbd "q") 'kill-this-buffer)
- (define-key map (kbd "?") 'describe-mode)
- map)
- "Keymap for `emms-metaplaylist-mode'.")
-
-;;; --------------------------------------------------------
-;;; Metaplaylist
-;;; --------------------------------------------------------
-
-(defun emms-metaplaylist-mode-goto-current ()
- "Switch to the buffer at point."
- (interactive)
- (let ((buffer (get-buffer
- (buffer-substring (point-at-bol)
- (point-at-eol)))))
- (emms-playlist-set-playlist-buffer buffer)
- (switch-to-buffer buffer)))
-
-(defun emms-metaplaylist-mode-write (playlists)
- "Print the sorted list of PLAYLISTS."
- (delete-region (point-min) (point-max))
- (mapc (lambda (buf)
- (let ((inhibit-read-only t))
- (insert (buffer-name buf))
- (add-text-properties
- (point-at-bol) (point-at-eol)
- (list 'face
- (if (eq buf emms-playlist-buffer)
- 'emms-metaplaylist-mode-current-face
- 'emms-metaplaylist-mode-face)))
- (newline)))
- playlists))
-
-;; Emms' list changes order, and that's OK, but we want something
-;; stable for display purposes.
-(defun emms-metaplaylist-mode-sorted-buffer-list ()
- "Return a sorted list of playlist buffers."
- (sort
- (copy-tree
- (emms-playlist-buffer-list))
- #'(lambda (a b)
- (string< (buffer-name a)
- (buffer-name b)))))
-
-(defun emms-metaplaylist-mode-center-current ()
- "Center on the current playlist buffer"
- (interactive)
- (when (buffer-name emms-playlist-buffer)
- (let ((p nil))
- (save-excursion
- (goto-char (point-min))
- (setq p (search-forward-regexp (regexp-quote
- (buffer-name emms-playlist-buffer))
- (point-max) t)))
- (when (not p) (error "cannot not find the current playlist buffer"))
- (goto-char p)
- (goto-char (point-at-bol)))))
-
-(defun emms-metaplaylist-mode-create ()
- "Create the meta-playlist buffer."
- (let ((name emms-metaplaylist-mode-buffer-name)
- (playlists (emms-metaplaylist-mode-sorted-buffer-list)))
- (if playlists
- (with-current-buffer (get-buffer-create name)
- (emms-metaplaylist-mode)
- (emms-metaplaylist-mode-write playlists)
- (emms-metaplaylist-mode-center-current)
- (current-buffer))
- (error "No Emms playlist buffers"))))
-
-(defun emms-metaplaylist-mode-assert-buffer ()
- "Assert that we are in the metaplaylist mode buffer."
- (when (not (eq (current-buffer)
- (get-buffer emms-metaplaylist-mode-buffer-name)))
- (error "not the metalplaylist buffer")))
-
-(defun emms-metaplaylist-mode-update ()
- "Update the metalplaylist display."
- (interactive)
- (emms-metaplaylist-mode-assert-buffer)
- (let ((inhibit-read-only t))
- (emms-metaplaylist-mode-write
- (emms-metaplaylist-mode-sorted-buffer-list)))
- (emms-metaplaylist-mode-center-current))
-
-(defun emms-metaplaylist-mode-kill-buffer ()
- "Kill the buffer at point"
- (interactive)
- (let ((buffer (get-buffer
- (buffer-substring (point-at-bol)
- (point-at-eol)))))
- (when (not buffer)
- (error "can't find buffer at point"))
- (if (y-or-n-p (format "kill playlist buffer \"%s\"?"
- (buffer-name buffer)))
- (kill-buffer buffer)
- (message "Buffer kill aborted."))
- (emms-metaplaylist-mode-update)))
-
-
-;;; --------------------------------------------------------
-;;; Playlist Management
-;;; --------------------------------------------------------
-
-(defun emms-metaplaylist-mode-new-buffer (buffer-name)
- "Creates a new buffer playlist buffer BUFFER-NAME."
- (interactive "sBuffer Name: ")
- (if (get-buffer buffer-name)
- (error "Buffer must not exist.")
- (let ((buf (get-buffer-create buffer-name)))
- (with-current-buffer buf
- (emms-playlist-mode)
- (setq emms-playlist-buffer-p t)))
- (emms-metaplaylist-mode-update)))
-
-(defun emms-metaplaylist-mode-set-active ()
- "Set the buffer at point to be the active playlist."
- (interactive)
- (emms-playlist-set-playlist-buffer
- (get-buffer (buffer-substring (point-at-bol) (point-at-eol))))
- (emms-metaplaylist-mode-update))
-
-
-;;; --------------------------------------------------------
-;;; Mode entry
-;;; --------------------------------------------------------
-
-(defun emms-metaplaylist-mode-go ()
- "Single entry point to the metaplaylist interface."
- (interactive)
- (let ((mpm-buffer (get-buffer emms-metaplaylist-mode-buffer-name)))
- (if mpm-buffer
- (with-current-buffer mpm-buffer
- (emms-metaplaylist-mode-update))
- (setq mpm-buffer (emms-metaplaylist-mode-create)))
- (switch-to-buffer mpm-buffer)))
-
-(defun emms-metaplaylist-mode ()
- "A major mode for Emms playlists.
-
-\\{emms-metaplaylist-mode-map}"
- ;; (interactive)
- (kill-all-local-variables)
-
- (use-local-map emms-metaplaylist-mode-map)
- (setq major-mode 'emms-metaplaylist-mode
- mode-name "Emms-MetaPlaylist")
-
- (setq buffer-read-only t)
-
- (run-hooks 'emms-metaplaylist-mode-hooks))
-
-(provide 'emms-metaplaylist-mode)
-
-;;; emms-metaplaylist-mode.el ends here
diff --git a/lisp/emms-mode-line-icon.el b/lisp/emms-mode-line-icon.el
deleted file mode 100644
index 82cf815..0000000
--- a/lisp/emms-mode-line-icon.el
+++ /dev/null
@@ -1,80 +0,0 @@
-;; emms-mode-line-icon.el --- show an icon in the Emacs mode-line
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Version: 1.1
-;; Keywords: emms
-
-;; Author: Daniel Brockman <daniel@brockman.se>
-;; Maintainer: Lucas Bonnet <lucas@rincevent.net>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;; Commentary:
-
-;; This EMMS extension shows an icon in the mode-line next to the
-;; info-tag.
-
-;; Code:
-
-(require 'emms-mode-line)
-
-(defvar emms-mode-line-icon-color "black"
- "Color of the little icon displayed in the mode-line.")
-
-(defvar emms-mode-line-icon-before-format ""
- "String to put before the icon, in the mode-line.
-For example, if you want to have something like :
-\[ <icon> Foo - The Foo Song ]
-You should set it to \"[\", and set emms-mode-line-format to \"%s ]\"")
-
-(defun emms-mode-line-icon-generate (color)
- `(image :type xpm :ascent center :data ,(concat "/* XPM */
-static char *note[] = {
-/* width height num_colors chars_per_pixel */
-\" 10 11 2 1\",
-/* colors */
-\". c " color "\",
-\"# c None s None\",
-/* pixels */
-\"###...####\",
-\"###.#...##\",
-\"###.###...\",
-\"###.#####.\",
-\"###.#####.\",
-\"#...#####.\",
-\"....#####.\",
-\"#..######.\",
-\"#######...\",
-\"######....\",
-\"#######..#\"};")))
-
-(defun emms-mode-line-icon-function ()
- (concat " "
- emms-mode-line-icon-before-format
- (emms-propertize "NP:" 'display
- (emms-mode-line-icon-generate
- emms-mode-line-icon-color))
- (emms-mode-line-playlist-current)))
-
-(setq emms-mode-line-mode-line-function 'emms-mode-line-icon-function)
-
-;; This is needed for text properties to work in the mode line.
-(put 'emms-mode-line-string 'risky-local-variable t)
-
-(provide 'emms-mode-line-icon)
-;;; emms-mode-line-icone.el ends here
diff --git a/lisp/emms-mode-line.el b/lisp/emms-mode-line.el
deleted file mode 100644
index caac8b1..0000000
--- a/lisp/emms-mode-line.el
+++ /dev/null
@@ -1,158 +0,0 @@
-;;; emms-mode-line.el --- Mode-Line and titlebar infos for emms
-
-;; Copyright (C) 2004, 2005, 2006, 2007, 2008,
-;; 2009 Free Software Foundation, Inc.
-
-;; Author: Mario Domgörgen <kanaldrache@gmx.de>
-;; Keywords: multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-;;
-;; To activate put simply the following line in your Emacs:
-;;
-;; (require 'emms-mode-line)
-;; (emms-mode-line 1)
-
-;;; Code:
-
-(require 'emms)
-
-(defgroup emms-mode-line nil
- "Showing information on mode-line and titlebar"
- :prefix "emms-mode-line-"
- :group 'emms)
-
-(defcustom emms-mode-line-mode-line-function 'emms-mode-line-playlist-current
- "Function for showing infos in mode-line or nil if don't want to."
- :type '(choice (const :tag "Don't show info on mode-line" nil) function)
- :group 'emms-mode-line)
-
-(defcustom emms-mode-line-titlebar-function nil
- "Function for showing infos in titlebar or nil if you don't want to."
- :type '(choice (const :tag "Don't show info on titlebar" nil) function)
- :group 'emms-mode-line)
-
-(defcustom emms-mode-line-format " [ %s ] "
- "String used for displaying the current track in mode-line and titlebar."
- :type 'string
- :group 'emms)
-
-(defun emms-mode-line-playlist-current ()
- "Format the currently playing song."
- (format emms-mode-line-format (emms-track-description
- (emms-playlist-current-selected-track))))
-
-(defvar emms-mode-line-active-p nil
- "If non-nil, emms mode line is active.")
-(defvar emms-mode-line-string "")
-
-(defvar emms-mode-line-initial-titlebar frame-title-format)
-
-(defun emms-mode-line (arg)
- "Turn on `emms-mode-line' if ARG is positive, off otherwise."
- (interactive "p")
- (or global-mode-string (setq global-mode-string '("")))
- (if (and arg (> arg 0))
- (progn
- (setq emms-mode-line-active-p t)
- (add-hook 'emms-track-updated-functions 'emms-mode-line-alter)
- (add-hook 'emms-player-finished-hook 'emms-mode-line-blank)
- (add-hook 'emms-player-stopped-hook 'emms-mode-line-blank)
- (add-hook 'emms-player-started-hook 'emms-mode-line-alter)
- (when (and emms-mode-line-mode-line-function
- (not (member 'emms-mode-line-string global-mode-string)))
- (setq global-mode-string
- (append global-mode-string
- '(emms-mode-line-string))))
- (when emms-player-playing-p (emms-mode-line-alter)))
- (setq emms-mode-line-active-p nil)
- (remove-hook 'emms-track-updated-functions 'emms-mode-line-alter)
- (remove-hook 'emms-player-finished-hook 'emms-mode-line-blank)
- (remove-hook 'emms-player-stopped-hook 'emms-mode-line-blank)
- (remove-hook 'emms-player-started-hook 'emms-mode-line-alter)
- (emms-mode-line-restore-titlebar)
- (emms-mode-line-restore-mode-line)))
-
-;;;###autoload
-(defun emms-mode-line-enable ()
- "Turn on `emms-mode-line'."
- (interactive)
- (emms-mode-line 1)
- (message "emms mode line enabled"))
-
-;;;###autoload
-(defun emms-mode-line-disable ()
- "Turn off `emms-mode-line'."
- (interactive)
- (emms-mode-line -1)
- (message "emms mode line disabled"))
-
-;;;###autoload
-(defun emms-mode-line-toggle ()
- "Toggle `emms-mode-line'."
- (interactive)
- (if emms-mode-line-active-p
- (emms-mode-line-disable)
- (emms-mode-line-enable)))
-
-(defun emms-mode-line-alter (&optional track)
- "Alter mode-line/titlebar.
-
-Optional TRACK is used to be compatible with
-`emms-track-updated-functions'. It's simply ignored currently."
- (emms-mode-line-alter-mode-line)
- (emms-mode-line-alter-titlebar))
-
-(defun emms-mode-line-alter-mode-line ()
- "Update the mode-line with song info."
- (when (and emms-mode-line-mode-line-function
- emms-player-playing-p)
- (setq emms-mode-line-string
- (funcall emms-mode-line-mode-line-function))
- (force-mode-line-update)))
-
-(defun emms-mode-line-alter-titlebar ()
- "Update the titlebar with song info."
- (when emms-mode-line-titlebar-function
- (setq frame-title-format
- (list "" emms-mode-line-initial-titlebar (funcall emms-mode-line-titlebar-function)))))
-
-
-(defun emms-mode-line-blank ()
- "Blank mode-line and titlebar but not quit `emms-mode-line'."
- (setq emms-mode-line-string nil)
- (force-mode-line-update)
- (emms-mode-line-restore-titlebar))
-
-(defun emms-mode-line-restore-mode-line ()
- "Restore the mode-line."
- (when emms-mode-line-mode-line-function
- (setq global-mode-string
- (remove 'emms-mode-line-string global-mode-string))
- (force-mode-line-update)))
-
-(defun emms-mode-line-restore-titlebar ()
- "Restore the mode-line."
- (when emms-mode-line-titlebar-function
- (setq frame-title-format
- (list emms-mode-line-initial-titlebar))))
-
-(provide 'emms-mode-line)
-;;; emms-mode-line.el ends here
diff --git a/lisp/emms-player-mpd.el b/lisp/emms-player-mpd.el
deleted file mode 100644
index 327938d..0000000
--- a/lisp/emms-player-mpd.el
+++ /dev/null
@@ -1,1320 +0,0 @@
-;;; emms-player-mpd.el --- MusicPD support for EMMS
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2014 Free Software Foundation, Inc.
-
-;; Author: Michael Olson <mwolson@gnu.org>, Jose Antonio Ortega Ruiz
-;; <jao@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;;; Benefits of MusicPD
-
-;; MusicPD features crossfade, very little skipping, minor CPU usage,
-;; many clients, many supported output formats, fast manipulation via
-;; network processes, and good abstraction of client and server.
-
-;;; MusicPD setup
-
-;; If you want to set up a local MusicPD server, you'll need to have
-;; mpd installed. If you want to use a remote server instance, no
-;; installation is needed.
-
-;; The website is at http://musicpd.org/. Debian packages are
-;; available. It is recommended to use mpd version 0.12.0 or higher.
-;;
-;; Copy the example configuration for mpd into ~/.mpdconf and edit it
-;; to your needs. Use your top level music directory for
-;; music_directory. If your playlists use absolute file names, be
-;; certain that music_directory has the leading directory part.
-;;
-;; Before you try to play anything, but after setting up the above,
-;; run `mkdir ~/.mpd && mpd --create-db' to create MusicPD's track
-;; database.
-;;
-;; Check to see if mpd is running. It must be running as a daemon for
-;; you to be able to play anything. Launch it by executing "mpd". It
-;; can be killed later with "mpd --kill" (or just "killall mpd" if
-;; you're not using the latest development version).
-
-;;; EMMS setup
-
-;; Add the following to your config.
-;;
-;; (require 'emms-player-mpd)
-
-;; Adjust `emms-player-mpd-server-name' and
-;; `emms-player-mpd-server-port' to match the location and port of
-;; your MusicPD server.
-;;
-;; (setq emms-player-mpd-server-name "localhost")
-;; (setq emms-player-mpd-server-port "6600")
-
-;; If your MusicPD setup requires a password, you will need to do the
-;; following.
-;;
-;; (setq emms-player-mpd-server-password "mypassword")
-
-;; To get track info from MusicPD, do the following.
-;;
-;; (add-to-list 'emms-info-functions 'emms-info-mpd)
-
-;; To change the volume using MusicPD, do the following.
-;;
-;; (setq emms-volume-change-function 'emms-volume-mpd-change)
-
-;; Add 'emms-player-mpd to the top of `emms-player-list'.
-;;
-;; (add-to-list 'emms-player-list 'emms-player-mpd)
-
-;; If you use absolute file names in your m3u playlists (which is most
-;; likely), make sure you set `emms-player-mpd-music-directory' to the
-;; value of "music_directory" from your MusicPD config. There are
-;; additional options available as well, but the defaults should be
-;; sufficient for most uses.
-
-;; You can set `emms-player-mpd-sync-playlist' to nil if your master
-;; EMMS playlist contains only stored playlists.
-
-;; If at any time you wish to replace the current EMMS playlist buffer
-;; with the contents of the MusicPD playlist, type
-;; M-x emms-player-mpd-connect.
-;;
-;; This will also run the relevant seek functions, so that if you use
-;; emms-playing-time, the displayed time will be accurate.
-
-;;; Contributors
-
-;; Adam Sjøgren implemented support for changing the volume.
-
-(require 'cl-lib)
-(require 'emms-player-simple)
-(require 'emms-source-playlist) ; for emms-source-file-parse-playlist
-(require 'tq)
-(require 'emms-cache)
-(require 'emms-url)
-
-(eval-when-compile
- (condition-case nil
- (progn
- (require 'url) ; load if available
- (require 'emms-url))
- (error nil)))
-
-(defgroup emms-player-mpd nil
- "EMMS player for MusicPD."
- :group 'emms-player
- :prefix "emms-player-mpd-")
-
-(defcustom emms-player-mpd (emms-player 'emms-player-mpd-start
- 'emms-player-mpd-stop
- 'emms-player-mpd-playable-p)
- "*Parameters for the MusicPD player."
- :type '(cons symbol alist)
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-music-directory nil
- "The value of 'music_directory' in your MusicPD configuration file.
-
-Unless your MusicPD is configured to use absolute file names, you must
-set this variable to the value of 'music_directory' in your MusicPD
-config."
- ;; The :format part ensures that entering directories happens on the
- ;; next line, where there is more space to work with
- :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
- (const nil)
- directory)
- :group 'emms-player-mpd)
-
-(defun emms-player-mpd-get-supported-regexp ()
- "Returns a regexp of file extensions that MusicPD supports,
-or nil if we cannot figure it out."
- (let ((out (shell-command-to-string "mpd --version")))
- ;; 0.17.x
- (if (string-match "Decoders plugins:$" out)
- (let* ((b (match-end 0))
- (e (string-match "Output plugins:$" out))
- (plugs (split-string (substring out b e) "\n" t))
- (plugs (cl-mapcan (lambda (x)
- (and (string-match " +\\[.*\\] +\\(.+\\)$" x)
- (split-string (match-string 1 x) nil t)))
- plugs))
- (b (and (string-match "Protocols:$" out) (match-end 0)))
- (prots (and b (substring out (+ 2 b) -1)))
- (prots (split-string (or prots "") nil t)))
- (concat "\\(\\.\\(m3u\\|pls\\|"
- (regexp-opt (delq nil plugs))
- "\\)\\'\\)\\|\\(\\`"
- (regexp-opt (delete "file://" prots)) "\\)"))
- (let ((found-start nil)
- (supported nil))
- (if (string-match "Supported decoders:\\([^0]+?\\)Supported outputs:" out)
- ;; 0.15.x
- (setq supported (replace-regexp-in-string "\\[.+?\\]" ""
- (match-string 1 out)))
- ;; < 0.15
- (setq out (split-string out "\n"))
- (while (car out)
- (cond ((string= (car out) "Supported formats:")
- (setq found-start t))
- ((string= (car out) "")
- (setq found-start nil))
- (found-start
- (setq supported (concat supported (car out)))))
- (setq out (cdr out))))
- ;; Create regexp
- (when (and (stringp supported)
- (not (string= supported "")))
- (concat "\\`http://\\|\\.\\(m3u\\|pls\\|"
- (regexp-opt (delq nil (split-string supported)))
- "\\)\\'"))))))
-
-(defcustom emms-player-mpd-supported-regexp
- ;; Use a sane default, just in case
- (or (emms-player-mpd-get-supported-regexp)
- (concat "\\`http://\\|"
- (emms-player-simple-regexp
- "m3u" "ogg" "flac" "mp3" "wav" "mod" "au" "aiff")))
- "Formats supported by MusicPD."
- :type 'regexp
- :set (function
- (lambda (sym value)
- (set sym value)
- (emms-player-set emms-player-mpd 'regex value)))
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-connect-function 'open-network-stream
- "Function used to initiate the connection to MusicPD.
-It should take same arguments as `open-network-stream' does."
- :type 'function
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-server-name (or (getenv "MPD_HOST") "localhost")
- "The MusicPD server that we should connect to."
- :type 'string
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-server-port (or (getenv "MPD_PORT") "6600")
- "The port of the MusicPD server that we should connect to."
- :type '(choice number string)
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-server-password nil
- "The password for the MusicPD server that we should connect to."
- :type '(choice (const :tag "None" nil)
- string)
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-check-interval 1
- "How often to check to see whether MusicPD has advanced to the
-next song. This may be an integer, a floating point number, or
-nil. If set to nil, this check will not be periodically
-performed.
-
-This variable is used only if `emms-player-mpd-sync-playlist' is
-non-nil."
- :type '(choice (const :tag "Disable check" nil)
- number)
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-verbose nil
- "Whether to provide notifications for server connection events
-and errors."
- :type 'boolean
- :group 'emms-player-mpd)
-
-(defcustom emms-player-mpd-sync-playlist t
- "Whether to synchronize the EMMS playlist with the MusicPD playlist.
-
-If your EMMS playlist contains music files rather than playlists,
-leave this set to non-nil.
-
-If your EMMS playlist contains stored playlists, set this to nil."
- :type 'boolean
- :group 'emms-player-mpd)
-
-(emms-player-set emms-player-mpd
- 'regex
- emms-player-mpd-supported-regexp)
-
-(emms-player-set emms-player-mpd
- 'pause
- 'emms-player-mpd-pause)
-
-(emms-player-set emms-player-mpd
- 'resume
- 'emms-player-mpd-pause)
-
-(emms-player-set emms-player-mpd
- 'seek
- 'emms-player-mpd-seek)
-
-(emms-player-set emms-player-mpd
- 'seek-to
- 'emms-player-mpd-seek-to)
-
-;;; Dealing with the MusicPD network process
-
-(defvar emms-player-mpd-process nil)
-(defvar emms-player-mpd-queue nil)
-
-(defvar emms-player-mpd-playlist-id nil)
-(make-variable-buffer-local 'emms-player-mpd-playlist-id)
-
-(defvar emms-player-mpd-current-song nil)
-(defvar emms-player-mpd-last-state nil)
-(defvar emms-player-mpd-status-timer nil)
-
-(defvar emms-player-mpd-status-regexp
- "^\\(OK\\( MPD \\)?\\|ACK \\[\\([0-9]+\\)@[0-9]+\\] \\(.+\\)\\)\n+\\'"
- "Regexp that matches the valid status strings that MusicPD can
-return at the end of a request.")
-
-(defun emms-player-mpd-sentinel (proc event)
- "The process sentinel for MusicPD."
- (let ((status (process-status proc)))
- (cond ((string-match "^deleted" event)
- (when emms-player-mpd-verbose
- (message "MusicPD process was deleted")))
- ((memq status '(exit signal closed))
- (emms-player-mpd-close-process t)
- (when emms-player-mpd-verbose
- (message "Closed MusicPD process")))
- ((memq status '(run open))
- (when emms-player-mpd-verbose
- (message "MusicPD process started successfully")))
- (t
- (when emms-player-mpd-verbose
- (message "Other MusicPD status change: %s, %s" status event))))))
-
-(defun emms-player-mpd-ensure-process ()
- "Make sure that a MusicPD process is currently active."
- (unless (and emms-player-mpd-process
- (processp emms-player-mpd-process)
- (memq (process-status emms-player-mpd-process) '(run open)))
- (setq emms-player-mpd-process
- (if emms-player-mpd-server-port
- (funcall emms-player-mpd-connect-function "mpd"
- nil
- emms-player-mpd-server-name
- emms-player-mpd-server-port)
- (make-network-process :name "emms-mpd"
- :service emms-player-mpd-server-name
- :family 'local)))
- (set-process-sentinel emms-player-mpd-process
- 'emms-player-mpd-sentinel)
- (setq emms-player-mpd-queue
- (tq-create emms-player-mpd-process))
- (if (fboundp 'set-process-query-on-exit-flag)
- (set-process-query-on-exit-flag emms-player-mpd-process nil)
- (set-process-query-on-exit-flag emms-player-mpd-process nil))
- ;; send password
- (when (stringp emms-player-mpd-server-password)
- (tq-enqueue emms-player-mpd-queue
- (concat "password " emms-player-mpd-server-password "\n")
- emms-player-mpd-status-regexp nil #'ignore t))))
-
-(defun emms-player-mpd-close-process (&optional from-sentinel)
- "Terminate the current MusicPD client process.
-FROM-SENTINEL indicates whether this was called by the process sentinel,
-in which case certain checks should not be made."
- (when (or from-sentinel
- (and (processp emms-player-mpd-process)
- (memq (process-status emms-player-mpd-process) '(run open))))
- (tq-close emms-player-mpd-queue)
- (setq emms-player-mpd-queue nil)
- (setq emms-player-mpd-process nil)))
-
-(defun emms-player-mpd-send (question closure fn)
- "Send the given QUESTION to the MusicPD server.
-When a reply comes, call FN with CLOSURE and the result."
- (emms-player-mpd-ensure-process)
- (unless (string= (substring question -1) "\n")
- (setq question (concat question "\n")))
- (tq-enqueue emms-player-mpd-queue question
- emms-player-mpd-status-regexp
- closure fn t))
-
-;;; Helper functions
-
-(defun emms-player-mpd-get-mpd-filename (file)
- "Turn FILE into something that MusicPD can understand.
-
-This usually means removing a prefix."
- (if (or (not emms-player-mpd-music-directory)
- (not (eq (aref file 0) ?/))
- (string-match "\\`http://" file))
- file
- (file-relative-name file emms-player-mpd-music-directory)))
-
-(defun emms-player-mpd-get-emms-filename (file)
- "Turn FILE into something that EMMS can understand.
-
-This usually means adding a prefix."
- (if (or (not emms-player-mpd-music-directory)
- (eq (aref file 0) ?/)
- (string-match "\\`http://" file))
- file
- (expand-file-name file emms-player-mpd-music-directory)))
-
-(defun emms-player-mpd-parse-response (response)
- "Convert the given MusicPD response into a list.
-
-The car of the list is special:
-If an error has occurred, it will contain a cons cell whose car is
-an error number and whose cdr is the corresponding message.
-Otherwise, it will be nil."
- (when (stringp response)
- (save-match-data
- (let* ((data (split-string response "\n"))
- (cruft (last data 3))
- (status (if (string= (cadr cruft) "")
- (car cruft)
- (cadr cruft))))
- (setcdr cruft nil)
- (when (and (stringp (car data))
- (string-match "^OK\\( MPD \\)?" (car data)))
- (setq data (cdr data)))
- (if (and (stringp status)
- (string-match "^ACK \\[\\([0-9]+\\)@[0-9]+\\] \\(.+\\)"
- status))
- (cons (cons (match-string 1 status)
- (match-string 2 status))
- data)
- (cons nil data))))))
-
-(defun emms-player-mpd-parse-line (line)
- "Turn the given LINE from MusicPD into a cons cell.
-
-The format of the cell is (name . value)."
- (when (string-match "\\`\\([^:\n]+\\):\\s-*\\(.+\\)" line)
- (let ((name (match-string 1 line))
- (value (match-string 2 line)))
- (if (and name value)
- (progn
- (setq name (downcase name))
- (cons name value))
- nil))))
-
-(defun emms-player-mpd-get-alist (info)
- "Turn the given parsed INFO from MusicPD into an alist."
- (when (and info
- (null (car info)) ; no error has occurred
- (cdr info)) ; data exists
- (let ((alist nil)
- cell old-cell)
- (dolist (line (cdr info))
- (when (setq cell (emms-player-mpd-parse-line line))
- (if (setq old-cell (assoc (car cell) alist))
- (setcdr old-cell (cdr cell))
- (setq alist (cons cell alist)))))
- alist)))
-
-(defun emms-player-mpd-get-alists (info)
- "Turn the given parsed INFO from MusicPD into an list of alists.
-
-The list will be in reverse order."
- (when (and info
- (null (car info)) ; no error has occurred
- (cdr info)) ; data exists
- (let ((alists nil)
- (alist nil)
- cell)
- (dolist (line (cdr info))
- (when (setq cell (emms-player-mpd-parse-line line))
- (if (assoc (car cell) alist)
- (setq alists (cons alist alists)
- alist (list cell))
- (setq alist (cons cell alist)))))
- (when alist
- (setq alists (cons alist alists)))
- alists)))
-
-(defun emms-player-mpd-get-tracks-1 (closure response)
- (let ((songs (emms-player-mpd-get-alists
- (emms-player-mpd-parse-response response)))
- (tracks nil))
- (when songs
- (dolist (song-info songs)
- (let ((file (cdr (assoc "file" song-info))))
- (when file
- (setq file (emms-player-mpd-get-emms-filename file))
- (let* ((type (if (string-match "\\`http://" file)
- 'url
- 'file))
- (track (emms-track type file)))
- (emms-info-mpd track song-info)
- (run-hook-with-args 'emms-track-info-filters track)
- (setq tracks (cons track tracks)))))))
- (funcall (car closure) (cdr closure) tracks)))
-
-(defun emms-player-mpd-get-tracks (closure callback)
- "Get the current playlist from MusicPD in the form of a list of
-EMMS tracks.
-Call CALLBACK with CLOSURE and result when the request is complete."
- (emms-player-mpd-send "playlistinfo" (cons callback closure)
- #'emms-player-mpd-get-tracks-1))
-
-(defun emms-player-mpd-get-status-1 (closure response)
- (funcall (car closure)
- (cdr closure)
- (emms-player-mpd-get-alist
- (emms-player-mpd-parse-response response))))
-
-(defun emms-player-mpd-get-status (closure callback)
- "Get status information from MusicPD.
-It will be returned in the form of an alist by calling CALLBACK
-with CLOSURE as its first argument, and the status as the
-second."
- (emms-player-mpd-send "status" (cons callback closure)
- #'emms-player-mpd-get-status-1))
-
-(defun emms-player-mpd-get-status-part (closure callback item &optional info)
- "Get ITEM from the current MusicPD status.
-Call CALLBACK with CLOSURE and result when the request is complete.
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD."
- (if info
- (funcall callback closure (cdr (assoc item info)))
- (emms-player-mpd-get-status
- (cons callback (cons closure item))
- (lambda (closure info)
- (let ((fn (car closure))
- (close (cadr closure))
- (item (cddr closure)))
- (funcall fn close (cdr (assoc item info))))))))
-
-(defun emms-player-mpd-get-playlist-id (closure callback &optional info)
- "Get the current playlist ID from MusicPD.
-Call CALLBACK with CLOSURE and result when the request is complete.
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD."
- (when info
- (setq callback (lambda (closure id) id)))
- (emms-player-mpd-get-status-part closure callback "playlist" info))
-
-(defun emms-player-mpd-get-volume (closure callback &optional info)
- "Get the current volume from MusicPD.
-Call CALLBACK with CLOSURE and result when the request is complete.
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD."
- (when info
- (setq callback (lambda (closure volume) volume)))
- (emms-player-mpd-get-status-part closure callback "volume" info))
-
-(defun emms-player-mpd-get-current-song (closure callback &optional info)
- "Get the current song from MusicPD.
-This is in the form of a number that indicates the position of
-the song on the current playlist.
-
-Call CALLBACK with CLOSURE and result when the request is complete.
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD."
- (when info
- (setq callback (lambda (closure id) id)))
- (emms-player-mpd-get-status-part closure callback "song" info))
-
-(defun emms-player-mpd-get-mpd-state (closure callback &optional info)
- "Get the current state of the MusicPD server.
-This is either \"play\", \"stop\", or \"pause\".
-
-Call CALLBACK with CLOSURE and result when the request is complete.
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD."
- (when info
- (setq callback (lambda (closure id) id)))
- (emms-player-mpd-get-status-part closure callback "state" info))
-
-(defun emms-player-mpd-get-playing-time (closure callback &optional info)
- "Get the number of seconds that the current song has been playing,
-or nil if we cannot obtain this information.
-
-Call CALLBACK with CLOSURE and result when the request is complete.
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD."
- (if info
- (emms-player-mpd-get-status-part
- nil
- (lambda (closure time)
- (and time
- (string-match "\\`\\([0-9]+\\):" time)
- (string-to-number (match-string 1 time))))
- "time" info)
- (emms-player-mpd-get-status-part
- (cons callback closure)
- (lambda (closure time)
- (funcall (car closure)
- (cdr closure)
- (and time
- (string-match "\\`\\([0-9]+\\):" time)
- (string-to-number (match-string 1 time)))))
- "time" info)))
-
-(defun emms-player-mpd-select-song (prev-song new-song)
- "Move to the given song position.
-
-The amount to move is the number difference between PREV-SONG and
-NEW-SONG. NEW-SONG should be a string containing a number.
-PREV-SONG may be either a string containing a number or nil,
-which indicates that we should start from the beginning of the
-buffer and move to NEW-SONG."
- (with-current-emms-playlist
- ;; move to current track
- (goto-char (if (and (stringp prev-song)
- emms-playlist-selected-marker
- (marker-position emms-playlist-selected-marker))
- emms-playlist-selected-marker
- (point-min)))
- ;; seek forward or backward
- (let ((diff (if (stringp prev-song)
- (- (string-to-number new-song)
- (string-to-number prev-song))
- (string-to-number new-song))))
- (condition-case nil
- (progn
- ;; skip to first track if not on one
- (when (and (> diff 0)
- (not (emms-playlist-track-at (point))))
- (emms-playlist-next))
- ;; move to new track
- (while (> diff 0)
- (emms-playlist-next)
- (setq diff (- diff 1)))
- (while (< diff 0)
- (emms-playlist-previous)
- (setq diff (+ diff 1)))
- ;; select track at point
- (unless (emms-playlist-selected-track-at-p)
- (emms-playlist-select (point))))
- (error (concat "Could not move to position " new-song))))))
-
-(defun emms-player-mpd-sync-from-emms-1 (closure)
- (emms-player-mpd-get-playlist-id
- closure
- (lambda (closure id)
- (let ((buffer (car closure))
- (fn (cdr closure)))
- (when (functionp fn)
- (funcall fn buffer id))))))
-
-(defun emms-player-mpd-sync-from-emms (&optional callback)
- "Synchronize the MusicPD playlist with the contents of the
-current EMMS playlist.
-
-If CALLBACK is provided, call it with the current EMMS playlist
-buffer and MusicPD playlist ID when we are done, if there were no
-errors."
- (emms-player-mpd-clear)
- (with-current-emms-playlist
- (let (tracks)
- (save-excursion
- (setq tracks (nreverse
- (emms-playlist-tracks-in-region
- (point-min) (point-max)))))
- (emms-player-mpd-add-several-tracks
- tracks
- (cons (current-buffer) callback)
- #'emms-player-mpd-sync-from-emms-1))))
-
-(defun emms-player-mpd-sync-from-mpd-2 (closure info)
- (let ((buffer (car closure))
- (fn (cadr closure))
- (close (cddr closure))
- (id (emms-player-mpd-get-playlist-id nil #'ignore info))
- (song (emms-player-mpd-get-current-song nil #'ignore info)))
- (when (buffer-live-p buffer)
- (let ((emms-playlist-buffer buffer))
- (with-current-emms-playlist
- (setq emms-player-mpd-playlist-id id)
- (set-buffer-modified-p nil)
- (if song
- (emms-player-mpd-select-song nil song)
- (goto-char (point-min)))))
- (when (functionp fn)
- (funcall fn close info)))))
-
-(defun emms-player-mpd-sync-from-mpd-1 (closure tracks)
- (let ((buffer (car closure)))
- (when (and tracks
- (buffer-live-p buffer))
- (let ((emms-playlist-buffer buffer))
- (with-current-emms-playlist
- (emms-playlist-clear)
- (mapc #'emms-playlist-insert-track tracks)))
- (emms-player-mpd-get-status closure
- #'emms-player-mpd-sync-from-mpd-2))))
-
-(defun emms-player-mpd-sync-from-mpd (&optional closure callback)
- "Synchronize the EMMS playlist with the contents of the current
-MusicPD playlist. Namely, clear the EMMS playlist buffer and add
-tracks to it that are present in the MusicPD playlist.
-
-If the current buffer is an EMMS playlist buffer, make it the
-main EMMS playlist buffer."
- (when (and emms-playlist-buffer-p
- (not (eq (current-buffer) emms-playlist-buffer)))
- (emms-playlist-set-playlist-buffer (current-buffer)))
- (with-current-emms-playlist
- (emms-player-mpd-get-tracks
- (cons emms-playlist-buffer (cons callback closure))
- #'emms-player-mpd-sync-from-mpd-1)))
-
-(defun emms-player-mpd-detect-song-change-2 (state info)
- "Perform post-sync tasks after returning from a stop."
- (setq emms-player-mpd-current-song nil)
- (setq emms-player-playing-p 'emms-player-mpd)
- (when (string= state "pause")
- (setq emms-player-paused-p t))
- (emms-player-mpd-detect-song-change info))
-
-(defun emms-player-mpd-detect-song-change-1 (closure info)
- (let ((song (emms-player-mpd-get-current-song nil #'ignore info))
- (state (emms-player-mpd-get-mpd-state nil #'ignore info))
- (time (emms-player-mpd-get-playing-time nil #'ignore info))
- (err-msg (cdr (assoc "error" info))))
- (if (stringp err-msg)
- (progn
- (message "MusicPD error: %s" err-msg)
- (emms-player-mpd-send
- "clearerror"
- nil #'ignore))
- (cond ((string= state "stop")
- (if song
- ;; a track remains: the user probably stopped MusicPD
- ;; manually, so we'll stop EMMS completely
- (let ((emms-player-stopped-p t))
- (setq emms-player-mpd-last-state "stop")
- (emms-player-stopped))
- ;; no more tracks are left: we probably ran out of things
- ;; to play, so let EMMS do something further if it wants
- (unless (string= emms-player-mpd-last-state "stop")
- (setq emms-player-mpd-last-state "stop")
- (emms-player-stopped))))
- ((and emms-player-mpd-last-state
- (string= emms-player-mpd-last-state "stop"))
- ;; resume from a stop that occurred outside of EMMS
- (setq emms-player-mpd-last-state nil)
- (emms-player-mpd-sync-from-mpd
- state
- #'emms-player-mpd-detect-song-change-2))
- ((string= state "pause")
- nil)
- ((string= state "play")
- (setq emms-player-mpd-last-state "play")
- (unless (or (null song)
- (and (stringp emms-player-mpd-current-song)
- (string= song emms-player-mpd-current-song)))
- (let ((emms-player-stopped-p t))
- (emms-player-stopped))
- (emms-player-mpd-select-song emms-player-mpd-current-song song)
- (setq emms-player-mpd-current-song song)
- (emms-player-started 'emms-player-mpd)
- (when time
- (run-hook-with-args 'emms-player-time-set-functions
- time))))))))
-
-(defun emms-player-mpd-detect-song-change (&optional info)
- "Detect whether a song change has occurred.
-This is usually called by a timer.
-
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD."
- (if info
- (emms-player-mpd-detect-song-change-1 nil info)
- (emms-player-mpd-get-status nil #'emms-player-mpd-detect-song-change-1)))
-
-(defun emms-player-mpd-quote-file (file)
- "Escape special characters in FILE and surround in double-quotes."
- (concat "\""
- (emms-replace-regexp-in-string
- "\"" "\\\\\""
- (emms-replace-regexp-in-string "\\\\" "\\\\\\\\" file))
- "\""))
-
-;;;###autoload
-(defun emms-player-mpd-clear ()
- "Clear the MusicPD playlist."
- (interactive)
- (when emms-player-mpd-status-timer
- (emms-cancel-timer emms-player-mpd-status-timer)
- (setq emms-player-mpd-status-timer nil))
- (setq emms-player-mpd-last-state nil)
- (emms-player-mpd-send "clear" nil #'ignore)
- (let ((emms-player-stopped-p t))
- (emms-player-stopped)))
-
-;;; Adding to the MusicPD playlist
-
-(defun emms-player-mpd-add-file (file closure callback)
- "Add FILE to the current MusicPD playlist.
-Execute CALLBACK with CLOSURE as its first argument when done.
-
-If an error occurs, display a relevant message."
- (setq file (emms-player-mpd-get-mpd-filename file))
- (emms-player-mpd-send
- (concat "add " (emms-player-mpd-quote-file file))
- (cons file (cons callback closure))
- (lambda (closure response)
- (let ((output (emms-player-mpd-parse-response response))
- (file (car closure))
- (callback (cadr closure))
- (close (cddr closure)))
- (if (car output)
- (message "MusicPD error: %s: %s" file (cdar output))
- (when (functionp callback)
- (funcall callback close)))))))
-
-(defun emms-player-mpd-add-buffer-contents (buffer closure callback)
- "Load contents of BUFFER into MusicPD by adding each line.
-Execute CALLBACK with CLOSURE as its first argument when done.
-
-This handles both m3u and pls type playlists."
- (with-current-buffer buffer
- (goto-char (point-min))
- (let ((format (emms-source-playlist-determine-format)))
- (when format
- (emms-player-mpd-add-several-files
- (emms-source-playlist-files format)
- closure callback)))))
-
-(defun emms-player-mpd-add-playlist (playlist closure callback)
- "Load contents of PLAYLIST into MusicPD by adding each line.
-Execute CALLBACK with CLOSURE as its first argument when done.
-
-This handles both m3u and pls type playlists."
- ;; This is useful for playlists of playlists
- (with-temp-buffer
- (emms-insert-file-contents playlist)
- (emms-player-mpd-add-buffer-contents (current-buffer) closure callback)))
-
-(defun emms-player-mpd-add-streamlist (url closure callback)
- "Download contents of URL and then add its feeds into MusicPD.
-Execute CALLBACK with CLOSURE as its first argument when done."
- ;; This is useful with emms-streams.el
- (if (fboundp 'url-insert-file-contents)
- (progn
- (require 'emms-url)
- (with-temp-buffer
- (url-insert-file-contents (emms-url-quote-entire url))
- (emms-http-decode-buffer (current-buffer))
- (emms-player-mpd-add-buffer-contents (current-buffer)
- closure callback)))
- (error (message (concat "You need to install url.el so that"
- " Emms can retrieve this stream")))))
-
-(defun emms-player-mpd-add (track closure callback)
- "Add TRACK to the MusicPD playlist.
-Execute CALLBACK with CLOSURE as its first argument when done."
- (let ((name (emms-track-get track 'name))
- (type (emms-track-get track 'type)))
- (cond ((eq type 'url)
- (emms-player-mpd-add-file name closure callback))
- ((eq type 'streamlist)
- (emms-player-mpd-add-streamlist name closure callback))
- ((or (eq type 'playlist)
- (string-match "\\.\\(m3u\\|pls\\)\\'" name))
- (emms-player-mpd-add-playlist name closure callback))
- ((and (eq type 'file)
- (string-match emms-player-mpd-supported-regexp name))
- (emms-player-mpd-add-file name closure callback)))))
-
-(defun emms-player-mpd-add-several-tracks (tracks closure callback)
- "Add TRACKS to the MusicPD playlist.
-Execute CALLBACK with CLOSURE as its first argument when done."
- (when (consp tracks)
- (while (cdr tracks)
- (emms-player-mpd-add (car tracks) nil #'ignore)
- (setq tracks (cdr tracks)))
- ;; only execute callback on last track
- (emms-player-mpd-add (car tracks) closure callback)))
-
-(defun emms-player-mpd-add-several-files (files closure callback)
- "Add FILES to the MusicPD playlist.
-Execute CALLBACK with CLOSURE as its first argument when done."
- (when (consp files)
- (while (cdr files)
- (emms-player-mpd-add-file (car files) nil #'ignore)
- (setq files (cdr files)))
- ;; only execute callback on last file
- (emms-player-mpd-add-file (car files) closure callback)))
-
-;;; EMMS API
-
-(defun emms-player-mpd-playable-p (track)
- "Return non-nil when we can play this track."
- (and (memq (emms-track-type track) '(file url playlist streamlist))
- (string-match (emms-player-get emms-player-mpd 'regex)
- (emms-track-name track))
- (condition-case nil
- (progn (emms-player-mpd-ensure-process)
- t)
- (error nil))))
-
-(defun emms-player-mpd-play (&optional id)
- "Play whatever is in the current MusicPD playlist.
-If ID is specified, play the song at that position in the MusicPD
-playlist."
- (interactive)
- (if id
- (progn
- (unless (stringp id)
- (setq id (number-to-string id)))
- (emms-player-mpd-send
- (concat "play " id)
- nil
- (lambda (closure response)
- (setq emms-player-mpd-current-song nil)
- (if emms-player-mpd-check-interval
- (setq emms-player-mpd-status-timer
- (run-at-time t emms-player-mpd-check-interval
- 'emms-player-mpd-detect-song-change))
- (emms-player-mpd-detect-song-change)))))
- ;; we only want to play one track, so don't start the timer
- (emms-player-mpd-send
- "play"
- nil
- (lambda (closure response)
- (emms-player-started 'emms-player-mpd)))))
-
-(defun emms-player-mpd-start-and-sync-2 (buffer id)
- (when (buffer-live-p buffer)
- (let ((emms-playlist-buffer buffer))
- (with-current-emms-playlist
- (setq emms-player-mpd-playlist-id id)
- (set-buffer-modified-p nil)
- (let ((track-cnt 0))
- (save-excursion
- (goto-char
- (if (and emms-playlist-selected-marker
- (marker-position emms-playlist-selected-marker))
- emms-playlist-selected-marker
- (point-min)))
- (condition-case nil
- (while t
- (emms-playlist-previous)
- (setq track-cnt (1+ track-cnt)))
- (error nil)))
- (emms-player-mpd-play track-cnt))))))
-
-(defun emms-player-mpd-start-and-sync-1 (closure id)
- (let ((buf-id (with-current-emms-playlist
- emms-player-mpd-playlist-id)))
- (if (and (not (buffer-modified-p emms-playlist-buffer))
- (stringp buf-id)
- (string= buf-id id))
- (emms-player-mpd-start-and-sync-2 emms-playlist-buffer id)
- (emms-player-mpd-sync-from-emms
- #'emms-player-mpd-start-and-sync-2))))
-
-(defun emms-player-mpd-start-and-sync ()
- "Ensure that MusicPD's playlist is up-to-date with EMMS's
-playlist, and then play the current track.
-
-This is called if `emms-player-mpd-sync-playlist' is non-nil."
- (when emms-player-mpd-status-timer
- (emms-cancel-timer emms-player-mpd-status-timer)
- (setq emms-player-mpd-status-timer nil))
- (emms-player-mpd-send
- "clearerror"
- nil
- (lambda (closure response)
- (emms-player-mpd-get-playlist-id
- nil
- #'emms-player-mpd-start-and-sync-1))))
-
-(defun emms-player-mpd-connect-1 (closure info)
- (setq emms-player-mpd-current-song nil)
- (let* ((state (emms-player-mpd-get-mpd-state nil #'ignore info)))
- (unless (string= state "stop")
- (setq emms-player-playing-p 'emms-player-mpd))
- (when (string= state "pause")
- (setq emms-player-paused-p t))
- (unless (string= state "stop")
- (emms-player-mpd-detect-song-change info)
- (when emms-player-mpd-check-interval
- (setq emms-player-mpd-status-timer
- (run-at-time t emms-player-mpd-check-interval
- 'emms-player-mpd-detect-song-change))))))
-
-;;;###autoload
-(defun emms-player-mpd-connect ()
- "Connect to MusicPD and retrieve its current playlist.
-
-Afterward, the status of MusicPD will be tracked.
-
-This also has the effect of changing the current EMMS playlist to
-be the same as the current MusicPD playlist. Thus, this
-function is useful to call if the contents of the EMMS playlist
-buffer get out-of-sync for some reason."
- (interactive)
- (when emms-player-mpd-status-timer
- (emms-cancel-timer emms-player-mpd-status-timer)
- (setq emms-player-mpd-status-timer nil))
- (emms-player-mpd-sync-from-mpd
- nil #'emms-player-mpd-connect-1))
-
-(defun emms-player-mpd-start (track)
- "Starts a process playing TRACK."
- (interactive)
- (if (and emms-player-mpd-sync-playlist
- (not (memq (emms-track-get track 'type) '(streamlist playlist))))
- (emms-player-mpd-start-and-sync)
- (emms-player-mpd-clear)
- ;; if we have loaded the item successfully, play it
- (emms-player-mpd-add track nil #'emms-player-mpd-play)))
-
-(defun emms-player-mpd-disconnect (&optional no-stop)
- "Terminate the MusicPD client process and disconnect from MusicPD.
-
-If NO-STOP is non-nil, do not indicate to EMMS that we are
-stopped. This argument is meant to be used when calling this
-from other functions."
- (interactive)
- (emms-cancel-timer emms-player-mpd-status-timer)
- (setq emms-player-mpd-status-timer nil)
- (setq emms-player-mpd-current-song nil)
- (setq emms-player-mpd-last-state nil)
- (emms-player-mpd-close-process)
- (unless no-stop
- (let ((emms-player-stopped-p t))
- (emms-player-stopped))))
-
-(defun emms-player-mpd-stop ()
- "Stop the currently playing song."
- (interactive)
- (condition-case nil
- (emms-player-mpd-send "stop" nil #'ignore)
- (error nil))
- (emms-player-mpd-disconnect t)
- (let ((emms-player-stopped-p t))
- (emms-player-stopped)))
-
-(defun emms-player-mpd-pause ()
- "Pause the currently playing song."
- (interactive)
- (emms-player-mpd-send "pause" nil #'ignore))
-
-(defun emms-player-mpd-seek (amount)
- "Seek backward or forward by AMOUNT seconds, depending on sign of AMOUNT."
- (interactive)
- (emms-player-mpd-get-status
- amount
- (lambda (amount info)
- (let ((song (emms-player-mpd-get-current-song nil #'ignore info))
- (secs (emms-player-mpd-get-playing-time nil #'ignore info)))
- (when (and song secs)
- (emms-player-mpd-send
- (concat "seek " song " " (number-to-string (round (+ secs amount))))
- nil #'ignore))))))
-
-(defun emms-player-mpd-seek-to (pos)
- "Seek to POS seconds from the start of the current track."
- (interactive)
- (emms-player-mpd-get-current-song
- pos
- (lambda (pos song)
- (when (and song pos)
- (emms-player-mpd-send
- (concat "seek " song " " (number-to-string (round pos)))
- nil #'ignore)))))
-
-(defun emms-player-mpd-next ()
- "Move forward by one track in MusicPD's internal playlist."
- (interactive)
- (emms-player-mpd-send "next" nil #'ignore))
-
-(defun emms-player-mpd-previous ()
- "Move backward by one track in MusicPD's internal playlist."
- (interactive)
- (emms-player-mpd-send "previous" nil #'ignore))
-
-;;; Volume
-
-(defun emms-volume-mpd-change (amount)
- "Change volume up or down by AMOUNT, depending on whether it is
-positive or negative."
- (interactive "MVolume change amount (+ increase, - decrease): ")
- (emms-player-mpd-get-volume
- amount
- (lambda (change volume)
- (let ((new-volume (+ (string-to-number volume) change)))
- (emms-player-mpd-send
- (concat "setvol \"" (number-to-string new-volume) "\"")
- nil #'ignore)))))
-
-;;; Now playing
-
-(defun emms-player-mpd-show-1 (closure response)
- (let* ((info (emms-player-mpd-get-alist
- (emms-player-mpd-parse-response response)))
- (insertp (car closure))
- (callback (cadr closure))
- (buffer (cddr closure))
- (name (cdr (assoc "name" info))) ; radio feeds sometimes set this
- (file (cdr (assoc "file" info)))
- (desc nil))
- ;; if we are playing lastfm radio, use its show function instead
- (if (and (boundp 'emms-lastfm-radio-stream-url)
- (stringp emms-lastfm-radio-stream-url)
- (string= emms-lastfm-radio-stream-url file))
- (with-current-buffer buffer
- (and (fboundp 'emms-lastfm-np)
- (emms-lastfm-np insertp callback)))
- ;; otherwise build and show the description
- (when info
- (when name
- (setq desc name))
- (when file
- (let ((track (emms-dictionary '*track*))
- track-desc)
- (if (string-match "\\`http://" file)
- (emms-track-set track 'type 'url)
- (emms-track-set track 'type 'file))
- (emms-track-set track 'name file)
- (emms-info-mpd track info)
- (run-hook-with-args 'emms-track-info-filters track)
- (setq track-desc (emms-track-description track))
- (when (and (stringp track-desc) (not (string= track-desc "")))
- (setq desc (if desc
- (concat desc ": " track-desc)
- track-desc))))))
- (if (not desc)
- (unless (functionp callback)
- (message "Nothing playing right now"))
- (setq desc (format emms-show-format desc))
- (cond ((functionp callback)
- (funcall callback buffer desc))
- (insertp
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (insert desc))))
- (t
- (message "%s" desc)))))))
-
-;;;###autoload
-(defun emms-player-mpd-show (&optional insertp callback)
- "Describe the current EMMS track in the minibuffer.
-
-If INSERTP is non-nil, insert the description into the current
-buffer instead.
-
-If CALLBACK is a function, call it with the current buffer and
-description as arguments instead of displaying the description or
-inserting it.
-
-This function uses `emms-show-format' to format the current track.
-It differs from `emms-show' in that it asks MusicPD for the current track,
-rather than EMMS."
- (interactive "P")
- (emms-player-mpd-send "currentsong"
- (cons insertp (cons callback (current-buffer)))
- #'emms-player-mpd-show-1))
-
-;;; Track info
-
-(defun emms-info-mpd-process (track info)
- (dolist (data info)
- (let ((name (car data))
- (value (cdr data)))
- (setq name (cond ((string= name "artist") 'info-artist)
- ((string= name "composer") 'info-composer)
- ((string= name "performer") 'info-performer)
- ((string= name "title") 'info-title)
- ((string= name "album") 'info-album)
- ((string= name "track") 'info-tracknumber)
- ((string= name "disc") 'info-discnumber)
- ((string= name "date") 'info-year)
- ((string= name "genre") 'info-genre)
- ((string= name "time")
- (setq value (string-to-number value))
- 'info-playing-time)
- (t nil)))
- (when name
- (emms-track-set track name value)))))
-
-(defun emms-info-mpd-1 (track response)
- (let ((info (emms-player-mpd-get-alist
- (emms-player-mpd-parse-response response))))
- (when info
- (emms-info-mpd-process track info)
- (emms-track-updated track))))
-
-(defun emms-info-mpd (track &optional info)
- "Add track information to TRACK.
-If INFO is specified, use that instead of acquiring the necessary
-info from MusicPD.
-
-This is a useful addition to `emms-info-functions'."
- (if info
- (emms-info-mpd-process track info)
- (when (and (eq 'file (emms-track-type track))
- (not (string-match "\\`http://" (emms-track-name track))))
- (let ((file (emms-player-mpd-get-mpd-filename (emms-track-name track))))
- (when (or emms-player-mpd-music-directory
- (and file
- (string-match emms-player-mpd-supported-regexp file)))
- (condition-case nil
- (emms-player-mpd-send
- (concat "find filename "
- (emms-player-mpd-quote-file file))
- track
- #'emms-info-mpd-1)
- (error nil)))))))
-
-;;; Caching
-
-(defun emms-cache-set-from-mpd-track (track-info)
- "Dump TRACK-INFO into the EMMS cache.
-
-The track should be an alist as per `emms-player-mpd-get-alist'."
- (when emms-cache-set-function
- (let ((track (emms-dictionary '*track*))
- (name (cdr (assoc "file" track-info))))
- (when name
- (setq name (emms-player-mpd-get-emms-filename name))
- (emms-track-set track 'type 'file)
- (emms-track-set track 'name name)
- (emms-info-mpd-process track track-info)
- (funcall emms-cache-set-function 'file name track)))))
-
-(defun emms-cache--info-cleanup (info)
- (let ((xs (mapcar (lambda (x)
- (and (stringp x)
- (not (string-match-p "\\`\\(Last-\\|direct\\)" x))
- x))
- info)))
- (cons nil (delq nil xs))))
-
-(defun emms-cache-set-from-mpd-directory (dir)
- "Dump all MusicPD data from DIR into the EMMS cache.
-
-This is useful to do when you have recently acquired new music."
- (interactive
- (list (if emms-player-mpd-music-directory
- (emms-read-directory-name "Directory: "
- emms-player-mpd-music-directory)
- (read-string "Directory: "))))
- (unless (string= dir "")
- (setq dir (emms-player-mpd-get-mpd-filename dir)))
- (if emms-cache-set-function
- (progn
- (message "Dumping MusicPD data to cache...")
- (emms-player-mpd-send
- (concat "listallinfo " dir)
- nil
- (lambda (closure response)
- (message "Dumping MusicPD data to cache...processing")
- (let ((info (emms-player-mpd-parse-response response)))
- (when (null (car info))
- (let* ((info (emms-cache--info-cleanup info))
- (info (emms-player-mpd-get-alists info))
- (track 1)
- (total (length info)))
- (dolist (track-info info)
- (message "Dumping MusicPD data to cache...%d/%d" track total)
- (emms-cache-set-from-mpd-track track-info)
- (setq track (+ 1 track)))
- (message "Dumping MusicPD data to cache... %d tracks processed"
- total)))))))
- (error "Caching is not enabled")))
-
-(defun emms-cache-set-from-mpd-all ()
- "Dump all MusicPD data into the EMMS cache.
-
-This is useful to do once, just before using emms-browser.el, in
-order to prime the cache."
- (interactive)
- (emms-cache-set-from-mpd-directory ""))
-
-;;; Updating tracks
-
-(defun emms-player-mpd-update-directory (dir)
- "Cause the tracks in DIR to be updated in the MusicPD database."
- (interactive
- (list (if emms-player-mpd-music-directory
- (emms-read-directory-name "Directory: "
- emms-player-mpd-music-directory)
- (read-string "Directory: "))))
- (unless (string= dir "")
- (setq dir (emms-player-mpd-get-mpd-filename dir)))
- (emms-player-mpd-send
- (concat "update " (emms-player-mpd-quote-file dir)) nil
- (lambda (closure response)
- (let ((id (cdr (assoc "updating_db"
- (emms-player-mpd-get-alist
- (emms-player-mpd-parse-response response))))))
- (if id
- (message "Updating DB with ID %s" id)
- (message "Could not update the DB"))))))
-
-(defun emms-player-mpd-update-all ()
- "Cause all tracks in the MusicPD music directory to be updated in
-the MusicPD database."
- (interactive)
- (emms-player-mpd-update-directory ""))
-
-(defvar emms-player-mpd-waiting-for-update-timer nil
- "Timer object when waiting for MPD update to finish.")
-
-(defun emms-player-mpd-update-all-reset-cache ()
- "Update all tracks in the MusicPD music directory.
-When update finishes, clear the EMMS cache and call
-`emms-cache-set-from-mpd-all' to dump the MusicPD data into the
-cache."
- (interactive)
- (if emms-player-mpd-waiting-for-update-timer
- (message "Already waiting for an update to finish.")
- (emms-player-mpd-send
- "update" nil
- 'emms-player-mpd-wait-for-update)))
-
-(defun emms-player-mpd-wait-for-update (&optional closure response)
- "Wait for a currently running mpd update to finish.
-Afterwards, clear the EMMS cache and call
-`emms-cache-set-from-mpd-all'."
- (if response
- ;; This is the first call after the update command
- (let ((id (cdr (assoc "updating_db"
- (emms-player-mpd-get-alist
- (emms-player-mpd-parse-response response))))))
- (if id
- (progn
- (message "Updating DB with ID %s. Waiting for the update to finish..." id)
- (setq emms-player-mpd-waiting-for-update-timer
- (run-at-time 1 nil 'emms-player-mpd-wait-for-update)))
- (message "Could not update the DB")))
- ;; Otherwise, check if update is still in progress
- (emms-player-mpd-get-status-part
- nil
- (lambda (closure updating)
- (if updating
- ;; MPD update still in progress, so wait another second
- (run-at-time 1 nil 'emms-player-mpd-wait-for-update)
- ;; MPD update finished
- (setq emms-player-mpd-waiting-for-update-timer nil)
- (message "MPD update finished.")
- (sit-for 1)
- (clrhash emms-cache-db)
- (emms-cache-set-from-mpd-all)))
- "updating_db")))
-
-
-(provide 'emms-player-mpd)
-
-;;; emms-player-mpd.el ends here
diff --git a/lisp/emms-player-mpg321-remote.el b/lisp/emms-player-mpg321-remote.el
deleted file mode 100644
index de242ea..0000000
--- a/lisp/emms-player-mpg321-remote.el
+++ /dev/null
@@ -1,223 +0,0 @@
-;;; emms-player-mpg321-remote.el --- play files with mpg321 -R
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Damien Elmes <emacs@repose.cx>
-;; Keywords: emms, mp3, mpeg, multimedia
-
-;; 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 3, 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., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;; This file provides an emms-player which uses mpg321's remote mode
-;; to play files. This is a persistent process which isn't killed each
-;; time a new file is played.
-
-;; The remote process copes graciously with errors in music files, and
-;; allows you to seek in files.
-
-;; To enable this code, add the following to your emacs configuration:
-
-;; (require 'emms-player-mpg321-remote)
-;; (push 'emms-player-mpg321-remote emms-player-list)
-
-;;; Code:
-
-(require 'emms)
-(require 'emms-player-simple)
-
-;; --------------------------------------------------
-;; Variables and configuration
-;; --------------------------------------------------
-
-(defgroup emms-player-mpg321-remote nil
- "*EMMS player using mpg321's remote mode."
- :group 'emms-player
- :prefix "emms-player-mpg321-remote")
-
-(defcustom emms-player-mpg321-remote-command "mpg321"
- "*The command name of mpg321."
- :type 'string
- :group 'emms-player-mpg321-remote)
-
-(defcustom emms-player-mpg321-remote-parameters nil
- "*Extra arguments to pass to mpg321 when using remote mode
-For example: (list \"-o\" \"alsa\")"
- :type '(repeat string)
- :group 'emms-player-mpg321-remote)
-
-(defcustom emms-player-mpg321-remote
- (emms-player 'emms-player-mpg321-remote-start-playing
- 'emms-player-mpg321-remote-stop-playing
- 'emms-player-mpg321-remote-playable-p)
- "*A player for EMMS."
- :type '(cons symbol alist)
- :group 'emms-player-mpg321-remote)
-
-(defvar emms-player-mpg321-remote-initial-args
- (list "--skip-printing-frames=10" "-R" "-")
- "Initial args to pass to the mpg321 process.")
-
-(defvar emms-player-mpg321-remote-process-name "emms-player-mpg321-remote-proc"
- "The name of the mpg321 remote player process")
-
-(defvar emms-player-mpg321-remote-ignore-stop 0
- "Number of stop messages to ignore, due to user action.")
-
-(defmacro emms-player-mpg321-remote-add (cmd func)
- `(emms-player-set 'emms-player-mpg321-remote
- ,cmd ,func))
-
-(emms-player-mpg321-remote-add
- 'regex (emms-player-simple-regexp "mp3" "mp2"))
-(emms-player-mpg321-remote-add
- 'pause 'emms-player-mpg321-remote-pause)
-(emms-player-mpg321-remote-add
- 'resume 'emms-player-mpg321-remote-pause)
-(emms-player-mpg321-remote-add
- 'seek 'emms-player-mpg321-remote-seek)
-
-;; --------------------------------------------------
-;; Process maintenence
-;; --------------------------------------------------
-
-(defun emms-player-mpg321-remote-start-process ()
- "Start a new remote process, and return the process."
- (let ((process (apply 'start-process
- emms-player-mpg321-remote-process-name
- nil
- emms-player-mpg321-remote-command
- (append emms-player-mpg321-remote-initial-args
- emms-player-mpg321-remote-parameters))))
- (set-process-sentinel process 'emms-player-mpg321-remote-sentinel)
- (set-process-filter process 'emms-player-mpg321-remote-filter)
- process))
-
-(defun emms-player-mpg321-remote-stop ()
- "Stop the currently playing process, if indeed there is one"
- (let ((process (emms-player-mpg321-remote-process)))
- (when process
- (kill-process process)
- (delete-process process))))
-
-(defun emms-player-mpg321-remote-process ()
- "Return the remote process, if it exists."
- (get-process emms-player-mpg321-remote-process-name))
-
-(defun emms-player-mpg321-remote-running-p ()
- "True if the remote process exists and is running."
- (let ((proc (emms-player-mpg321-remote-process)))
- (and proc
- (eq (process-status proc) 'run))))
-
-(defun emms-player-mpg321-remote-sentinel (proc str)
- "Sentinel for determining the end of process"
- (when (or (eq (process-status proc) 'exit)
- (eq (process-status proc) 'signal))
- ;; reset
- (setq emms-player-mpg321-remote-ignore-stop 0)
- (message "Remote process died!")))
-
-(defun emms-player-mpg321-remote-send (text)
- "Send TEXT to the mpg321 remote process, and add a newline."
- (let (proc)
- ;; we shouldn't be trying to send to a dead process
- (unless (emms-player-mpg321-remote-running-p)
- (emms-player-mpg321-remote-start-process))
- (setq proc (emms-player-mpg321-remote-process))
- (process-send-string proc (concat text "\n"))))
-
-;; --------------------------------------------------
-;; Interfacing with emms
-;; --------------------------------------------------
-
-(defun emms-player-mpg321-remote-filter (proc str)
- (let* ((data-lines (split-string str "\n" t))
- data line cmd)
- (dolist (line data-lines)
- (setq data (split-string line))
- (setq cmd (car data))
- (cond
- ;; stop notice
- ((and (string= cmd "@P")
- (or (string= (cadr data) "0")
- (string= (cadr data) "3")))
- (emms-player-mpg321-remote-notify-emms))
- ;; frame notice
- ((string= cmd "@F")
- ;; even though a timer is constantly updating this variable,
- ;; updating it here will cause it to stay pretty much in sync.
- (run-hook-with-args 'emms-player-time-set-functions
- (truncate (string-to-number (nth 3 data)))))))))
-
-(defun emms-player-mpg321-remote-start-playing (track)
- "Start playing a song by telling the remote process to play it.
-If the remote process is not running, launch it."
- (unless (emms-player-mpg321-remote-running-p)
- (emms-player-mpg321-remote-start-process))
- (emms-player-mpg321-remote-play-track track))
-
-(defun emms-player-mpg321-remote-notify-emms (&optional user-action)
- "Tell emms that the current song has finished.
-If USER-ACTION, set `emms-player-mpg321-remote-ignore-stop' so that we
-ignore the next message from mpg321."
- (if user-action
- (let ((emms-player-ignore-stop t))
- ;; so we ignore the next stop message
- (setq emms-player-mpg321-remote-ignore-stop
- (1+ emms-player-mpg321-remote-ignore-stop))
- (emms-player-stopped))
- ;; not a user action
- (if (not (zerop emms-player-mpg321-remote-ignore-stop))
- (setq emms-player-mpg321-remote-ignore-stop
- (1- emms-player-mpg321-remote-ignore-stop))
- (emms-player-stopped))))
-
-(defun emms-player-mpg321-remote-stop-playing ()
- "Stop the current song playing."
- (emms-player-mpg321-remote-notify-emms t)
- (emms-player-mpg321-remote-send "stop"))
-
-(defun emms-player-mpg321-remote-play-track (track)
- "Send a play command to the remote, based on TRACK."
- (emms-player-mpg321-remote-send
- (concat "load " (emms-track-get track 'name)))
- (emms-player-started 'emms-player-mpg321-remote))
-
-(defun emms-player-mpg321-remote-playable-p (track)
- ;; use the simple definition.
- (emms-player-mpg321-playable-p track))
-
-(defun emms-player-mpg321-remote-pause ()
- "Pause the player."
- (emms-player-mpg321-remote-send "pause"))
-
-(defun emms-player-mpg321-remote-resume ()
- "Resume the player."
- (emms-player-mpg321-remote-send "pause"))
-
-(defun emms-player-mpg321-remote-seek (seconds)
- "Seek forward or backward in the file."
- ;; since mpg321 only supports seeking by frames, not seconds, we
- ;; make a very rough guess as to how much a second constitutes
- (let ((frame-string (number-to-string (* 35 seconds))))
- ;; if we're not going backwards, we need to add a '+'
- (unless (eq ?- (string-to-char frame-string))
- (setq frame-string (concat "+" frame-string)))
- (emms-player-mpg321-remote-send (concat "jump " frame-string))))
-
-(provide 'emms-player-mpg321-remote)
-;;; emms-player-mpg321-remote.el ends here
diff --git a/lisp/emms-player-mplayer.el b/lisp/emms-player-mplayer.el
deleted file mode 100644
index aa1f5c7..0000000
--- a/lisp/emms-player-mplayer.el
+++ /dev/null
@@ -1,81 +0,0 @@
-;;; emms-player-mplayer.el --- mplayer support for EMMS
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Authors: William Xu <william.xwl@gmail.com>
-;; Jorgen Schaefer <forcer@forcix.cx>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; This provides a player that uses mplayer. It supports pause and
-;; seeking. For loading subtitles automatically, try adding
-;; "sub-fuzziness=1" to your `~/.mplayer/config', see mplayer manual for
-;; more.
-
-;;; Code:
-
-(require 'emms-compat)
-(require 'emms-player-simple)
-
-(define-emms-simple-player mplayer '(file url)
- (concat "\\`\\(http[s]?\\|mms\\)://\\|"
- (apply #'emms-player-simple-regexp
- emms-player-base-format-list))
- "mplayer" "-slave" "-quiet" "-really-quiet")
-
-(define-emms-simple-player mplayer-playlist '(streamlist)
- "\\`http[s]?://"
- "mplayer" "-slave" "-quiet" "-really-quiet" "-playlist")
-
-(emms-player-set emms-player-mplayer
- 'pause
- 'emms-player-mplayer-pause)
-
-;;; Pause is also resume for mplayer
-(emms-player-set emms-player-mplayer
- 'resume
- nil)
-
-(emms-player-set emms-player-mplayer
- 'seek
- 'emms-player-mplayer-seek)
-
-(emms-player-set emms-player-mplayer
- 'seek-to
- 'emms-player-mplayer-seek-to)
-
-(defun emms-player-mplayer-pause ()
- "Depends on mplayer's -slave mode."
- (process-send-string
- emms-player-simple-process-name "pause\n"))
-
-(defun emms-player-mplayer-seek (sec)
- "Depends on mplayer's -slave mode."
- (process-send-string
- emms-player-simple-process-name
- (format "seek %d\n" sec)))
-
-(defun emms-player-mplayer-seek-to (sec)
- "Depends on mplayer's -slave mode."
- (process-send-string
- emms-player-simple-process-name
- (format "seek %d 2\n" sec)))
-
-(provide 'emms-player-mplayer)
-;;; emms-player-mplayer.el ends here
diff --git a/lisp/emms-player-mpv.el b/lisp/emms-player-mpv.el
deleted file mode 100644
index c4fc541..0000000
--- a/lisp/emms-player-mpv.el
+++ /dev/null
@@ -1,847 +0,0 @@
-;;; emms-player-mpv.el --- mpv support for EMMS
-;;
-;; Copyright (C) 2018 Free Software Foundation, Inc.
-
-;; Authors: Mike Kazantsev <mk.fraggod@gmail.com>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;;
-;; This code provides EMMS backend for using mpv player.
-;;
-;; It works in one of two modes, depending on `emms-player-mpv-ipc-method'
-;; customizable value or installed mpv version:
-;;
-;; - Using long-running mpv instance and JSON IPC interface to switch tracks
-;; and receive player feedback/metadata - for mpv 0.7.0 2014-10-16 and later.
-;;
-;; - Starting new mpv instance for each track, using its exit
-;; as "next track" signal and --input-file interface for pause/seek.
-;; Used as a fallback for any older mpv versions (supported in all of them).
-;;
-;; In default configuration, mpv will read its configuration files
-;; (see its manpage for locations), and can display window for
-;; video, subtitles, album-art or audio visualization.
-;;
-;; Useful `emms-player-mpv-parameters' tweaks:
-;;
-;; - Ignore config file(s): (add-to-list 'emms-player-mpv-parameters "--no-config")
-;; - Disable vo window: (add-to-list 'emms-player-mpv-parameters "--vo=null")
-;; - Show simple cqt visualizer window:
-;; (add-to-list 'emms-player-mpv-parameters
-;; "--lavfi-complex=[aid1]asplit[ao][a]; [a]showcqt[vo]")
-;;
-;; See "M-x customize-group emms-player-mpv" and mpv manpage for more options.
-;;
-;; See `emms-player-mpv-event-connect-hook' and `emms-player-mpv-event-functions',
-;; as well as `emms-player-mpv-ipc-req-send' for handling more mpv events,
-;; processing more playback info and metadata from it, as well as extending
-;; control over its vast functionality.
-;;
-
-;;; Code:
-
-
-(require 'emms)
-(require 'emms-player-simple)
-(require 'json)
-(require 'cl-lib)
-
-
-(defcustom emms-player-mpv
- (emms-player
- #'emms-player-mpv-start
- #'emms-player-mpv-stop
- #'emms-player-mpv-playable-p)
- "*Parameters for mpv player."
- :type '(cons symbol alist)
- :group 'emms-player-mpv)
-
-(emms-player-set emms-player-mpv 'regex
- (apply #'emms-player-simple-regexp emms-player-base-format-list))
-
-(defcustom emms-player-mpv-command-name "mpv"
- "mpv binary to use. Can be absolute path or just binary name."
- :type 'file
- :group 'emms-player-mpv)
-
-(defcustom emms-player-mpv-parameters
- '("--quiet" "--really-quiet" "--no-audio-display")
- "Extra command-line arguments for started mpv process(es).
-Either a list of strings or function returning such list.
-Extra arguments --idle and --input-file/--input-ipc-server
-are added automatically, depending on mpv version.
-Note that unless --no-config option is specified here,
-mpv will also use options from its configuration files.
-For mpv binary path, see `emms-player-mpv-command-name'."
- :type '(choice (repeat :tag "List of mpv arguments" string)
- function)
- :group 'emms-player-mpv)
-
-(defcustom emms-player-mpv-environment ()
- "List of extra environment variables (\"VAR=value\" strings) to pass on to mpv process.
-These are added on top of `process-environment' by default.
-Adding nil as an element to this list will discard emacs
-`process-environment' and only pass variables that are specified in the list."
- :type '(repeat (choice string (const :tag "Start from blank environment" nil)))
- :group 'emms-player-mpv)
-
-(defcustom emms-player-mpv-ipc-method nil
- "Switch for which IPC method to use with mpv.
-Possible symbols: detect, ipc-server, unix-socket, file.
-Defaults to nil value, which will cause `emms-player-mpv-ipc-detect'
-to pick one based on mpv --version output.
-Using JSON-IPC variants (ipc-server and unix-socket) enables
-support for various feedback and metadata options from mpv."
- :type '(choice
- (const :tag "Auto-detect from mpv --version" nil)
- (const :tag "Use --input-ipc-server JSON IPC (v0.17.0 2016-04-11)" ipc-server)
- (const :tag "Use --input-unix-socket JSON IPC (v0.7.0 2014-10-16)" unix-socket)
- (const :tag "Use --input-file FIFO (any mpv version)" file))
- :group 'emms-player-mpv)
-
-(defcustom emms-player-mpv-ipc-socket
- (concat (file-name-as-directory emms-directory)
- "mpv-ipc.sock")
- "Unix IPC socket or FIFO to use with mpv --input-* options,
-depending on `emms-player-mpv-ipc-method' value and/or mpv version."
- :type 'file
- :group 'emms-player-mpv)
-
-(defvar emms-player-mpv-ipc-proc nil) ; to avoid warnings while keeping useful defs at the top
-
-(defcustom emms-player-mpv-update-duration t
- "Update track duration when played by mpv.
-Uses `emms-player-mpv-event-functions' hook."
- :type 'boolean
- :set (lambda (sym value)
- (run-at-time 0.1 nil
- (lambda (value)
- (if value
- (add-hook
- 'emms-player-mpv-event-functions
- #'emms-player-mpv-info-duration-event-func)
- (remove-hook
- 'emms-player-mpv-event-functions
- #'emms-player-mpv-info-duration-event-func)))
- value))
- :group 'emms-player-mpv)
-
-(defcustom emms-player-mpv-update-metadata nil
- "Update track info (artist, album, name, etc) from mpv events, when it is played.
-This allows to dynamically update stream info from ICY tags, for example.
-Uses `emms-player-mpv-event-connect-hook' and `emms-player-mpv-event-functions' hooks."
- :type 'boolean
- :set (lambda (sym value)
- (run-at-time 0.1 nil
- (lambda (value)
- (if value
- (progn
- (add-hook
- 'emms-player-mpv-event-connect-hook
- #'emms-player-mpv-info-meta-connect-func)
- (add-hook
- 'emms-player-mpv-event-functions
- #'emms-player-mpv-info-meta-event-func)
- (when (process-live-p emms-player-mpv-ipc-proc)
- (emms-player-mpv-info-meta-connect-func)))
- (progn
- (remove-hook
- 'emms-player-mpv-event-connect-hook
- #'emms-player-mpv-info-meta-connect-func)
- (remove-hook
- 'emms-player-mpv-event-functions
- #'emms-player-mpv-info-meta-event-func))))
- value))
- :group 'emms-player-mpv)
-
-
-(defvar emms-player-mpv-proc nil
- "Running mpv process, controlled over --input-ipc-server/--input-file sockets.")
-
-(defvar emms-player-mpv-proc-kill-delay 5
- "Delay until SIGKILL gets sent to `emms-player-mpv-proc',
-if it refuses to exit cleanly on `emms-player-mpv-proc-stop'.")
-
-
-(defvar emms-player-mpv-ipc-proc nil
- "Unix socket process that communicates with running `emms-player-mpv-proc' instance.")
-
-(defvar emms-player-mpv-ipc-buffer " *emms-player-mpv-ipc*"
- "Buffer to associate with `emms-player-mpv-ipc-proc' socket/pipe process.")
-
-(defvar emms-player-mpv-ipc-connect-timer nil
- "Timer for connection attempts to JSON IPC unix socket.")
-(defvar emms-player-mpv-ipc-connect-delays
- '(0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.3 0.3 0.5 1.0 1.0 2.0)
- "List of delays before initiating socket connection for new mpv process.")
-
-(defvar emms-player-mpv-ipc-connect-command nil
- "JSON command for `emms-player-mpv-ipc-sentinel' to run as soon as it connects to mpv.
-I.e. last command that either initiated connection or was used while connecting to mpv.
-Set by `emms-player-mpv-start' and such,
-cleared once it gets sent by `emms-player-mpv-ipc-sentinel'.")
-
-(defvar emms-player-mpv-ipc-id 1
- "Auto-incremented value sent in JSON requests for request_id and observe_property id's.
-Use `emms-player-mpv-ipc-id-get' to get and increment this value, instead of using it directly.
-Wraps-around upon reaching `emms-player-mpv-ipc-id-max' (unlikely to ever happen).")
-
-(defvar emms-player-mpv-ipc-id-max (expt 2 30)
- "Max value for `emms-player-mpv-ipc-id' to wrap around after.
-Should be fine with both mpv and emacs, and probably never reached anyway.")
-
-(defvar emms-player-mpv-ipc-req-table nil
- "Auto-initialized hash table of outstanding API req_ids to their handler funcs.")
-
-(defvar emms-player-mpv-ipc-stop-command nil
- "Internal flag to track when stop command starts/finishes before next loadfile.
-Set to either nil, t or playback start function to call on end-file event after stop command.
-This is a workaround for mpv-0.30+ behavior, when 'stop + loadfile' only runs 'stop'.")
-
-
-(defvar emms-player-mpv-event-connect-hook nil
- "Normal hook run right after establishing new JSON IPC
-connection to mpv instance and before `emms-player-mpv-ipc-connect-command' if any.
-Best place to send any observe_property, request_log_messages, enable_event commands.
-Use `emms-player-mpv-ipc-id-get' to get unique id values for these.
-See also `emms-player-mpv-event-functions'.")
-
-(defvar emms-player-mpv-event-functions nil
- "List of functions to call for each event emitted from JSON IPC.
-One argument is passed to each function - JSON line,
-as sent by mpv and decoded by `json-read-from-string'.
-See also `emms-player-mpv-event-connect-hook'.")
-
-
-(defvar emms-player-mpv-stopped nil
- "Non-nil if playback was stopped by call from emms.
-Similar to `emms-player-stopped-p', but set for future async events,
-to indicate that playback should stop instead of switching to next track.")
-
-(defvar emms-player-mpv-idle-timer (timer-create)
- "Timer to delay `emms-player-stopped' when mpv unexpectedly goes idle.")
-
-(defvar emms-player-mpv-idle-delay 0.5
- "Delay before issuing `emms-player-stopped' when mpv unexpectedly goes idle.")
-
-
-(defvar emms-player-mpv-ipc-conn-emacs-26.1-workaround
- (and (= emacs-major-version 26)
- (= emacs-minor-version 1))
- "Non-nil to enable workaround for issue #31901 in emacs 26.1.
-Emacs 26.1 fails to indicate missing socket file error for unix socket network processes
-that were started with :nowait t, so blocking connections are used there instead.")
-
-
-;; ----- helpers
-
-(defvar emms-player-mpv-debug nil
- "Enable to print sent/received JSON lines and process
-start/stop events to *Messages* buffer using `emms-player-mpv-debug-msg'.")
-
-(defvar emms-player-mpv-debug-ts-offset nil
- "Timestamp offset for `emms-player-mpv-debug-msg'.
-Set on first use, with intent to both shorten and obfuscate time in logs.")
-
-(defun emms-player-mpv-debug-trim (s)
- (if (stringp s)
- (replace-regexp-in-string "\\(^[ \t\n\r]+\\|[ \t\n\r]+$\\)" "" s t t)
- s))
-
-(defun emms-player-mpv-debug-msg (tpl-or-msg &rest tpl-values)
- "Print debug message to *Messages* if `emms-player-mpv-debug' is non-nil.
-Message is only formatted if TPL-VALUES is non-empty.
-Strips whitespace from start/end of TPL-OR-MSG and strings in TPL-VALUES."
- (when emms-player-mpv-debug
- (setq
- tpl-or-msg (emms-player-mpv-debug-trim tpl-or-msg)
- tpl-values (seq-map #'emms-player-mpv-debug-trim tpl-values))
- (unless tpl-values
- (setq tpl-or-msg (replace-regexp-in-string "%" "%%" tpl-or-msg t t)))
- (let ((ts (float-time)))
- (unless emms-player-mpv-debug-ts-offset (setq emms-player-mpv-debug-ts-offset ts))
- (apply 'message
- (concat "emms-player-mpv %.1f " tpl-or-msg)
- (- ts emms-player-mpv-debug-ts-offset)
- tpl-values))))
-
-(defun emms-player-mpv-ipc-fifo-p ()
- "Returns non-nil if --input-file fifo should be used.
-Runs `emms-player-mpv-ipc-detect' to detect/set `emms-player-mpv-ipc-method' if necessary."
- (unless emms-player-mpv-ipc-method
- (setq emms-player-mpv-ipc-method
- (emms-player-mpv-ipc-detect emms-player-mpv-command-name)))
- (eq emms-player-mpv-ipc-method 'file))
-
-(defun emms-player-mpv-ipc-detect (cmd)
- "Run mpv --version and return symbol for best IPC method supported.
-CMD should be either name of mpv binary to use or full path to it.
-Return values correspond to `emms-player-mpv-ipc-method' options.
-Error is signaled if mpv binary fails to run."
- (with-temp-buffer
- (let ((exit-code (call-process cmd nil '(t t)
- nil "--version")))
- (unless (zerop exit-code)
- (insert (format "----- process exited with code %d -----" exit-code))
- (error (format "Failed to run mpv binary [%s]:\n%s" cmd (buffer-string))))
- (goto-char (point-min))
- (pcase
- (if (re-search-forward "^mpv\\s-+\\(\\([0-9]+\\.?\\)+\\)" nil t 1)
- (mapconcat (lambda (n)
- (format "%03d" n))
- (seq-map 'string-to-number
- (split-string (match-string-no-properties 1)
- "\\." t))
- ".")
- "000.000.000")
- ((pred (string> "000.006.999"))
- 'file)
- ((pred (string> "000.016.999"))
- 'unix-socket)
- (- 'ipc-server)))))
-
-
-;; ----- mpv process
-
-(defun emms-player-mpv-proc-playing-p (&optional proc)
- "Return whether playback in PROC or `emms-player-mpv-proc' is started,
-which is distinct from 'start-command sent' and 'process is running' states.
-Used to signal emms via `emms-player-started' and `emms-player-stopped' calls."
- (let ((proc (or proc emms-player-mpv-proc)))
- (and proc (process-get proc 'mpv-playing))))
-
-(defun emms-player-mpv-proc-playing (state &optional proc)
- "Set process mpv-playing state flag for `emms-player-mpv-proc-playing-p'."
- (let ((proc (or proc emms-player-mpv-proc)))
- (when proc (process-put proc 'mpv-playing state))))
-
-(defun emms-player-mpv-proc-symbol-id (sym &optional proc)
- "Get unique process-specific id integer for SYM or nil if it was already requested."
- (let
- ((proc (or proc emms-player-mpv-proc))
- (sym-id (intern (concat "mpv-sym-" (symbol-name sym)))))
- (unless (process-get proc sym-id)
- (let ((id (emms-player-mpv-ipc-id-get)))
- (process-put proc sym-id id)
- id))))
-
-(defun emms-player-mpv-proc-init-fifo (path &optional mode)
- "Create named pipe (fifo) socket for mpv --input-file PATH, if not exists already.
-Optional MODE should be 12-bit octal integer, e.g. #o600 (safe default).
-Signals error if mkfifo exits with non-zero code."
- (let ((attrs (file-attributes path)))
- (when
- (and attrs (not (string-prefix-p "p" (nth 8 attrs))))
- (delete-file path)
- (setq attrs nil))
- (unless attrs
- (unless
- (zerop (call-process "mkfifo" nil nil nil
- (format "--mode=%o" (or mode #o600))
- path))
- (error (format "Failed to run mkfifo for mpv --input-file path: %s" path))))))
-
-(defun emms-player-mpv-proc-sentinel (proc ev)
- (let
- ((status (process-status proc))
- (playing (emms-player-mpv-proc-playing-p proc)))
- (emms-player-mpv-debug-msg
- "proc[%s]: %s (status=%s, playing=%s)" proc ev status playing)
- (when (and (memq status '(exit signal))
- playing)
- (emms-player-stopped))))
-
-(defun emms-player-mpv-proc-init (&rest media-args)
- "initialize new mpv process as `emms-player-mpv-proc'.
-MEDIA-ARGS are used instead of --idle, if specified."
- (emms-player-mpv-proc-stop)
- (unless (file-directory-p (file-name-directory emms-player-mpv-ipc-socket))
- (make-directory (file-name-directory emms-player-mpv-ipc-socket)))
- (when (emms-player-mpv-ipc-fifo-p)
- (emms-player-mpv-proc-init-fifo emms-player-mpv-ipc-socket))
- (let*
- ((argv emms-player-mpv-parameters)
- (argv (append
- (list emms-player-mpv-command-name)
- (if (functionp argv)
- (funcall argv)
- argv)
- (list (format "--input-%s=%s"
- emms-player-mpv-ipc-method emms-player-mpv-ipc-socket))
- (or media-args '("--idle"))))
- (env emms-player-mpv-environment)
- (process-environment (append
- (unless (seq-some 'not env)
- process-environment)
- (seq-filter 'identity env))))
- (setq emms-player-mpv-proc
- (make-process :name "emms-player-mpv"
- :buffer nil :command argv :noquery t :sentinel #'emms-player-mpv-proc-sentinel))
- (when (emms-player-mpv-ipc-fifo-p)
- (emms-player-mpv-proc-playing t))
- (emms-player-mpv-debug-msg "proc[%s]: start %s" emms-player-mpv-proc argv)))
-
-(defun emms-player-mpv-proc-stop ()
- "Stop running `emms-player-mpv-proc' instance via SIGINT, if any.
-`delete-process' (SIGKILL) timer is started if `emms-player-mpv-proc-kill-delay' is non-nil."
- (when emms-player-mpv-proc
- (let ((proc emms-player-mpv-proc))
- (emms-player-mpv-debug-msg "proc[%s]: stop" proc)
- (if (not (process-live-p proc))
- (delete-process proc)
- (emms-player-mpv-proc-playing nil proc)
- (interrupt-process proc)
- (when emms-player-mpv-proc-kill-delay
- (run-at-time
- emms-player-mpv-proc-kill-delay nil
- (lambda (proc)
- (delete-process proc))
- proc))))
- (setq emms-player-mpv-proc nil)))
-
-
-;; ----- IPC socket/fifo
-
-(defun emms-player-mpv-ipc-sentinel (proc ev)
- (emms-player-mpv-debug-msg "ipc[%s]: %s" proc ev)
- (when (memq (process-status proc)
- '(open run))
- (run-hooks 'emms-player-mpv-event-connect-hook)
- (when emms-player-mpv-ipc-connect-command
- (let ((cmd emms-player-mpv-ipc-connect-command))
- (setq emms-player-mpv-ipc-connect-command nil)
- (emms-player-mpv-ipc-req-send cmd nil proc)))))
-
-(defun emms-player-mpv-ipc-filter (proc s)
- (when (buffer-live-p (process-buffer proc))
- (with-current-buffer (process-buffer proc)
- (let ((moving (= (point)
- (process-mark proc))))
- (save-excursion
- (goto-char (process-mark proc))
- (insert s)
- (set-marker (process-mark proc)
- (point)))
- (if moving (goto-char (process-mark proc))))
- ;; Process/remove all complete lines of json, if any
- (let ((p0 (point-min)))
- (while
- (progn
- (goto-char p0)
- (end-of-line)
- (equal (following-char)
- ?\n))
- (let*
- ((p1 (point))
- (json (buffer-substring p0 p1)))
- (delete-region p0 (+ p1 1))
- (emms-player-mpv-ipc-recv json)))))))
-
-(defun emms-player-mpv-ipc-connect (delays)
- "Make IPC connection attempt, rescheduling if there's no socket by (car DELAYS).
-(cdr DELAYS) gets passed to next connection attempt,
-so it can be rescheduled further until function runs out of DELAYS values.
-Sets `emms-player-mpv-ipc-proc' value to resulting process on success."
- ;; Note - emacs handles missing unix socket files in different ways between versions:
- ;; emacs <26 returns nil, emacs 26.1 leaves process in a stuck 'open
- ;; state (see issue #31901), emacs 26.2+ sets 'file-missing status.
- ;; None of these cases call sentinel function, so status must also be checked here.
- (emms-player-mpv-debug-msg "ipc: connect-delay %s" (car delays))
- (let ((use-nowait (not emms-player-mpv-ipc-conn-emacs-26.1-workaround)))
- (setq emms-player-mpv-ipc-proc
- (condition-case nil
- (make-network-process
- :name "emms-player-mpv-ipc"
- :family 'local
- :service emms-player-mpv-ipc-socket
- :nowait use-nowait
- :coding '(utf-8 . utf-8)
- :buffer (get-buffer-create emms-player-mpv-ipc-buffer)
- :noquery t
- :filter #'emms-player-mpv-ipc-filter
- :sentinel #'emms-player-mpv-ipc-sentinel)
- (file-error nil)))
- (unless (process-live-p emms-player-mpv-ipc-proc)
- (setq emms-player-mpv-ipc-proc nil))
- (when (and emms-player-mpv-ipc-proc (not use-nowait))
- (emms-player-mpv-ipc-sentinel emms-player-mpv-ipc-proc 'open)))
- (when (and (not emms-player-mpv-ipc-proc)
- delays)
- (run-at-time (car delays)
- nil #'emms-player-mpv-ipc-connect (cdr delays))))
-
-(defun emms-player-mpv-ipc-connect-fifo ()
- "Set `emms-player-mpv-ipc-proc' to process wrapper for
-writing to a named pipe (fifo) file/node or signal error."
- (setq emms-player-mpv-ipc-proc
- (start-process-shell-command "emms-player-mpv-input-file" nil
- (format "cat > \"%s\"" (shell-quote-argument emms-player-mpv-ipc-socket))))
- (set-process-query-on-exit-flag emms-player-mpv-ipc-proc nil)
- (unless emms-player-mpv-ipc-proc (error (format
- "Failed to start cat-pipe to fifo: %s" emms-player-mpv-ipc-socket)))
- (when emms-player-mpv-ipc-connect-command
- (let ((cmd emms-player-mpv-ipc-connect-command))
- (setq emms-player-mpv-ipc-connect-command nil)
- (emms-player-mpv-ipc-fifo-cmd cmd emms-player-mpv-ipc-proc))))
-
-(defun emms-player-mpv-ipc-init ()
- "Initialize new mpv ipc socket/file process and associated state."
- (emms-player-mpv-ipc-stop)
- (emms-player-mpv-debug-msg "ipc: init")
- (if (emms-player-mpv-ipc-fifo-p)
- (emms-player-mpv-ipc-connect-fifo)
- (when emms-player-mpv-ipc-connect-timer (cancel-timer emms-player-mpv-ipc-connect-timer))
- (with-current-buffer (get-buffer-create emms-player-mpv-ipc-buffer)
- (erase-buffer))
- (setq
- emms-player-mpv-ipc-id 1
- emms-player-mpv-ipc-req-table nil
- emms-player-mpv-ipc-connect-timer nil
- emms-player-mpv-ipc-connect-timer
- (run-at-time (car emms-player-mpv-ipc-connect-delays)
- nil
- #'emms-player-mpv-ipc-connect (cdr emms-player-mpv-ipc-connect-delays)))))
-
-(defun emms-player-mpv-ipc-stop ()
- (when emms-player-mpv-ipc-proc
- (emms-player-mpv-debug-msg "ipc: stop")
- (delete-process emms-player-mpv-ipc-proc)
- (setq emms-player-mpv-ipc-proc nil)))
-
-(defun emms-player-mpv-ipc ()
- "Return open IPC socket/fifo process or nil, (re-)starting mpv/connection if necessary.
-Return nil when starting async process/connection, and any follow-up
-command should be stored to `emms-player-mpv-ipc-connect-command' in this case."
- (unless
- ;; Don't start idle processes for fifo - just ignore all ipc requests there
- (and (not (process-live-p emms-player-mpv-proc))
- (emms-player-mpv-ipc-fifo-p))
- (unless (process-live-p emms-player-mpv-proc)
- (emms-player-mpv-proc-init))
- (unless (process-live-p emms-player-mpv-ipc-proc)
- (emms-player-mpv-ipc-init))
- (and
- emms-player-mpv-ipc-proc
- (memq (process-status emms-player-mpv-ipc-proc)
- '(open run))
- emms-player-mpv-ipc-proc)))
-
-
-;; ----- IPC protocol
-
-(defun emms-player-mpv-ipc-id-get ()
- "Get new connection-unique id value, tracked via `emms-player-mpv-ipc-id'."
- (let ((ipc-id emms-player-mpv-ipc-id))
- (setq emms-player-mpv-ipc-id
- (if (< emms-player-mpv-ipc-id emms-player-mpv-ipc-id-max)
- (1+ emms-player-mpv-ipc-id)
- 1))
- ipc-id))
-
-(defun emms-player-mpv-ipc-req-send (cmd &optional handler proc)
- "Send JSON IPC request and assign HANDLER to response for it, if any.
-CMD value is encoded via `json-encode'.
-HANDLER func will be called with decoded response JSON as (handler data err),
-where ERR will be either nil on \"success\", 'connection-error or whatever is in JSON.
-If HANDLER is nil, default `emms-player-mpv-ipc-req-error-printer'
-will be used to at least log errors.
-PROC can be specified to avoid `emms-player-mpv-ipc' call (e.g. from sentinel/filter funcs)."
- (let
- ((req-id (emms-player-mpv-ipc-id-get))
- (req-proc (or proc (emms-player-mpv-ipc)))
- (handler (or handler #'emms-player-mpv-ipc-req-error-printer)))
- (unless emms-player-mpv-ipc-req-table
- (setq emms-player-mpv-ipc-req-table (make-hash-table)))
- (let ((json (concat (json-encode (list :command cmd :request_id req-id))
- "\n")))
- (emms-player-mpv-debug-msg "json >> %s" json)
- (condition-case err
- ;; On any disconnect, assume that mpv process is to blame and force restart.
- (process-send-string req-proc json)
- (error
- (emms-player-mpv-proc-stop)
- (funcall handler nil 'connection-error)
- (setq handler nil))))
- (when handler (puthash req-id handler emms-player-mpv-ipc-req-table))))
-
-(defun emms-player-mpv-ipc-req-resolve (req-id data err)
- "Run handler-func for specified req-id."
- (when emms-player-mpv-ipc-req-table
- (let
- ((handler (gethash req-id emms-player-mpv-ipc-req-table))
- (err (if (string= err "success")
- nil err)))
- (remhash req-id emms-player-mpv-ipc-req-table)
- (when handler (funcall handler data err)))))
-
-(defun emms-player-mpv-ipc-req-error-printer (data err)
- "Simple default `emms-player-mpv-ipc-req-send' handler to log errors, if any."
- (when err (message "emms-player-mpv ipc-error: %s" err)))
-
-(defun emms-player-mpv-ipc-recv (json)
- "Handler for all JSON lines from mpv process.
-Only used with JSON IPC, never called with --input-file as there's no feedback there."
- (emms-player-mpv-debug-msg "json << %s" json)
- (let*
- ((json-data (json-read-from-string json))
- (req-id (alist-get 'request_id json-data))
- (ev (alist-get 'event json-data)))
- (when req-id
- ;; Response to command
- (emms-player-mpv-ipc-req-resolve req-id
- (alist-get 'data json-data)
- (alist-get 'error json-data)))
- (when ev
- ;; mpv event
- (emms-player-mpv-event-handler json-data)
- (run-hook-with-args 'emms-player-mpv-event-functions json-data))))
-
-(defun emms-player-mpv-ipc-fifo-cmd (cmd &optional proc)
- "Send --input-file command string for older mpv versions.
-PROC can be specified to avoid `emms-player-mpv-ipc' call."
- (let
- ((proc (or proc (emms-player-mpv-ipc)))
- (cmd-line (concat (mapconcat (lambda (s)
- (format "%s" s))
- cmd " ")
- "\n")))
- (emms-player-mpv-debug-msg "fifo >> %s" cmd-line)
- (process-send-string proc cmd-line)))
-
-(defun emms-player-mpv-observe-property (sym)
- "Send mpv observe_property command for property identified by SYM.
-Only sends command once per process, removing any
-potential duplication if used for same properties from different functions."
- (let ((id (emms-player-mpv-proc-symbol-id sym)))
- (when id (emms-player-mpv-ipc-req-send `(observe_property ,id ,sym)))))
-
-(defun emms-player-mpv-event-idle ()
- "Delayed check for switching tracks when mpv goes idle for no good reason."
- (emms-player-mpv-debug-msg "idle-check (stopped=%s)" emms-player-mpv-stopped)
- (unless emms-player-mpv-stopped (emms-player-stopped)))
-
-(defun emms-player-mpv-event-handler (json-data)
- "Handler for supported mpv events, including property changes.
-Called before `emms-player-mpv-event-functions' and does same thing as these hooks."
- (pcase (alist-get 'event json-data)
- ("playback-restart"
- ;; Separate emms-player-mpv-proc-playing state is used for emms started/stopped signals,
- ;; because start-file/end-file are also emitted after track-change and for playlists,
- ;; and don't correspond to actual playback state.
- (unless (emms-player-mpv-proc-playing-p)
- (emms-player-mpv-proc-playing t)
- (emms-player-started emms-player-mpv)))
- ("end-file"
- (when (emms-player-mpv-proc-playing-p)
- (emms-player-mpv-proc-playing nil)
- (emms-player-stopped))
- (when emms-player-mpv-ipc-stop-command
- (unless (eq emms-player-mpv-ipc-stop-command t)
- (funcall emms-player-mpv-ipc-stop-command))
- (setq emms-player-mpv-ipc-stop-command nil)))
- ("idle"
- ;; Can mean any kind of error before or during playback.
- ;; Example can be access/format error, resulting in start+end without playback-restart.
- (cancel-timer emms-player-mpv-idle-timer)
- (setq
- emms-player-mpv-idle-timer
- (run-at-time emms-player-mpv-idle-delay nil #'emms-player-mpv-event-idle)
- emms-player-mpv-ipc-stop-command nil))
- ("start-file" (cancel-timer emms-player-mpv-idle-timer))))
-
-
-;; ----- Metadata update hooks
-
-(defun emms-player-mpv-info-meta-connect-func ()
- "Hook function for `emms-player-mpv-event-connect-hook' to update metadata from mpv."
- (emms-player-mpv-observe-property 'metadata))
-
-(defun emms-player-mpv-info-meta-event-func (json-data)
- "Hook function for `emms-player-mpv-event-functions' to update metadata from mpv."
- (when
- (and
- (string= (alist-get 'event json-data)
- "property-change")
- (string= (alist-get 'name json-data)
- "metadata"))
- (let ((info-alist (alist-get 'data json-data)))
- (when info-alist (emms-player-mpv-info-meta-update-track info-alist)))))
-
-(defun emms-player-mpv-info-meta-update-track (info-alist &optional track)
- "Update TRACK with mpv metadata from INFO-ALIST.
-`emms-playlist-current-selected-track' is used by default."
- (mapc
- (lambda (cc)
- (setcar cc (intern (downcase (symbol-name (car cc))))))
- info-alist)
- (cl-macrolet
- ((key (k)
- `(alist-get ',k info-alist))
- (set-track-info (track &rest body)
- (cons 'progn
- (cl-loop for (k v)
- on body by 'cddr collect
- `(let ((value ,v))
- (when value
- (emms-track-set ,track ',(intern (format "info-%s" k))
- value)))))))
- (unless track (setq track (emms-playlist-current-selected-track)))
- (set-track-info track
- title (or (key title)
- (key icy-title))
- artist (or (key artist)
- (key album_artist)
- (key icy-name))
- album (key album)
- tracknumber (key track)
- year (key date)
- genre (key genre)
- note (key comment))
- (emms-track-updated track)))
-
-(defun emms-player-mpv-info-duration-event-func (json-data)
- "Hook function for `emms-player-mpv-event-functions' to update track duration from mpv."
- (when
- (string= (alist-get 'event json-data)
- "playback-restart")
- (emms-player-mpv-info-duration-check)))
-
-(defun emms-player-mpv-info-duration-check ()
- "Check whether current mpv track has reliable duration info and request it."
- (emms-player-mpv-ipc-req-send '(get_property stream-end)
- (lambda (pts-end err)
- (if err
- (unless (and (stringp err)
- (string= err "property unavailable"))
- (emms-player-mpv-ipc-req-error-printer pts-end err))
- (when pts-end
- (emms-player-mpv-ipc-req-send '(get_property duration)
- #'emms-player-mpv-info-duration-handler))))))
-
-(defun emms-player-mpv-info-duration-handler (duration err)
- "Duration property request handler to update it for current emms track."
- (if err
- (emms-player-mpv-debug-msg "duration-req-error: %s" err)
- ;; Duration can be nil or 0 for network streams, depending on version/stream
- (when (and (numberp duration)
- (> duration 0))
- (let
- ((duration (round duration))
- (track (emms-playlist-current-selected-track)))
- (emms-track-set track 'info-playing-time duration)
- (emms-track-set track 'info-playing-time-min (/ duration 60))
- (emms-track-set track 'info-playing-time-sec (% duration 60))))))
-
-
-;; ----- High-level EMMS interface
-
-(defun emms-player-mpv-cmd (cmd &optional handler)
- "Send mpv command to process/connection if both are running,
-or otherwise schedule start/connect and set
-`emms-player-mpv-ipc-start-track' for `emms-player-mpv-ipc-sentinel'."
- (setq emms-player-mpv-ipc-connect-command nil)
- (let ((proc (emms-player-mpv-ipc)))
- (if proc
- (if (emms-player-mpv-ipc-fifo-p)
- (emms-player-mpv-ipc-fifo-cmd cmd proc)
- (emms-player-mpv-ipc-req-send cmd handler proc))
- (setq emms-player-mpv-ipc-connect-command cmd))))
-
-(defmacro emms-player-mpv-cmd-prog (cmd &rest handler-body)
- "Macro around `emms-player-mpv-cmd' that creates
-handler callback (see `emms-player-mpv-ipc-req-send') from HANDLER-BODY forms,
-which have following bindings:
-- mpv-cmd for CMD.
-- mpv-data for response data (decoded json, nil if none).
-- mpv-error for response error (nil if no error, decoded json or 'connection-error)."
- `(emms-player-mpv-cmd ,cmd (apply-partially
- (lambda (mpv-cmd mpv-data mpv-error)
- ,@handler-body)
- ,cmd)))
-
-
-(defun emms-player-mpv-playable-p (track)
- (memq (emms-track-type track)
- '(file url streamlist playlist)))
-
-(defun emms-player-mpv-start-error-handler (mpv-cmd mpv-data mpv-error)
- "Playback-restart error handler for `emms-player-mpv-cmd',
-to restart/reconnect-to mpv and re-run MPV-CMD,
-if there was any issue when trying to start it initially."
- (if (eq mpv-error 'connection-error)
- ;; Reconnect and restart playback if current connection fails (e.g. mpv crash)
- (emms-player-mpv-cmd-prog
- (emms-player-mpv-cmd mpv-cmd)
- (emms-player-mpv-cmd `(set pause no)))
- (emms-player-mpv-cmd `(set pause no))))
-
-(defun emms-player-mpv-start (track)
- (setq emms-player-mpv-stopped nil)
- (emms-player-mpv-proc-playing nil)
- (let
- ((track-name (emms-track-get track 'name))
- (track-is-playlist (memq (emms-track-get track 'type)
- '(streamlist playlist))))
- (if (emms-player-mpv-ipc-fifo-p)
- (progn
- ;; ipc-stop is to clear any buffered commands
- (emms-player-mpv-ipc-stop)
- (emms-player-mpv-proc-init (if track-is-playlist "--playlist" "--")
- track-name)
- (emms-player-started emms-player-mpv))
- (let*
- ((start-cmd (list (if track-is-playlist 'loadlist 'loadfile)
- track-name 'replace))
- (start-func `(lambda ()
- (emms-player-mpv-cmd ',start-cmd
- (apply-partially 'emms-player-mpv-start-error-handler ',start-cmd)))))
- (if emms-player-mpv-ipc-stop-command
- (setq emms-player-mpv-ipc-stop-command start-func)
- (funcall start-func))))))
-
-(defun emms-player-mpv-stop ()
- (setq
- emms-player-mpv-stopped t
- emms-player-mpv-ipc-stop-command t)
- (emms-player-mpv-proc-playing nil)
- (emms-player-mpv-cmd `(stop))
- (emms-player-stopped))
-
-
-(defun emms-player-mpv-pause ()
- (emms-player-mpv-cmd `(set pause yes)))
-
-(defun emms-player-mpv-resume ()
- (emms-player-mpv-cmd `(set pause no)))
-
-(defun emms-player-mpv-seek (sec)
- (emms-player-mpv-cmd `(seek ,sec relative)))
-
-(defun emms-player-mpv-seek-to (sec)
- (emms-player-mpv-cmd `(seek ,sec absolute)))
-
-(emms-player-set emms-player-mpv 'pause #'emms-player-mpv-pause)
-(emms-player-set emms-player-mpv 'resume #'emms-player-mpv-resume)
-(emms-player-set emms-player-mpv 'seek #'emms-player-mpv-seek)
-(emms-player-set emms-player-mpv 'seek-to #'emms-player-mpv-seek-to)
-
-
-(provide 'emms-player-mpv)
-;;; emms-player-mpv.el ends here
diff --git a/lisp/emms-player-simple.el b/lisp/emms-player-simple.el
deleted file mode 100644
index fd93137..0000000
--- a/lisp/emms-player-simple.el
+++ /dev/null
@@ -1,210 +0,0 @@
-;;; emms-player-simple.el --- A generic simple player.
-
-;; Copyright (C) 2003, 2004, 2006, 2007, 2008,
-;; 2009 Free Software Foundation, Inc.
-
-;; Authors: Ulrik Jensen <terryp@daimi.au.dk>
-;; Jorgen Schäfer <forcer@forcix.cx>
-;; Keywords: emms, mpg321, ogg123
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; 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 is a simple player interface - if you have an external player
-;; that just expects the filename to play as an argument, this should
-;; be able to use it. See the define-emms-simple-player lines at the
-;; end of this file for examples.
-
-;; Add the following to your `emms-player-list':
-
-;; emms-player-mpg321
-;; emms-player-ogg123
-
-;;; Code:
-
-;; Version control
-(defvar emms-player-simple-version "0.2 $Revision: 1.26 $"
- "Simple player for EMMS version string.")
-;; $Id: emms-player-simple.el,v 1.26 2005/08/02 15:27:51 forcer Exp $
-
-(require 'emms)
-
-;; Customization
-
-(defmacro define-emms-simple-player (name types regex command &rest args)
- "Define a simple player with the use of `emms-define-player'.
-NAME is used to contruct the name of the function like
-emms-player-NAME. TYPES is a list of track types understood by
-this player. REGEX must be a regexp that matches the filenames
-the player can play. COMMAND specifies the command line arguement
-to call the player and ARGS are the command line arguements."
- (let ((group (intern (concat "emms-player-" (symbol-name name))))
- (command-name (intern (concat "emms-player-"
- (symbol-name name)
- "-command-name")))
- (parameters (intern (concat "emms-player-"
- (symbol-name name)
- "-parameters")))
- (player-name (intern (concat "emms-player-" (symbol-name name))))
- (start (intern (concat "emms-player-" (symbol-name name) "-start")))
- (stop (intern (concat "emms-player-" (symbol-name name) "-stop")))
- (playablep (intern (concat "emms-player-" (symbol-name name) "-playable-p"))))
- `(progn
- (defgroup ,group nil
- ,(concat "EMMS player for " command ".")
- :group 'emms-player
- :prefix ,(concat "emms-player-" (symbol-name name) "-"))
- (defcustom ,command-name ,command
- ,(concat "*The command name of " command ".")
- :type 'string
- :group ',group)
- (defcustom ,parameters ',args
- ,(concat "*The arguments to `" (symbol-name command-name) "'.")
- :type '(repeat string)
- :group ',group)
- (defcustom ,player-name (emms-player ',start ',stop ',playablep)
- ,(concat "*A player for EMMS.")
- :type '(cons symbol alist)
- :group ',group)
- (emms-player-set ,player-name 'regex ,regex)
- (emms-player-set ,player-name 'pause 'emms-player-simple-pause)
- (emms-player-set ,player-name 'resume 'emms-player-simple-resume)
- (defun ,start (track)
- "Start the player process."
- (emms-player-simple-start (emms-track-name track)
- ,player-name
- ,command-name
- ,parameters))
- (defun ,stop ()
- "Stop the player process."
- (emms-player-simple-stop))
- (defun ,playablep (track)
- "Return non-nil when we can play this track."
- (and (executable-find ,command-name)
- (memq (emms-track-type track) ,types)
- (string-match (emms-player-get ,player-name 'regex)
- (emms-track-name track)))))))
-
-;; Global variables
-(defvar emms-player-simple-process-name "emms-player-simple-process"
- "The name of the simple player process")
-
-(defun emms-player-simple-stop ()
- "Stop the currently playing process, if indeed there is one"
- (let ((process (get-process emms-player-simple-process-name)))
- (when process
- (kill-process process)
- (delete-process process))))
-
-;; Utility-functions
-(defun emms-player-simple-start (filename player cmdname params)
- "Starts a process playing FILENAME using the specified CMDNAME with
-the specified PARAMS.
-PLAYER is the name of the current player."
- (let ((process (apply 'start-process
- emms-player-simple-process-name
- nil
- cmdname
- ;; splice in params here
- (append params (list filename)))))
- ;; add a sentinel for signaling termination
- (set-process-sentinel process 'emms-player-simple-sentinel))
- (emms-player-started player))
-
-(defun emms-player-simple-sentinel (proc str)
- "Sentinel for determining the end of process"
- (when (or (eq (process-status proc) 'exit)
- (eq (process-status proc) 'signal))
- (emms-player-stopped)))
-
-(defun emms-player-simple-pause ()
- "Pause the player by sending a SIGSTOP."
- (signal-process (get-process emms-player-simple-process-name)
- 'SIGSTOP))
-
-(defun emms-player-simple-resume ()
- "Resume the player by sending a SIGCONT."
- (signal-process (get-process emms-player-simple-process-name)
- 'SIGCONT))
-
-(defun emms-player-simple-regexp (&rest extensions)
- "Return a regexp matching all EXTENSIONS, case-insensitively."
- (concat "\\.\\("
- (mapconcat (lambda (extension)
- (mapconcat (lambda (char)
- (let ((u (upcase char))
- (d (downcase char)))
- (if (= u d)
- (format "%c" char)
- (format "[%c%c]" u d))))
- extension
- ""))
- extensions
- "\\|")
- "\\)\\'"))
-
-(define-emms-simple-player mpg321 '(file url)
- (emms-player-simple-regexp "mp3" "mp2")
- "mpg321")
-(define-emms-simple-player ogg123 '(file)
- (emms-player-simple-regexp "ogg" "flac")
- "ogg123")
-(define-emms-simple-player speexdec '(file)
- (emms-player-simple-regexp "spx")
- "speexdec")
-(define-emms-simple-player playsound '(file)
- (emms-player-simple-regexp "wav")
- "playsound")
-(define-emms-simple-player mikmod '(file)
- (emms-player-simple-regexp "669" "amf" "dsm" "far" "gdm" "it"
- "imf" "mod" "med" "mtm" "okt" "s3m"
- "stm" "stx" "ult" "apun" "xm" "mod")
- "mikmod" "-q" "-p" "1" "-X")
-(define-emms-simple-player timidity '(file)
- (emms-player-simple-regexp "mid" "rmi" "rcp" "r36" "g18" "g36" "mfi")
- "timidity")
-(define-emms-simple-player fluidsynth '(file)
- (emms-player-simple-regexp "mid")
- "fluidsynth" "-aalsa" "-in" "/media/music/sf/FluidR3-GM.SF2")
-(define-emms-simple-player alsaplayer '(file url)
- (concat "\\`http[s]?://\\|"
- (emms-player-simple-regexp "ogg" "mp3" "wav" "flac" "pls" "m3u"))
- "alsaplayer" "--quiet" "--nosave" "\"--interface text\"")
-
-(emms-player-set emms-player-alsaplayer
- 'pause
- 'emms-player-alsaplayer-pause)
-
-;;; Pause is also resume for alsaplayer
-(emms-player-set emms-player-alsaplayer
- 'resume
- nil)
-
-(emms-player-set emms-player-alsaplayer
- 'seek
- 'emms-player-alsaplayer-seek)
-
-(defun emms-player-alsaplayer-pause ()
- (call-process "alsaplayer" nil nil nil "--pause"))
-
-(defun emms-player-alsaplayer-seek (sec)
- (call-process "alsaplayer" nil nil nil "--relative" (format "%d" sec)))
-
-(provide 'emms-player-simple)
-;;; emms-player-simple.el ends here
diff --git a/lisp/emms-player-vlc.el b/lisp/emms-player-vlc.el
deleted file mode 100644
index 7c2130d..0000000
--- a/lisp/emms-player-vlc.el
+++ /dev/null
@@ -1,85 +0,0 @@
-;;; emms-player-vlc.el --- vlc support for EMMS
-
-;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
-
-;; Authors: Yoni Rabkin <yrk@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'emms-compat)
-(require 'emms-player-simple)
-
-;; I use this macro, and later override some of the stuff it defines
-;; in order to accomodate VLC's particular idioms.
-(define-emms-simple-player vlc '(file url)
- (concat "\\`\\(http[s]?\\|mms\\)://\\|"
- (apply #'emms-player-simple-regexp
- emms-player-base-format-list))
- "vlc" "--intf=rc")
-
-(define-emms-simple-player vlc-playlist '(streamlist)
- "\\`http[s]?://"
- "vlc" "--intf=rc")
-
-;; (kludge) By default, VLC does not quit after finishing to play a
-;; track, so the player sentinel has no way of telling that the next
-;; track should be played. Therefore I redefine this low-level
-;; function and add a "quit" track which is invisible to Emms.
-(defadvice emms-player-vlc-start (around quit-vlc-after-finish activate)
- (let ((process (apply 'start-process
- emms-player-simple-process-name
- nil
- emms-player-vlc-command-name
- ;; splice in params here
- (append emms-player-vlc-parameters
- (list (emms-track-name (ad-get-arg 0)))
- '("vlc://quit")))))
- ;; add a sentinel for signaling termination
- (set-process-sentinel process 'emms-player-simple-sentinel))
- (emms-player-started emms-player-vlc))
-
-(defun emms-player-vlc-pause ()
- "Depends on vlc's rc mode."
- (process-send-string
- emms-player-simple-process-name "pause\n"))
-
-(defun emms-player-vlc-seek (sec)
- "Seek relative within a stream."
- (when (not (= 0 sec))
- (process-send-string
- emms-player-simple-process-name
- (if (< 0 sec) "fastforward\n" "rewind\n"))))
-
-(defun emms-player-vlc-seek-to (sec)
- "Seek to time SEC within the stream."
- (process-send-string
- emms-player-simple-process-name
- (format "seek %d\n" sec)))
-
-(emms-player-set emms-player-vlc 'pause 'emms-player-vlc-pause)
-(emms-player-set emms-player-vlc 'resume nil) ; pause is also resume
-(emms-player-set emms-player-vlc 'start 'emms-player-vlc-start)
-(emms-player-set emms-player-vlc 'seek 'emms-player-vlc-seek)
-(emms-player-set emms-player-vlc 'seek-to 'emms-player-vlc-seek-to)
-
-(provide 'emms-player-vlc)
-
-;;; emms-player-vlc.el ends here
diff --git a/lisp/emms-player-xine.el b/lisp/emms-player-xine.el
deleted file mode 100644
index 2fc60e7..0000000
--- a/lisp/emms-player-xine.el
+++ /dev/null
@@ -1,92 +0,0 @@
-;;; emms-player-xine.el --- xine support for EMMS
-
-;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Tassilo Horn <tassilo@member.fsf.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3
-;; of the License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; This provides a player that uses xine. It supports pause and
-;; seeking.
-
-;;; Code:
-
-;; TODO: The video window cannot be disabled. I asked on
-;; gmane.comp.video.xine.user (<87y7ohqcbq.fsf@baldur.tsdh.de>)...
-
-;; TODO: Implement seek-to with "SetPositionX%\n" where X is in {0,10,..,90}
-
-(require 'emms-player-simple)
-
-(define-emms-simple-player xine '(file url)
- (concat "\\`\\(http[s]?\\|mms\\)://\\|"
- (emms-player-simple-regexp
- "ogg" "mp3" "wav" "mpg" "mpeg" "wmv" "wma"
- "mov" "avi" "divx" "ogm" "ogv" "asf" "mkv"
- "rm" "rmvb" "mp4" "flac" "vob"))
- "xine" "--no-gui" "--no-logo" "--no-splash" "--no-reload" "--stdctl")
-
-(emms-player-set emms-player-xine
- 'pause
- 'emms-player-xine-pause)
-
-;;; Pause is also resume for xine
-(emms-player-set emms-player-xine
- 'resume
- nil)
-
-(emms-player-set emms-player-xine
- 'seek
- 'emms-player-xine-seek)
-
-(defun emms-player-xine-pause ()
- "Depends on xine's --stdctl mode."
- (process-send-string
- emms-player-simple-process-name "pause\n"))
-
-(defun emms-player-xine-seek (secs)
- "Depends on xine's --stdctl mode."
- ;; xine-ui's stdctl supports only seeking forward/backward in 7/15/30 and 60
- ;; second steps, so we take the value that is nearest to SECS.
- (let ((s (emms-nearest-value secs '(-60 -30 -15 -7 7 15 30 60))))
- (when (/= s secs)
- (message (concat "EMMS: Xine only supports seeking for [+/-] 7/15/30/60 "
- "seconds, so we seeked %d seconds") s))
- (process-send-string
- emms-player-simple-process-name
- (if (< s 0)
- (format "SeekRelative%d\n" s)
- (format "SeekRelative+%d\n" s)))))
-
-(defun emms-nearest-value (val list)
- "Returns the value of LIST which is nearest to VAL.
-
-LIST should be a list of integers."
- (let* ((nearest (car list))
- (dist (abs (- val nearest))))
- (dolist (lval (cdr list))
- (let ((ndist (abs (- val lval))))
- (when (< ndist dist)
- (setq nearest lval
- dist ndist))))
- nearest))
-
-
-(provide 'emms-player-xine)
-;;; emms-player-xine.el ends here
diff --git a/lisp/emms-playing-time.el b/lisp/emms-playing-time.el
deleted file mode 100644
index 8b14e16..0000000
--- a/lisp/emms-playing-time.el
+++ /dev/null
@@ -1,239 +0,0 @@
-;;; emms-playing-time.el --- Display emms playing time on mode line
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2019 Free Software Foundation, Inc.
-
-;; Author: William Xu <william.xwl@gmail.com>, Yoni Rabkin (yrk@gnu.org)
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; Display playing time on mode line, it looks like: 01:32/04:09.
-
-;; Put this file into your load-path and the following into your
-;; ~/.emacs:
-;; (require 'emms-playing-time)
-;; (emms-playing-time 1)
-
-;; Note: `(emms-playing-time -1)' will disable emms-playing-time module
-;; completely, and is not recommended. (since some other emms modules
-;; may rely on it, such as `emms-lastfm.el')
-
-;; Instead, to toggle displaying playing time on mode line, one could
-;; call `emms-playing-time-enable-display' and
-;; `emms-playing-time-disable-display'."
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'emms-info)
-(require 'emms-player-simple)
-
-;;; Customizations
-
-(defgroup emms-playing-time nil
- "Playing-time module for EMMS."
- :group 'emms)
-
-(defcustom emms-playing-time-display-short-p nil
- "Non-nil will only display elapsed time.
-e.g., display 02:37 instead of 02:37/05:49."
- :type 'boolean
- :group 'emms-playing-time)
-
-(defcustom emms-playing-time-display-format " %s "
- "Format used for displaying playing time."
- :type 'string
- :group 'emms-playing-time)
-
-(defcustom emms-playing-time-style 'time
- "Style used for displaying playing time.
-Valid styles are `time' (e.g., 01:30/4:20),
- `bar' (e.g., [===> ]),
-and `downtime' (e.g. -03:58)."
- :type 'symbol
- :group 'emms-playing-time)
-
-
-;;; Emms Playing Time
-
-(defvar emms-playing-time-display-p nil
- "Whether to display playing time on mode line or not")
-
-(defvar emms-playing-time 0
- "Time elapsed in current track.")
-
-(defvar emms-playing-time-string "")
-
-(defvar emms-playing-time-display-timer nil)
-
-(defvar emms-playing-time-p nil
- "Whether emms-playing-time module is enabled or not")
-
-(defun emms-playing-time-start ()
- "Get ready for display playing time."
- (setq emms-playing-time 0)
- (unless emms-playing-time-display-timer
- (setq emms-playing-time-display-timer
- (run-at-time t 1 'emms-playing-time-display))))
-
-(defun emms-playing-time-stop ()
- "Remove playing time on the mode line."
- (if (or (not emms-player-paused-p)
- emms-player-stopped-p)
- (progn
- (setq emms-playing-time-string "")
- (force-mode-line-update)))
- (emms-cancel-timer emms-playing-time-display-timer)
- (setq emms-playing-time-display-timer nil))
-
-(defun emms-playing-time-pause ()
- "Pause playing time."
- (if emms-player-paused-p
- (emms-playing-time-stop)
- (unless emms-playing-time-display-timer
- (setq emms-playing-time-display-timer
- (run-at-time t 1 'emms-playing-time-display)))))
-
-(defun emms-playing-time-seek (sec)
- "Seek forward or backward SEC playing time."
- (setq emms-playing-time (+ emms-playing-time sec))
- (when (< emms-playing-time 0) ; back to start point
- (setq emms-playing-time 0)))
-
-(defun emms-playing-time-set (sec)
- "Set the playing time to SEC."
- (setq emms-playing-time sec)
- (when (< emms-playing-time 0) ; back to start point
- (setq emms-playing-time 0)))
-
-(defun emms-playing-time (arg)
- "Turn on emms playing time if ARG is positive, off otherwise.
-
-Note: `(emms-playing-time -1)' will disable emms-playing-time
-module completely, and is not recommended. (since some other emms
-modules may rely on it, such as `emms-lastfm.el')
-
-Instead, to toggle displaying playing time on mode line, one
-could call `emms-playing-time-enable-display' and
-`emms-playing-time-disable-display'."
- (if (and arg (> arg 0))
- (progn
- (setq emms-playing-time-p t
- emms-playing-time-display-p t)
- (emms-playing-time-mode-line)
- (add-hook 'emms-player-started-hook 'emms-playing-time-start)
- (add-hook 'emms-player-stopped-hook 'emms-playing-time-stop)
- (add-hook 'emms-player-finished-hook 'emms-playing-time-stop)
- (add-hook 'emms-player-paused-hook 'emms-playing-time-pause)
- (add-hook 'emms-player-seeked-functions 'emms-playing-time-seek)
- (add-hook 'emms-player-time-set-functions 'emms-playing-time-set))
- (setq emms-playing-time-p nil
- emms-playing-time-display-p nil)
- (emms-playing-time-stop)
- (emms-playing-time-restore-mode-line)
- (remove-hook 'emms-player-started-hook 'emms-playing-time-start)
- (remove-hook 'emms-player-stopped-hook 'emms-playing-time-stop)
- (remove-hook 'emms-player-finished-hook 'emms-playing-time-stop)
- (remove-hook 'emms-player-paused-hook 'emms-playing-time-pause)
- (remove-hook 'emms-player-seeked-functions 'emms-playing-time-seek)
- (remove-hook 'emms-player-time-set-functions 'emms-playing-time-set)))
-
-;;;###autoload
-(defun emms-playing-time-enable-display ()
- "Display playing time on mode line."
- (interactive)
- (setq emms-playing-time-display-p t))
-
-;;;###autoload
-(defun emms-playing-time-disable-display ()
- "Remove playing time from mode line."
- (interactive)
- (setq emms-playing-time-display-p nil))
-
-(defun emms-playing-time-display ()
- "Display playing time on the mode line."
- (setq emms-playing-time (round (1+ emms-playing-time)))
- (setq emms-playing-time-string "")
- (when emms-playing-time-display-p
- (let* ((min (/ emms-playing-time 60))
- (sec (% emms-playing-time 60))
- (total-playing-time
- (or (emms-track-get
- (emms-playlist-current-selected-track)
- 'info-playing-time)
- 0))
- (total-min-only (/ total-playing-time 60))
- (total-sec-only (% total-playing-time 60)))
- (cl-case emms-playing-time-style
- ((downtime) ; `downtime' style
- (setq emms-playing-time-string
- (emms-replace-regexp-in-string
- " " "0"
- (if (or emms-playing-time-display-short-p
- ;; unable to get total playing-time
- (eq total-playing-time 0))
- (format "%2d:%2d" min sec)
- (format "-%2d:%2d"
- (/ (- total-playing-time emms-playing-time) 60)
- (% (- total-playing-time sec) 60))))))
- ((bar) ; `bar' style
- (if (zerop total-playing-time)
- (setq emms-playing-time-string "[==>........]")
- (let ((progress "[")
- ;; percent based on 10
- (percent (/ (* emms-playing-time 10) total-playing-time)))
- (dotimes (i percent)
- (setq progress (concat progress "=")))
- (setq progress (concat progress ">"))
- (dotimes (i (- 10 percent))
- (setq progress (concat progress " ")))
- (setq progress (concat progress "]"))
- (setq emms-playing-time-string progress))))
- (t ; `time' style
- (setq emms-playing-time-string
- (emms-replace-regexp-in-string
- " " "0"
- (if (or emms-playing-time-display-short-p
- ;; unable to get total playing-time
- (eq total-playing-time 0))
- (format "%2d:%2d" min sec)
- (format "%2d:%2d/%2s:%2s"
- min sec total-min-only total-sec-only))))))
- (setq emms-playing-time-string
- (format emms-playing-time-display-format
- emms-playing-time-string))))
- (force-mode-line-update))
-
-(defun emms-playing-time-mode-line ()
- "Add playing time to the mode line."
- (or global-mode-string (setq global-mode-string '("")))
- (unless (member 'emms-playing-time-string
- global-mode-string)
- (setq global-mode-string
- (append global-mode-string
- '(emms-playing-time-string)))))
-
-(defun emms-playing-time-restore-mode-line ()
- "Restore the mode line."
- (setq global-mode-string
- (remove 'emms-playing-time-string global-mode-string))
- (force-mode-line-update))
-
-(provide 'emms-playing-time)
-
-;;; emms-playing-time.el ends here
diff --git a/lisp/emms-playlist-limit.el b/lisp/emms-playlist-limit.el
deleted file mode 100644
index 91eff1e..0000000
--- a/lisp/emms-playlist-limit.el
+++ /dev/null
@@ -1,224 +0,0 @@
-;;; emms-playlist-limit.el --- Limit playlist by various info -*- lexical-binding: t -*-
-
-;; Copyright (C) 2018 Free Software Foundation, Inc.
-
-;; Author: William Xu <william.xwl@gmail.com>
-;; Author: Fran Burstall <fran.burstall@gmail.com>
-;; Keywords: emms, limit
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; 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 code allows you to "limit" a playlist in the current buffer
-;; by creating, and switching to, a derived playlist containing only
-;; those tracks with a type (info-artist and the like) matching a
-;; regexp.
-
-;; If the current buffer is the current playlist then the derived
-;; playlist is made current.
-
-;; Usage:
-;; ------------------------------------------------------------------
-
-;; This code is activated by (emms-all). Otherwise simply do:
-
-;; (require 'emms-playlist-limit)
-
-;; Key bindings
-;; ------------------------------------------------------------------
-
-;; / / emms-playlist-limit-to-all
-;; / a emms-playlist-limit-to-info-artist
-;; / b emms-playlist-limit-to-info-album
-;; / c emms-playlist-limit-to-info-composer
-;; / d emms-playlist-limit-to-description
-;; / g emms-playlist-limit-to-info-genre
-;; / n emms-playlist-limit-to-name
-;; / p emms-playlist-limit-to-info-performer
-;; / t emms-playlist-limit-to-info-title
-;; / y emms-playlist-limit-to-info-year
-
-;;; Code:
-
-(require 'seq)
-(require 'emms-playlist-mode)
-
-;; User Interfaces
-
-(defgroup emms-playlist-limit nil
- "Playlist limit module for EMMS."
- :group 'emms)
-
-(defcustom emms-playlist-limit-hook nil
- "Hooks to run after each limit operation."
- :type 'symbol
- :group 'emms-playlist-limit)
-
-(defmacro define-emms-playlist-limit (attribute)
- "Macro for defining emms playlist limit to ATTRIBUTE function."
- `(defun ,(intern (format "emms-playlist-limit-to-%s" attribute)) (regexp)
- ,(format "Switch to a playlist comprising tracks with %s matching REGEXP.
-
-REGEXP defaults to the value of %s for the track at point.
-
-When the current buffer is the current playlist, make the derived playlist
-the current playlist." attribute attribute)
- (interactive
- (list
- (let* ((curr
- (or (emms-playlist-limit-track-get
- (or (emms-playlist-track-at)
- (emms-playlist-track-at (max 1 (1- (point))))) ; at eol
- (quote ,attribute))
- (emms-playlist-limit-track-get
- (emms-playlist-selected-track) (quote ,attribute))))
- (attr-name ,(emms-replace-regexp-in-string
- "info-" "" (symbol-name attribute)))
- (fmt (if curr
- (format "Limit to %s (regexp = %s): " attr-name curr)
- (format "Limit to %s (regexp): " attr-name))))
- (read-string fmt))))
- (when (string= regexp "")
- (setq regexp (or (emms-playlist-limit-track-get
- (or (emms-playlist-track-at)
- (emms-playlist-track-at (max 1 (1- (point))))) ; at eol
- (quote ,attribute))
- (emms-playlist-limit-track-get
- (emms-playlist-selected-track) (quote ,attribute)))))
- (if regexp
- (emms-playlist-limit-do (quote ,attribute) regexp)
- (message "Limit cancelled: no regexp."))))
-
-(define-emms-playlist-limit info-artist)
-(define-emms-playlist-limit info-composer)
-(define-emms-playlist-limit info-performer)
-(define-emms-playlist-limit info-title)
-(define-emms-playlist-limit info-album)
-(define-emms-playlist-limit info-year)
-(define-emms-playlist-limit info-genre)
-(define-emms-playlist-limit name)
-(define-emms-playlist-limit description)
-
-(defvar-local emms-playlist-limit--original-playlist nil
- "Playlist buffer from which we derive the limited playlist.")
-
-(defun emms-playlist-limit-to-all ()
- "Switch to playlist from which this playlist was derived (if it still exists)
-and bury this playlist.
-
-If this playlist is current, make the playlist we switch to current."
- (interactive)
- (when (and emms-playlist-limit--original-playlist
- (buffer-live-p emms-playlist-limit--original-playlist))
- (let* ((old-buf (current-buffer))
- (old-buf-is-current-playlist (eq old-buf emms-playlist-buffer)))
- (switch-to-buffer emms-playlist-limit--original-playlist)
- (when old-buf-is-current-playlist
- (emms-playlist-set-playlist-buffer))
- (bury-buffer old-buf))))
-
-(define-key emms-playlist-mode-map (kbd "/ n") 'emms-playlist-limit-to-name)
-(define-key emms-playlist-mode-map (kbd "/ a") 'emms-playlist-limit-to-info-artist)
-(define-key emms-playlist-mode-map (kbd "/ c") 'emms-playlist-limit-to-info-composer)
-(define-key emms-playlist-mode-map (kbd "/ p") 'emms-playlist-limit-to-info-performer)
-(define-key emms-playlist-mode-map (kbd "/ t") 'emms-playlist-limit-to-info-title)
-(define-key emms-playlist-mode-map (kbd "/ b") 'emms-playlist-limit-to-info-album)
-(define-key emms-playlist-mode-map (kbd "/ y") 'emms-playlist-limit-to-info-year)
-(define-key emms-playlist-mode-map (kbd "/ g") 'emms-playlist-limit-to-info-genre)
-(define-key emms-playlist-mode-map (kbd "/ d") 'emms-playlist-limit-to-description)
-(define-key emms-playlist-mode-map (kbd "/ /") 'emms-playlist-limit-to-all)
-
-
-;;; Low Level Functions
-
-(defun emms-playlist-limit-track-get (track type)
- "Return the value of TYPE from TRACK.
-
-Here TYPE is a field available to `emms-track-get' or
-'description which gives the result of
-`emms-track-description-function'.
-
-When type is 'info-year, also tries 'info-originalyear,
- 'info-originaldate and 'info-date to get a usable date."
- (cond ((eq type 'info-year)
- (let ((date (or (emms-track-get track 'info-originaldate)
- (emms-track-get track 'info-originalyear)
- (emms-track-get track 'info-date)
- (emms-track-get track 'info-year))))
- (or (emms-format-date-to-year date)
- "<unknown year>")))
- ((eq type 'description) (funcall emms-track-description-function track))
- (t (emms-track-get track type))))
-
-(defun emms-playlist-limit--derive-playlist (playlist pred name)
- "Return a new playlist NAME of tracks in PLAYLIST for which (PRED track)
-is non-nil."
- (let* ((tracks (nreverse (with-current-buffer playlist
- (save-excursion (emms-playlist-tracks-in-region (point-min) (point-max))))))
- (filtered-tracks (seq-filter pred tracks))
- (new-playlist (or (get-buffer name)
- (emms-playlist-new name))))
- (with-current-buffer new-playlist
- (emms-with-inhibit-read-only-t (erase-buffer))
- (mapc #'emms-playlist-insert-track filtered-tracks))
- new-playlist))
-
-(defun emms-playlist-limit--limit-playlist (playlist type regexp)
- "Return a new playlist of tracks in PLAYLIST with TYPE matching REGEXP."
- (let* ((bufname (concat (buffer-name playlist)
- (format "/%s=%s"
- (emms-replace-regexp-in-string "info-" "" (symbol-name type)) regexp))))
- (emms-playlist-limit--derive-playlist
- playlist
- `(lambda (track) (let ((field (emms-playlist-limit-track-get track (quote ,type))))
- (and field (string-match ,regexp field))))
- bufname)))
-
-
-
-(defun emms-playlist-limit-do (type regexp)
- "Switch to a derived playlist containing the tracks with TYPE matching REGEXP.
-e.g.,
- (emms-playlist-limit-do 'info-artist \"Jane Zhang\")
-
-See `emms-info-mp3find-arguments' for possible options for TYPE."
- (emms-playlist-ensure-playlist-buffer)
- (let* ((curr (emms-playlist-selected-track))
- (old-buf (current-buffer))
- (old-buf-is-current-playlist (eq old-buf emms-playlist-buffer))
- (buf (emms-playlist-limit--limit-playlist old-buf type regexp)))
- (with-current-buffer buf
- (if (= (point-min) (point-max))
- (progn
- (message "No matching tracks found!")
- (kill-buffer))
- (let ((pos (when curr (text-property-any (point-min) (point-max)
- 'emms-track curr))))
- (if pos
- (emms-playlist-select pos)
- (emms-playlist-select-first)))
- (emms-playlist-mode-center-current)
- (setq emms-playlist-limit--original-playlist old-buf)
- (when old-buf-is-current-playlist
- (emms-playlist-set-playlist-buffer))
- (run-hooks 'emms-playlist-limit-hook)
- (switch-to-buffer buf)))))
-
-
-(provide 'emms-playlist-limit)
-
-;;; emms-playlist-limit.el ends here
diff --git a/lisp/emms-playlist-mode.el b/lisp/emms-playlist-mode.el
deleted file mode 100644
index 6979b79..0000000
--- a/lisp/emms-playlist-mode.el
+++ /dev/null
@@ -1,614 +0,0 @@
-;;; emms-playlist-mode.el --- Playlist mode for Emms.
-
-;; Copyright (C) 2005-2019 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-;;;
-;;; This is a method of displaying and manipulating the different Emms
-;;; playlist buffers.
-;;;
-;;; Emms developer's motto: "When forcer says (require 'jump) we say
-;;; (funcall #'jump height)"
-
-;;; Code:
-
-;;; --------------------------------------------------------
-;;; Variables
-;;; --------------------------------------------------------
-
-(require 'emms)
-(condition-case nil
- (require 'overlay)
- (error nil))
-(require 'emms-source-playlist)
-
-(defvar emms-playlist-mode-hook nil
- "Emms playlist mode hook.")
-
-(defvar emms-playlist-mode-selected-overlay nil
- "Last selected track. Use for updating the display.")
-
-(defvar emms-playlist-mode-switched-buffer nil
- "Last buffer visited before calling `emms-playlist-mode-switch-buffer'.")
-
-(defvar emms-playlist-mode-popup-enabled nil
- "True when the playlist was called as a popup window.")
-
-(defvar emms-playlist-mode-kill-whole-line-p t
- "When true line kills behave like a typical music player.")
-
-(make-variable-buffer-local
- 'emms-playlist-mode-selected-overlay)
-
-(defgroup emms-playlist-mode nil
- "*The Emacs Multimedia System playlist mode."
- :prefix "emms-playlist-mode-"
- :group 'emms)
-
-(defcustom emms-playlist-mode-open-playlists nil
- "*Determine whether to open playlists in a new EMMS buffer on RET.
-This is useful if you have a master playlist buffer that is
-composed of other playlists."
- :type 'boolean
- :group 'emms-playlist-mode)
-
-(defcustom emms-playlist-mode-window-width 25
- "*Determine the width of the Emms popup window.
-The value should a positive integer."
- :type 'integer
- :group 'emms-playlist-mode)
-
-(defcustom emms-playlist-mode-center-when-go nil
- "*Determine whether to center on the currently selected track.
-This is true for every invocation of `emms-playlist-mode-go'."
- :type 'boolean
- :group 'emms-playlist-mode)
-
-;;; --------------------------------------------------------
-;;; Faces
-;;; --------------------------------------------------------
-
-(defface emms-playlist-track-face
- '((((class color) (background dark))
- (:foreground "DarkSeaGreen"))
- (((class color) (background light))
- (:foreground "Blue"))
- (((type tty) (class mono))
- (:inverse-video t))
- (t (:background "Blue")))
- "Face for the tracks in a playlist buffer."
- :group 'emms-playlist-mode)
-
-(defface emms-playlist-selected-face
- '((((class color) (background dark))
- (:foreground "SteelBlue3"))
- (((class color) (background light))
- (:background "blue3" :foreground "white"))
- (((type tty) (class mono))
- (:inverse-video t))
- (t (:background "blue3")))
- "Face for highlighting the selected track."
- :group 'emms-playlist-mode)
-
-;;; --------------------------------------------------------
-;;; Keys
-;;; --------------------------------------------------------
-
-(defvar emms-playlist-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map text-mode-map)
- (define-key map (kbd "C-x C-s") 'emms-playlist-save)
- (define-key map (kbd "C-y") 'emms-playlist-mode-yank)
- (define-key map (kbd "C-k") 'emms-playlist-mode-kill-track)
- (define-key map (kbd "C-w") 'emms-playlist-mode-kill)
- (define-key map (kbd "C-_") 'emms-playlist-mode-undo)
- (define-key map (kbd "C-/") 'emms-playlist-mode-undo)
- (define-key map (kbd "C-x u") 'emms-playlist-mode-undo)
- (define-key map (kbd "C-n") 'next-line)
- (define-key map (kbd "C-p") 'previous-line)
- (define-key map (kbd "C-j") 'emms-playlist-mode-insert-newline)
- (define-key map (kbd "M-y") 'emms-playlist-mode-yank-pop)
- (define-key map (kbd "M-<") 'emms-playlist-mode-first)
- (define-key map (kbd "M->") 'emms-playlist-mode-last)
- (define-key map (kbd "M-n") 'emms-playlist-mode-next)
- (define-key map (kbd "M-p") 'emms-playlist-mode-previous)
- (define-key map (kbd "a") 'emms-playlist-mode-add-contents)
- (define-key map (kbd "b") 'emms-playlist-set-playlist-buffer)
- (define-key map (kbd "D") 'emms-playlist-mode-kill-track)
- (define-key map (kbd "n") 'emms-next)
- (define-key map (kbd "p") 'emms-previous)
- (define-key map (kbd "SPC") 'scroll-up)
- (define-key map (kbd ">") 'emms-seek-forward)
- (define-key map (kbd "<") 'emms-seek-backward)
- (define-key map (kbd "P") 'emms-pause)
- (define-key map (kbd "s") 'emms-stop)
- (define-key map (kbd "f") 'emms-show)
- (define-key map (kbd "c") 'emms-playlist-mode-center-current)
- (define-key map (kbd "q") 'emms-playlist-mode-bury-buffer)
- (define-key map (kbd "K") 'emms-playlist-mode-current-kill)
- (define-key map (kbd "?") 'describe-mode)
- (define-key map (kbd "r") 'emms-random)
- (define-key map (kbd "C") 'emms-playlist-clear)
- (define-key map (kbd "d") 'emms-playlist-mode-goto-dired-at-point)
- (define-key map (kbd "<mouse-2>") 'emms-playlist-mode-play-current-track)
- (define-key map (kbd "RET") 'emms-playlist-mode-play-smart)
- map)
- "Keymap for `emms-playlist-mode'.")
-
-(defmacro emms-playlist-mode-move-wrapper (name fun)
- "Create a function NAME which is an `interactive' version of FUN.
-
-NAME should be a symbol.
-FUN should be a function."
- `(defun ,name ()
- ,(format "Interactive wrapper around `%s' for playlist-mode."
- fun)
- (interactive)
- (,fun)))
-
-(emms-playlist-mode-move-wrapper emms-playlist-mode-first
- emms-playlist-first)
-
-(emms-playlist-mode-move-wrapper emms-playlist-mode-select-next
- emms-playlist-next)
-
-(emms-playlist-mode-move-wrapper emms-playlist-mode-select-previous
- emms-playlist-previous)
-
-(defun emms-playlist-mode-bury-buffer ()
- "Wrapper around `bury-buffer' for popup windows."
- (interactive)
- (if emms-playlist-mode-popup-enabled
- (unwind-protect
- (delete-window)
- (setq emms-playlist-mode-popup-enabled nil))
- (bury-buffer)))
-
-(defun emms-playlist-mode-current-kill ()
- "If the current buffer is an EMMS playlist buffer, kill it.
-Otherwise, kill the current EMMS playlist buffer."
- (interactive)
- (if (and emms-playlist-buffer-p
- (not (eq (current-buffer) emms-playlist-buffer)))
- (kill-buffer (current-buffer))
- (emms-playlist-current-kill)))
-
-(defun emms-playlist-mode-last ()
- "Move to directly after the last track in the current buffer."
- (interactive)
- (emms-playlist-ensure-playlist-buffer)
- (let ((last (condition-case nil
- (save-excursion
- (goto-char (point-max))
- (point))
- (error
- nil))))
- (if last
- (goto-char last)
- (error "No last track"))))
-
-(defun emms-playlist-mode-center-current ()
- "Move point to the currently selected track."
- (interactive)
- (goto-char (if emms-playlist-mode-selected-overlay
- (overlay-start emms-playlist-mode-selected-overlay)
- (point-min))))
-
-(defun emms-playlist-mode-play-current-track ()
- "Start playing track at point."
- (interactive)
- (emms-playlist-set-playlist-buffer (current-buffer))
- (unless (emms-playlist-track-at (point))
- (emms-playlist-next))
- (emms-playlist-select (point))
- (when emms-player-playing-p
- (emms-stop))
- (emms-start))
-
-(defun emms-playlist-mode-play-smart ()
- "Determine the best operation to take on the current track.
-
-If on a playlist, and `emms-playlist-mode-open-playlists' is
-non-nil, load the playlist at point into a new buffer.
-
-Otherwise play the track immediately."
- (interactive)
- (save-excursion
- ;; move to the start of the line, in case the point is on the \n,
- ;; which isn't propertized
- (emms-move-beginning-of-line nil)
- (if (not emms-playlist-mode-open-playlists)
- (emms-playlist-mode-play-current-track)
- (unless (emms-playlist-track-at)
- (emms-playlist-next))
- (let* ((track (emms-playlist-track-at))
- (name (emms-track-get track 'name))
- (type (emms-track-get track 'type)))
- (if (or (eq type 'playlist)
- (and (eq type 'file)
- (string-match "\\.\\(m3u\\|pls\\)\\'" name)))
- (emms-playlist-mode-load-playlist)
- (emms-playlist-mode-play-current-track))))))
-
-(defun emms-playlist-mode-switch-buffer ()
- "Switch to the playlist buffer and then switch back if called again.
-
-This function switches to the current Emms playlist buffer and
-remembers the buffer switched from. When called again the
-function switches back to the remembered buffer."
- (interactive)
- (if (eq (current-buffer)
- emms-playlist-buffer)
- (switch-to-buffer emms-playlist-mode-switched-buffer)
- (setq emms-playlist-mode-switched-buffer (current-buffer))
- (switch-to-buffer emms-playlist-buffer)))
-
-(defun emms-playlist-mode-insert-newline ()
- "Insert a newline at point."
- (interactive)
- (emms-with-inhibit-read-only-t
- (newline)))
-
-(defun emms-playlist-mode-undo ()
- "Wrapper around `undo'."
- (interactive)
- (emms-with-inhibit-read-only-t
- (undo)))
-
-(defun emms-playlist-mode-add-contents ()
- "Add files in the playlist at point to the current playlist buffer.
-
-If we are in the current playlist, make a new playlist buffer and
-set it as current."
- (interactive)
- (save-excursion
- (emms-move-beginning-of-line nil)
- (unless (emms-playlist-track-at)
- (emms-playlist-next))
- (let* ((track (emms-playlist-track-at))
- (name (emms-track-get track 'name))
- (type (emms-track-get track 'type))
- (playlist-p (or (eq type 'playlist)
- (and (eq type 'file)
- (save-match-data
- (string-match "\\.\\(m3u\\|pls\\)\\'"
- name))))))
- (emms-playlist-select (point))
- (unless (and (buffer-live-p emms-playlist-buffer)
- (not (eq (current-buffer) emms-playlist-buffer)))
- (setq emms-playlist-buffer
- (emms-playlist-set-playlist-buffer (emms-playlist-new))))
- (with-current-emms-playlist
- (goto-char (point-max))
- (when playlist-p
- (insert (emms-track-force-description track) "\n"))
- (let ((beg (point)))
- (if playlist-p
- (emms-add-playlist name)
- (let ((func (intern (concat "emms-add-" (symbol-name type)))))
- (if (functionp func)
- (funcall func name)
- ;; fallback
- (emms-add-file name))))
- (when playlist-p
- (goto-char (point-max))
- (while (progn
- (forward-line -1)
- (>= (point) beg))
- (insert " ")))
- (goto-char (point-min))
- (message "Added %s" (symbol-name type)))))))
-
-(defun emms-playlist-mode-goto-dired-at-point ()
- "Visit the track at point in a `dired' buffer."
- (interactive)
- (let ((track (emms-playlist-track-at)))
- (if track
- (let ((name (emms-track-get track 'name))
- (type (emms-track-get track 'type)))
- (if (eq type 'file)
- (dired (file-name-directory name))
- (error "Can't visit this track type in Dired")))
- (error "No track at point"))))
-
-;;; --------------------------------------------------------
-;;; Killing and yanking
-;;; --------------------------------------------------------
-
-(defun emms-playlist-mode-between-p (p a b)
- "Return t if P is a point between points A and B."
- (and (<= a p)
- (<= p b)))
-
-;; D
-(defun emms-playlist-mode-kill-entire-track ()
- "Kill track at point, including newline."
- (interactive)
- (let ((kill-whole-line t))
- (emms-playlist-mode-kill-track)))
-
-;; C-k
-(defun emms-playlist-mode-kill-track ()
- "Kill track at point."
- (interactive)
- (emms-with-inhibit-read-only-t
- (let ((track (emms-playlist-track-at)))
- (when track
- (let ((track-region (emms-property-region (point)
- 'emms-track)))
- (when (and emms-player-playing-p
- (emms-playlist-selected-track-at-p))
- (emms-stop)
- (delete-overlay emms-playlist-mode-selected-overlay)
- (setq emms-playlist-mode-selected-overlay nil))))
- (let ((kill-whole-line emms-playlist-mode-kill-whole-line-p))
- (goto-char (point-at-bol))
- (kill-line)))))
-
-;; C-w
-(defun emms-playlist-mode-kill ()
- "Kill from mark to point."
- (interactive)
- (emms-with-inhibit-read-only-t
- ;; Are we killing the playing/selected track?
- (when (and (markerp emms-playlist-selected-marker)
- (emms-playlist-mode-between-p
- (marker-position emms-playlist-selected-marker)
- (region-beginning)
- (region-end)))
- (emms-stop)
- (delete-overlay emms-playlist-mode-selected-overlay)
- (setq emms-playlist-mode-selected-overlay nil))
- (kill-region (region-beginning)
- (region-end))))
-
-(defun emms-playlist-mode-correct-previous-yank ()
- "Fix the previous yank if needed."
- (when (and (< (point-at-bol) (point))
- (< (point) (point-at-eol)))
- (newline)))
-
-;; C-y
-(defun emms-playlist-mode-yank ()
- "Yank into the playlist buffer."
- (interactive)
- (emms-with-inhibit-read-only-t
- (goto-char (point-at-bol))
- (yank)
- (emms-playlist-mode-correct-previous-yank)))
-
-;; M-y
-(defun emms-playlist-mode-yank-pop ()
- "Cycle through the kill-ring."
- (interactive)
- (emms-with-inhibit-read-only-t
- (yank-pop nil)
- (emms-playlist-mode-correct-previous-yank)))
-
-;;; --------------------------------------------------------
-;;; Overlay
-;;; --------------------------------------------------------
-
-(defun emms-playlist-mode-overlay-selected ()
- "Place an overlay over the currently selected track."
- (when emms-playlist-selected-marker
- (save-excursion
- (goto-char emms-playlist-selected-marker)
- (let ((reg (emms-property-region (point) 'emms-track)))
- (if emms-playlist-mode-selected-overlay
- (move-overlay emms-playlist-mode-selected-overlay
- (car reg)
- (cdr reg))
- (setq emms-playlist-mode-selected-overlay
- (make-overlay (car reg)
- (cdr reg)
- nil t nil))
- (overlay-put emms-playlist-mode-selected-overlay
- 'face 'emms-playlist-selected-face)
- (overlay-put emms-playlist-mode-selected-overlay
- 'evaporate t))))))
-
-;;; --------------------------------------------------------
-;;; Saving/Restoring
-;;; --------------------------------------------------------
-
-(defun emms-playlist-mode-open-buffer (filename)
- "Opens a previously saved playlist buffer.
-
-It creates a buffer called \"filename\", and restores the contents
-of the saved playlist inside."
- (interactive "fFile: ")
- (let* ((s)
- (buffer (get-buffer-create filename))
- (name (buffer-name buffer)))
- (with-current-buffer buffer
- (emms-insert-file-contents filename)
- (setq s (read (buffer-string))))
- (kill-buffer buffer)
- (with-current-buffer (emms-playlist-new name)
- (emms-with-inhibit-read-only-t
- (insert s)
- (goto-char (point-min))
- (emms-walk-tracks
- (emms-playlist-update-track)))
- (emms-playlist-first)
- (emms-playlist-select (point))
- (switch-to-buffer (current-buffer)))))
-
-(defun emms-playlist-mode-load-playlist ()
- "Load the playlist into a new EMMS buffer.
-This preserves the current EMMS buffer."
- (interactive)
- (let* ((track (emms-playlist-track-at))
- (name (emms-track-get track 'name))
- (type (emms-track-get track 'type)))
- (emms-playlist-select (point))
- (run-hooks 'emms-player-stopped-hook)
- (switch-to-buffer
- (emms-playlist-set-playlist-buffer (emms-playlist-new)))
- (emms-add-playlist name)))
-
-;;; --------------------------------------------------------
-;;; Local functions
-;;; --------------------------------------------------------
-
-(defun emms-playlist-mode-insert-track (track &optional no-newline)
- "Insert the description of TRACK at point.
-When NO-NEWLINE is non-nil, do not insert a newline after the track."
- (emms-playlist-ensure-playlist-buffer)
- (emms-with-inhibit-read-only-t
- (insert (emms-propertize (emms-track-force-description track)
- 'emms-track track
- 'face 'emms-playlist-track-face))
- (when (emms-playlist-selected-track-at-p)
- (emms-playlist-mode-overlay-selected))
- (unless no-newline
- (insert "\n"))))
-
-(defun emms-playlist-mode-update-track-function ()
- "Update the track display at point."
- (emms-playlist-ensure-playlist-buffer)
- (emms-with-inhibit-read-only-t
- (let ((track-region (emms-property-region (point)
- 'emms-track))
- (track (get-text-property (point)
- 'emms-track))
- (selectedp (emms-playlist-selected-track-at-p)))
- (save-excursion
- (delete-region (car track-region)
- (cdr track-region))
- (when selectedp
- (delete-overlay emms-playlist-mode-selected-overlay)
- (setq emms-playlist-mode-selected-overlay nil))
- (emms-playlist-mode-insert-track track t))
- (when selectedp
- (emms-playlist-select (point))))))
-
-;;; --------------------------------------------------------
-;;; Entry
-;;; --------------------------------------------------------
-
-(defun emms-playlist-mode-go ()
- "Switch to the current emms-playlist buffer and use emms-playlist-mode."
- (interactive)
- (if (or (null emms-playlist-buffer)
- (not (buffer-live-p emms-playlist-buffer)))
- (error "No current Emms buffer")
- (switch-to-buffer emms-playlist-buffer)
- (when (and (not (eq major-mode 'emms-playlist-mode))
- emms-playlist-buffer-p)
- (emms-playlist-mode))
- (when emms-playlist-mode-center-when-go
- (emms-playlist-mode-center-current))))
-
-(defun emms ()
- "Switch to the current emms-playlist buffer, use
-emms-playlist-mode and query for a directory tree to add to the
-playlist."
- (interactive)
- (if (or (null emms-playlist-buffer)
- (not (buffer-live-p emms-playlist-buffer)))
- (call-interactively 'emms-add-directory))
- (emms-playlist-mode-go))
-
-(defun emms-playlist-mode-go-popup (&optional window-width)
- "Popup emms-playlist buffer as a side window.
-
-Default value for WINDOW-WIDTH is `emms-playlist-mode-window-width'.
-WINDOW-WIDTH should be a positive integer."
- (interactive)
- (setq emms-playlist-mode-window-width
- (round (or window-width emms-playlist-mode-window-width)))
- (split-window-horizontally (- emms-playlist-mode-window-width))
- (other-window 1)
- (emms-playlist-mode-go)
- (setq emms-playlist-mode-popup-enabled t))
-
-(defun emms-playlist-mode-next (arg)
- "Navigate between playlists."
- (interactive "p")
- (let ((playlists (emms-playlist-buffer-list))
- bufs idx)
- (if playlists
- ;; if not in playlist mode, switch to emms-playlist-buffer
- (if (not (member (current-buffer) playlists))
- (switch-to-buffer (if (and emms-playlist-buffer
- (buffer-live-p emms-playlist-buffer))
- emms-playlist-buffer
- (car playlists)))
- (setq bufs (member (current-buffer) playlists))
- (setq idx
- (+ (- (length playlists) (length bufs))
- (if (> arg 0) 1 -1)))
- (switch-to-buffer (nth (mod idx (length playlists)) playlists)))
- (message "No playlist found!"))))
-(defun emms-playlist-mode-previous (arg)
- (interactive "p")
- (emms-playlist-mode-next (- arg)))
-
-(defun emms-playlist-mode-startup ()
- "Instigate emms-playlist-mode on the current buffer."
- ;; when there is neither a current emms track or a playing one...
- (when (not (or emms-playlist-selected-marker
- emms-player-playing-p))
- ;; ...then stop the player.
- (emms-stop)
- ;; why select the first track?
- (when emms-playlist-buffer-p
- (emms-playlist-select-first)))
- ;; when there is a selected track.
- (when emms-playlist-selected-marker
- (emms-playlist-mode-overlay-selected))
- (emms-with-inhibit-read-only-t
- (add-text-properties (point-min)
- (point-max)
- '(face emms-playlist-track-face)))
- (setq buffer-read-only t)
- (setq truncate-lines t)
- (setq buffer-undo-list nil))
-
-;;;###autoload
-(defun emms-playlist-mode ()
- "A major mode for Emms playlists.
-\\{emms-playlist-mode-map}"
- (interactive)
- (let ((val emms-playlist-buffer-p))
- (kill-all-local-variables)
- (setq emms-playlist-buffer-p val))
-
- (use-local-map emms-playlist-mode-map)
- (setq major-mode 'emms-playlist-mode
- mode-name "EMMS")
-
- (setq emms-playlist-insert-track-function
- 'emms-playlist-mode-insert-track)
- (setq emms-playlist-update-track-function
- 'emms-playlist-mode-update-track-function)
- (add-hook 'emms-playlist-selection-changed-hook
- 'emms-playlist-mode-overlay-selected)
-
- (emms-playlist-mode-startup)
-
- (run-hooks 'emms-playlist-mode-hook))
-
-(provide 'emms-playlist-mode)
-
-;;; emms-playlist-mode.el ends here
diff --git a/lisp/emms-playlist-sort.el b/lisp/emms-playlist-sort.el
deleted file mode 100644
index e23604b..0000000
--- a/lisp/emms-playlist-sort.el
+++ /dev/null
@@ -1,228 +0,0 @@
-;;; emms-playlist-sort.el --- sort emms playlist
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2018 Free Software Foundation, Inc.
-
-;; Author: William Xu <william.xwl@gmail.com>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'emms-last-played)
-(require 'emms-playlist-mode)
-
-;;; User Customizations
-
-(defgroup emms-playlist-sort nil
- "Sorting Emacs Multimedia System playlists."
- :prefix "emms-playlist-sort-"
- :group 'emms)
-
-(defcustom emms-playlist-sort-list '(info-artist info-album)
- "Sorting list used by `emms-playlist-sort-by-list'.
-Currently it understands the following fields: name info-artist
-imfo-composer info-performer info-title info-album info-genre
-info-playing-time info-tracknumber info-discnumber."
- :type 'symbol
- :group 'emms-playlist-sort)
-
-(defcustom emms-playlist-sort-prefix "S"
- "Prefix key sequence for `emms-playlist-sort-map'.
-Remember to call `emms-playlist-sort-map-setup' if you modify it."
- :type 'string
- :group 'emms-playlist-sort)
-
-
-;;; User Interfaces
-
-(defmacro define-emms-playlist-sort (attribute)
- "Macro for defining emms playlist sort functions on strings ."
- `(defun ,(intern (format "emms-playlist-sort-by-%s" attribute)) ()
- ,(format "Sort emms playlist by %s, increasingly.
-With a prefix argument, decreasingly." attribute)
- (interactive)
- (emms-playlist-sort
- '(lambda (a b)
- (funcall
- (if current-prefix-arg 'emms-string> 'emms-string<)
- (emms-track-get a (quote ,attribute))
- (emms-track-get b (quote ,attribute)))))))
-
-(define-emms-playlist-sort name)
-(define-emms-playlist-sort info-artist)
-(define-emms-playlist-sort info-composer)
-(define-emms-playlist-sort info-performer)
-(define-emms-playlist-sort info-title)
-(define-emms-playlist-sort info-album)
-(define-emms-playlist-sort info-year)
-(define-emms-playlist-sort info-note)
-
-(defun emms-playlist-sort-by-natural-order ()
- "Sort emms playlist by natural order.
-See `emms-sort-natural-order-less-p'."
- (interactive)
- (emms-playlist-sort 'emms-sort-natural-order-less-p))
-
-(defun emms-playlist-sort-by-list ()
- "Sort emms playlist by `emms-playlist-sort-list'.
-The sort will be carried out until comparsion succeeds, increasingly."
- (interactive)
- (emms-playlist-sort 'emms-playlist-sort-by-list-p))
-
-(defun emms-playlist-sort-by-last-played ()
- "Sort emms playlist by last played time, increasingly.
-With a prefix argument, decreasingly."
- (interactive)
- (emms-playlist-sort
- '(lambda (a b)
- (funcall
- (if current-prefix-arg 'not 'identity)
- (time-less-p
- (or (emms-track-get a 'last-played) '(0 0 0))
- (or (emms-track-get b 'last-played) '(0 0 0)))))))
-
-(defun emms-playlist-sort-by-play-count ()
- "Sort emms playlist by play-count, increasingly.
-With a prefix argument, decreasingly."
- (interactive)
- (emms-playlist-sort
- '(lambda (a b)
- (funcall
- (if current-prefix-arg 'not 'identity)
- (< (or (emms-track-get a 'play-count) 0)
- (or (emms-track-get b 'play-count) 0))))))
-
-(defun emms-playlist-sort-by-file-extension ()
- "Sort emms playlist by file extension, increasingly.
-With a prefix argument, decreasingly."
- (interactive)
- (emms-playlist-sort
- '(lambda (a b)
- (funcall
- (if current-prefix-arg 'emms-string> 'emms-string<)
- (file-name-extension (emms-track-get a 'name))
- (file-name-extension (emms-track-get b 'name))))))
-
-(defun emms-playlist-sort-by-file-mtime ()
- "Sort emms playlist by file mtime, newest first.
-With a prefix argument, oldest first."
- (interactive)
- (emms-playlist-sort
- '(lambda (a b)
- (funcall
- (if current-prefix-arg
- 'time-less-p
- (lambda (t1 t2) (not (time-less-p t1 t2))))
- (emms-info-track-file-mtime a)
- (emms-info-track-file-mtime b)))))
-
-
-(defvar emms-playlist-sort-map nil)
-
-(defun emms-playlist-sort-map-setup ()
- "Setup sort map with latest `emms-playlist-sort-prefix'."
- (setq emms-playlist-sort-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "n") 'emms-playlist-sort-by-natural-order)
- (define-key map (kbd "a") 'emms-playlist-sort-by-info-artist)
- (define-key map (kbd "c") 'emms-playlist-sort-by-play-count)
- (define-key map (kbd "b") 'emms-playlist-sort-by-info-album)
- (define-key map (kbd "l") 'emms-playlist-sort-by-last-played)
- (define-key map (kbd "t") 'emms-playlist-sort-by-info-title)
- (define-key map (kbd "e") 'emms-playlist-sort-by-file-extension)
-
- (define-key map (kbd "p") 'emms-playlist-sort-by-info-performer)
- (define-key map (kbd "y") 'emms-playlist-sort-by-info-year)
- (define-key map (kbd "o") 'emms-playlist-sort-by-info-note)
- (define-key map (kbd "C") 'emms-playlist-sort-by-info-composer)
- (define-key map (kbd "L") 'emms-playlist-sort-by-list)
- (define-key map (kbd "N") 'emms-playlist-sort-by-name)
- (define-key map (kbd "T") 'emms-playlist-sort-by-file-mtime)
- map))
-
- (define-key emms-playlist-mode-map
- emms-playlist-sort-prefix emms-playlist-sort-map))
-
-(setq emms-playlist-sort-map (emms-playlist-sort-map-setup))
-
-
-;;; Low Level Functions
-
-(defun emms-playlist-sort (predicate)
- "Sort the playlist buffer by PREDICATE."
- (emms-with-inhibit-read-only-t
- (emms-playlist-ensure-playlist-buffer)
- (let ((current (emms-playlist-selected-track))
- (tracks (nreverse
- (emms-playlist-tracks-in-region
- (point-min) (point-max)))))
- (delete-region (point-min) (point-max))
- (run-hooks 'emms-playlist-cleared-hook)
- (mapc 'emms-playlist-insert-track (sort tracks predicate))
- (let ((pos (when current (text-property-any (point-min) (point-max)
- 'emms-track current))))
- (if pos
- (emms-playlist-select pos)
- (emms-playlist-first)))
- (goto-char (point-min)))))
-
-(defun emms-sort-natural-order-less-p (a b)
- "Sort two tracks by natural order.
-This is the order in which albums where intended to be played.
-ie. by album name and then by track number."
- (let ((album-a (emms-track-get a 'info-album))
- (album-b (emms-track-get b 'info-album))
- (discnum-a (string-to-number (or (emms-track-get a 'info-discnumber) "0")))
- (discnum-b (string-to-number (or (emms-track-get b 'info-discnumber) "0")))
- (tracknum-a (string-to-number (or (emms-track-get a 'info-tracknumber) "0")))
- (tracknum-b (string-to-number (or (emms-track-get b 'info-tracknumber) "0"))))
- (or (emms-string< album-a album-b)
- (and album-a album-b
- (string= album-a album-b)
- (or (< discnum-a discnum-b)
- (and (= discnum-a discnum-b)
- (< tracknum-a tracknum-b)))))))
-
-(defun emms-playlist-sort-by-list-p (a b)
- (catch 'return
- (dolist (info emms-playlist-sort-list)
- (cl-case info
- ((name info-artist info-composer info-performer info-title info-album info-genre)
- (when (emms-string< (emms-track-get a info)
- (emms-track-get b info))
- (throw 'return t)))
- ((info-playing-time)
- (when (< (emms-track-get a info)
- (emms-track-get b info))
- (throw 'return t)))
- ((info-tracknumber info-discnumber)
- (when (< (string-to-number (or (emms-track-get a info) "0"))
- (string-to-number (or (emms-track-get b info) "0")))
- (throw 'return t)))))))
-
-(defun emms-string< (s1 s2)
- (string< (downcase (or s1 "")) (downcase (or s2 ""))))
-
-(defun emms-string> (s1 s2)
- (let ((a (downcase (or s1 "")))
- (b (downcase (or s2 ""))))
- (not (or (string= a b) (string< a b)))))
-
-(provide 'emms-playlist-sort)
-
-;;; emms-playlist-sort.el ends here
diff --git a/lisp/emms-score.el b/lisp/emms-score.el
deleted file mode 100644
index 8c783c5..0000000
--- a/lisp/emms-score.el
+++ /dev/null
@@ -1,272 +0,0 @@
-;;; emms-score.el --- Scoring system for mp3player
-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-;; 2009, 2018 Free Software Foundation, Inc.
-
-;; Authors: Jean-Philippe Theberge <jphiltheberge@videotron.ca>,
-;; Yoni Rabkin <yrk@gnu.org>
-;;
-;; Keywords: emms, mp3, mpeg, multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; NOTE: This is experimental stuff - comments welcome! There
-;; shouldn't worky anything in that file... scores aren't saved, they
-;; even don't have any consequence on playing order and there's just
-;; one mood in the moment. But it's a beginning and you can score down
-;; or up tracks... :)
-;;
-;; * How to use scoring in emms
-;;
-;; When you load emms, you are set to a default mood
-;; 'emms-default-mood' A mood is a one word string describing how
-;; you feel (like "funny", "tired", "aggresive"...) Each mood have is
-;; own set of scoring rules.
-;;
-;; You can change your mood with M-x emms-score-change-mood.
-;;
-;; Every music file start with a default score of 0 the command
-;; emms-score-up-playing and emms-score-down-playing modify the
-;; score of the file you are curently listening by 1 In addition,
-;; skipping a file (with emms-skip) automaticaly score the file
-;; down.
-;;
-;; With scoring on (this mean the variable emms-use-scoring is t),
-;; emms will compare the score of the file with your tolerance to
-;; decide if it is played or not.
-;;
-;; The default tolerance level is 0 (or the variable
-;; emms-score-min-score). This mean files with a score of 0 or more will
-;; be played and files with a score of -1 or less will be skipped.
-;;
-;; You can change the tolerance (by 1) with M-x
-;; emms-score-lower-tolerance and M-x
-;; emms-score-be-more-tolerant
-
-;;; Code:
-
-(require 'emms)
-
-(defvar emms-scores-list nil)
-(defvar emms-score-current-mood 'default)
-(defvar emms-score-min-score 0)
-(defvar emms-score-default-score 0)
-(defvar emms-score-hash (make-hash-table :test 'equal))
-(defvar emms-score-enabled-p nil
- "If non-nil, emms score is active.")
-
-(defcustom emms-score-file (concat (file-name-as-directory emms-directory) "scores")
- "*Directory to store the score file."
- :type 'directory
- :group 'emms)
-
-
-;;; User Interfaces
-
-(defun emms-score (arg)
- "Turn on emms-score if prefix argument ARG is a positive integer,
-off otherwise."
- (interactive "p")
- (if (and arg (> arg 0))
- (progn
- (setq emms-score-enabled-p t)
- (emms-score-load-hash)
- (setq emms-ok-track-function 'emms-score-ok-track-function)
- (unless noninteractive
- (add-hook 'kill-emacs-hook 'emms-score-save-hash)))
- (setq emms-score-enabled-p nil)
- (emms-score-save-hash)
- (setq emms-ok-track-function 'emms-default-ok-track-function)
- (remove-hook 'kill-emacs-hook 'emms-score-save-hash)))
-
-;;;###autoload
-(defun emms-score-enable ()
- "Turn on emms-score."
- (interactive)
- (emms-score 1)
- (message "emms score enabled"))
-
-;;;###autoload
-(defun emms-score-disable ()
- "Turn off emms-score."
- (interactive)
- (emms-score -1)
- (message "emms score disabled"))
-
-;;;###autoload
-(defun emms-score-toggle ()
- "Toggle emms-score."
- (interactive)
- (if emms-score-enabled-p
- (emms-score-disable)
- (emms-score-enable)))
-
-(defun emms-score-change-mood (mood)
- "Change the current MOOD.
-The score hash is automatically saved."
- (interactive "sMood: ")
- (emms-score-save-hash)
- (setq emms-score-current-mood (intern (downcase mood))))
-
-(defun emms-score-up-playing ()
- (interactive)
- (if emms-player-playing-p
- (emms-score-change-score 1 (emms-score-current-selected-track-filename))
- (error "No track currently playing")))
-
-(defun emms-score-down-playing ()
- (interactive)
- (if emms-player-playing-p
- (emms-score-change-score -1 (emms-score-current-selected-track-filename))
- (error "No track currently playing")))
-
-(defun emms-score-up-file-on-line ()
- (interactive)
- (emms-score-change-score 1 (emms-score-track-at-filename)))
-
-(defun emms-score-down-file-on-line ()
- (interactive)
- (emms-score-change-score -1 (emms-score-track-at-filename)))
-
-(defun emms-score-less-tolerant ()
- "Only play mp3 with a higher score"
- (interactive)
- (setq emms-score-min-score (+ emms-score-min-score 1))
- (message "Will play songs with a score >= %d" emms-score-min-score))
-
-(defun emms-score-more-tolerant ()
- "Allow playing of mp3 with a lower score."
- (interactive)
- (setq emms-score-min-score (- emms-score-min-score 1))
- (message "Will play songs with a score >= %d" emms-score-min-score))
-
-(defun emms-score-set-playing (score)
- "Set score for current playing track."
- (interactive "nSet score for playing track: ")
- (let ((filename (emms-score-current-selected-track-filename)))
- (if emms-player-playing-p
- (emms-score-change-score
- (- score (emms-score-get-score filename))
- filename)
- (error "No track currently playing"))))
-
-(defun emms-score-set-file-on-line (score)
- "Set score for track at point in emms-playlist buffer."
- (interactive "nSet score for track at point: ")
- (let ((filename (emms-score-track-at-filename)))
- (if emms-player-playing-p
- (emms-score-change-score
- (- score (emms-score-get-score filename))
- filename))))
-
-(defun emms-score-set-tolerance (tolerance)
- "Allow playing tracks with a score >= tolerance."
- (interactive "nSet tolerance: ")
- (setq emms-score-min-score tolerance)
- (message "Will play songs with a score >= %d" emms-score-min-score))
-
-(defun emms-score-show-playing ()
- "Show score for current playing track in minibuf."
- (interactive)
- (message "track/tolerance score: %d/%d"
- (emms-score-get-score
- (emms-score-current-selected-track-filename))
- emms-score-min-score))
-
-(defun emms-score-show-file-on-line ()
- "Show score for track at point in emms-playlist buffer."
- (interactive)
- (message "track/tolerance score: %d/%d"
- (emms-score-get-score
- (emms-score-track-at-filename))
- emms-score-min-score))
-
-
-;;; Internal Functions
-
-(defun emms-score-current-selected-track-filename ()
- "Return filename of current selected track."
- (emms-track-get (emms-playlist-current-selected-track) 'name))
-
-(defun emms-score-track-at-filename ()
- "Return file of track at point in emms-playlist buffer."
- (emms-track-get (emms-playlist-track-at) 'name))
-
-(defun emms-score-ok-track-function (track)
- "Decide if to skip or play TRACK."
- (emms-score-check-score (emms-track-get track 'name)))
-
-(defun emms-score-save-hash ()
- "Save score hash in `emms-score-file'."
- (interactive)
- (unless (file-directory-p (file-name-directory emms-score-file))
- (make-directory (file-name-directory emms-score-file)))
- (with-temp-file emms-score-file
- (let ((standard-output (current-buffer)))
- (insert "(")
- (maphash (lambda (key value)
- (prin1 (cons key value)))
- emms-score-hash)
- (insert ")"))))
-
-(defun emms-score-load-hash ()
- "Load score hash from `emms-score-file'."
- (interactive)
- (if (file-exists-p emms-score-file)
- (let ((score-string (with-temp-buffer
- (emms-insert-file-contents emms-score-file)
- (buffer-string))))
- (if (> (length score-string) 0)
- (mapc (lambda (elt)
- (puthash (car elt) (cdr elt) emms-score-hash))
- (read score-string)))
- ;; when file not exists, make empty but valid score file
- (emms-score-save-hash))))
-
-(defun emms-score-get-plist (filename)
- (gethash filename emms-score-hash))
-
-(defun emms-score-change-score (score filename)
- (let ((sp (emms-score-get-plist filename) )
- (sc (emms-score-get-score filename)))
- (puthash filename
- (plist-put sp emms-score-current-mood (+ sc score))
- emms-score-hash)
- (message "New score is %s" (+ score sc))))
-
-(defun emms-score-create-entry (filename)
- (puthash filename
- `(,emms-score-current-mood ,emms-score-default-score)
- emms-score-hash))
-
-(defun emms-score-get-score (filename)
- "Return score of TRACK."
- (let ((plist (emms-score-get-plist filename)))
- (if (member emms-score-current-mood plist)
- (plist-get plist emms-score-current-mood)
- (emms-score-create-entry filename)
- (emms-score-get-score filename))))
-
-(defun emms-score-check-score (filename)
- (>= (emms-score-get-score filename) emms-score-min-score))
-
-(provide 'emms-score)
-
-;;; emms-scores.el ends here
diff --git a/lisp/emms-setup.el b/lisp/emms-setup.el
deleted file mode 100644
index fed2a36..0000000
--- a/lisp/emms-setup.el
+++ /dev/null
@@ -1,156 +0,0 @@
-;;; emms-setup.el --- Setup script for EMMS
-
-;; Copyright (C) 2005-2020 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-;; Keywords: emms setup multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 EMMS; 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 the `emms-setup' feature. With `emms-setup' we
-;; can setup Emms with different features enabled. The use of this
-;; feature is documented in the Emms manual which is distributed with
-;; Emms.
-;;
-;; The use this feature we can invoke (for example):
-;;
-;; (require 'emms-setup)
-;; (emms-all)
-;;
-;; The first command loads the feature into Emacs and the second
-;; chooses the `emms-all' level.
-
-;;; Code:
-
-(require 'emms)
-
-(defgroup emms-setup nil
- "*The Emacs Multimedia System setup utility."
- :prefix "emms-setup"
- :group 'multimedia)
-
-(defcustom emms-setup-default-player-list
- '(emms-player-mpg321
- emms-player-ogg123
- emms-player-mplayer-playlist
- emms-player-mplayer
- emms-player-mpv
- emms-player-vlc
- emms-player-vlc-playlist)
- "*Default list of players for emms-setup."
- :group 'emms-setup
- :type 'list)
-
-;;;###autoload
-(defun emms-minimalistic ()
- "An Emms setup script.
-Invisible playlists and all the basics for playing media."
- (require 'emms-source-file)
- (require 'emms-source-playlist)
- (require 'emms-player-simple)
- (require 'emms-player-mplayer)
- (require 'emms-player-mpv)
- (require 'emms-player-vlc))
-
-;;;###autoload
-(defun emms-all ()
- "An Emms setup script.
-Everything included in the `emms-minimalistic' setup and adds all
-the stable features which come with the Emms distribution."
- ;; include
- (emms-minimalistic)
- ;; define
- (eval-and-compile
- (require 'emms-playlist-mode)
- (require 'emms-info)
- (require 'emms-info-mp3info)
- (require 'emms-info-ogginfo)
- (require 'emms-info-opusinfo)
- (require 'emms-info-metaflac)
- (require 'emms-info-tinytag)
- (require 'emms-cache)
- (require 'emms-mode-line)
- (require 'emms-mark)
- (require 'emms-tag-editor)
- (require 'emms-show-all)
- (require 'emms-streams)
- (require 'emms-lyrics)
- (require 'emms-playing-time)
- (require 'emms-player-mpd)
- (require 'emms-player-xine)
- (require 'emms-playlist-sort)
- (require 'emms-browser)
- (require 'emms-mode-line-icon)
- (require 'emms-cue)
- (require 'emms-bookmarks)
- (require 'emms-last-played)
- (require 'emms-metaplaylist-mode)
- (require 'emms-stream-info)
- (require 'emms-score)
- (require 'emms-history)
- (require 'emms-i18n)
- (require 'emms-volume)
- (require 'emms-playlist-limit)
- (require 'emms-librefm-scrobbler)
- (require 'emms-librefm-stream))
- ;; setup
- (setq emms-playlist-default-major-mode 'emms-playlist-mode)
- (add-to-list 'emms-track-initialize-functions 'emms-info-initialize-track)
- (when (executable-find emms-info-mp3info-program-name)
- (add-to-list 'emms-info-functions 'emms-info-mp3info))
- (when (executable-find emms-info-ogginfo-program-name)
- (add-to-list 'emms-info-functions 'emms-info-ogginfo))
- (when (executable-find emms-info-opusinfo-program-name)
- (add-to-list 'emms-info-functions 'emms-info-opusinfo))
- (setq emms-track-description-function 'emms-info-track-description)
- (when (fboundp 'emms-cache) ; work around compiler warning
- (emms-cache 1))
- (emms-mode-line 1)
- (emms-mode-line-blank)
- (emms-lyrics 1)
- (emms-playing-time 1)
- (add-to-list 'emms-info-functions 'emms-info-cueinfo)
- (add-hook 'emms-player-started-hook 'emms-last-played-update-current)
- (emms-score 1))
-
-
-;;;###autoload
-(defun emms-default-players ()
- "Set `emms-player-list' to `emms-setup-default-player-list'."
- (setq emms-player-list
- emms-setup-default-player-list))
-
-
-
-;; These are kept around in order not to break anyone's existing
-;; setup.
-;;;###autoload
-(defun emms-devel ()
- (emms-all))
-(make-obsolete 'emms-devel 'emms-all "4.1")
-
-;;;###autoload
-(defun emms-standard ()
- (emms-all))
-(make-obsolete 'emms-standard 'emms-all "4.1")
-
-
-(provide 'emms-setup)
-;;; emms-setup.el ends here
diff --git a/lisp/emms-show-all.el b/lisp/emms-show-all.el
deleted file mode 100644
index f37ef5e..0000000
--- a/lisp/emms-show-all.el
+++ /dev/null
@@ -1,125 +0,0 @@
-;;; emms-show-all.el --- Detailed track information for Emms.
-
-;; Copyright (C) 2016 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-;;;
-;;; Shows all of the available information Emms can provide on the
-;;; currently playing track. Based on an idea suggested on the
-;;; emms-help mailing list by Ivan Truskov.
-
-;;; Code:
-
-(require 'emms)
-(require 'emms-tag-editor)
-
-
-(defvar emms-show-all-buffer-name "Emms Track Information"
- "Name of buffer used by `emms-show-all'.")
-
-(defvar emms-show-all-kill-buffer-on-quit-p nil
- "If t, kill the show-all buffer when quitting.")
-
-(defvar emms-show-all-track-alist nil
- "Declare so as to silence the compiler.")
-
-(defvar emms-show-all-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map text-mode-map)
- (define-key map (kbd "q") 'emms-show-all-mode-bury-buffer)
- (define-key map (kbd "E") 'emms-show-all-edit-track)
- map)
- "Keymap for `emms-show-all-mode'.")
-
-(define-derived-mode emms-show-all-mode text-mode "Emms-Show-All"
- "Major mode for `emms-show-all'
- \\{emms-show-all-mode-map}")
-
-(defun emms-show-all-edit-track ()
- "Edit the track being shown."
- (interactive)
- (let ((track emms-show-all-track-alist))
- (emms-show-all-mode-bury-buffer)
- (emms-tag-editor-edit-track track)))
-
-(defun emms-show-all-mode-bury-buffer ()
- "Bury, and optionally kill the show buffer."
- (interactive)
- (quit-restore-window
- (selected-window)
- (when emms-show-all-kill-buffer-on-quit-p 'kill)))
-
-(defun emms-show-all-setup-buffer ()
- "Prepare the display buffer."
- (let ((buffer (get-buffer-create emms-show-all-buffer-name)))
- (with-current-buffer buffer
- (when (not (local-variable-p 'emms-show-all-track-alist))
- (make-local-variable 'emms-show-all-track-alist))
- (setq buffer-read-only t)
- (when (not (equal major-mode 'emms-show-all-mode))
- (emms-show-all-mode))
- (let ((inhibit-read-only t))
- (erase-buffer)))
- buffer))
-
-(defun emms-show-all-format (track)
- "Format information for TRACK."
- (let ((s ""))
- (dolist (e (mapcar #'(lambda (tag)
- (cons
- (format "%s" (car tag))
- (or (emms-track-get track (car tag)) "")))
- emms-tag-editor-tags))
- (setq s (concat s (format "%-17s: %s\n" (car e) (cdr e)))))
- s))
-
-(defun emms-show-all-insert (track)
- "Insert information for TRACK in current buffer."
- (let ((type (emms-track-type track)))
- (cond ((eq 'file type)
- (insert (emms-show-all-format track)))
- ((eq 'url type)
- (insert
- (emms-format-url-track-name (emms-track-name track))))
- (t (concat (symbol-name type)
- ": " (emms-track-name track))))))
-
-(defun emms-show-all-track (track)
- "Display information for TRACK."
- (let ((buffer (emms-show-all-setup-buffer)))
- (with-current-buffer buffer
- (let ((inhibit-read-only t))
- (setq emms-show-all-track-alist track)
- (emms-show-all-insert track))
- (pop-to-buffer (current-buffer)))))
-
-(defun emms-show-all ()
- "Describe the current EMMS track in detail."
- (interactive)
- (if emms-player-playing-p
- (emms-show-all-track
- (emms-playlist-current-selected-track))
- (message "nothing playing right now")))
-
-
-(provide 'emms-show-all)
-
-;;; emms-playlist-mode.el ends here
diff --git a/lisp/emms-source-file.el b/lisp/emms-source-file.el
deleted file mode 100644
index 2be6538..0000000
--- a/lisp/emms-source-file.el
+++ /dev/null
@@ -1,314 +0,0 @@
-;;; emms-source-file.el --- EMMS sources from the filesystem.
-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-;; 2009 Free Software Foundation, Inc.
-
-;; Author: Jorgen Schäfer <forcer@forcix.cx>
-;; Keywords: emms, mp3, mpeg, multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; 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 contains a track source for EMMS that is based on the
-;; file system. You can retrieve single files or whole directories.
-;; Also, this file offers the commands to play from these sources.
-
-;;; Code:
-
-;; Version control
-(defvar emms-source-file-version "0.2 $Revision: 1.30 $"
- "emms-source-file.el version string")
-;; $Id: emms-source-file.el,v 1.30 2005/08/11 06:16:15 yonirabkin Exp $
-
-;;; User Customization
-
-(require 'emms)
-(require 'dired)
-(require 'locate)
-(eval-when-compile
- (condition-case nil
- (require 'locate)
- (error nil)))
-(require 'dired)
-
-(defgroup emms-source-file nil
- "*Sources for EMMS that use the file system."
- :prefix "emms-source-file-"
- :group 'emms-source)
-
-(defcustom emms-source-file-default-directory nil
- "*The default directory to look for media files."
- :type '(choice (const :tag "None" nil) file)
- :group 'emms-source-file)
-
-(defcustom emms-source-file-directory-tree-function
- 'emms-source-file-directory-tree-internal
- "*A function to call that searches in a given directory all files
-that match a given regex. DIR and REGEX are the only arguments passed
-to this function.
-You have two build-in options:
-`emms-source-file-directory-tree-internal' will work always, but might
-be slow.
-`emms-source-file-directory-tree-find' will work only if you have GNU
-find, but it's faster."
- :type 'function
- :options '(emms-source-file-directory-tree-internal
- emms-source-file-directory-tree-find)
- :group 'emms-source-file)
-
-(defcustom emms-source-file-exclude-regexp
- (concat "\\`\\(#.*#\\|.*,v\\|.*~\\|\\.\\.?\\|\\.#.*\\|,.*\\)\\'\\|"
- "/\\(CVS\\|RCS\\|\\.arch-ids\\|{arch}\\|,.*\\|\\.svn\\|"
- "_darcs\\)\\(/\\|\\'\\)")
- "A regexp matching files to be ignored when adding directories.
-
-You should set case-fold-search to nil before using this regexp
-in code."
- :type 'regexp
- :group 'emms-source-file)
-
-(defcustom emms-source-file-gnu-find "find"
- "*The program name for GNU find."
- :type 'string
- :group 'emms-source-file)
-
-(defcustom emms-source-file-directory-hint-p t
- "*When non-nil, guess the directory based on a track at point."
- :type 'boolean
- :group 'emms-source-file)
-
-;; The `read-directory-name' function is not available in Emacs 21.
-(defalias 'emms-read-directory-name
- (if (fboundp 'read-directory-name)
- #'read-directory-name
- #'read-file-name))
-
-(defun emms-source-file-directory-hint ()
- (if (and emms-source-file-directory-hint-p
- emms-playlist-buffer-p
- (emms-playlist-track-at))
- (let ((name (emms-track-get (emms-playlist-track-at) 'name))
- (type (emms-track-get (emms-playlist-track-at) 'type)))
- (when (eq type 'file)
- (file-name-directory name)))
- emms-source-file-default-directory))
-
-
-;;; Sources
-
-;;;###autoload (autoload 'emms-play-file "emms-source-file" nil t)
-;;;###autoload (autoload 'emms-add-file "emms-source-file" nil t)
-(define-emms-source file (file)
- "An EMMS source for a single file - either FILE, or queried from the
-user."
- (interactive (list (read-file-name "Play file: "
- (emms-source-file-directory-hint)
- emms-source-file-default-directory
- t)))
- (if (file-directory-p file)
- (emms-source-directory file)
- (emms-playlist-insert-track
- (emms-track 'file (expand-file-name file)))))
-
-;;;###autoload (autoload 'emms-play-directory "emms-source-file" nil t)
-;;;###autoload (autoload 'emms-add-directory "emms-source-file" nil t)
-(define-emms-source directory (dir)
- "An EMMS source for a whole directory tree - either DIR, or queried
-from the user."
- (interactive (list
- (emms-read-directory-name "Play directory: "
- (emms-source-file-directory-hint)
- emms-source-file-default-directory
- t)))
- (mapc (lambda (file)
- (unless (or (let ((case-fold-search nil))
- (string-match emms-source-file-exclude-regexp file))
- (file-directory-p file))
- (emms-playlist-insert-track
- (emms-track 'file (expand-file-name file)))))
- (directory-files dir t (emms-source-file-regex))))
-
-;;;###autoload (autoload 'emms-play-directory-tree "emms-source-file" nil t)
-;;;###autoload (autoload 'emms-add-directory-tree "emms-source-file" nil t)
-(define-emms-source directory-tree (dir)
- "An EMMS source for multiple directory trees - either DIR, or the
-value of `emms-source-file-default-directory'."
- (interactive (list
- (emms-read-directory-name "Play directory tree: "
- (emms-source-file-directory-hint)
- emms-source-file-default-directory
- t)))
- (let ((files (emms-source-file-directory-tree (expand-file-name dir)
- (emms-source-file-regex)))
- (case-fold-search nil))
- (emms-playlist-ensure-playlist-buffer)
- (mapc (lambda (file)
- (unless (string-match emms-source-file-exclude-regexp file)
- (funcall emms-playlist-insert-track-function
- (emms-track 'file file))))
- files)))
-
-;;;###autoload (autoload 'emms-play-find "emms-source-file" nil t)
-;;;###autoload (autoload 'emms-add-find "emms-source-file" nil t)
-(define-emms-source find (dir regex)
- "An EMMS source that will find files in DIR or
-`emms-source-file-default-directory' that match REGEX."
- (interactive (list
- (emms-read-directory-name "Find in directory: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)
- (read-from-minibuffer "Find files matching: ")))
- (mapc (lambda (file)
- (unless (let ((case-fold-search nil))
- (string-match emms-source-file-exclude-regexp file))
- (emms-playlist-insert-track
- (emms-track 'file file))))
- (emms-source-file-directory-tree (expand-file-name dir) regex)))
-
-;;;###autoload (autoload 'emms-play-dired "emms-source-file" nil t)
-;;;###autoload (autoload 'emms-add-dired "emms-source-file" nil t)
-(define-emms-source dired ()
- "Return all marked files of a dired buffer"
- (interactive)
- (mapc (lambda (file)
- (if (file-directory-p file)
- (emms-source-directory-tree file)
- (emms-source-file file)))
- (with-current-buffer emms-source-old-buffer
- (dired-get-marked-files))))
-
-
-;;; Helper functions
-
-;;;###autoload
-(defun emms-source-file-directory-tree (dir regex)
- "Return a list of all files under DIR that match REGEX.
-This function uses `emms-source-file-directory-tree-function'."
- (message "Building playlist...")
- (let ((pl (sort (funcall emms-source-file-directory-tree-function
- dir
- regex)
- 'string<)))
- (message "Building playlist...done")
- pl))
-
-(defun emms-source-file-directory-tree-internal (dir regex)
- "Return a list of all files under DIR that match REGEX.
-This function uses only emacs functions, so it might be a bit slow."
- (let ((files '())
- (dirs (list dir)))
- (while dirs
- (cond
- ((file-directory-p (car dirs))
- (if (or (string-match "/\\.\\.?$" (car dirs))
- (let ((symlink (file-symlink-p (car dirs))))
- (and symlink
- (string-equal dir (substring symlink 0 (string-width dir))))))
- (setq dirs (cdr dirs))
- (setq dirs
- (condition-case nil
- (append (cdr dirs)
- (directory-files (car dirs)
- t nil t))
- (error
- (cdr dirs))))))
- ((string-match regex (car dirs))
- (setq files (cons (car dirs) files)
- dirs (cdr dirs)))
- (t
- (setq dirs (cdr dirs)))))
- files))
-
-(defun emms-source-file-directory-tree-find (dir regex)
- "Return a list of all files under DIR that match REGEX.
-This function uses the external find utility. The name for GNU find
-may be supplied using `emms-source-file-gnu-find'."
- (with-temp-buffer
- (call-process emms-source-file-gnu-find
- nil t nil
- "-L" ; follow symlinks
- (expand-file-name dir)
- "-type" "f"
- "-iregex" (concat ".*\\(" regex "\\).*"))
- (delete ""
- (split-string (buffer-substring (point-min)
- (point-max))
- "\n"))))
-
-(defmacro emms-with-excluded-directories (directory-list &rest body)
- "Run BODY while excluding DIRECTORY-LIST."
- `(let ((emms-source-file-exclude-regexp
- (concat (or ,emms-source-file-exclude-regexp "")
- "\\|\\("
- (or (regexp-opt ,directory-list) "")
- "\\)")))
- ,@body))
-
-;;;###autoload
-(defun emms-source-file-regex ()
- "Return a regexp that matches everything any player (that supports
-files) can play."
- (mapconcat (lambda (player)
- (or (emms-player-get player 'regex)
- ""))
- emms-player-list
- "\\|"))
-
-;; emms-locate should be part of a once to be emms-dired, with maybe
-;; file rename after tag functions and so on, but till then i park it
-;; here... :)
-
-;;;###autoload
-(defun emms-locate (regexp)
- "Search for REGEXP and display the results in a locate buffer"
- (interactive "sRegexp to search for: ")
- (require 'locate)
- (save-window-excursion
- (set-buffer (get-buffer-create "*EMMS Find*"))
- (locate-mode)
- (erase-buffer)
- (mapc (lambda (elt) (insert (cdr (assoc 'name elt)) "\n"))
- (emms-source-find emms-source-file-default-directory regexp))
- (locate-do-setup regexp))
- (and (not (string-equal (buffer-name) "*EMMS Find*"))
- (switch-to-buffer-other-window "*EMMS Find*"))
- (run-hooks 'dired-mode-hook)
- (dired-next-line 2))
-
-;; Strictly speaking, this does not belong in this file (URLs are not
-;; real files), but it's close enough :-)
-
-;;;###autoload (autoload 'emms-play-url "emms-source-file" nil t)
-;;;###autoload (autoload 'emms-add-url "emms-source-file" nil t)
-(define-emms-source url (url)
- "An EMMS source for an URL - for example, for streaming."
- (interactive "sPlay URL: ")
- (emms-playlist-insert-track (emms-track 'url url)))
-
-;;;###autoload (autoload 'emms-play-streamlist "emms-source-file" nil t)
-;;;###autoload (autoload 'emms-add-streamlist "emms-source-file" nil t)
-(define-emms-source streamlist (streamlist)
- "An EMMS source for streaming playlists (usually URLs ending in .pls)."
- (interactive "sPlay streamlist URL: ")
- (emms-playlist-insert-track (emms-track 'streamlist streamlist)))
-
-
-(provide 'emms-source-file)
-;;; emms-source-file.el ends here
diff --git a/lisp/emms-source-playlist.el b/lisp/emms-source-playlist.el
deleted file mode 100644
index 327be8c..0000000
--- a/lisp/emms-source-playlist.el
+++ /dev/null
@@ -1,494 +0,0 @@
-;;; emms-source-playlist.el --- EMMS sources from playlist files
-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-;; 2009 Free Software Foundation, Inc.
-
-;; Author: Jorgen Schäfer <forcer@forcix.cx>
-;; Keywords: emms, mp3, mpeg, multimedia
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; 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 contains track sources for EMMS which read playlist
-;; files. EMMS' own playlist files are supported as well as .m3u and
-;; .pls files.
-
-;;; Code:
-
-;; Version control
-(defvar emms-source-playlist-version "0.5 $Revision: 1.30 $"
- "emms-source-playlist.el version string")
-;; $Id: emms-source-file.el,v 1.30 2005/08/11 06:16:15 yonirabkin Exp $
-
-(require 'emms)
-(require 'emms-source-file)
-
-(defcustom emms-source-playlist-formats '(native pls m3u)
- "*A list of playlist formats.
-Each entry must have at least three corresponding functions.
-
-First, a function named `emms-source-playlist-FORMAT-p' which
-returns non-nil if the current buffer is of the type FORMAT. It
-is called with no arguments.
-
-Second, a function named `emms-source-playlist-parse-FORMAT'
-which parses the current buffer into tracks. It is called with
-no arguments.
-
-Third, a function named `emms-source-playlist-unparse-FORMAT'
-which creates an output file in the type FORMAT that contains the
-tracks of a playlist buffer. It is called with two arguments:
-The playlist buffer and the file buffer.
-
-It is also recommended to have a function named
-`emms-source-playlist-FORMAT-files' which returns a list of the
-files contained in the playlist."
- :type '(repeat (symbol :tag "Format"))
- :group 'emms)
-
-(defcustom emms-source-playlist-default-format nil
- "*The default format to use for saving playlists.
-If this is nil, you will be prompted for a format to use."
- :type '(choice (const :tag "Prompt each time" nil)
- (const :tag "Native" native)
- (const :tag "m3u" m3u)
- (const :tag "pls" pls)
- (symbol :tag "Other"))
- :group 'emms)
-
-(defcustom emms-source-playlist-ask-before-overwrite t
- "*Ask before saving over an existing playlist.
-If this is nil, existing playlists will be quietly overwritten."
- :type 'boolean
- :group 'emms)
-
-(defvar emms-source-playlist-native-header-line
- ";;; This is an EMMS playlist file"
- "Line which identifies a native emms playlist.")
-
-;;; General playlist
-
-(defsubst emms-source-playlist-p-sym (format)
- (intern (concat "emms-source-playlist-" (symbol-name format) "-p")))
-
-(defsubst emms-source-playlist-parse-sym (format)
- (intern (concat "emms-source-playlist-parse-" (symbol-name format))))
-
-(defsubst emms-source-playlist-unparse-sym (format)
- (intern (concat "emms-source-playlist-unparse-" (symbol-name format))))
-
-(defsubst emms-source-playlist-files-sym (format)
- (intern (concat "emms-source-playlist-" (symbol-name format) "-files")))
-
-(defun emms-source-playlist-p (format &optional parse-files)
- (let ((sym (emms-source-playlist-p-sym format)))
- (when (and (functionp sym)
- (or (not parse-files)
- (functionp (emms-source-playlist-files-sym format))))
- (funcall sym))))
-
-(defun emms-source-playlist-parse (format file)
- (funcall (emms-source-playlist-parse-sym format) file))
-
-(defun emms-source-playlist-unparse (format playlist-buf file-buf)
- (funcall (emms-source-playlist-unparse-sym format) playlist-buf file-buf))
-
-(defun emms-source-playlist-files (format)
- (let ((sym (emms-source-playlist-files-sym format)))
- (if (functionp sym)
- (funcall sym)
- (error "The `%s' format cannot parse files from a playlist" format))))
-
-(defvar emms-source-playlist-format-history nil
- "List of recently-entered formats; used by `emms-playlist-save'.")
-
-(defun emms-source-playlist-read-format ()
- "Read a playlist format from the user.
-If `emms-source-playlist-default-format' is non-nil, use it
-instead of prompting the user."
- (or emms-source-playlist-default-format
- (let ((format
- (emms-completing-read
- (concat "Playlist format: (default: "
- (if emms-source-playlist-format-history
- (car emms-source-playlist-format-history)
- "native")
- ") ")
- (mapcar #'symbol-name emms-source-playlist-formats)
- nil nil nil 'emms-source-playlist-format-history
- (if emms-source-playlist-format-history
- (car emms-source-playlist-format-history)
- "native"))))
- ;; Sometimes the completion function can put partial results
- ;; onto the history, so pop the last one off and include the
- ;; completed version instead.
- (setq emms-source-playlist-format-history
- (cons format
- (cdr emms-source-playlist-format-history)))
- (intern format))))
-
-(defun emms-playlist-save (format file)
- "Store the current playlist to FILE as the type FORMAT.
-The default format is specified by `emms-source-playlist-default-format'."
- (interactive (list (emms-source-playlist-read-format)
- (read-file-name "Store as: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- nil)))
- (if (or (eq emms-playlist-buffer (current-buffer))
- (and (not (eq emms-playlist-buffer (current-buffer)))
- (y-or-n-p
- (format "Current playlist buffer (%s) is not the one you are visiting (%s). Save anyway?"
- emms-playlist-buffer (current-buffer)))))
- (with-temp-buffer
- (emms-source-playlist-unparse format
- (with-current-emms-playlist
- (current-buffer))
- (current-buffer))
- (let ((backup-inhibited t))
- (write-file file emms-source-playlist-ask-before-overwrite)))
- (message "aborting save")))
-
-(defun emms-source-playlist-determine-format (&optional parse-files)
- "Determine the playlist format of the current buffer.
-If PARSE-FILES is specified, the given format must be able to
-return a list of the files contained in the playlist."
- (catch 'return
- (let ((formats emms-source-playlist-formats))
- (while formats
- (when (emms-source-playlist-p (car formats) parse-files)
- (throw 'return (car formats)))
- (setq formats (cdr formats))))))
-
-;;;###autoload (autoload 'emms-play-playlist "emms-source-playlist" nil t)
-;;;###autoload (autoload 'emms-add-playlist "emms-source-playlist" nil t)
-(define-emms-source playlist (file)
- "An EMMS source for playlists.
-See `emms-source-playlist-formats' for a list of supported formats."
- (interactive (list (read-file-name "Playlist file: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)))
- (mapc #'emms-playlist-insert-track
- (with-temp-buffer
- (emms-insert-file-contents file)
- (goto-char (point-min))
- (let ((format (emms-source-playlist-determine-format)))
- (if format
- (emms-source-playlist-parse format file)
- (error "Not a recognized playlist format"))))))
-
-;;; Emms native playlists
-
-;; An Emms native playlist file starts with the contents of
-;; `emms-source-playlist-native-header-line' and is followed by
-;; tracks in sexp format.
-
-(defun emms-source-playlist-native-p ()
- "Return non-nil if the current buffer contains a native EMMS playlist."
- (save-excursion
- (goto-char (point-min))
- (looking-at (concat "^" emms-source-playlist-native-header-line))))
-
-(defun emms-source-playlist-parse-native (file)
- "Parse the native EMMS playlist in the current buffer."
- (save-excursion
- (goto-char (point-min))
- (read (current-buffer))))
-
-(defun emms-source-playlist-unparse-native (in out)
- "Unparse a native playlist from IN to OUT.
-IN should be a buffer with a EMMS playlist in it.
-OUT should be the buffer where tracks are stored in the native EMMS format."
- (with-current-buffer in ;; Don't modify the position
- (save-excursion ;; in the IN buffer
- (with-current-buffer out
- (insert emms-source-playlist-native-header-line
- " Play it with M-x emms-play-playlist\n")
- (insert "("))
- (let ((firstp t))
- (goto-char (point-min))
- (emms-walk-tracks
- (let ((track (emms-playlist-track-at (point))))
- (with-current-buffer out
- (if (not firstp)
- (insert "\n ")
- (setq firstp nil))
- (prin1 track (current-buffer))))))
- (with-current-buffer out
- (insert ")\n")))))
-
-;;;###autoload (autoload 'emms-play-native-playlist "emms-source-playlist" nil t)
-;;;###autoload (autoload 'emms-add-native-playlist "emms-source-playlist" nil t)
-(define-emms-source native-playlist (file)
- "An EMMS source for a native EMMS playlist file."
- (interactive (list (read-file-name "Playlist file: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)))
- (mapc #'emms-playlist-insert-track
- (with-temp-buffer
- (emms-insert-file-contents file)
- (goto-char (point-min))
- (when (not (emms-source-playlist-native-p))
- (error "Not a native EMMS playlist file."))
- (emms-source-playlist-parse-native file))))
-
-;;; m3u files
-
-;; Format:
-;; Either a list of filename-per-line, ignore lines beginning with #
-;; or:
-;; #EXTM3U
-;; #EXTINF:<length in seconds>,<name>
-;; <filename>
-
-; emms-source-playlist-m3u-p
-; emms-source-playlist-parse-m3u
-; emms-source-playlist-m3u-files
-; emms-source-playlist-unparse-m3u
-
-(defun emms-source-playlist-m3u-p ()
- "Return non-nil if the current buffer contains an m3u playlist.
-
-We currently have no metric for determining whether a buffer is
-an .m3u playlist based on its contents alone, so we assume that
-the more restrictive playlist formats have already been
-detected and simply return non-nil always."
- t)
-
-(defun emms-source-playlist-parse-m3u (playlist-file)
- "Parse the m3u playlist in the current buffer.
-Files will be relative to the directory of PLAYLIST-FILE, unless
-they have absolute paths."
- (let ((dir (file-name-directory playlist-file)))
- (mapcar (lambda (file)
- (if (string-match "\\`\\(http[s]?\\|mms\\)://" file)
- (emms-track 'url file)
- (emms-track 'file (expand-file-name file dir))))
- (emms-source-playlist-m3u-files))))
-
-(defun emms-source-playlist-m3u-files ()
- "Extract a list of filenames from the given m3u playlist.
-
-Empty lines and lines starting with '#' are ignored."
- (let ((files nil))
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward "^[^# \n].*$" nil t)
- (setq files (cons (match-string 0) files))))
- (nreverse files)))
-
-(defun emms-source-playlist-unparse-m3u (in out)
- "Unparse an m3u playlist from IN to OUT.
-IN should be a buffer containing an m3u playlist.
-OUT should be the buffer where tracks are stored in m3u format."
- (with-current-buffer in ;; Don't modify the position
- (save-excursion ;; in the IN buffer
- (goto-char (point-min))
- (emms-walk-tracks
- (let ((track (emms-playlist-track-at (point))))
- (with-current-buffer out
- (insert (emms-track-name track) ?\n)))))))
-
-;;;###autoload (autoload 'emms-play-m3u-playlist "emms-source-playlist" nil t)
-;;;###autoload (autoload 'emms-add-m3u-playlist "emms-source-playlist" nil t)
-(define-emms-source m3u-playlist (file)
- "An EMMS source for an m3u playlist file."
- (interactive (list (read-file-name "Playlist file: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)))
- (mapc #'emms-playlist-insert-track
- (with-temp-buffer
- (emms-insert-file-contents file)
- (goto-char (point-min))
- (when (not (emms-source-playlist-m3u-p))
- (error "Not an m3u playlist file."))
- (emms-source-playlist-parse-m3u file))))
-
-;;; pls files
-
-;; Format:
-;; A list of one filename per line.
-;; [playlist]
-;; NumberOfEntries=<num_entries>
-;; File<position>=<filename>
-
-; emms-source-playlist-pls-p
-; emms-source-playlist-parse-pls
-; emms-source-playlist-pls-files
-; emms-source-playlist-unparse-pls
-
-(defun emms-source-playlist-pls-p ()
- "Return non-nil if the current buffer contains a pls playlist."
- (save-excursion
- (goto-char (point-min))
- (if (re-search-forward "^File[0-9]*=.+$" nil t)
- t
- nil)))
-
-(defun emms-source-playlist-parse-pls (playlist-file)
- "Parse the pls playlist in the current buffer.
-Files will be relative to the directory of PLAYLIST-FILE, unless
-they have absolute paths."
- (let ((dir (file-name-directory playlist-file)))
- (mapcar (lambda (file)
- (if (string-match "\\`\\(http[s]?\\|mms\\)://" file)
- (emms-track 'url file)
- (if (string-match "\\`file://" file) ;; handle file:// uris
- (let ((file (url-unhex-string (substring file 7))))
- (emms-track 'file file))
- (emms-track 'file (expand-file-name file dir)))))
- (emms-source-playlist-pls-files))))
-
-
-(defun emms-source-playlist-pls-files ()
- "Extract a list of filenames from the given pls playlist.
-
-Empty lines and lines starting with '#' are ignored."
- (let ((files nil))
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward "^File[0-9]*=\\(.+\\)$" nil t)
- (setq files (cons (match-string 1) files))))
- (nreverse files)))
-
-(defun emms-source-playlist-unparse-pls (in out)
- "Unparse a pls playlist from IN to OUT.
-IN should be a buffer conatining a pls playlist.
-OUT should be the buffer where tracks are stored in pls format."
- (with-current-buffer in ;; Don't modify the position
- (save-excursion ;; in the IN buffer
- (let ((pos 0)
- beg)
- (with-current-buffer out
- (insert "[playlist]\n")
- (setq beg (point)))
- (goto-char (point-min))
- (emms-walk-tracks
- (let ((track (emms-playlist-track-at (point))))
- (setq pos (1+ pos))
- (with-current-buffer out
- (insert "File" (number-to-string pos) "="
- (emms-track-name track) ?\n))))
- (with-current-buffer out
- (goto-char beg)
- (insert "NumberOfEntries=" (number-to-string pos) ?\n))))))
-
-;;;###autoload (autoload 'emms-play-pls-playlist "emms-source-playlist" nil t)
-;;;###autoload (autoload 'emms-add-pls-playlist "emms-source-playlist" nil t)
-(define-emms-source pls-playlist (file)
- "An EMMS source for a pls playlist file."
- (interactive (list (read-file-name "Playlist file: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)))
- (mapc #'emms-playlist-insert-track
- (with-temp-buffer
- (emms-insert-file-contents file)
- (goto-char (point-min))
- (when (not (emms-source-playlist-pls-p))
- (error "Not a pls playlist file."))
- (emms-source-playlist-parse-pls file))))
-
-;;; extm3u files
-
-;; Format:
-;; #EXTM3U
-;; #EXTINF:<length in seconds>,<name>
-;; <filename>
-
-; emms-source-playlist-extm3u-p
-; emms-source-playlist-parse-extm3u
-; emms-source-playlist-unparse-extm3u
-
-;; (erase-buffer)
-;; (insert "#EXTM3U\n")
-;; (mapc (lambda (track)
-;; (let ((time (or (emms-track-get track 'info-mtime) ""))
-;; (artist (emms-track-get track 'info-artist))
-;; (title (emms-track-get track 'info-title))
-;; (name (emms-track-get track 'name)))
-;; (insert (format "#EXTINF: %s,%s - %s\n%s\n"
-;; time artist title name))))
-;; tracklist)
-;; (save-buffer)
-;; (kill-buffer (current-buffer)))))
-
-;; Not implemented yet
-
-;;; Adding playlists as files
-
-;;;###autoload (autoload 'emms-play-playlist-file "emms-source-playlist" nil t)
-;;;###autoload (autoload 'emms-add-playlist-file "emms-source-playlist" nil t)
-(define-emms-source playlist-file (file)
- "An EMMS source for playlist files.
-This adds the given file to the current EMMS playlist buffer,
-without adding its contents.
-
-See `emms-source-playlist-formats' for a list of supported formats."
- (interactive (list (read-file-name "Playlist file: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)))
- (emms-playlist-insert-track
- (emms-track 'playlist (expand-file-name file))))
-
-;;;###autoload (autoload 'emms-play-playlist-directory
-;;;###autoload "emms-source-playlist" nil t)
-;;;###autoload (autoload 'emms-add-playlist-directory
-;;;###autoload "emms-source-playlist" nil t)
-(define-emms-source playlist-directory (dir)
- "An EMMS source for a whole directory tree of playlist files.
-If DIR is not specified, it is queried from the user."
- (interactive (list
- (emms-read-directory-name "Play directory: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)))
- (mapc (lambda (file)
- (unless (or (let ((case-fold-search nil))
- (string-match emms-source-file-exclude-regexp file))
- (file-directory-p file))
- (emms-playlist-insert-track
- (emms-track 'playlist (expand-file-name file)))))
- (directory-files dir t "^[^.]")))
-
-;;;###autoload (autoload 'emms-play-playlist-directory-tree
-;;;###autoload "emms-source-playlist" nil t)
-;;;###autoload (autoload 'emms-add-playlist-directory-tree
-;;;###autoload "emms-source-file" nil t)
-(define-emms-source playlist-directory-tree (dir)
- "An EMMS source for multiple directory trees of playlist files.
-If DIR is not specified, it is queried from the user."
- (interactive (list
- (emms-read-directory-name "Play directory tree: "
- emms-source-file-default-directory
- emms-source-file-default-directory
- t)))
- (mapc (lambda (file)
- (unless (let ((case-fold-search nil))
- (string-match emms-source-file-exclude-regexp file))
- (emms-playlist-insert-track
- (emms-track 'playlist file))))
- (emms-source-file-directory-tree (expand-file-name dir) "^[^.]")))
-
-(provide 'emms-source-playlist)
-;;; emms-source-playlist.el ends here
diff --git a/lisp/emms-stream-info.el b/lisp/emms-stream-info.el
deleted file mode 100644
index 2bc7a41..0000000
--- a/lisp/emms-stream-info.el
+++ /dev/null
@@ -1,30 +0,0 @@
-;;; emms-stream-info.el --- Info from streaming audio
-
-;; Copyright (C) 2004, 2005, 2006, 2007, 2008,
-;; 2009, 2019 Free Software Foundation, Inc.
-
-;; Author: Yoni Rabkin <yrk@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3 of the
-;; License, or (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Code:
-
-;; to be implemented!
-
-(provide 'emms-stream-info)
-
-;;; emms-stream-info.el ends here
diff --git a/lisp/emms-streams.el b/lisp/emms-streams.el
deleted file mode 100644
index c3b2d11..0000000
--- a/lisp/emms-streams.el
+++ /dev/null
@@ -1,179 +0,0 @@
-;; emms-streams.el -- A collection of online streaming audio
-
-;; Copyright (C) 2019 Free Software Foundation, Inc.
-
-;; Authors: Yoni Rabkin <yrk@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3 of the License, or
-;; (at your option) any later version.
-
-;; EMMS 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 EMMS; if not, write to the Free Software Foundation,
-;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; 2019-11-05 - This is a complete re-write of the emms-streams.el,
-;; using a different approach.
-
-;; This includes the built-in list of streams which come with Emms by
-;; default. Emms has no affiliation of any kind with the streaming
-;; audio stations listed below, nor is this an endorsement of these
-;; stations. Instead, this is a collection of stations submitted to
-;; the project over the years by people who enjoy Emms. We hope you
-;; will enjoy them too.
-
-;;; Code:
-
-(require 'emms)
-(require 'emms-source-playlist)
-(require 'emms-playlist-mode)
-
-
-;;; ------------------------------------------------------------------
-;;; definitions
-;;; ------------------------------------------------------------------
-
-(defvar emms-streams-buffer-name "Emms Streams"
- "Name for creating a streams buffer.")
-
-(defvar emms-streams-built-in-disclaimer
- ";; This includes the built-in list of streams which come with Emms by
-;; default. Emms has no affiliation of any kind with the streaming
-;; audio stations listed below, nor is this an endorsement of these
-;; stations. Instead, this is a collection of stations submitted to
-;; the project over the years by people who enjoy Emms. We hope you
-;; will enjoy them too."
- "Explaining the relationship between Emms and these streams.")
-
-(defvar emms-streams-built-in-list
- '((*track* (type . streamlist)
- (name . "http://www.somafm.com/beatblender.pls")
- (metadata "SomaFM: Beatblender" "http://www.somafm.com/beatblender.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.somafm.com/secretagent.pls")
- (metadata "SomaFM: Secret Agent" "http://www.somafm.com/secretagent.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.somafm.com/groovesalad.pls")
- (metadata "SomaFM: Groove Salad" "http://www.somafm.com/groovesalad.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.somafm.com/dronezone.pls")
- (metadata "SomaFM: Drone Zone" "http://www.somafm.com/dronezone.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.somafm.com/tagstrance.pls")
- (metadata "SomaFM: Tag's Trance" "http://www.somafm.com/tagstrance.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.somafm.com/indiepop.pls")
- (metadata "SomaFM: Indie Pop Rocks" "http://www.somafm.com/indiepop.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.somafm.com/doomed.pls")
- (metadata "SomaFM: Doomed" "http://www.somafm.com/doomed.pls" 1 streamlist))
- (*track* (type . url) (name . "http://listen.radionomy.com:80/-PHILOSOMATIKAPROGRESSIVE-")
- (metadata "P H I L O S O M A T I K A - Progressive Psytrance" "http://listen.radionomy.com:80/-PHILOSOMATIKAPROGRESSIVE-" 1 url))
- (*track* (type . streamlist)
- (name . "http://www.bassdrive.com/BassDrive.m3u")
- (metadata "Drum and Bass Radio, BassDrive" "http://www.bassdrive.com/BassDrive.m3u" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.ibiblio.org/wcpe/wcpe.pls")
- (metadata "WCPE, Classical Music" "http://www.ibiblio.org/wcpe/wcpe.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://stream.nute.net/kohina/stream.ogg.m3u")
- (metadata "Kohina - Old school game and demo music" "http://stream.nute.net/kohina/stream.ogg.m3u" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://privat.is-by.us:8000/necta192.mp3.m3u")
- (metadata "Nectarine, Demoscene Radio, DE Continuum's relay 192 mp3" "http://privat.is-by.us:8000/necta192.mp3.m3u" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://nectarine.from-de.com/necta192.m3u")
- (metadata "Nectarine, Demoscene Radio, DE stream (High Bitrate)" "http://nectarine.from-de.com/necta192.m3u" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://www.wfmu.org/wfmu.pls")
- (metadata "WFMU, Freeform radio" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://wfmu.org/wfmu_rock.pls")
- (metadata "WFMU, Rock'n'Soul Ichiban!" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://wfmu.org/wfmu_drummer.pls")
- (metadata "WFMU, Give the Drummer Radio" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://wfmu.org/wfmu_sheena.pls")
- (metadata "WFMU, Sheena's Jungle Room" "http://www.wfmu.org/wfmu.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://nyc01.egihosting.com:6232/listen.pls")
- (metadata "WBCR-LP - Berkshire Community Radio" "http://nyc01.egihosting.com:6232/listen.pls" 1 streamlist))
- (*track* (type . streamlist)
- (name . "http://199.244.85.125:8000/wxhq1")
- (metadata "WXHQ-LP - Newport Radio" "http://199.244.85.125:8000/wxhq1" 1 streamlist))))
-
-(defcustom emms-streams-file (concat (file-name-as-directory emms-directory)
- "streams.emms")
- "A file used to store the built-in streams."
- :group 'emms
- :type 'file)
-
-
-;;; ------------------------------------------------------------------
-;;; private functions
-;;; ------------------------------------------------------------------
-
-(defun emms-streams-install-file (file)
- "Install FILE, containing streams."
- (when (not (file-directory-p (file-name-directory emms-streams-file)))
- (make-directory (file-name-directory emms-streams-file)))
- (if (or (not (file-exists-p file))
- (and (file-exists-p file)
- (y-or-n-p (format "overwrite existing %s?" file))))
- (progn
- (message "writing %s" file)
- (with-temp-buffer
- (insert emms-source-playlist-native-header-line)
- (insert (format "\n%s\n\n" emms-streams-built-in-disclaimer))
- (insert
- (concat "("
- (mapconcat
- #'(lambda (e)
- (format "%S" e))
- emms-streams-built-in-list "\n")
- ")"))
- (write-region (point-min) (point-max) file))
- (message "writing %s... done" file))
- (message "aborting")))
-
-
-;;; ------------------------------------------------------------------
-;;; interface
-;;; ------------------------------------------------------------------
-
-(defun emms-streams-install ()
- (interactive)
- "Install the built-in streams file."
- (emms-streams-install-file emms-streams-file))
-
-(defun emms-streams ()
- (interactive)
- "Create or switch to the built-in streaming audio playlist."
- (when (and (not (file-exists-p emms-streams-file))
- (y-or-n-p "Emms' built-in streams file hasn't been installed yet. Install it now?"))
- (emms-streams-install))
- (let ((buf (get-buffer emms-streams-buffer-name)))
- (when (not buf)
- (with-current-buffer (get-buffer-create emms-streams-buffer-name)
- (setq buf (current-buffer))
- (emms-playlist-mode)
- (setq emms-playlist-buffer-p t)
- (emms-playlist-set-playlist-buffer (current-buffer))
- (emms-add-native-playlist emms-streams-file)))
- (switch-to-buffer buf)))
-
-
-(provide 'emms-streams)
-
-;;; emms-streams.el ends here
diff --git a/lisp/emms-tag-editor.el b/lisp/emms-tag-editor.el
deleted file mode 100644
index ca7941a..0000000
--- a/lisp/emms-tag-editor.el
+++ /dev/null
@@ -1,775 +0,0 @@
-;;; emms-tag-editor.el --- Edit track tags.
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-;;
-;; Author: Ye Wenbin <wenbinye@163.com>
-
-;; This file is part of EMMS.
-
-;; This program 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 3, or (at your option)
-;; any later version.
-;;
-;; This program 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 this program; if not, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-;;; Commentary:
-
-;; Put this file into your load-path and the following into your ~/.emacs:
-;; (require 'emms-tag-editor)
-
-;;; Code:
-
-(condition-case nil
- (require 'overlay)
- (error nil))
-(require 'emms)
-(eval-when-compile
- (require 'emms-info-metaflac))
-(require 'emms-info-mp3info)
-(require 'emms-playlist-mode)
-(require 'emms-mark)
-(require 'format-spec)
-
-(defvar emms-tag-editor-tags
- '((info-artist . "a")
- (info-composer . "C")
- (info-performer . "p")
- (info-title . "t")
- (info-album . "l")
- (info-tracknumber . "n")
- (info-year . "y")
- (info-genre . "g")
- (info-date . "d")
- (info-note . "c"))
- "An alist to determine the format of various info tags.")
-
-(defvar emms-tag-editor-edit-buffer "*EMMS-TAGS*"
- "Name of the buffer used for editing tags.")
-(defvar emms-tag-editor-log-buffer "*EMMS-LOG*"
- "Name of emms-tag-editor's log buffer.")
-
-(defun emms-tag-editor-make-format (tags)
- "Make a format string based on TAGS."
- (concat "%m\n" (emms-propertize (format "%-16s = " "name")
- 'read-only t 'rear-nonsticky t
- 'face 'bold)
- "%f\n"
- (mapconcat
- (lambda (tag)
- (concat (emms-propertize (format "%-16s = " (symbol-name tag))
- 'read-only t 'rear-nonsticky t
- 'face 'bold)
- "%" (cdr (assoc tag emms-tag-editor-tags))))
- tags "\n")
- "\n\n"))
-
-(defvar emms-tag-editor-formats
- (let* ((tags (mapcar 'car emms-tag-editor-tags))
- (default (emms-tag-editor-make-format (remove 'info-date tags))))
- `(("mp3" . ,default)
- ("ogg" . ,(emms-tag-editor-make-format (remove 'info-year tags)))
- ("flac" . ,(emms-tag-editor-make-format (remove 'info-year tags)))
- ("default" . ,default)))
- "Format to use when inserting 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
- c -- Track info-composer
- p -- Track info-performer
- t -- Track info-title
- l -- Track info-album
- n -- Track info-tracknumber
- D -- Track info-discnumber
- y -- Track info-year
- g -- Track info-genre
- ; -- Track info-note
-
-You can add new specifications in `emms-tag-editor-tags', and use
-`emms-tag-editor-make-format' to create a new format string.
-
-The CDR part also can be a function, which accepts one parameter,
-the track, and returns a string to insert in
-`emms-tag-editor-edit-buffer'.")
-
-(defvar emms-tag-editor-get-format-function 'emms-tag-editor-get-format
- "Determines which function to call to get the format string, which is
-used for inserting the track.")
-
-(defvar emms-tag-editor-parse-function 'emms-tag-editor-default-parser
- "Function to parse tags in `emms-tag-editor-edit-buffer'.
-It should find all modified tags, and return all the tracks. The
-tracks for which a tag has been modified should set a property
-'tag-modified to t. If the track name has been changed, the
-function should set a new property 'newname instead of setting
-the 'name directly.
-
-See also `emms-tag-editor-default-parser'.")
-
-(defvar emms-tag-editor-tagfile-functions
- '(("mp3" "mid3v2"
- ((info-artist . "a")
- (info-title . "t")
- (info-album . "A")
- (info-tracknumber . "T")
- (info-year . "y")
- (info-genre . "g")
- (info-note . "c")))
- ("ogg" . emms-tag-editor-tag-ogg)
- ("flac" . emms-tag-editor-tag-flac))
- "An alist used when committing changes to tags in files.
-If the external program sets tags by command line options
-one-by-one, then the list should like:
- (EXTENSION PROGRAM COMMAND_LINE_OPTIONS)
-
-Otherwise, a function that accepts a single parameter, the track,
-should be given.
-
-See also `emms-tag-editor-tag-file' and `emms-tag-editor-tag-ogg'.")
-
-(defun emms-tag-editor-tag-flac (track)
- "Commit changes to an FLAC file according to TRACK."
- (require 'emms-info-metaflac)
- (with-temp-buffer
- (let ((tags '("artist" "composer" "performer" "title" "album" "tracknumber" "discnumber" "date" "genre" "note"))
- need val)
- (mapc (lambda (tag)
- (let ((info-tag (intern (concat "info-" tag))))
- (when (> (length (setq val (emms-track-get track info-tag))) 0)
- (insert (upcase tag) "=" val "\n"))))
- tags)
- (when (buffer-string)
- (apply #'call-process-region (point-min) (point-max)
- emms-info-metaflac-program-name nil
- (get-buffer-create emms-tag-editor-log-buffer)
- nil
- (append
- (mapcar (lambda (tag)
- (concat "--remove-tag=" tag))
- tags)
- '("--import-tags-from=-")
- '("--")
- (list (emms-track-name track))))))))
-
-(defun emms-tag-editor-tag-ogg (track)
- "Commit changes to an OGG file according to TRACK."
- (let (args val)
- (mapc (lambda (tag)
- (let ((info-tag (intern (concat "info-" tag))))
- (when (> (length (setq val (emms-track-get track info-tag))) 0)
- (setq args (append (list "-t" (concat (upcase tag) "=" val)) args)))))
- '("artist" "composer" "performer" "title" "album" "tracknumber" "date" "genre" "note"))
- (when args
- (apply #'call-process "vorbiscomment" nil
- (get-buffer-create emms-tag-editor-log-buffer)
- nil
- "-w"
- (append args (list (emms-track-name track)))))))
-
-(defun emms-tag-editor-tag-file (track program tags filename)
- "Change TAGS in FILE, using PROGRAM.
-Valid tags are given by `emms-tag-editor-tagfile-functions'."
- (let (args val)
- (mapc (lambda (tag)
- (setq val (emms-track-get track (car tag)))
- (if (and val (stringp val))
- (setq args (append (list (concat "-" (cdr tag)) val) args))))
- tags)
- (apply 'call-process program
- nil (get-buffer-create emms-tag-editor-log-buffer) nil
- (nconc args (list filename)))))
-
-(defun emms-tag-editor-get-format (track)
- "Get the format string to use for committing changes to TRACK."
- (let ((format
- (assoc (file-name-extension (emms-track-name track))
- emms-tag-editor-formats)))
- (if format
- (cdr format)
- (cdr (assoc "default" emms-tag-editor-formats)))))
-
-(defun emms-tag-editor-format-track (track)
- "Return a string representing the info tags contained in TRACK.
-This string is suitable for inserting into the tags buffer."
- (let ((format (funcall emms-tag-editor-get-format-function track)))
- (if (functionp format)
- (funcall format track)
- (format-spec
- format
- (apply 'format-spec-make
- ?m (emms-propertize (emms-track-force-description track)
- 'face 'emms-playlist-track-face
- 'emms-track (copy-sequence track))
- ?f (emms-track-name track)
- (apply 'append
- (mapcar (lambda (tag)
- (list (string-to-char (cdr tag))
- (or (emms-track-get track (car tag)) "")))
- emms-tag-editor-tags)))))))
-
-(defun emms-tag-editor-track-at (&optional pos)
- "Return a copy of the track at POS. Defaults to point if POS is nil."
- (let ((track (emms-playlist-track-at pos))
- newtrack)
- (when track
- (setq newtrack (copy-sequence track))
- (emms-track-set newtrack 'position (point-marker))
- (emms-track-set newtrack 'orig-track track)
- newtrack)))
-
-(defsubst emms-tag-editor-erase-buffer (&optional buf)
- "Erase the buffer BUF, and ensure that it exists."
- (let ((inhibit-read-only t))
- (with-current-buffer (get-buffer-create buf)
- (erase-buffer))))
-
-(defsubst emms-tag-editor-insert-track (track)
- "Insert TRACK, if it is specified."
- (and track
- (insert (emms-tag-editor-format-track track))))
-
-(defsubst emms-tag-editor-display-log-buffer-maybe ()
- "Display the log buffer if it has any contents."
- (if (> (buffer-size (get-buffer emms-tag-editor-log-buffer)) 0)
- (display-buffer emms-tag-editor-log-buffer)))
-
-(defun emms-tag-editor-insert-tracks (tracks)
- "Insert TRACKS into the tag editor buffer."
- (save-excursion
- (emms-tag-editor-erase-buffer emms-tag-editor-log-buffer)
- (emms-tag-editor-erase-buffer emms-tag-editor-edit-buffer)
- (set-buffer (get-buffer emms-tag-editor-edit-buffer))
- (mapc 'emms-tag-editor-insert-track tracks)
- (emms-tag-editor-mode)
- (pop-to-buffer (current-buffer))
- (goto-char (point-min))
- (emms-tag-editor-display-log-buffer-maybe)))
-
-(defun emms-tag-editor-edit-track (track)
- "Edit the track at point, or TRACK."
- (interactive (list (emms-tag-editor-track-at)))
- (if (null track)
- (message "No track at point!")
- (emms-tag-editor-insert-tracks (list track))))
-
-(defun emms-tag-editor-edit-marked-tracks ()
- "Edit all tracks marked in the current buffer."
- (interactive)
- (let ((tracks (emms-mark-mapcar-marked-track 'emms-tag-editor-track-at t)))
- (if (null tracks)
- (message "No track marked!")
- (emms-tag-editor-insert-tracks tracks))))
-
-(defun emms-tag-editor-edit ()
- "Edit tags of either the track at point or all marked tracks."
- (interactive)
- (if (emms-mark-has-markedp)
- (emms-tag-editor-edit-marked-tracks)
- (emms-tag-editor-edit-track (emms-tag-editor-track-at))))
-
-(defvar emms-tag-editor-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map [tab] 'emms-tag-editor-next-field)
- (define-key map [backtab] 'emms-tag-editor-prev-field)
- (define-key map "\C-c\C-n" 'emms-tag-editor-next-track)
- (define-key map "\C-c\C-p" 'emms-tag-editor-prev-track)
- (define-key map "\C-c\C-c" 'emms-tag-editor-submit-and-exit)
- (define-key map "\C-c\C-s" 'emms-tag-editor-submit)
- (define-key map "\C-x\C-s" 'emms-tag-editor-submit)
- (define-key map "\C-c\C-r" 'emms-tag-editor-set-all)
- (define-key map "\C-c\C-a" 'emms-tag-editor-replace-in-tag)
- (define-key map "\C-c\C-t" 'emms-tag-editor-transpose-tag)
- map)
- "Keymap for `emms-tag-editor-mode'.")
-(define-key emms-playlist-mode-map "E" 'emms-tag-editor-edit)
-
-(define-derived-mode emms-tag-editor-mode text-mode "Tag-Edit"
- "Major mode to edit track tags.
-\\{emms-tag-editor-mode-map}")
-
-(defun emms-tag-editor-set-all (tag value)
- "Set TAG to VALUE in all tracks.
-If transient-mark-mode is turned on, you can apply the command to
-a selected region.
-
- If `transient-mark-mode' is on and the mark is active, the
-changes will only take effect on the tracks in the region."
- (interactive
- (list (emms-completing-read "Set tag: "
- (mapcar (lambda (arg)
- (list (symbol-name (car arg))))
- emms-tag-editor-tags)
- nil t)
- (read-from-minibuffer "To: ")))
- (save-excursion
- (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 tag)) nil t)
- (skip-chars-forward " \t=")
- (delete-region (point) (line-end-position))
- (insert value)))))
-
-(defun emms-tag-editor-replace-in-tag (tag from to)
- "Query and replace text in selected TAG.
-For example, if the info-title tag is selected, then only perform
-replacement in title tags.
-
-If `transient-mark-mode' is on and the mark is active, the
-changes will only take effect on the tracks in the region."
- (interactive
- (cons (emms-completing-read "Replace in tag: "
- (mapcar (lambda (arg)
- (list (symbol-name (car arg))))
- emms-tag-editor-tags)
- nil t)
- (let ((common (query-replace-read-args
- (if (and transient-mark-mode mark-active)
- "Query replace regexp in region"
- "Query replace regexp")
- t)))
- (butlast common 2))))
- (let ((overlay (make-overlay (point-min) (1+ (point-min)))))
- (overlay-put overlay 'face 'match)
- (unwind-protect
- (save-excursion
- (save-restriction
- (when (and mark-active transient-mark-mode)
- (narrow-to-region (region-beginning) (region-end))
- (deactivate-mark))
- (setq tag (concat (regexp-quote tag) "[ \t]+=[ \t]+"))
- (goto-char (point-min))
- (map-y-or-n-p
- (lambda (match)
- (move-overlay overlay (match-beginning 0) (match-end 0))
- (format "Replace %s to %s" (car match) (cadr match)))
- (lambda (match)
- (delete-region (- (point) (length (car match))) (point))
- (insert (cadr match)))
- (lambda ()
- (if (and (save-excursion
- (re-search-backward tag (line-beginning-position) t))
- (not (= (point) (line-end-position)))
- (re-search-forward from (line-end-position) t))
- (list (match-string 0) (cond
- ((and (listp to)
- (fboundp (car to)) (funcall (car to) (cdr to) 0)))
- ((string-match-p "\\\\[&[:digit:]]" to)
- (match-substitute-replacement to nil nil))
- ((stringp to) to)
- (t (error "Wrong type argument: string or cons cell, %s" to))))
- (let (found)
- (while (and (not found)
- (re-search-forward tag nil t))
- (if (re-search-forward from (line-end-position) t)
- (setq found t)))
- (and found (list (match-string 0) (cond
- ((and (listp to)
- (fboundp (car to)) (funcall (car to) (cdr to) 0)))
- ((string-match-p "\\\\[&[:digit:]]" to)
- (match-substitute-replacement to nil nil))
- ((stringp to) to)
- (t (error "Wrong type argument: string or cons cell, %s" to)))))))))))
- (delete-overlay overlay))))
-
-(defun emms-tag-editor-transpose-tag (tag1 tag2)
- "Transpose value of TAG1 and TAG2.
-If `transient-mark-mode' is on and the mark is active, the
-changes will only take effect on the tracks in the region."
- (interactive
- (let* ((tag1 (intern (emms-completing-read
- "Tag 1: "
- (mapcar (lambda (arg)
- (list (symbol-name (car arg))))
- emms-tag-editor-tags)
- nil t)))
- (tag2 (intern (emms-completing-read
- "Tag 2: "
- (mapcar (lambda (arg)
- (list (symbol-name (car arg))))
- (assq-delete-all
- tag1
- (copy-sequence emms-tag-editor-tags)))
- nil t))))
- (list tag1 tag2)))
- (save-excursion
- (save-restriction
- (if (and mark-active transient-mark-mode)
- (narrow-to-region (region-beginning) (region-end)))
- (let* ((emms-playlist-buffer-p t)
- (tracks (emms-playlist-tracks-in-region (point-min)
- (point-max)))
- (inhibit-read-only t)
- temp)
- (erase-buffer)
- (dolist (track (nreverse tracks))
- (setq temp (emms-track-get track tag1))
- (emms-track-set track tag1 (emms-track-get track tag2))
- (emms-track-set track tag2 temp)
- (emms-track-set track 'tag-modified t)
- (emms-tag-editor-insert-track track))))))
-
-(defun emms-tag-editor-guess-tag-filename (pattern fullname)
- "A pattern is a string like \"%a-%t-%y\" which stand for
-the file name is constructed by artist, title, year with seperator '-'.
-see `emms-tag-editor-compile-pattern' for detail about pattern syntax.
-Available tags are list in `emms-tag-editor-tags'.
-
-if with prefix argument, the information will extract from full
-name, otherwise just match in file name.
-
-An example to guess tag from file name, which the file directory is
-the aritist and file name is the title. It can be done like:
-C-u M-x emms-tag-editor-guess-tag-filename RET
-%{a:[^/]+}/%{t:[^/]+}\.mp3 RET
-"
- (interactive
- (list
- (read-from-minibuffer (format "Match in %sfile name(C-h for help): "
- (if current-prefix-arg "FULL " ""))
- nil
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map minibuffer-local-map)
- (define-key map "\C-h"
- (lambda ()
- (interactive)
- (with-output-to-temp-buffer "*Help*"
- (princ
- "A pattern is a string like \"%a-%t-%y\" which stand for
-the file name is constructed by artist, title, year with seperator '-'.
-see `emms-tag-editor-compile-pattern' for detail about pattern syntax.
-
-Available tags are:
-")
- (mapc (lambda (tag)
- (princ (format "\t%s - %S\n" (cdr tag) (car tag))))
- emms-tag-editor-tags)
- (with-current-buffer standard-output
- (help-mode)))))
- map))
- current-prefix-arg))
- (setq pattern (emms-tag-editor-compile-pattern pattern))
- (save-excursion
- (save-restriction
- (if (and mark-active transient-mark-mode)
- (narrow-to-region (region-beginning) (region-end)))
- (let* ((emms-playlist-buffer-p t)
- (tracks (emms-playlist-tracks-in-region (point-min)
- (point-max)))
- (inhibit-read-only t)
- filename)
- (erase-buffer)
- (dolist (track (nreverse tracks))
- (emms-track-set track 'tag-modified t)
- (setq filename (emms-track-name track))
- (or fullname (setq filename (file-name-nondirectory filename)))
- (when (string-match (car pattern) filename)
- (mapc (lambda (pair)
- (emms-track-set
- track
- (car (rassoc (char-to-string (car pair))
- emms-tag-editor-tags))
- (match-string (cdr pair) filename)))
- (cdr pattern)))
- (emms-tag-editor-insert-track track))))))
-
-(defun emms-tag-editor-compile-pattern (pattern)
- "A pattern to regexp convertor. \"%a-%{b:[a-z]+}\" will compile to
-\"\\([^-]+\\)-\\([a-z]+\\)\"."
- (let ((index 0)
- (paren 0)
- (i 0)
- (len (length pattern))
- (compiled "")
- registers register match
- escape c)
- (while (< i len)
- (setq c (aref pattern i)
- i (1+ i))
- (cond ((= c ?\\)
- (setq c (aref pattern i)
- i (1+ i))
- (cond ((= c ?\()
- (setq paren (1+ paren)
- index (1+ index)))
- ((= c ?\))
- (setq paren (1- paren))))
- (setq compiled (concat compiled "\\" (char-to-string c))))
- ((= c ?%)
- (setq c (aref pattern i)
- i (1+ i))
- ;; How to repressent } in the pattern?
- (if (= c ?{)
- (if (/= (aref pattern (1+ i)) ?:)
- (error "Compile error")
- (setq register (aref pattern i)
- match ""
- i (+ i 2))
- (while (and (< i len)
- (or escape (/= (aref pattern i) ?})))
- (if escape
- (setq escape nil)
- (if (= (aref pattern i) ?\\)
- (setq escape t)))
- (setq match (concat match (char-to-string (aref pattern i)))
- i (1+ i)))
- (setq i (1+ i)))
- (setq register c
- match "[^-]+"))
- (setq compiled (concat compiled "\\(" match "\\)")
- index (1+ index))
- (add-to-list 'registers (cons register index)))
- (t (setq compiled (concat compiled (char-to-string c))))))
- (if (/= paren 0) (error "Paren not match!"))
- (cons compiled registers)))
-
-(defun emms-tag-editor-next-field (arg)
- "Move to the next tag field."
- (interactive "p")
- (if (> arg 0)
- (re-search-forward "\\s-*=[ \t]*" nil nil arg)
- (emms-tag-editor-prev-field (- arg))))
-
-(defun emms-tag-editor-prev-field (arg)
- "Move to the previous tag field."
- (interactive "p")
- (if (< arg 0)
- (emms-tag-editor-next-field (- arg))
- (skip-chars-backward " \t=")
- (re-search-backward "\\s-*=[ \t]*" nil nil arg)
- (skip-chars-forward " \t=")))
-
-(defun emms-tag-editor-prev-track ()
- "Move to the previous track."
- (interactive)
- (let ((prev (previous-single-property-change (point)
- 'emms-track)))
- (when (not prev)
- (error "No previous track"))
- (when (not (get-text-property prev 'emms-track))
- (setq prev (or (previous-single-property-change prev 'emms-track)
- (point-min))))
- (when (or (not prev)
- (not (get-text-property prev 'emms-track)))
- (error "No previous track"))
- (goto-char prev)))
-
-(defun emms-tag-editor-next-track ()
- "Move to the next track."
- (interactive)
- (let ((next (next-single-property-change (point)
- 'emms-track)))
- (when (not next)
- (error "No next track"))
- (when (not (get-text-property next 'emms-track))
- (setq next (next-single-property-change next 'emms-track)))
- (when (or (not next)
- (= next (point-max)))
- (error "No next track"))
- (goto-char next)))
-
-(defun emms-tag-editor-submit (arg)
- "Make modified tags take affect.
-With prefix argument, bury the tag edit buffer."
- (interactive "P")
- (let ((tracks (funcall emms-tag-editor-parse-function)))
- (if (not (and tracks (y-or-n-p "Submit changes? ")))
- (message "No tags were modified")
- (emms-tag-editor-erase-buffer emms-tag-editor-log-buffer)
- (emms-tag-editor-apply tracks)))
- (if arg (bury-buffer)))
-
-(defun emms-tag-editor-apply (tracks)
- "Apply all changes made to TRACKS."
- (message "Setting tags...")
- (let (filename func exit old pos val need-sync)
- (save-excursion
- (dolist (track tracks)
- (when (emms-track-get track 'tag-modified)
- (setq filename (emms-track-name track)
- old (emms-track-get track 'orig-track))
- ;; rename local file
- (when (and (emms-track-get track 'newname)
- (eq (emms-track-get track 'type) 'file)
- (file-writable-p (emms-track-name track))
- (y-or-n-p (format "Rename %s to %s? "
- (emms-track-name track)
- (emms-track-get track 'newname))))
- (setq filename (emms-track-get track 'newname))
- (ignore-errors
- ;; Ignore errors so that renaming multiple files doesn't stop
- ;; because of one that fails. In that case it's probably
- ;; old-file = newfile which causes the problem.
- (rename-file (emms-track-name track) filename 1))
- (emms-track-set old 'name filename)
- ;; for re-enter this function
- (emms-track-set track 'name filename)
- (setq need-sync t)
- ;; register to emms-cache-db
- (when (boundp 'emms-cache-modified-function)
- (funcall emms-cache-modified-function)
- (funcall emms-cache-set-function 'file filename old)))
- (emms-track-set track 'newname nil)
- ;; set tags to original track
- (dolist (tag emms-tag-editor-tags)
- (when (setq val (emms-track-get track (car tag)))
- (emms-track-set old (car tag) val)))
- ;; use external program to change tags in the file
- (when (and (eq (emms-track-get track 'type) 'file)
- (file-writable-p (emms-track-name track))
- (setq func (assoc (file-name-extension filename)
- emms-tag-editor-tagfile-functions)))
- (setq exit
- (if (functionp (cdr func))
- (funcall (cdr func) track)
- (emms-tag-editor-tag-file track (cadr func) (nth 2 func) filename)))
- (if (zerop exit)
- (emms-track-get track 'info-mtime (butlast (current-time)))
- (emms-tag-editor-log
- "Changing 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))
- (set-buffer (marker-buffer pos))
- (goto-char pos)
- (funcall emms-playlist-update-track-function))
- ;; clear modified tag
- (emms-track-set track 'tag-modified nil))))
- (if (and (featurep 'emms-cache)
- need-sync
- (y-or-n-p "You have changed some track names; sync the cache? "))
- (and (fboundp 'emms-cache-sync) ; silence byte-compiler
- (emms-cache-sync)))
- (unless (emms-tag-editor-display-log-buffer-maybe)
- (message "Setting tags...done"))))
-
-(defun emms-tag-editor-submit-and-exit ()
- "Submit changes to track information and exit the tag editor."
- (interactive)
- (emms-tag-editor-submit t))
-
-(defun emms-tag-editor-default-parser ()
- "Default function used to parse tags in `emms-tag-editor-edit-buffer'."
- (let (next tracks track key val)
- (goto-char (point-min))
- (if (get-text-property (point) 'emms-track)
- (setq next (point))
- (setq next (next-single-property-change (point)
- 'emms-track)))
- (when next
- (while
- (progn
- (goto-char next)
- (setq track (get-text-property (point) 'emms-track))
- (forward-line 1)
- (mapc (lambda (pair)
- (when (string-match "\\s-*=\\s-*" pair)
- (setq key (intern-soft (substring pair 0 (match-beginning 0)))
- val (substring pair (match-end 0)))
- (when (and key
- (let ((old (emms-track-get track key)))
- (if old
- (not (string= val old))
- (string< "" val))))
- (if (eq key 'name)
- (emms-track-set track 'newname val)
- (emms-track-set track key val))
- (emms-track-set track 'tag-modified t))))
- (let ((end-point (next-single-property-change
- (point) 'emms-track)))
- (if (and end-point (save-excursion
- (goto-char end-point)
- (bolp)))
- (setq next end-point)
- (progn
- (setq next nil
- end-point (point-max))))
- (split-string (buffer-substring (point) end-point)
- "\n")))
- (if (emms-track-get track 'tag-modified)
- (push track tracks))
- next))
- tracks)))
-
-(defun emms-tag-editor-log (&rest args)
- (with-current-buffer (get-buffer-create emms-tag-editor-log-buffer)
- (goto-char (point-max))
- (insert (apply 'format args) "\n")))
-
-;;
-;; Renaming files according their tags
-;;
-
-(defvar emms-tag-editor-rename-format "%a - %l - %n - %t"
- "When `emms-tag-editor-rename' is invoked the track's file will
-be renamed according this format specification. The file
-extension will be added automatically.
-
-It uses the format specs defined in `emms-tag-editor-tags'.")
-
-(defun emms-tag-editor-rename ()
- "Rename the file corresponding to track at point or all marked
-tracks according to the value of
-`emms-tag-editor-rename-format'."
- (interactive)
- (if (emms-mark-has-markedp)
- (emms-tag-editor-rename-marked-tracks)
- (emms-tag-editor-rename-track (emms-tag-editor-track-at))))
-
-(defun emms-tag-editor-rename-track (track &optional dont-apply)
- "Rename TRACK's file according `emms-tag-editor-rename-format's
-value.
-
-If DONT-APPLY is non-nil the changes won't be applied directly.
-Then it's the callers job to apply them afterwards with
-`emms-tag-editor-apply'."
- (if (eq (emms-track-get track 'type) 'file)
- (let* ((old-file (emms-track-name track))
- (path (file-name-directory old-file))
- (suffix (file-name-extension old-file))
- (new-file (concat
- path
- (format-spec
- emms-tag-editor-rename-format
- (apply 'format-spec-make
- (apply 'append
- (mapcar
- (lambda (tag)
- (list (string-to-char (cdr tag))
- (or (emms-track-get track (car tag))
- "")))
- emms-tag-editor-tags))))
- "." suffix)))
- (emms-track-set track 'newname new-file)
- (emms-track-set track 'tag-modified t)
- (unless dont-apply
- (emms-tag-editor-apply (list track))))
- (message "Only files can be renamed.")))
-
-(defun emms-tag-editor-rename-marked-tracks ()
- "Rename the files corresponding to all marked tracks according
-`emms-tag-editor-rename-format's value."
- (let ((tracks (emms-mark-mapcar-marked-track
- 'emms-tag-editor-track-at t)))
- (if (null tracks)
- (message "No track marked!")
- (dolist (track tracks)
- (emms-tag-editor-rename-track track t))
- (emms-tag-editor-apply tracks))))
-
-(define-key emms-playlist-mode-map "R" 'emms-tag-editor-rename)
-
-(provide 'emms-tag-editor)
-;;; Emms-tag-editor.el ends here
diff --git a/lisp/emms-url.el b/lisp/emms-url.el
deleted file mode 100644
index 59d5cfa..0000000
--- a/lisp/emms-url.el
+++ /dev/null
@@ -1,114 +0,0 @@
-;;; emms-url.el --- Make URL and EMMS work together well
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;;; Commentary:
-
-;; These routines sanify input to URL and parse data returned by URL.
-
-;;; Code:
-
-(require 'url)
-(require 'emms-compat)
-
-(defvar emms-url-specials-entire
- '((?\ . "%20")
- (?\n . "%0D%0A"))
- "*An alist of characters which must be represented specially in URLs.
-The transformation is the key of the pair.
-
-This is used by `emms-url-quote-entire'.")
-
-(defun emms-url-quote-entire (url)
- "Escape specials conservatively in an entire URL.
-
-The specials to escape are specified by the `emms-url-specials-entire'
-variable.
-
-If you want to escape parts of URLs thoroughly, then use
-`emms-url-quote' instead."
- (apply (function concat)
- (mapcar
- (lambda (ch)
- (let ((repl (assoc ch emms-url-specials-entire)))
- (if (null repl)
- (char-to-string ch)
- (cdr repl))))
- (append url nil))))
-
-(defun emms-url-quote (s &optional safe)
- "Replace special characters in S using the `%xx' escape.
-This is useful for escaping parts of URLs, but not entire URLs.
-
-Characters in [a-zA-Z_.-/] and SAFE(default is \"\") will never be
-quoted.
-e.g.,
- (emms-url-quote \"abc def\") => \"abc%20def\"."
- (if (not (stringp s))
- ""
- (or safe (setq safe ""))
- (save-match-data
- (let ((re (if (string-match "]" safe)
- ;; `]' should be placed at the beginning inside []
- (format "[]a-zA-Z_.-/%s]"
- (emms-replace-regexp-in-string "]" "" safe))
- (format "[a-zA-Z_.-/%s]" safe))))
- (mapconcat
- (lambda (c)
- (let ((s1 (char-to-string c)))
- (if (string-match re s1)
- s1
- (format "%%%02x" c))))
- (string-to-list (encode-coding-string s 'utf-8))
- "")))))
-
-(defun emms-url-quote-plus (s &optional safe)
- "Run (emms-url-quote s \" \"), then replace ` ' with `+'."
- (emms-replace-regexp-in-string
- " " "+" (emms-url-quote s (concat safe " "))))
-
-(defun emms-url-quote-underscore (s &optional safe)
- "Run (emms-url-quote s \" \"), then replace ` ' with `_'."
- (emms-replace-regexp-in-string
- " " "_" (emms-url-quote s (concat safe " "))))
-
-(defun emms-http-content-coding ()
- (save-match-data
- (and (boundp 'url-http-content-type)
- (stringp url-http-content-type)
- (string-match ";\\s-*charset=\\([^;[:space:]]+\\)"
- url-http-content-type)
- (intern-soft (downcase (match-string 1 url-http-content-type))))))
-
-(defun emms-http-decode-buffer (&optional buffer)
- "Recode the buffer with `url-retrieve's contents. Else the
-buffer would contain multibyte chars like \\123\\456."
- (with-current-buffer (or buffer (current-buffer))
- (let* ((default (or (car default-process-coding-system) 'utf-8))
- (coding (or (emms-http-content-coding) default)))
- (when coding
- ;; (pop-to-buffer (current-buffer))
- ;; (message "content-type: %s" url-http-content-type)
- ;; (message "coding: %S [default: %S]" coding default)
- (set-buffer-multibyte t)
- (decode-coding-region (point-min) (point-max) coding)))))
-
-(provide 'emms-url)
-;;; emms-url.el ends here
diff --git a/lisp/emms-volume-amixer.el b/lisp/emms-volume-amixer.el
deleted file mode 100644
index 190f6b0..0000000
--- a/lisp/emms-volume-amixer.el
+++ /dev/null
@@ -1,76 +0,0 @@
-;;; emms-volume-amixer.el --- a mode for changing volume using amixer
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Martin Schoenmakers <aiviru@diamond-age.net>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; 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 defines a few simple functions to raise or lower the volume
-;; using amixer. It can be used stand-alone, though it's meant for usage
-;; with EMMS, particularly with emms-volume.el
-
-;;; History:
-
-;; May 30 2006: First cleanup and collation of amixer functions into a
-;; separate file for releasability.
-
-;;; Todo:
-
-;; There probably needs to be more configurability, which may in turn
-;; mean adding some more functions.
-;; Some of this could benefit from adding customize interfaces.
-
-;;; Code:
-
-(defcustom emms-volume-amixer-control "Master"
- "The control to change the volume with.
-Controls includes \"Master\", \"PCM\", etc. For a full list of available
-controls, run `amixer controls' in a shell."
- :type '(choice (const :tag "Master" "Master")
- (const :tag "PCM" "PCM")
- (string :tag "Something else: "))
- :group 'emms-volume)
-
-(defcustom emms-volume-amixer-card 0
- "The card number to change volume.
-The card is identified by a number. For a full list run `cat
-/proc/asound/cards' in a shell."
- :type 'integer
- :group 'emms-volume)
-
-;;;###autoload
-(defun emms-volume-amixer-change (amount)
- "Change amixer master volume by AMOUNT."
- (message "Playback channels: %s"
- (with-temp-buffer
- (when (zerop
- (call-process "amixer" nil (current-buffer) nil
- "-c"
- (format "%d" emms-volume-amixer-card)
- "sset" emms-volume-amixer-control
- (format "%d%%%s" (abs amount)
- (if (< amount 0) "-" "+"))))
- (if (re-search-backward "\\[\\([0-9]+%\\)\\]" nil t)
- (match-string 1))))))
-
-(provide 'emms-volume-amixer)
-
-;;; emms-volume-amixer.el ends here
diff --git a/lisp/emms-volume-mixerctl.el b/lisp/emms-volume-mixerctl.el
deleted file mode 100644
index 4ca7820..0000000
--- a/lisp/emms-volume-mixerctl.el
+++ /dev/null
@@ -1,80 +0,0 @@
-;;; emms-volume-mixerctl.el --- a mode for changing volume using mixerctl
-
-;; Copyright (C) 2006, 2007, 2008, 2009, 2019 Free Software Foundation, Inc.
-
-;; Authors: Martin Schoenmakers <aiviru@diamond-age.net>
-;; Bruno Félix Rezende Ribeiro <oitofelix@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; 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 defines a few simple functions to raise or lower the volume
-;; using mixerctl. It can be used stand-alone, though it's meant for usage
-;; with EMMS, particularly with emms-volume.el
-
-;;; History:
-
-;; Jul 06 2019: Based on emms-volume-amixer.el by Martin Schoenmakers
-
-;;; Todo:
-
-;; There probably needs to be more configurability, which may in turn
-;; mean adding some more functions.
-;; Some of this could benefit from adding customize interfaces.
-
-;;; Code:
-
-(defcustom emms-volume-mixerctl-control "master"
- "The control to change the volume with.
-Controls includes \"master\", \"mono\", etc. For a full list of available
-controls, run `mixerctl -a' in a shell."
- :type '(choice (const :tag "master" "master")
- (const :tag "mono" "mono")
- (string :tag "Something else: "))
- :group 'emms-volume)
-
-(defcustom emms-volume-mixerctl-card 0
- "The card number to change volume.
-The card is identified by a number. For a full list run `ls
-/dev/mixer?*' in a shell."
- :type 'integer
- :group 'emms-volume)
-
-;;;###autoload
-(defun emms-volume-mixerctl-change (amount)
- "Change mixerctl master volume by AMOUNT."
- (message "Playback channels: %s"
- (with-temp-buffer
- (when (zerop
- (call-process "mixerctl" nil (current-buffer) nil
- "-f"
- (format "/dev/mixer%d" emms-volume-mixerctl-card)
- (let ((amount-str
- (format "%s%d" (if (< amount 0) "-" "+")
- (abs amount))))
- (format "outputs.%s=%s,%s"
- emms-volume-mixerctl-control
- amount-str amount-str))))
- (if (and (forward-line -1)
- (re-search-forward "^\\(.*\\):.*->.*,\\(.*\\)$" nil t))
- (format "%s -> %s" (match-string 1) (match-string 2)))))))
-
-(provide 'emms-volume-mixerctl)
-
-;;; emms-volume-mixerctl.el ends here
diff --git a/lisp/emms-volume-pulse.el b/lisp/emms-volume-pulse.el
deleted file mode 100644
index 440ab7f..0000000
--- a/lisp/emms-volume-pulse.el
+++ /dev/null
@@ -1,110 +0,0 @@
-;;; emms-volume-pulse.el --- a mode for changing volume using PulseAudio pactl
-
-;; Copyright (C) 2015 Free Software Foundation, Inc.
-
-;; Author: Rasmus Pank Roulund <emacs@pank.eu>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; 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 defines a few simple functions to raise or lower the volume
-;; using pactl. It can be used stand-alone, though it's meant for usage
-;; with EMMS, particularly with emms-volume.el.
-;;
-;; To use add the following to your EMMS configuration
-;; (setq emms-volume-change-function 'emms-volume-pulse-change)
-
-;;; History:
-
-;; Marts 2015: First release. Partly based on emms-volume-amixer.el
-
-;;; Todo:
-
-;; There probably needs to be more configurability, which may in turn
-;; mean adding some more functions.
-;; Some of this could benefit from adding customize interfaces.
-
-;;; Code:
-
-(require 'cl-lib)
-
-;; TODO: it would be great if custom could have
-;; choices based on pactl list short sinks | cut -f1-2
-
-(defcustom emms-volume-pulse-sink 0
- "The sink to use for volume adjustment.
-
-See full list of devices on your system by running
- pactl list short sinks"
- :type '(choice (number :tag "Sink number")
- (string :tag "Sink symbolic name"))
- :group 'emms-volume)
-
-(defcustom emms-volume-pulse-max-volume 100
- "The maximum volume percentage."
- :type 'integer
- :group 'emms-volume)
-
-
-(defun emms-volume--pulse-get-volume ()
- "Return `emms-volume-pulse-sink' volume."
- (let ((sink-number-p (numberp emms-volume-pulse-sink))
- (start 0)
- (output
- (shell-command-to-string
- (concat "pactl list sinks" "|"
- "grep -E -e 'Sink' -e 'Name' -e '^[^a-zA-Z]*Volume'"))))
- (string-to-number
- (car
- (reverse
- (funcall
- (if sink-number-p 'assq 'assoc)
- emms-volume-pulse-sink
- (mapcar (if sink-number-p 'identity 'cdr)
- (cl-loop while
- (string-match
- (mapconcat 'identity
- '(".*Sink[ \t]+\\#\\([0-9]+\\)"
- ".*Name:[ \t]\\([^\n]+\\)"
- ".*Volume:.*?\\([0-9]+\\)%.*\n?")
- "\n")
- output)
- collect (list (string-to-number (match-string 1 output))
- (match-string 2 output)
- (match-string 3 output))
- do (setq output (replace-match "" nil nil output))))))))))
-
-
-;;;###autoload
-(defun emms-volume-pulse-change (amount)
- "Change PulseAudio volume by AMOUNT."
- (message "Volume is %s%%"
- (let ((pactl (or (executable-find "pactl")
- (error "pactl is not in PATH")))
- (next-vol (max (min (+ (emms-volume--pulse-get-volume) amount)
- emms-volume-pulse-max-volume)
- 0)))
- (when (zerop (shell-command
- (format "%s set-sink-volume %s %s%%"
- pactl emms-volume-pulse-sink next-vol)))
- next-vol))))
-
-(provide 'emms-volume-pulse)
-
-;;; emms-volume-pulse.el ends here
diff --git a/lisp/emms-volume.el b/lisp/emms-volume.el
deleted file mode 100644
index 7a6ff5f..0000000
--- a/lisp/emms-volume.el
+++ /dev/null
@@ -1,154 +0,0 @@
-;;; emms-volume.el --- Volume functions and a minor mode to adjust volume easily
-
-;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Martin Schoenmakers <aiviru@diamond-age.net>
-;; Bruno Félix Rezende Ribeiro <oitofelix@gnu.org>
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-;;
-;; EMMS 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 EMMS; 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 generally two things:
-;; Generic volume setting functions and some appropriate bindings for EMMS
-;; playlist buffers. These can also be bound to global keys,however, the
-;; second part may be more useful for this. This part provides functions
-;; meant to be bound to a global key (the author uses C-c e + and C-c e -),
-;; which then temporarily activates a minor mode allowing you to change the
-;; volume with just + and -. This mode deactivates a short (configurable)
-;; amount of time after the last volume change. This allows for easier volume
-;; adjustment without getting in the way.
-
-;;; History:
-
-;; May 2006: First stab at writing the minor mode.
-;;
-;; 30 May 2006: Cleanup and restructuring to fit with EMMS.
-
-;;; Todo:
-
-;; Some of this could benefit from adding customize interfaces.
-
-;;; Code:
-
-
-(require 'emms)
-(require 'emms-playlist-mode)
-(require 'emms-volume-amixer)
-(require 'emms-volume-pulse)
-(require 'emms-volume-mixerctl)
-
-;; Customize group
-(defgroup emms-volume nil
- "Volume setting for EMMS."
- :group 'emms)
-
-;; General volume setting related code.
-(defcustom emms-volume-change-function
- (cond
- ((executable-find "amixer") 'emms-volume-amixer-change)
- ((executable-find "pactl") 'emms-volume-pulse-change)
- ((executable-find "mixerctl") emms-volume-mixerctl-change)
- (t #'(lambda (amount) (user-error "%s" "No supported mixer found. Please, define ‘emms-volume-change-function’."))))
- "*The function to use to change the volume.
-If you have your own functions for changing volume, set this."
- :type '(choice (const :tag "Amixer" emms-volume-amixer-change)
- (const :tag "MPD" emms-volume-mpd-change)
- (const :tag "PulseAudio" emms-volume-pulse-change)
- (const :tag "Mixerctl" emms-volume-mixerctl-change)
- (function :tag "Lisp function"))
- :group 'emms-volume)
-
-(defcustom emms-volume-change-amount 2
- "The amount to use when raising or lowering the volume using the
-emms-volume interface.
-
-This should be a positive integer."
- :type 'integer
- :group 'emms-volume)
-
-;;;###autoload
-(defun emms-volume-raise ()
- "Raise the speaker volume."
- (interactive)
- (funcall emms-volume-change-function emms-volume-change-amount))
-
-;;;###autoload
-(defun emms-volume-lower ()
- "Lower the speaker volume."
- (interactive)
- (funcall emms-volume-change-function (- emms-volume-change-amount)))
-
-(define-key emms-playlist-mode-map (kbd "+") 'emms-volume-raise)
-(define-key emms-playlist-mode-map (kbd "-") 'emms-volume-lower)
-
-;; Code specific to the minor mode.
-(define-minor-mode emms-volume-minor-mode
- "Allows volume setting with + and - after an initial key combo."
- :global t
- :init-value nil
- :lighter " (+/-)"
- :keymap '(("+" . emms-volume-mode-plus)
- ("-" . emms-volume-mode-minus)))
-
-(defvar emms-volume-mode-timeout 2
- "*The timeout in amount of seconds used by `emms-volume-minor-mode'.")
-
-(defvar emms-volume-mode-timer nil
- "The timer `emms-volume-minor-mode' uses.")
-
-;;;###autoload
-(defun emms-volume-mode-plus ()
- "Raise volume and enable or extend the `emms-volume-minor-mode' timeout."
- (interactive)
- (emms-volume-raise)
- (emms-volume-mode-start-or-extend))
-
-;;;###autoload
-(defun emms-volume-mode-minus ()
- "Lower volume and enable or extend the `emms-volume-minor-mode' timeout."
- (interactive)
- (emms-volume-lower)
- (emms-volume-mode-start-or-extend))
-
-(defun emms-volume-mode-disable-timer ()
- "Disable `emms-volume-minor-mode' timer."
- (cancel-timer emms-volume-mode-timer)
- (setq emms-volume-mode-timer nil))
-
-(defun emms-volume-mode-set-timer ()
- "Set a new `emms-volume-minor-mode' timer."
- (when emms-volume-mode-timer
- (emms-volume-mode-disable-timer))
- (setq emms-volume-mode-timer (run-at-time emms-volume-mode-timeout
- nil
- 'emms-volume-mode-timer-timeout)))
-
-(defun emms-volume-mode-timer-timeout ()
- "Function to disable `emms-volume-minor-mode' at timeout."
- (setq emms-volume-mode-timer nil)
- (emms-volume-minor-mode -1))
-
-(defun emms-volume-mode-start-or-extend ()
- "Start `emms-volume-minor-mode' or extend its running time."
- (when (null emms-volume-minor-mode)
- (emms-volume-minor-mode 1))
- (emms-volume-mode-set-timer))
-
-(provide 'emms-volume)
-;;; emms-volume.el ends here
diff --git a/lisp/emms.el b/lisp/emms.el
deleted file mode 100644
index ff786b7..0000000
--- a/lisp/emms.el
+++ /dev/null
@@ -1,1539 +0,0 @@
-;;; emms.el --- The Emacs Multimedia System
-
-;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-;; 2009, 2018, 2020 Free Software Foundation, Inc.
-
-;; Author: Jorgen Schäfer <forcer@forcix.cx>, the Emms developers (see AUTHORS file)
-;; Maintainer: Yoni Rabkin <yrk@gnu.org>
-;; Version: 5.4
-;; Keywords: emms, mp3, ogg, flac, music, mpeg, video, multimedia
-;; Package-Requires: ((cl-lib "0.5"))
-;; url: https://www.gnu.org/software/emms/
-
-;; This file is part of EMMS.
-
-;; EMMS 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 3, or (at your option)
-;; any later version.
-
-;; EMMS 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 this program. If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This is the very core of EMMS. It provides ways to play a track
-;; using `emms-start', to go through the playlist using the commands
-;; `emms-next' and `emms-previous', to stop the playback using
-;; `emms-stop', and to see what's currently playing using `emms-show'.
-
-;; But in itself, this core is useless, because it doesn't know how to
-;; play any tracks --- you need players for this. In fact, it doesn't
-;; even know how to find any tracks to consider playing --- for this,
-;; you need sources.
-
-;; A sample configuration is offered in emms-setup.el, and the
-;; Friendly Manual in the doc/ directory is both detailed, and kept up
-;; to date.
-
-
-;;; Code:
-
-(defvar emms-version "5.4"
- "EMMS version string.")
-
-
-;;; User Customization
-
-(defgroup emms nil
- "*The Emacs Multimedia System."
- :prefix "emms-"
- :group 'multimedia
- :group 'applications)
-
-(defgroup emms-player nil
- "*Track players for EMMS."
- :prefix "emms-player-"
- :group 'emms)
-
-(defgroup emms-source nil
- "*Track sources for EMMS."
- :prefix "emms-source-"
- :group 'emms)
-
-(defcustom emms-player-list nil
- "*List of players that EMMS can use. You need to set this!"
- :group 'emms
- :type '(repeat (symbol :tag "Player")))
-
-(defcustom emms-show-format "Currently playing: %s"
- "*The format to use for `emms-show'.
-Any \"%s\" is replaced by what `emms-track-description-function' returns
-for the currently playing track."
- :group 'emms
- :type 'string)
-
-(defcustom emms-repeat-playlist nil
- "*Non-nil if the EMMS playlist should automatically repeat.
-If nil, playback will stop when the last track finishes playing.
-If non-nil, EMMS will wrap back to the first track when that happens."
- :group 'emms
- :type 'boolean)
-
-(defcustom emms-random-playlist nil
- "*Non-nil means that tracks are played randomly. If nil, tracks
-are played sequentially."
- :group 'emms
- :type 'boolean)
-
-(defcustom emms-repeat-track nil
- "Non-nil, playback will repeat current track. If nil, EMMS will play
-track by track normally."
- :group 'emms
- :type 'boolean)
-
-(defvar-local emms-single-track nil
- "Non-nil, play the current track and then stop.")
-
-(defcustom emms-completing-read-function
- (if (and (boundp 'ido-mode)
- ido-mode)
- 'ido-completing-read
- 'completing-read)
- "Function to call when prompting user to choose between a list of options.
-This should take the same arguments as `completing-read'. Some
-possible values are `completing-read' and `ido-completing-read'.
-Note that you must set `ido-mode' if using
-`ido-completing-read'."
- :group 'emms
- :type 'function)
-
-(defcustom emms-track-description-function 'emms-track-simple-description
- "*Function for describing an EMMS track in a user-friendly way."
- :group 'emms
- :type 'function)
-
-(defcustom emms-player-delay 0
- "The delay to pause after a player finished.
-This is a floating-point number of seconds. This is necessary
-for some platforms where it takes a bit to free the audio device
-after a player has finished. If EMMS is skipping songs, increase
-this number."
- :type 'number
- :group 'emms)
-
-(defcustom emms-playlist-shuffle-function 'emms-playlist-simple-shuffle
- "*The function to use for shuffling the playlist."
- :type 'function
- :group 'emms)
-
-(defcustom emms-playlist-sort-function 'emms-playlist-simple-sort
- "*The function to use for sorting the playlist."
- :type 'function
- :group 'emms)
-
-(defcustom emms-playlist-uniq-function 'emms-playlist-simple-uniq
- "*The function to use for removing duplicate tracks in the playlist."
- :type 'function
- :group 'emms)
-
-(defcustom emms-sort-lessp-function 'emms-sort-track-name-less-p
- "*Function for comparing two EMMS tracks.
-The function should return non-nil if and only if the first track
-sorts before the second (see `sort')."
- :group 'emms
- :type 'function)
-
-(defcustom emms-playlist-buffer-name " *EMMS Playlist*"
- "*The default name of the EMMS playlist buffer."
- :type 'string
- :group 'emms)
-
-(defcustom emms-playlist-default-major-mode 'emms-playlist-mode
- "*The default major mode for EMMS playlist."
- :type 'function
- :group 'emms)
-
-(defcustom emms-playlist-insert-track-function 'emms-playlist-simple-insert-track
- "*A function to insert a track into the playlist buffer."
- :group 'emms
- :type 'function)
-(make-variable-buffer-local 'emms-playlist-insert-track-function)
-
-(defcustom emms-playlist-update-track-function 'emms-playlist-simple-update-track
- "*A function to update the track at point.
-This is called when the track information changed. This also
-shouldn't assume that the track has been inserted before."
- :group 'emms
- :type 'function)
-(make-variable-buffer-local 'emms-playlist-insert-track-function)
-
-(defcustom emms-playlist-delete-track-function 'emms-playlist-simple-delete-track
- "*A function to delete the track at point in the playlist buffer."
- :group 'emms
- :type 'function)
-(make-variable-buffer-local 'emms-playlist-delete-track-function)
-
-(defcustom emms-ok-track-function 'emms-default-ok-track-function
- "*Function returns true if we shouldn't skip this track."
- :group 'emms
- :type 'function)
-
-(defcustom emms-playlist-source-inserted-hook nil
- "*Hook run when a source got inserted into the playlist.
-The buffer is narrowed to the new tracks."
- :type 'hook
- :group 'emms)
-
-(defcustom emms-playlist-selection-changed-hook nil
- "*Hook run after another track is selected in the EMMS playlist."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-playlist-cleared-hook nil
- "*Hook run after the current EMMS playlist is cleared.
-This happens both when the playlist is cleared and when a new
-buffer is created for it."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-track-initialize-functions nil
- "*List of functions to call for each new EMMS track.
-This can be used to initialize tracks with various info."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-track-info-filters nil
- "*List of functions to call when a track changes data, before updating
-the display.
-These functions are passed the track as an argument."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-track-updated-functions nil
- "*List of functions to call when a track changes data, after updating
-the display.
-These functions are passed the track as an argument."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-player-started-hook nil
- "*Hook run when an EMMS player starts playing."
- :group 'emms
- :type 'hook
- :options '(emms-show))
-
-(defcustom emms-player-stopped-hook nil
- "*Hook run when an EMMS player is stopped by the user.
-See `emms-player-finished-hook'."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-player-finished-hook nil
- "*Hook run when an EMMS player finishes playing a track.
-Please pay attention to the differences between
-`emms-player-finished-hook' and `emms-player-stopped-hook'. The
-former is called only when the player actually finishes playing a
-track; the latter, only when the player is stopped
-interactively."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-player-next-function 'emms-next-noerror
- "*A function run when EMMS thinks the next song should be played."
- :group 'emms
- :type 'function
- :options '(emms-next-noerror
- emms-random))
-
-(defcustom emms-player-paused-hook nil
- "*Hook run when a player is paused or resumed.
-Use `emms-player-paused-p' to find the current state."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-seek-seconds 10
- "The number of seconds to seek forward or backward when seeking."
- :group 'emms
- :type 'number)
-
-(defcustom emms-player-seeked-functions nil
- "*Functions called when a player is seeking.
-The functions are called with a single argument, the amount of
-seconds the player did seek."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-player-time-set-functions nil
- "*Functions called when a player is setting the elapsed time of a track.
-The functions are called with a single argument, the time elapsed
-since the beginning of the current track."
- :group 'emms
- :type 'hook)
-
-(defcustom emms-cache-get-function nil
- "A function to retrieve a track entry from the cache.
-This is called with two arguments, the type and the name."
- :group 'emms
- :type 'function)
-
-(defcustom emms-cache-set-function nil
- "A function to add/set a track entry from the cache.
-This is called with three arguments: the type of the track, the
-name of the track, and the track itself."
- :group 'emms
- :type 'function)
-
-(defcustom emms-cache-modified-function nil
- "A function to be called when a track is modified.
-The modified track is passed as the argument to this function."
- :group 'emms
- :type 'function)
-
-(defcustom emms-directory (expand-file-name "emms" user-emacs-directory)
- "*Directory variable from which all other emms file variables are derived."
- :group 'emms
- :type 'string)
-
-(defvar emms-player-playing-p nil
- "The currently playing EMMS player, or nil.")
-
-(defvar emms-player-paused-p nil
- "Whether the current player is paused or not.")
-
-(defvar emms-source-old-buffer nil
- "The active buffer before a source was invoked.
-This can be used if the source depends on the current buffer not
-being the playlist buffer.")
-
-(defvar emms-playlist-buffer nil
- "The current playlist buffer, if any.")
-
-
-;;; Macros
-
-;;; These need to be at the top of the file so that compilation works.
-
-(defmacro with-current-emms-playlist (&rest body)
- "Run BODY with the current buffer being the current playlist buffer.
-This also disables any read-onliness of the current buffer."
- `(progn
- (when (or (not emms-playlist-buffer)
- (not (buffer-live-p emms-playlist-buffer)))
- (emms-playlist-current-clear))
- (let ((emms-source-old-buffer (or emms-source-old-buffer
- (current-buffer))))
- (with-current-buffer emms-playlist-buffer
- (let ((inhibit-read-only t))
- ,@body)))))
-(put 'with-current-emms-playlist 'lisp-indent-function 0)
-(put 'with-current-emms-playlist 'edebug-form-spec '(body))
-
-(defmacro emms-with-inhibit-read-only-t (&rest body)
- "Simple wrapper around `inhibit-read-only'."
- `(let ((inhibit-read-only t))
- ,@body))
-(put 'emms-with-inhibit-read-only-t 'edebug-form-spec '(body))
-
-(defmacro emms-with-widened-buffer (&rest body)
- `(save-restriction
- (widen)
- ,@body))
-(put 'emms-with-widened-buffer 'edebug-form-spec '(body))
-
-(defmacro emms-walk-tracks (&rest body)
- "Execute BODY for each track in the current buffer, starting at point.
-Point will be placed at the beginning of the track before
-executing BODY.
-
-Point will not be restored afterward."
- (let ((donep (make-symbol "donep")))
- `(let ((,donep nil))
- ;; skip to first track if not on one
- (unless (emms-playlist-track-at (point))
- (condition-case nil
- (emms-playlist-next)
- (error
- (setq ,donep t))))
- ;; walk tracks
- (while (not ,donep)
- ,@body
- (condition-case nil
- (emms-playlist-next)
- (error
- (setq ,donep t)))))))
-(put 'emms-walk-tracks 'lisp-indent-function 0)
-(put 'emms-walk-tracks 'edebug-form-spec '(body))
-
-(defvar emms-player-base-format-list
- '("ogg" "mp3" "wav" "mpg" "mpeg" "wmv" "wma"
- "mov" "avi" "divx" "ogm" "ogv" "asf" "mkv"
- "rm" "rmvb" "mp4" "flac" "vob" "m4a" "ape"
- "flv" "webm" "aif")
- "A list of common formats which player definitions can use.")
-
-
-;;; User Interface
-
-(defun emms-start ()
- "Start playing the current track in the EMMS playlist."
- (interactive)
- (unless emms-player-playing-p
- (emms-player-start (emms-playlist-current-selected-track))))
-
-(defun emms-stop ()
- "Stop any current EMMS playback."
- (interactive)
- (when emms-player-playing-p
- (emms-player-stop)))
-
-(defun emms-next ()
- "Start playing the next track in the EMMS playlist.
-This might behave funny if called from `emms-player-next-function',
-so use `emms-next-noerror' in that case."
- (interactive)
- (when emms-player-playing-p
- (emms-stop))
- (emms-playlist-current-select-next)
- (emms-start))
-
-(defun emms-next-noerror ()
- "Start playing the next track in the EMMS playlist.
-Unlike `emms-next', this function doesn't signal an error when called
-at the end of the playlist.
-This function should only be called when no player is playing.
-This is a good function to put in `emms-player-next-function'."
- (interactive)
- (when emms-player-playing-p
- (error "A track is already being played"))
- (cond (emms-repeat-track
- (emms-start))
- (emms-single-track ; buffer local
- (emms-stop))
- ;; attempt to play the next track but ignore errors
- ((condition-case nil
- (progn
- (emms-playlist-current-select-next)
- t)
- (error nil))
- (if (funcall emms-ok-track-function
- (emms-playlist-current-selected-track))
- (emms-start)
- (emms-next-noerror)))
- (t
- (message "No next track in playlist"))))
-
-(defun emms-previous ()
- "Start playing the previous track in the EMMS playlist."
- (interactive)
- (when emms-player-playing-p
- (emms-stop))
- (emms-playlist-current-select-previous)
- (emms-start))
-
-(defun emms-random ()
- "Jump to a random track."
- (interactive)
- (when emms-player-playing-p
- (emms-stop))
- (emms-playlist-current-select-random)
- (emms-start))
-
-(defun emms-pause ()
- "Pause the current player.
-If player hasn't started, then start it now."
- (interactive)
- (if emms-player-playing-p
- (emms-player-pause)
- (emms-start)))
-
-(defun emms-seek (seconds)
- "Seek the current player SECONDS seconds.
-This can be a floating point number for sub-second fractions.
-It can also be negative to seek backwards."
- (interactive "nSeconds to seek: ")
- (emms-ensure-player-playing-p)
- (emms-player-seek seconds))
-
-(defun emms-seek-to (seconds)
- "Seek the current player to SECONDS seconds.
-This can be a floating point number for sub-second fractions.
-It can also be negative to seek backwards."
- (interactive "nSeconds to seek to: ")
- (emms-ensure-player-playing-p)
- (emms-player-seek-to seconds))
-
-(defun emms-seek-forward ()
- "Seek ten seconds forward."
- (interactive)
- (when emms-player-playing-p
- (emms-player-seek emms-seek-seconds)))
-
-(defun emms-seek-backward ()
- "Seek ten seconds backward."
- (interactive)
- (when emms-player-playing-p
- (emms-player-seek (- emms-seek-seconds))))
-
-(defun emms-show (&optional insertp)
- "Describe the current EMMS track in the minibuffer.
-If INSERTP is non-nil, insert the description into the current buffer instead.
-This function uses `emms-show-format' to format the current track."
- (interactive "P")
- (let ((string (if emms-player-playing-p
- (format emms-show-format
- (emms-track-description
- (emms-playlist-current-selected-track)))
- "Nothing playing right now")))
- (if insertp
- (insert string)
- (message "%s" string))))
-
-(defun emms-shuffle ()
- "Shuffle the current playlist.
-This uses `emms-playlist-shuffle-function'."
- (interactive)
- (with-current-emms-playlist
- (save-excursion
- (funcall emms-playlist-shuffle-function))))
-
-(defun emms-sort ()
- "Sort the current playlist.
-This uses `emms-playlist-sort-function'."
- (interactive)
- (with-current-emms-playlist
- (save-excursion
- (funcall emms-playlist-sort-function))))
-
-(defun emms-uniq ()
- "Remove duplicates from the current playlist.
-This uses `emms-playlist-uniq-function'."
- (interactive)
- (with-current-emms-playlist
- (save-excursion
- (funcall emms-playlist-uniq-function))))
-
-(defun emms-toggle-single-track ()
- "Toggle if Emms plays a single track and stops."
- (interactive)
- (with-current-emms-playlist
- (cond (emms-single-track
- (setq emms-single-track nil)
- (message "single track mode disabled for %s"
- (buffer-name)))
- (t (setq emms-single-track t)
- (message "single track mode enabled for %s"
- (buffer-name))))))
-
-(defun emms-toggle-random-playlist ()
- "Toggle whether emms plays the tracks randomly or sequentially.
-See `emms-random-playlist'."
- (interactive)
- (setq emms-random-playlist (not emms-random-playlist))
- (if emms-random-playlist
- (progn (setq emms-player-next-function 'emms-random)
- (message "Will play the tracks randomly."))
- (setq emms-player-next-function 'emms-next-noerror)
- (message "Will play the tracks sequentially.")))
-
-(defun emms-toggle-repeat-playlist ()
- "Toggle whether emms repeats the playlist after it is done.
-See `emms-repeat-playlist'."
- (interactive)
- (setq emms-repeat-playlist (not emms-repeat-playlist))
- (if emms-repeat-playlist
- (message "Will repeat the playlist after it is done.")
- (message "Will stop after the playlist is over.")))
-
-(defun emms-toggle-repeat-track ()
- "Toggle whether emms repeats the current track.
-See `emms-repeat-track'."
- (interactive)
- (setq emms-repeat-track (not emms-repeat-track))
- (if emms-repeat-track
- (message "Will repeat the current track.")
- (message "Will advance to the next track after this one.")))
-
-(defun emms-sort-track-name-less-p (a b)
- "Return non-nil if the track name of A sorts before B."
- (string< (emms-track-name a)
- (emms-track-name b)))
-
-(defun emms-ensure-player-playing-p ()
- "Raise an error if no player is playing right now."
- (when (not emms-player-playing-p)
- (error "No EMMS player playing right now")))
-
-(defun emms-completing-read (&rest args)
- "Read a string in the minibuffer, with completion.
-Set `emms-completing-read' to determine which function to use.
-
-See `completing-read' for a description of ARGS."
- (apply emms-completing-read-function args))
-
-(defun emms-display-modes ()
- "Display the current EMMS play modes."
- (interactive)
- (with-current-emms-playlist
- (message
- "repeat playlist: %s, repeat track: %s, random: %s, single %s"
- (if emms-repeat-playlist "yes" "no")
- (if emms-repeat-track "yes" "no")
- (if emms-random-playlist "yes" "no")
- (if emms-single-track "yes" "no"))))
-
-
-;;; Compatibility functions
-
-(require 'emms-compat)
-
-
-;;; Utility functions
-
-(defun emms-insert-file-contents (filename &optional visit)
- "Insert the contents of file FILENAME after point.
-Do character code conversion and end-of-line conversion, but none
-of the other unnecessary things like format decoding or
-`find-file-hook'.
-
-If VISIT is non-nil, the buffer's visited filename
-and last save file modtime are set, and it is marked unmodified.
-If visiting and the file does not exist, visiting is completed
-before the error is signaled."
- (let ((format-alist nil)
- (after-insert-file-functions nil)
- (inhibit-file-name-handlers
- (append '(jka-compr-handler image-file-handler epa-file-handler)
- inhibit-file-name-handlers))
- (inhibit-file-name-operation 'insert-file-contents))
- (insert-file-contents filename visit)))
-
-
-;;; Dictionaries
-
-;; This is a simple helper data structure, used by both players
-;; and tracks.
-
-(defsubst emms-dictionary (name)
- "Create a new dictionary of type NAME."
- (list name))
-
-(defsubst emms-dictionary-type (dict)
- "Return the type of the dictionary DICT."
- (car dict))
-
-(defun emms-dictionary-get (dict name &optional default)
- "Return the value of NAME in DICT."
- (let ((item (assq name (cdr dict))))
- (if item
- (cdr item)
- default)))
-
-(defun emms-dictionary-set (dict name value)
- "Set the value of NAME in DICT to VALUE."
- (let ((item (assq name (cdr dict))))
- (if item
- (setcdr item value)
- (setcdr dict (append (cdr dict)
- (list (cons name value))))))
- dict)
-
-
-;;; Tracks
-
-;; This is a simple datatype to store track information.
-;; Each track consists of a type (a symbol) and a name (a string).
-;; In addition, each track has an associated dictionary of information.
-
-(defun emms-track (type name)
- "Create an EMMS track with type TYPE and name NAME."
- (let ((track (when emms-cache-get-function
- (funcall emms-cache-get-function type name))))
- (when (not track)
- (setq track (emms-dictionary '*track*))
- ;; Prevent the cache from being called for these two sets
- (let ((emms-cache-modified-function nil))
- (emms-track-set track 'type type)
- (emms-track-set track 'name name))
- (when emms-cache-set-function
- (funcall emms-cache-set-function type name track)))
- ;; run any hooks regardless of a cache hit, as the entry may be
- ;; old
- (run-hook-with-args 'emms-track-initialize-functions track)
- track))
-
-(defun emms-track-p (obj)
- "True if OBJ is an emms track."
- (and (listp obj)
- (eq (car obj) '*track*)))
-
-(defun emms-track-type (track)
- "Return the type of TRACK."
- (emms-track-get track 'type))
-
-(defun emms-track-name (track)
- "Return the name of TRACK."
- (emms-track-get track 'name))
-
-(defun emms-track-get (track name &optional default)
- "Return the value of NAME for TRACK.
-If there is no value, return DEFAULT (or nil, if not given)."
- (emms-dictionary-get track name default))
-
-(defun emms-track-set (track name value)
- "Set the value of NAME for TRACK to VALUE."
- (emms-dictionary-set track name value)
- (when emms-cache-modified-function
- (funcall emms-cache-modified-function track)))
-
-(defun emms-track-description (track)
- "Return a description of TRACK.
-This function uses the global value for
-`emms-track-description-function', rather than anything the
-current mode might have set.
-
-Use `emms-track-force-description' instead if you need to insert
-a description into a playlist buffer."
- (funcall (default-value 'emms-track-description-function) track))
-
-(defun emms-track-updated (track)
- "Information in TRACK got updated."
- (run-hook-with-args 'emms-track-info-filters track)
- (emms-playlist-track-updated track)
- (run-hook-with-args 'emms-track-updated-functions track))
-
-(defun emms-track-simple-description (track)
- "Simple function to give a user-readable description of a track.
-If it's a file track, just return the file name. Otherwise,
-return the type and the name with a colon in between.
-Hex-encoded characters in URLs are replaced by the decoded
-character."
- (let ((type (emms-track-type track)))
- (cond ((eq 'file type)
- (emms-track-name track))
- ((eq 'url type)
- (emms-format-url-track-name (emms-track-name track)))
- (t (concat (symbol-name type)
- ": " (emms-track-name track))))))
-
-(defun emms-format-url-track-name (name)
- "Format URL track name for better readability."
- (url-unhex-string name))
-
-(defun emms-track-force-description (track)
- "Always return text that describes TRACK.
-This is used when inserting a description into a buffer.
-
-The reason for this is that if no text was returned (i.e. the
-user defined a track function that returned nil or the empty
-string), a confusing error message would result."
- (let ((desc (funcall emms-track-description-function track)))
- (if (and (stringp desc) (not (string= desc "")))
- desc
- (emms-track-simple-description track))))
-
-(defun emms-track-get-year (track)
- "Get year of TRACK for display.
-There is the separation between the 'release date' and the
-'original date'. This difference matters e.g. for
-re-releases (anniversaries and such) where the release date is
-more recent than the original release date. In such cases the
-user probably wants the original release date so this is what we
-show."
- (or
- (emms-format-date-to-year (emms-track-get track 'info-date))
- (emms-format-date-to-year (emms-track-get track 'info-originaldate))
- (emms-track-get track 'info-year)
- (emms-track-get track 'info-originalyear)))
-
-(defun emms-format-date-to-year (date)
- "Try to extract year part from DATE.
-Return nil if the year cannot be extracted."
- (when date
- (let ((year (nth 5 (parse-time-string date))))
- (if year (number-to-string year)
- (when (string-match "^[ \t]*\\([0-9]\\{4\\}\\)" date)
- (match-string 1 date))))))
-
-
-;;; The Playlist
-
-;; Playlists are stored in buffers. The current playlist buffer is
-;; remembered in the `emms-playlist' variable. The buffer consists of
-;; any kind of data. Strings of text with a `emms-track' property are
-;; the tracks in the buffer.
-
-(defvar emms-playlist-buffers nil
- "The list of EMMS playlist buffers.
-You should use the `emms-playlist-buffer-list' function to
-retrieve a current list of EMMS buffers. Never use this variable
-for that purpose.")
-
-(defvar emms-playlist-selected-marker nil
- "The marker for the currently selected track.")
-(make-variable-buffer-local 'emms-playlist-selected-marker)
-
-(defvar emms-playlist-buffer-p nil
- "Non-nil if the current buffer is an EMMS playlist.")
-(make-variable-buffer-local 'emms-playlist-buffer-p)
-
-(defun emms-playlist-ensure-playlist-buffer ()
- "Throw an error if we're not in a playlist-buffer."
- (when (not emms-playlist-buffer-p)
- (error "Not an EMMS playlist buffer")))
-
-(defun emms-playlist-set-playlist-buffer (&optional buffer)
- "Set the current playlist buffer."
- (interactive
- (list (let* ((buf-list (mapcar #'(lambda (buf)
- (list (buffer-name buf)))
- (emms-playlist-buffer-list)))
- (sorted-buf-list (sort buf-list
- #'(lambda (lbuf rbuf)
- (< (length (car lbuf))
- (length (car rbuf))))))
- (default (or (and emms-playlist-buffer-p
- ;; default to current buffer
- (buffer-name))
- ;; pick shortest buffer name, since it is
- ;; likely to be a shared prefix
- (car sorted-buf-list))))
- (emms-completing-read "Playlist buffer to make current: "
- sorted-buf-list nil t default))))
- (let ((buf (if buffer
- (get-buffer buffer)
- (current-buffer))))
- (with-current-buffer buf
- (emms-playlist-ensure-playlist-buffer))
- (setq emms-playlist-buffer buf)
- (when (called-interactively-p 'interactive)
- (message "Set current EMMS playlist buffer"))
- buf))
-
-(defun emms-playlist-new (&optional name)
- "Create a new playlist buffer.
-The buffer is named NAME, but made unique. NAME defaults to
-`emms-playlist-buffer-name'. If called interactively, the new
-buffer is also selected."
- (interactive)
- (let ((buf (generate-new-buffer (or name
- emms-playlist-buffer-name))))
- (with-current-buffer buf
- (when (not (eq major-mode emms-playlist-default-major-mode))
- (funcall emms-playlist-default-major-mode))
- (setq emms-playlist-buffer-p t))
- (add-to-list 'emms-playlist-buffers buf)
- (when (called-interactively-p 'interactive)
- (switch-to-buffer buf))
- buf))
-
-(defun emms-playlist-buffer-list ()
- "Return a list of EMMS playlist buffers.
-The first element is guaranteed to be the current EMMS playlist
-buffer, if it exists, otherwise the slot will be used for the
-other EMMS buffers. The list will be in newest-first order."
- ;; prune dead buffers
- (setq emms-playlist-buffers (emms-delete-if (lambda (buf)
- (not (buffer-live-p buf)))
- emms-playlist-buffers))
- ;; add new buffers
- (mapc (lambda (buf)
- (when (buffer-live-p buf)
- (with-current-buffer buf
- (when (and emms-playlist-buffer-p
- (not (memq buf emms-playlist-buffers)))
- (setq emms-playlist-buffers
- (cons buf emms-playlist-buffers))))))
- (buffer-list))
- ;; force current playlist buffer to head position
- (when (and (buffer-live-p emms-playlist-buffer)
- (not (eq (car emms-playlist-buffers) emms-playlist-buffer)))
- (setq emms-playlist-buffers (cons emms-playlist-buffer
- (delete emms-playlist-buffer
- emms-playlist-buffers))))
- emms-playlist-buffers)
-
-(defun emms-playlist-current-kill ()
- "Kill the current EMMS playlist buffer and switch to the next one."
- (interactive)
- (when (buffer-live-p emms-playlist-buffer)
- (let ((new (cadr (emms-playlist-buffer-list))))
- (if new
- (let ((old emms-playlist-buffer))
- (setq emms-playlist-buffer new
- emms-playlist-buffers (cdr emms-playlist-buffers))
- (kill-buffer old)
- (switch-to-buffer emms-playlist-buffer))
- (with-current-buffer emms-playlist-buffer
- (bury-buffer))))))
-
-(defun emms-playlist-current-clear ()
- "Clear the current playlist.
-If no current playlist exists, a new one is generated."
- (interactive)
- (if (or (not emms-playlist-buffer)
- (not (buffer-live-p emms-playlist-buffer)))
- (setq emms-playlist-buffer (emms-playlist-new))
- (with-current-buffer emms-playlist-buffer
- (emms-playlist-clear))))
-
-(defun emms-playlist-clear ()
- "Clear the current buffer."
- (interactive)
- (emms-playlist-ensure-playlist-buffer)
- (let ((inhibit-read-only t))
- (widen)
- (delete-region (point-min)
- (point-max)))
- (run-hooks 'emms-playlist-cleared-hook))
-
-;;; Point movement within the playlist buffer.
-(defun emms-playlist-track-at (&optional pos)
- "Return the track at POS (point if not given), or nil if none."
- (emms-playlist-ensure-playlist-buffer)
- (emms-with-widened-buffer
- (get-text-property (or pos (point))
- 'emms-track)))
-
-(defun emms-playlist-next ()
- "Move to the next track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (let ((next (next-single-property-change (point)
- 'emms-track)))
- (when (not next)
- (error "No next track"))
- (when (not (emms-playlist-track-at next))
- (setq next (next-single-property-change next 'emms-track)))
- (when (or (not next)
- (= next (point-max)))
- (error "No next track"))
- (goto-char next)))
-
-(defun emms-playlist-previous ()
- "Move to the previous track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (let ((prev (previous-single-property-change (point)
- 'emms-track)))
- (when (not prev)
- (error "No previous track"))
- (when (not (get-text-property prev 'emms-track))
- (setq prev (or (previous-single-property-change prev 'emms-track)
- (point-min))))
- (when (or (not prev)
- (not (get-text-property prev 'emms-track)))
- (error "No previous track"))
- (goto-char prev)))
-
-(defun emms-playlist-first ()
- "Move to the first track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (let ((first (condition-case nil
- (save-excursion
- (goto-char (point-min))
- (when (not (emms-playlist-track-at (point)))
- (emms-playlist-next))
- (point))
- (error
- nil))))
- (if first
- (goto-char first)
- (error "No first track"))))
-
-(defun emms-playlist-last ()
- "Move to the last track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (let ((last (condition-case nil
- (save-excursion
- (goto-char (point-max))
- (emms-playlist-previous)
- (point))
- (error
- nil))))
- (if last
- (goto-char last)
- (error "No last track"))))
-
-(defun emms-playlist-delete-track ()
- "Delete the track at point."
- (emms-playlist-ensure-playlist-buffer)
- (funcall emms-playlist-delete-track-function))
-
-;;; Track selection
-(defun emms-playlist-selected-track ()
- "Return the currently selected track."
- (emms-playlist-ensure-playlist-buffer)
- (when emms-playlist-selected-marker
- (emms-playlist-track-at emms-playlist-selected-marker)))
-
-(defun emms-playlist-current-selected-track ()
- "Return the currently selected track in the current playlist."
- (with-current-emms-playlist
- (emms-playlist-selected-track)))
-
-(defun emms-playlist-selected-track-at-p (&optional point)
- "Return non-nil if POINT (defaulting to point) is on the selected track."
- (when emms-playlist-selected-marker
- (or (= emms-playlist-selected-marker
- (or point (point)))
- (let ((p (previous-single-property-change (or point (point))
- 'emms-track)))
- (when p
- (= emms-playlist-selected-marker
- p))))))
-
-(defun emms-playlist-select (pos)
- "Select the track at POS."
- (emms-playlist-ensure-playlist-buffer)
- (when (not (emms-playlist-track-at pos))
- (error "No track at position %s" pos))
- (when (not emms-playlist-selected-marker)
- (setq emms-playlist-selected-marker (make-marker)))
- (set-marker-insertion-type emms-playlist-selected-marker t)
- (set-marker emms-playlist-selected-marker pos)
- (run-hooks 'emms-playlist-selection-changed-hook))
-
-(defun emms-playlist-select-next ()
- "Select the next track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (save-excursion
- (goto-char (if (and emms-playlist-selected-marker
- (marker-position emms-playlist-selected-marker))
- emms-playlist-selected-marker
- (point-min)))
- (condition-case nil
- (progn
- (if emms-repeat-playlist
- (condition-case nil
- (emms-playlist-next)
- (error
- (emms-playlist-first)))
- (emms-playlist-next))
- (emms-playlist-select (point)))
- (error
- (error "No next track in playlist")))))
-
-(defun emms-playlist-current-select-next ()
- "Select the next track in the current playlist."
- (with-current-emms-playlist
- (emms-playlist-select-next)))
-
-(defun emms-playlist-select-previous ()
- "Select the previous track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (save-excursion
- (goto-char (if (and emms-playlist-selected-marker
- (marker-position emms-playlist-selected-marker))
- emms-playlist-selected-marker
- (point-max)))
- (condition-case nil
- (progn
- (if emms-repeat-playlist
- (condition-case nil
- (emms-playlist-previous)
- (error
- (emms-playlist-last)))
- (emms-playlist-previous))
- (emms-playlist-select (point)))
- (error
- (error "No previous track in playlist")))))
-
-(defun emms-playlist-current-select-previous ()
- "Select the previous track in the current playlist."
- (with-current-emms-playlist
- (emms-playlist-select-previous)))
-
-(defun emms-playlist-select-random ()
- "Select a random track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- ;; FIXME: This is rather inefficient.
- (save-excursion
- (let ((track-indices nil))
- (goto-char (point-min))
- (emms-walk-tracks
- (setq track-indices (cons (point)
- track-indices)))
- (setq track-indices (vconcat track-indices))
- (emms-playlist-select (aref track-indices
- (random (length track-indices)))))))
-
-(defun emms-playlist-current-select-random ()
- "Select a random track in the current playlist."
- (with-current-emms-playlist
- (emms-playlist-select-random)))
-
-(defun emms-playlist-select-first ()
- "Select the first track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (save-excursion
- (emms-playlist-first)
- (emms-playlist-select (point))))
-
-(defun emms-playlist-current-select-first ()
- "Select the first track in the current playlist."
- (with-current-emms-playlist
- (emms-playlist-select-first)))
-
-(defun emms-playlist-select-last ()
- "Select the last track in the current buffer."
- (emms-playlist-ensure-playlist-buffer)
- (save-excursion
- (emms-playlist-last)
- (emms-playlist-select (point))))
-
-(defun emms-playlist-current-select-last ()
- "Select the last track in the current playlist."
- (with-current-emms-playlist
- (emms-playlist-select-last)))
-
-;;; Playlist manipulation
-(defun emms-playlist-insert-track (track)
- "Insert TRACK at the current position into the playlist.
-This uses `emms-playlist-insert-track-function'."
- (emms-playlist-ensure-playlist-buffer)
- (funcall emms-playlist-insert-track-function track))
-
-(defun emms-playlist-update-track ()
- "Update TRACK at point.
-This uses `emms-playlist-update-track-function'."
- (emms-playlist-ensure-playlist-buffer)
- (funcall emms-playlist-update-track-function))
-
-(defun emms-playlist-insert-source (source &rest args)
- "Insert tracks from SOURCE, supplying ARGS as arguments."
- (emms-playlist-ensure-playlist-buffer)
- (save-restriction
- (narrow-to-region (point)
- (point))
- (apply source args)
- (run-hooks 'emms-playlist-source-inserted-hook)))
-
-(defun emms-playlist-current-insert-source (source &rest args)
- "Insert tracks from SOURCE in the current playlist.
-This is supplying ARGS as arguments to the source."
- (with-current-emms-playlist
- (apply 'emms-playlist-insert-source source args)))
-
-(defun emms-playlist-tracks-in-region (beg end)
- "Return all tracks between BEG and END."
- (emms-playlist-ensure-playlist-buffer)
- (let ((tracks nil))
- (save-restriction
- (narrow-to-region beg end)
- (goto-char (point-min))
- (emms-walk-tracks
- (setq tracks (cons (emms-playlist-track-at (point))
- tracks))))
- tracks))
-
-(defun emms-playlist-track-updated (track)
- "Update TRACK in all playlist buffers."
- (mapc (lambda (buf)
- (with-current-buffer buf
- (when emms-playlist-buffer-p
- (save-excursion
- (let ((pos (text-property-any (point-min) (point-max)
- 'emms-track track)))
- (while pos
- (goto-char pos)
- (emms-playlist-update-track)
- (setq pos (text-property-any
- (next-single-property-change (point)
- 'emms-track)
- (point-max)
- 'emms-track
- track))))))))
- (buffer-list))
- t)
-
-;;; Simple playlist buffer
-(defun emms-playlist-simple-insert-track (track)
- "Insert the description of TRACK at point."
- (emms-playlist-ensure-playlist-buffer)
- (let ((inhibit-read-only t))
- (insert (emms-propertize (emms-track-force-description track)
- 'emms-track track)
- "\n")))
-
-(defun emms-playlist-simple-update-track ()
- "Update the track at point.
-Since we don't do anything special with the track anyway, just
-ignore this."
- nil)
-
-(defun emms-playlist-simple-delete-track ()
- "Delete the track at point."
- (emms-playlist-ensure-playlist-buffer)
- (when (not (emms-playlist-track-at (point)))
- (error "No track at point"))
- (let ((inhibit-read-only t)
- (region (emms-property-region (point) 'emms-track)))
- (delete-region (car region)
- (cdr region))))
-
-(defun emms-playlist-simple-shuffle ()
- "Shuffle the whole playlist buffer."
- (emms-playlist-ensure-playlist-buffer)
- (let ((inhibit-read-only t)
- (current nil))
- (widen)
- (when emms-player-playing-p
- (setq current (emms-playlist-selected-track))
- (goto-char emms-playlist-selected-marker)
- (emms-playlist-delete-track))
- (let* ((tracks (vconcat (emms-playlist-tracks-in-region (point-min)
- (point-max))))
- (len (length tracks))
- (i 0))
- (delete-region (point-min)
- (point-max))
- (run-hooks 'emms-playlist-cleared-hook)
- (emms-shuffle-vector tracks)
- (when current
- (emms-playlist-insert-track current))
- (while (< i len)
- (emms-playlist-insert-track (aref tracks i))
- (setq i (1+ i))))
- (emms-playlist-select-first)
- (goto-char (point-max))))
-
-(defun emms-playlist-simple-sort ()
- "Sort the whole playlist buffer."
- (emms-playlist-ensure-playlist-buffer)
- (widen)
- (let ((inhibit-read-only t)
- (current (emms-playlist-selected-track))
- (tracks (emms-playlist-tracks-in-region (point-min)
- (point-max))))
- (delete-region (point-min)
- (point-max))
- (run-hooks 'emms-playlist-cleared-hook)
- (mapc 'emms-playlist-insert-track
- (sort tracks emms-sort-lessp-function))
- (let ((pos (text-property-any (point-min)
- (point-max)
- 'emms-track current)))
- (if pos
- (emms-playlist-select pos)
- (emms-playlist-first)))))
-
-(defun emms-uniq-list (list stringify)
- "Compare stringfied element of list, and remove duplicate elements."
- ;; This uses a fast append list, keeping a pointer to the last cons
- ;; cell of the list (TAIL). It might be worthwhile to provide an
- ;; abstraction for this eventually.
- (let* ((hash (make-hash-table :test 'equal))
- (result (cons nil nil))
- (tail result))
- (dolist (element list)
- (let ((str (funcall stringify element)))
- (when (not (gethash str hash))
- (setcdr tail (cons element nil))
- (setq tail (cdr tail)))
- (puthash str t hash)))
- (cdr result)))
-
-(defun emms-playlist-simple-uniq ()
- "Remove duplicate tracks."
- ;; TODO: This seems unnecessarily destructive.
- (emms-playlist-ensure-playlist-buffer)
- (widen)
- (let ((inhibit-read-only t)
- (current (emms-playlist-selected-track))
- (tracks (emms-playlist-tracks-in-region (point-min)
- (point-max))))
- (delete-region (point-min) (point-max))
- (run-hooks 'emms-playlist-cleared-hook)
- (mapc 'emms-playlist-insert-track
- (nreverse
- (emms-uniq-list tracks 'emms-track-name)))
- (let ((pos (text-property-any (point-min)
- (point-max)
- 'emms-track current)))
- (if pos
- (emms-playlist-select pos)
- (emms-playlist-first)))))
-
-(defun emms-default-ok-track-function (track)
- "A function which OKs all tracks for playing by default."
- t)
-
-;;; Helper functions
-(defun emms-property-region (pos prop)
- "Return a pair of the beginning and end of the property PROP at POS.
-If POS does not contain PROP, try to find PROP just before POS."
- (let (begin end)
- (if (and (> pos (point-min))
- (get-text-property (1- pos) prop))
- (setq begin (previous-single-property-change (1- pos) prop))
- (if (get-text-property pos prop)
- (setq begin pos)
- (error "Cannot find the %s property at the given position" prop)))
- (if (get-text-property pos prop)
- (setq end (next-single-property-change pos prop))
- (if (and (> pos (point-min))
- (get-text-property (1- pos) prop))
- (setq end pos)
- (error "Cannot find the %s property at the given position" prop)))
- (cons (or begin (point-min))
- (or end (point-max)))))
-
-(defun emms-shuffle-vector (vector)
- "Shuffle VECTOR."
- (let ((i (- (length vector) 1)))
- (while (>= i 0)
- (let* ((r (random (1+ i)))
- (old (aref vector r)))
- (aset vector r (aref vector i))
- (aset vector i old))
- (setq i (- i 1))))
- vector)
-
-
-;;; Sources
-
-;; A source is just a function which is called in a playlist buffer.
-;; It should use `emms-playlist-insert-track' to insert the tracks it
-;; knows about.
-;;
-;; The define-emms-source macro also defines functions
-;; emms-play-SOURCE and emms-add-SOURCE. The former will replace the
-;; current playlist, while the latter will add to the end.
-
-(defmacro define-emms-source (name arglist &rest body)
- "Define a new EMMS source called NAME.
-This macro defines three functions: `emms-source-NAME',
-`emms-play-NAME' and `emms-add-NAME'. BODY should use
-`emms-playlist-insert-track' to insert all tracks to be played,
-which is exactly what `emms-source-NAME' will do. The other two
-functions will be simple wrappers around `emms-source-NAME'; any
-`interactive' form that you specify in BODY will end up in these.
-See emms-source-file.el for some examples."
- (let ((source-name (intern (format "emms-source-%s" name)))
- (source-play (intern (format "emms-play-%s" name)))
- (source-add (intern (format "emms-add-%s" name)))
- (source-insert (intern (format "emms-insert-%s" name)))
- (docstring "A source of tracks for EMMS.")
- (interactive nil)
- (call-args (delete '&rest
- (delete '&optional
- arglist))))
- (when (stringp (car body))
- (setq docstring (car body)
- body (cdr body)))
- (when (eq 'interactive (caar body))
- (setq interactive (car body)
- body (cdr body)))
- `(progn
- (defun ,source-name ,arglist
- ,docstring
- ,@body)
- (defun ,source-play ,arglist
- ,docstring
- ,interactive
- (if current-prefix-arg
- (let ((current-prefix-arg nil))
- (emms-source-add ',source-name ,@call-args))
- (emms-source-play ',source-name ,@call-args)))
- (defun ,source-add ,arglist
- ,docstring
- ,interactive
- (if current-prefix-arg
- (let ((current-prefix-arg nil))
- (emms-source-play ',source-name ,@call-args))
- (emms-source-add ',source-name ,@call-args)))
- (defun ,source-insert ,arglist
- ,docstring
- ,interactive
- (emms-source-insert ',source-name ,@call-args)))))
-
-(defun emms-source-play (source &rest args)
- "Play the tracks of SOURCE, after first clearing the EMMS playlist."
- (emms-stop)
- (emms-playlist-current-clear)
- (apply 'emms-playlist-current-insert-source source args)
- (emms-playlist-current-select-first)
- (emms-start))
-
-(defun emms-source-add (source &rest args)
- "Add the tracks of SOURCE at the current position in the playlist."
- (with-current-emms-playlist
- (save-excursion
- (goto-char (point-max))
- (apply 'emms-playlist-current-insert-source source args))
- (when (or (not emms-playlist-selected-marker)
- (not (marker-position emms-playlist-selected-marker)))
- (emms-playlist-select-first))))
-
-(defun emms-source-insert (source &rest args)
- "Insert the tracks from SOURCE in the current buffer."
- (if (not emms-playlist-buffer-p)
- (error "Not in an EMMS playlist buffer")
- (apply 'emms-playlist-insert-source source args)))
-
-;;; User-defined playlists
-;;; FIXME: Shuffle is bogus here! (because of narrowing)
-(defmacro define-emms-combined-source (name shufflep sources)
- "Define a `emms-play-X' and `emms-add-X' function for SOURCES."
- `(define-emms-source ,name ()
- "An EMMS source for a tracklist."
- (interactive)
- (mapc (lambda (source)
- (apply (car source)
- (cdr source)))
- ,sources)
- ,(when shufflep
- '(save-restriction
- (widen)
- (emms-shuffle)))))
-
-
-;;; Players
-
-;; A player is a data structure created by `emms-player'.
-;; See the docstring of that function for more information.
-
-(defvar emms-player-stopped-p nil
- "Non-nil if the last EMMS player was stopped by the user.")
-
-(defun emms-player (start stop playablep)
- "Create a new EMMS player.
-The start function will be START, and the stop function STOP.
-PLAYABLEP should return non-nil for tracks that this player can
-play.
-
-When trying to play a track, EMMS walks through
-`emms-player-list'. For each player, it calls the PLAYABLEP
-function. The player corresponding to the first PLAYABLEP
-function that returns non-nil is used to play the track. To
-actually play the track, EMMS calls the START function, passing
-the chosen track as a parameter.
-
-If the user tells EMMS to stop playing, the STOP function is
-called. Once the player has finished playing, it should call
-`emms-player-stopped' to let EMMS know."
- (let ((p (emms-dictionary '*player*)))
- (emms-player-set p 'start start)
- (emms-player-set p 'stop stop)
- (emms-player-set p 'playablep playablep)
- p))
-
-(defun emms-player-get (player name &optional inexistent)
- "Return the value of entry NAME in PLAYER."
- (let ((p (if (symbolp player)
- (symbol-value player)
- player)))
- (emms-dictionary-get p name inexistent)))
-
-(defun emms-player-set (player name value)
- "Set the value of entry NAME in PLAYER to VALUE."
- (let ((p (if (symbolp player)
- (symbol-value player)
- player)))
- (emms-dictionary-set p name value)))
-
-(defun emms-player-for (track)
- "Return an EMMS player capable of playing TRACK.
-This will be the first player whose PLAYABLEP function returns
-non-nil, or nil if no such player exists."
- (let ((lis emms-player-list))
- (while (and lis
- (not (funcall (emms-player-get (car lis) 'playablep)
- track)))
- (setq lis (cdr lis)))
- (if lis
- (car lis)
- nil)))
-
-(defun emms-player-start (track)
- "Start playing TRACK."
- (if emms-player-playing-p
- (error "A player is already playing")
- (let ((player (emms-player-for track)))
- (if (not player)
- (error "Don't know how to play track: %S" track)
- ;; Change default-directory so we don't accidentally block any
- ;; directories the current buffer was visiting.
- (let ((default-directory "/"))
- (funcall (emms-player-get player 'start)
- track))))))
-
-(defun emms-player-started (player)
- "Declare that the given EMMS PLAYER has started.
-This should only be done by the current player itself."
- (setq emms-player-playing-p player
- emms-player-paused-p nil)
- (run-hooks 'emms-player-started-hook))
-
-(defun emms-player-stop ()
- "Stop the current EMMS player."
- (when emms-player-playing-p
- (let ((emms-player-stopped-p t))
- (funcall (emms-player-get emms-player-playing-p 'stop)))
- (setq emms-player-playing-p nil)))
-
-(defun emms-player-stopped ()
- "Declare that the current EMMS player is finished.
-This should only be done by the current player itself."
- (setq emms-player-playing-p nil)
- (if emms-player-stopped-p
- (run-hooks 'emms-player-stopped-hook)
- (sleep-for emms-player-delay)
- (run-hooks 'emms-player-finished-hook)
- (funcall emms-player-next-function)))
-
-(defun emms-player-pause ()
- "Pause the current EMMS player."
- (cond
- ((not emms-player-playing-p)
- (error "Can't pause player, nothing is playing"))
- (emms-player-paused-p
- (let ((resume (emms-player-get emms-player-playing-p 'resume))
- (pause (emms-player-get emms-player-playing-p 'pause)))
- (cond
- (resume
- (funcall resume))
- (pause
- (funcall pause))
- (t
- (error "Player does not know how to pause"))))
- (setq emms-player-paused-p nil)
- (run-hooks 'emms-player-paused-hook))
- (t
- (let ((pause (emms-player-get emms-player-playing-p 'pause)))
- (if pause
- (funcall pause)
- (error "Player does not know how to pause")))
- (setq emms-player-paused-p t)
- (run-hooks 'emms-player-paused-hook))))
-
-(defun emms-player-seek (seconds)
- "Seek the current player by SECONDS seconds.
-This can be a floating point number for fractions of a second, or
-negative to seek backwards."
- (if (not emms-player-playing-p)
- (error "Can't seek player, nothing playing right now")
- (let ((seek (emms-player-get emms-player-playing-p 'seek)))
- (if (not seek)
- (error "Player does not know how to seek")
- (funcall seek seconds)
- (run-hook-with-args 'emms-player-seeked-functions seconds)))))
-
-(defun emms-player-seek-to (seconds)
- "Seek the current player to SECONDS seconds.
-This can be a floating point number for fractions of a second, or
-negative to seek backwards."
- (if (not emms-player-playing-p)
- (error "Can't seek-to player, nothing playing right now")
- (let ((seek (emms-player-get emms-player-playing-p 'seek-to)))
- (if (not seek)
- (error "Player does not know how to seek-to")
- (funcall seek seconds)
- (run-hook-with-args 'emms-player-time-set-functions seconds)))))
-
-(provide 'emms)
-;;; emms.el ends here
diff --git a/lisp/jack.el b/lisp/jack.el
deleted file mode 100644
index d248a12..0000000
--- a/lisp/jack.el
+++ /dev/null
@@ -1,368 +0,0 @@
-;;; jack.el --- Jack Audio Connection Kit support
-
-;; Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-
-;; Author: Mario Lang <mlang@delysid.org>
-;; Keywords: multimedia, processes
-
-;; 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 3, 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., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;; JACK is a low-latency audio server, written for POSIX conformant
-;; operating systems such as GNU/Linux and Apple's OS X. It can connect a
-;; number of different applications to an audio device, as well as
-;; allowing them to share audio between themselves. Its clients can run in
-;; their own processes (ie. as normal applications), or they can run
-;; within the JACK server (ie. as a "plugin").
-;;
-;; JACK was designed from the ground up for professional audio work, and
-;; its design focuses on two key areas: synchronous execution of all
-;; clients, and low latency operation.
-;;
-;; jack.el provides a fascility for starting jackd from within Emacs.
-;; It also povides convenience functions for prompting the user for
-;; jack client and port names in the minibuffer, as well as the
-;; functions `jack-connect' and `jack-disconnect' which can be used to
-;; rearrange jack port wiring with a minimum of keystrokes.
-
-;;; Code:
-
-(require 'emms-compat)
-
-(defgroup jack ()
- "Jack Audio Connection Kit"
- :group 'processes)
-
-(defcustom jack-rc '("~/.jackdrc" "/etc/jackd.conf")
- "*JACK run control paths."
- :group 'jack
- :type 'repeat)
-
-(defcustom jack-use-jack-rc t
- "*If non-nil, try to retrieve jack startup arguments from run control files
-listed in `jack-rc'. If no rc file is found or this variable is set
-to nil, use the Emacs variables to build the startup args."
- :group 'jack
- :type 'boolean)
-
-(defcustom jack-program (executable-find "jackd")
- "*JACK executable path."
- :group 'jack
- :type 'file)
-
-(defcustom jack-sample-rate 44100
- "*Default sampling rate for JACK."
- :group 'jack
- :type 'integer)
-
-(defcustom jack-period-size 128
- "*Period size to use when launching new JACK process."
- :group 'jack
- :type 'integer)
-
-(defcustom jack-alsa-device nil
- "*ALSA soundcard to use."
- :group 'jack
- :type '(choice (const :tag "Ask" nil) string))
-
-(defun jack-read-alsa-device ()
- "Read an ALSA device name using the minibuffer."
- (let (cards)
- (with-temp-buffer
- (insert-file-contents "/proc/asound/cards")
- (while (not (eobp))
- (if (looking-at "^\\([0-9]\\) \\[.+\\]: \\(.+\\)\n +\\(.*\\)$")
- (setq cards (append (list (cons (match-string 3) (match-string 1))) cards)))
- (forward-line 1)))
- (concat "hw:" (cdr (assoc (completing-read "Card: " cards nil t) cards)))))
-
-(defun jack-alsa-device ()
- (or jack-alsa-device (jack-read-alsa-device)))
-
-(defcustom jack-output-buffer-name "*JACK output*"
- "*Output buffer name."
- :group 'jack
- :type 'string)
-
-(defun jack-args ()
- "Return a list of startup arguments to use.
-First element is the executable path."
- (or (and jack-use-jack-rc
- (catch 'rc-found
- (let ((files (mapcar 'expand-file-name jack-rc)))
- (while files
- (if (file-exists-p (car files))
- (with-temp-buffer
- (insert-file-contents (car files))
- (when (> (buffer-size) 0)
- (throw 'rc-found
- (split-string (buffer-string) "[\n \t]+")))))
- (setq files (cdr files))))
- nil))
- (list jack-program
- "-v"
- "-R"
- "-dalsa"
- (format "-d%s" (jack-alsa-device))
- (format "-r%d" jack-sample-rate)
- (format "-p%d" jack-period-size))))
-
-(defcustom jack-set-rtlimits t
- "*Use set_rtlimits (if available) to gain realtime priorities if -R
-is given in jackd command-line."
- :group 'jack
- :type 'boolean)
-
-(defcustom jack-set-rtlimits-program (executable-find "set_rtlimits")
- "*Path to set_rtlimits."
- :group 'jack
- :type 'file)
-
-(defun jack-maybe-rtlimits (args)
- (if (and jack-set-rtlimits
- (or (member "-R" args) (member "--realtime" args))
- (file-exists-p jack-set-rtlimits-program))
- (append (list jack-set-rtlimits-program "-r") args)
- args))
-
-(defvar jack-process nil)
-
-(defvar jack-load 0)
-
-(defvar jack-max-usecs 0)
-
-(defvar jack-spare 0)
-
-(defun jack-output-buffer ()
- (or (get-buffer jack-output-buffer-name)
- (with-current-buffer (get-buffer-create jack-output-buffer-name)
- (setq major-mode 'jack-mode
- mode-name "JACK"
- mode-line-format (copy-tree mode-line-format))
- (setcar (nthcdr 16 mode-line-format)
- `(:eval (format "load:%.2f" jack-load)))
- (add-hook 'kill-buffer-hook 'jack-kill nil t)
- (current-buffer))))
-
-(defvar jack-xruns nil)
-
-(defun jack-filter (proc string)
- (with-current-buffer (process-buffer proc)
- (let ((moving (= (point) (process-mark proc))))
- (save-excursion
- (save-match-data
- (if (string-match "^load = \\([^ ]+\\) max usecs: \\([^,]+\\), spare = \\(.+\\)$" string)
- (setq jack-load (string-to-number (match-string 1 string))
- jack-max-usecs (string-to-number (match-string 2 string))
- jack-spare (string-to-number (match-string 3 string)))
- (if (string-match "^**** alsa_pcm: xrun of at least \\([^ ]+\\) msecs$" string)
- (push (string-to-number (match-string 1 string)) jack-xruns)
- (goto-char (process-mark proc))
- (insert string)
- (set-marker (process-mark proc) (point))))))
- (when moving (goto-char (process-mark proc))))))
-
-(defun jack-running-p ()
- (and jack-process (processp jack-process)
- (eq (process-status jack-process) 'run)))
-
-(defcustom jack-started-hook nil
- "*Hook run when `jack-start' successfully started a new JACK intance."
- :group 'jack
- :type 'hook)
-
-(defun jack-start ()
- "Start the JACK process."
- (interactive)
- (if (jack-running-p) (error "JACK already running")
- (setq jack-process
- (apply 'start-process "jack" (jack-output-buffer)
- (jack-maybe-rtlimits (jack-args))))
- (set-process-filter jack-process #'jack-filter)
- (run-hooks 'jack-started-hook)
- (switch-to-buffer (jack-output-buffer))))
-
-(defun jack-kill ()
- "Kill the currently running JACK process."
- (interactive)
- (when (jack-running-p) (delete-process jack-process))
- (setq jack-process nil))
-
-(defun jack-restart ()
- "Restart JACK."
- (interactive)
- (if (jack-running-p) (jack-kill))
- (sit-for 0)
- (jack-start))
-
-(defun jack-list ()
- "Retrieve a list of JACK clients/ports."
- (with-temp-buffer
- (call-process "jack_lsp" nil t nil "-cpl")
- (goto-char (point-min))
- (let (result current-port)
- (while (not (eobp))
- (cond
- ((looking-at "^\\([^ \t:]+\\):\\(.+\\)$")
- (let ((program (match-string 1))
- (port (match-string 2)))
- (if (assoc program result)
- (setcdr (assoc program result)
- (append (cdr (assoc program result)) (list (setq current-port (list port)))))
- (setq result
- (append (list (list program (setq current-port (list port)))) result)))))
- ((looking-at "^ \\([^ \t:]+\\):\\(.+\\)$")
- (if (assoc 'connections (cdr current-port))
- (setcdr (assoc 'connections (cdr current-port))
- (append (cdr (assoc 'connections current-port))
- (list (list (match-string 1) (match-string 2)))))
- (setcdr current-port
- (append (list (list 'connections (list (match-string 1) (match-string 2)))) (cdr current-port)))))
- ((looking-at "^\tproperties: \\(.+\\),$")
- (setcdr current-port
- (append (list (append (list 'properties) (mapcar #'intern (split-string (match-string 1) ",")))) (cdr current-port)))))
- (forward-line 1))
- result)))
-
-(defun jack-ports (program)
- (cdr (assoc program (jack-list))))
-
-(defun jack-get-port-connections (program port)
- (cdr (assoc 'connections (cdr (assoc port (jack-ports program))))))
-
-(defun jack-get-port-properties (program port)
- (cdr (assoc 'properties (cdr (assoc port (jack-ports program))))))
-
-(defun jack-get-direction (program port)
- (let ((props (jack-get-port-properties program port)))
- (or (car (member 'output props))
- (car (member 'input props))
- (error "Neither input nor output port"))))
-
-(defun jack-read-program (prompt &optional predicate)
- (let ((progs (if (functionp predicate)
- (emms-remove-if-not predicate (jack-list))
- (jack-list))))
- (unless progs (error "No matching JACK clients found"))
- (if (< (length progs) 2) (caar progs)
- (completing-read prompt progs nil t))))
-
-(defun jack-unique-port-name (strings)
- (let ((start "")
- (maxlen (apply 'min (mapcar #'length strings))))
- (while (and (< (length start) maxlen)
- (catch 'not-ok
- (let ((nextchar (substring (car strings) (length start) (1+ (length start)))))
- (mapc (lambda (str)
- (unless (string= (concat start nextchar) (substring str 0 (1+ (length start))))
- (throw 'not-ok nil)))
- strings)
- t)))
- (setq start (substring (car strings) 0 (1+ (length start)))))
- start))
-
-(defun jack-read-port (program prompt &optional predicate)
- (let ((ports (if (functionp predicate)
- (emms-remove-if-not predicate (jack-ports program))
- (jack-ports program))))
- (if (< (length ports) 2) (caar ports)
- (completing-read prompt ports nil t (jack-unique-port-name (mapcar 'car ports))))))
-
-(defun jack-connect (from-program from-port to-program to-port)
- "Connect FROM-PROGRAM's output port FROM-PORT to TO-PROGRAM's input port
-TO-PORT.
-If called interactively, the direction does not matter."
- (interactive
- (let* ((prog (jack-read-program "Connect: "))
- (port (jack-read-port prog (format "Connect %s port: " prog)))
- (to-type (if (eq (jack-get-direction prog port) 'input) 'output 'input))
- (to-prog (jack-read-program
- (format "Connect %s port %s to: " prog port)
- (lambda (prog)
- (emms-find-if (lambda (port)
- (member to-type (assoc 'properties
- (cdr port))))
- (cdr prog)))))
- (to-port (jack-read-port
- to-prog
- (format "Connect %s port %s to %s port: " prog port to-prog)
- (lambda (port)
- (member to-type (cdr (assoc 'properties (cdr port))))))))
- (if (eq to-type 'input)
- (list prog port to-prog to-port)
- (list to-prog to-port prog port))))
- (let ((result (call-process "jack_connect" nil nil nil
- (format "%s:%s" from-program from-port)
- (format "%s:%s" to-program to-port))))
- (if (= result 0)
- (message "JACK: Connected %s:%s to %s:%s"
- from-program from-port to-program to-port))))
-
-(defun jack-disconnect (from-program from-port to-program to-port)
- "Disconnect FROM-PROGRAM's output port FROM-PORT from TO-PROGRAM's
-input port TO-PORT.
-If called interactively, the direction is not relevant."
- (interactive
- (let* ((prog (jack-read-program
- "Disconnect: "
- (lambda (prog)
- (emms-find-if (lambda (port) (assoc 'connections (cdr port)))
- (cdr prog)))))
- (port (jack-read-port prog
- (format "Disconnect %s port: " prog)
- (lambda (port)
- (assoc 'connections (cdr port)))))
- (connections (jack-get-port-connections prog port))
- (from (list prog port))
- (to (if (< (length connections) 2)
- (car connections)
- (let* ((to-progs (let (result)
- (mapc (lambda (conn)
- (if (not (member (car conn) result))
- (setq result
- (append (list (car conn))
- result))))
- connections)
- (mapcar #'list result)))
- (to-prog (if (< (length to-progs) 2)
- (caar to-progs)
- (completing-read
- (format "Disconnect %s port %s from: "
- prog port) to-progs nil t))))
- (setq connections (emms-remove-if-not
- (lambda (conn)
- (string= (car conn) to-prog))
- connections))
- (if (< (length connections) 2)
- (car connections)
- (let ((to-port (completing-read
- (format "Disconnect %s port %s from %s port: "
- prog port to-prog)
- (mapcar #'cdr connections) nil t)))
- (list to-prog to-port)))))))
- (if (eq (jack-get-direction prog port) 'output)
- (append from to)
- (append to from))))
- (let ((result (call-process "jack_disconnect" nil nil nil
- (format "%s:%s" from-program from-port)
- (format "%s:%s" to-program to-port))))
- (if (= result 0)
- (message "JACK: Disconnected %s:%s from %s:%s"
- from-program from-port to-program to-port))))
-
-(provide 'jack)
-;;; jack.el ends here
diff --git a/lisp/later-do.el b/lisp/later-do.el
deleted file mode 100644
index 5908ac5..0000000
--- a/lisp/later-do.el
+++ /dev/null
@@ -1,86 +0,0 @@
-;;; later-do.el --- execute lisp code ... later
-
-;; Copyright (C) 2004, 2005, 2006, 2007, 2008,
-;; 2009, 2018 Free Software Foundation, Inc.
-
-;; Author: Jorgen Schaefer <forcer@forcix.cx>
-
-;;; This program 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 3
-;;; of the License, or (at your option) any later version.
-
-;;; This program 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 this program; if not, write to the Free Software
-;;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-;;; 02110-1301 USA
-
-;;; Commentary
-
-;; This file will execute lisp code ``later on''. This way it is
-;; possible to work while elisp does some longer calculations, if you
-;; can convert those calculations into a sequence of function calls.
-
-;;; Code:
-
-(defvar later-do-version "0.2emms4 (2018-04-07)"
- "Version string of later-do.")
-
-(defgroup later-do nil
- "*Running functions ... later!"
- :prefix "later-do-"
- :group 'development)
-
-(defcustom later-do-interval 0.5
- "How many seconds to wait between running events."
- :group 'later-do
- :type 'number)
-
-(defcustom later-do-batch 20
- "How many functions to process before waiting `later-do-interval'.
-The functions are processed from `later-do-list'. Must be 1 or
-greater. Too high a value might make Emacs slower while the
-list is being processed."
- :group 'later-do
- :type 'number)
-
-(defvar later-do-list nil
- "A list of functions to be called later on.")
-
-(defvar later-do-timer nil
- "The timer that later-do uses.")
-
-(defun later-do (function &rest args)
- "Apply FUNCTION to ARGS later on. This is an unspecified
-amount of time after this call, and definitely not while lisp is
-still executing. Code added using `later-do' is guaranteed to be
-executed in the sequence it was added."
- (setq later-do-list (nconc later-do-list
- (list (cons function args))))
- (unless later-do-timer
- (setq later-do-timer
- (run-with-timer later-do-interval nil 'later-do-timer))))
-
-(defun later-do-timer ()
- "Run the next element in `later-do-list', or do nothing if it's
-empty."
- (if (null later-do-list)
- (setq later-do-timer nil)
- (let (res)
- (unwind-protect
- (dotimes (b (min later-do-batch (length later-do-list)) res)
- (let ((fun (caar later-do-list))
- (args (cdar later-do-list)))
- (setq later-do-list (cdr later-do-list))
- (setq res (apply fun args)))))
- (setq later-do-timer (run-with-timer later-do-interval
- nil
- 'later-do-timer)))))
-
-(provide 'later-do)
-;;; later-do.el ends here