emacs.d

My Emacs configuration
git clone https://git.jamzattack.xyz/emacs.d
Log | Files | Refs | LICENSE

commit edb5c23734bf110e5e28b2304f60b7563374def8
parent 426f7566fd3a68c9740063474e48c0bf88d55e41
Author: Jamie Beardslee <beardsleejamie@gmail.com>
Date:   Tue, 10 Mar 2020 20:51:43 +1300

updated elpa packages

Diffstat:
Delpa/dimmer-20200302.2032/dimmer-autoloads.el | 82-------------------------------------------------------------------------------
Delpa/dimmer-20200302.2032/dimmer-pkg.el | 2--
Delpa/dimmer-20200302.2032/dimmer.el | 612-------------------------------------------------------------------------------
Delpa/dimmer-20200302.2032/dimmer.elc | 0
Aelpa/dimmer-20200308.2331/dimmer-autoloads.el | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/dimmer-20200308.2331/dimmer-pkg.el | 2++
Aelpa/dimmer-20200308.2331/dimmer.el | 621+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/dimmer-20200308.2331/dimmer.elc | 0
Delpa/emms-20200212.1825/dir | 18------------------
Delpa/emms-20200212.1825/emms-autoloads.el | 552-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-bookmarks.el | 153-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-bookmarks.elc | 0
Delpa/emms-20200212.1825/emms-browser.el | 2254-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-browser.elc | 0
Delpa/emms-20200212.1825/emms-cache.el | 195-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-cache.elc | 0
Delpa/emms-20200212.1825/emms-compat.el | 185-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-compat.elc | 0
Delpa/emms-20200212.1825/emms-cue.el | 120-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-cue.elc | 0
Delpa/emms-20200212.1825/emms-history.el | 134-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-history.elc | 0
Delpa/emms-20200212.1825/emms-i18n.el | 180-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-i18n.elc | 0
Delpa/emms-20200212.1825/emms-info-libtag.el | 116-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-info-libtag.elc | 0
Delpa/emms-20200212.1825/emms-info-metaflac.el | 107-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-info-metaflac.elc | 0
Delpa/emms-20200212.1825/emms-info-mp3info.el | 104-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-info-mp3info.elc | 0
Delpa/emms-20200212.1825/emms-info-ogginfo.el | 85-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-info-ogginfo.elc | 0
Delpa/emms-20200212.1825/emms-info-opusinfo.el | 85-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-info-opusinfo.elc | 0
Delpa/emms-20200212.1825/emms-info.el | 140-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-info.elc | 0
Delpa/emms-20200212.1825/emms-last-played.el | 123-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-last-played.elc | 0
Delpa/emms-20200212.1825/emms-librefm-scrobbler.el | 327-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-librefm-scrobbler.elc | 0
Delpa/emms-20200212.1825/emms-librefm-stream.el | 393-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-librefm-stream.elc | 0
Delpa/emms-20200212.1825/emms-lyrics.el | 585-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-lyrics.elc | 0
Delpa/emms-20200212.1825/emms-maint.el | 1-
Delpa/emms-20200212.1825/emms-maint.elc | 0
Delpa/emms-20200212.1825/emms-mark.el | 295-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-mark.elc | 0
Delpa/emms-20200212.1825/emms-metaplaylist-mode.el | 246-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-metaplaylist-mode.elc | 0
Delpa/emms-20200212.1825/emms-mode-line-icon.el | 80-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-mode-line-icon.elc | 0
Delpa/emms-20200212.1825/emms-mode-line.el | 158-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-mode-line.elc | 0
Delpa/emms-20200212.1825/emms-pkg.el | 12------------
Delpa/emms-20200212.1825/emms-player-mpd.el | 1320-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-player-mpd.elc | 0
Delpa/emms-20200212.1825/emms-player-mpg321-remote.el | 223-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-player-mpg321-remote.elc | 0
Delpa/emms-20200212.1825/emms-player-mplayer.el | 81-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-player-mplayer.elc | 0
Delpa/emms-20200212.1825/emms-player-mpv.el | 847-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-player-mpv.elc | 0
Delpa/emms-20200212.1825/emms-player-simple.el | 210-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-player-simple.elc | 0
Delpa/emms-20200212.1825/emms-player-vlc.el | 85-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-player-vlc.elc | 0
Delpa/emms-20200212.1825/emms-player-xine.el | 92-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-player-xine.elc | 0
Delpa/emms-20200212.1825/emms-playing-time.el | 239-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-playing-time.elc | 0
Delpa/emms-20200212.1825/emms-playlist-limit.el | 224-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-playlist-limit.elc | 0
Delpa/emms-20200212.1825/emms-playlist-mode.el | 614-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-playlist-mode.elc | 0
Delpa/emms-20200212.1825/emms-playlist-sort.el | 228-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-playlist-sort.elc | 0
Delpa/emms-20200212.1825/emms-score.el | 272-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-score.elc | 0
Delpa/emms-20200212.1825/emms-setup.el | 155-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-setup.elc | 0
Delpa/emms-20200212.1825/emms-show-all.el | 125-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-show-all.elc | 0
Delpa/emms-20200212.1825/emms-source-file.el | 314-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-source-file.elc | 0
Delpa/emms-20200212.1825/emms-source-playlist.el | 494-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-source-playlist.elc | 0
Delpa/emms-20200212.1825/emms-stream-info.el | 30------------------------------
Delpa/emms-20200212.1825/emms-stream-info.elc | 0
Delpa/emms-20200212.1825/emms-streams.el | 179-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-streams.elc | 0
Delpa/emms-20200212.1825/emms-tag-editor.el | 775-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-tag-editor.elc | 0
Delpa/emms-20200212.1825/emms-url.el | 114-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-url.elc | 0
Delpa/emms-20200212.1825/emms-volume-amixer.el | 76----------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-volume-amixer.elc | 0
Delpa/emms-20200212.1825/emms-volume-mixerctl.el | 80-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-volume-mixerctl.elc | 0
Delpa/emms-20200212.1825/emms-volume-pulse.el | 110-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-volume-pulse.elc | 0
Delpa/emms-20200212.1825/emms-volume.el | 154-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms-volume.elc | 0
Delpa/emms-20200212.1825/emms.el | 1537-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/emms.elc | 0
Delpa/emms-20200212.1825/emms.info | 3759-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/jack.el | 368-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/jack.elc | 0
Delpa/emms-20200212.1825/later-do.el | 86-------------------------------------------------------------------------------
Delpa/emms-20200212.1825/later-do.elc | 0
Delpa/helm-core-20200302.638/helm-core-pkg.el | 7-------
Delpa/helm-core-20200302.638/helm-lib.el | 1595-------------------------------------------------------------------------------
Delpa/helm-core-20200302.638/helm-lib.elc | 0
Relpa/helm-core-20200302.638/helm-core-autoloads.el -> elpa/helm-core-20200306.1417/helm-core-autoloads.el | 0
Aelpa/helm-core-20200306.1417/helm-core-pkg.el | 7+++++++
Aelpa/helm-core-20200306.1417/helm-lib.el | 1585+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/helm-core-20200306.1417/helm-lib.elc | 0
Relpa/helm-core-20200302.638/helm-multi-match.el -> elpa/helm-core-20200306.1417/helm-multi-match.el | 0
Relpa/helm-core-20200302.638/helm-multi-match.elc -> elpa/helm-core-20200306.1417/helm-multi-match.elc | 0
Relpa/helm-core-20200302.638/helm-source.el -> elpa/helm-core-20200306.1417/helm-source.el | 0
Relpa/helm-core-20200302.638/helm-source.elc -> elpa/helm-core-20200306.1417/helm-source.elc | 0
Relpa/helm-core-20200302.638/helm.el -> elpa/helm-core-20200306.1417/helm.el | 0
Relpa/helm-core-20200302.638/helm.elc -> elpa/helm-core-20200306.1417/helm.elc | 0
Delpa/system-packages-20200227.1741/system-packages-autoloads.el | 140-------------------------------------------------------------------------------
Delpa/system-packages-20200227.1741/system-packages-pkg.el | 2--
Delpa/system-packages-20200227.1741/system-packages.el | 510-------------------------------------------------------------------------------
Delpa/system-packages-20200227.1741/system-packages.elc | 0
Aelpa/system-packages-20200310.34/system-packages-autoloads.el | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/system-packages-20200310.34/system-packages-pkg.el | 2++
Aelpa/system-packages-20200310.34/system-packages.el | 548+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aelpa/system-packages-20200310.34/system-packages.elc | 0
131 files changed, 3007 insertions(+), 22389 deletions(-)

diff --git a/elpa/dimmer-20200302.2032/dimmer-autoloads.el b/elpa/dimmer-20200302.2032/dimmer-autoloads.el @@ -1,82 +0,0 @@ -;;; dimmer-autoloads.el --- automatically extracted autoloads -;; -;;; Code: - -(add-to-list 'load-path (directory-file-name - (or (file-name-directory #$) (car load-path)))) - - -;;;### (autoloads nil "dimmer" "dimmer.el" (0 0 0 0)) -;;; Generated autoloads from dimmer.el - -(autoload 'dimmer-configure-company-box "dimmer" "\ -Convenience setting for company-box users. -This predicate prevents dimming the buffer you are editing when -company-box pops up a list of completion." nil nil) - -(autoload 'dimmer-configure-helm "dimmer" "\ -Convenience settings for helm users." nil nil) - -(autoload 'dimmer-configure-hydra "dimmer" "\ -Convenience settings for hydra users." nil nil) - -(autoload 'dimmer-configure-magit "dimmer" "\ -Convenience settings for magit users." nil nil) - -(autoload 'dimmer-configure-org "dimmer" "\ -Convenience settings for org users." nil nil) - -(autoload 'dimmer-configure-posframe "dimmer" "\ -Convenience settings for packages depending on posframe. - -Note, packages that use posframe aren't required to be consistent -about how they name their buffers, but many of them tend to -include the words \"posframe\" and \"buffer\" in the buffer's -name. Examples include: - - - \" *ivy-posframe-buffer*\" - - \" *company-posframe-buffer*\" - - \" *flycheck-posframe-buffer*\" - - \" *ddskk-posframe-buffer*\" - -If this setting doesn't work for you, you still have the option -of adding another regular expression to catch more things, or -in some cases you can customize the other package and ensure it -uses a buffer name that fits this pattern." nil nil) - -(autoload 'dimmer-configure-which-key "dimmer" "\ -Convenience settings for which-key-users." nil nil) - -(defvar dimmer-mode nil "\ -Non-nil if Dimmer mode is enabled. -See the `dimmer-mode' command -for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `dimmer-mode'.") - -(custom-autoload 'dimmer-mode "dimmer" nil) - -(autoload 'dimmer-mode "dimmer" "\ -visually highlight the selected buffer - -If called interactively, enable Dimmer mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, -also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. - -\(fn &optional ARG)" t nil) - -(define-obsolete-function-alias 'dimmer-activate 'dimmer-mode) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dimmer" '("dimmer-"))) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; dimmer-autoloads.el ends here diff --git a/elpa/dimmer-20200302.2032/dimmer-pkg.el b/elpa/dimmer-20200302.2032/dimmer-pkg.el @@ -1,2 +0,0 @@ -;;; Generated package description from /home/jdb/.config/emacs/elpa/dimmer-20200302.2032/dimmer.el -*- no-byte-compile: t -*- -(define-package "dimmer" "20200302.2032" "Visually highlight the selected buffer" '((emacs "25.1")) :commit "2544f0da13a54961f8776d0d57151829ed106376" :keywords '("faces" "editing") :authors '(("Neil Okamoto")) :maintainer '("Neil Okamoto") :url "https://github.com/gonewest818/dimmer.el") diff --git a/elpa/dimmer-20200302.2032/dimmer.el b/elpa/dimmer-20200302.2032/dimmer.el @@ -1,612 +0,0 @@ -;;; dimmer.el --- Visually highlight the selected buffer - -;; Copyright (C) 2017-2020 Neil Okamoto - -;; Filename: dimmer.el -;; Author: Neil Okamoto -;; Version: 0.4.2 -;; Package-Version: 20200302.2032 -;; Package-Requires: ((emacs "25.1")) -;; URL: https://github.com/gonewest818/dimmer.el -;; Keywords: faces, editing -;; -;; This file is NOT part of GNU Emacs. -;; -;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. -;; -;;; Commentary: -;; -;; This module provides a minor mode that indicates which buffer is -;; currently active by dimming the faces in the other buffers. It -;; does this nondestructively, and computes the dimmed faces -;; dynamically such that your overall color scheme is shown in a muted -;; form without requiring you to define what is a "dim" version of -;; every face. -;; -;; `dimmer.el' can be configured to adjust foreground colors (default), -;; background colors, or both. -;; -;; Usage: -;; -;; (require 'dimmer) -;; (dimmer-configure-which-key) -;; (dimmer-configure-helm) -;; (dimmer-mode t) -;; -;; Configuration: -;; -;; By default dimmer excludes the minibuffer and echo areas from -;; consideration, so that most packages that use the minibuffer for -;; interaction will behave as users expect. -;; -;; `dimmer-configure-company-box' is a convenience function for users -;; of company-box. It prevents dimming the buffer you are editing when -;; a company-box popup is displayed. -;; -;; `dimmer-configure-helm' is a convenience function for helm users to -;; ensure helm buffers are not dimmed. -;; -;; `dimmer-configure-hydra' is a convenience function for hydra users to -;; ensure "*LV*" buffers are not dimmed. -;; -;; `dimmer-configure-magit' is a convenience function for magit users to -;; ensure transients are not dimmed. -;; -;; `dimmer-configure-org' is a convenience function for org users to -;; ensure org-mode buffers are not dimmed. -;; -;; `dimmer-configure-posframe' is a convenience function for posframe -;; users to ensure posframe buffers are not dimmed. -;; -;; `dimmer-configure-which-key' is a convenience function for which-key -;; users to ensure which-key popups are not dimmed. -;; -;; Please submit pull requests with configurations for other packages! -;; -;; Customization: -;; -;; `dimmer-adjustment-mode' controls what aspect of the color scheme is adjusted -;; when dimming. Choices are :foreground (default), :background, or :both. -;; -;; `dimmer-fraction' controls the degree to which buffers are dimmed. -;; Range is 0.0 - 1.0, and default is 0.20. Increase value if you -;; like the other buffers to be more dim. -;; -;; `dimmer-buffer-exclusion-regexps' can be used to specify buffers that -;; should never be dimmed. If the buffer name matches any regexp in -;; this list then `dimmer.el' will not dim that buffer. -;; -;; `dimmer-buffer-exclusion-predicates' can be used to specify buffers that -;; should never be dimmed. If any predicate function in this list -;; returns true for the buffer then `dimmer.el' will not dim that buffer. -;; -;; `dimmer-prevent-dimming-predicates' can be used to prevent dimmer from -;; altering the dimmed buffer list. This can be used to detect cases -;; where a package pops up a window temporarily, and we don't want the -;; dimming to change. If any function in this list returns a non-nil -;; value, dimming state will not be changed. -;; -;; `dimmer-watch-frame-focus-events' controls whether dimmer will dim all -;; buffers when Emacs no longer has focus in the windowing system. This -;; is enabled by default. Some users may prefer to set this to nil, and -;; have the dimmed / not dimmed buffers stay as-is even when Emacs -;; doesn't have focus. -;; -;; `dimmer-use-colorspace' allows you to specify what color space the -;; dimming calculation is performed in. In the majority of cases you -;; won't need to touch this setting. See the docstring below for more -;; information. -;; -;;; Code: - -(require 'cl-lib) -(require 'color) -(require 'face-remap) -(require 'seq) -(require 'subr-x) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; customization - -(defgroup dimmer nil - "Highlight the current buffer by dimming the colors on the others." - :prefix "dimmer-" - :group 'convenience - :link '(url-link :tag "GitHub" "https://github.com/gonewest818/dimmer.el")) - -(define-obsolete-variable-alias 'dimmer-percent 'dimmer-fraction) -(defcustom dimmer-fraction 0.20 - "Control the degree to which buffers are dimmed (0.0 - 1.0)." - :type '(float) - :group 'dimmer) - -(defcustom dimmer-adjustment-mode :foreground - "Control what aspect of the color scheme is adjusted when dimming. -Choices are :foreground (default), :background, or :both." - :type '(radio (const :tag "Foreground colors are dimmed" :foreground) - (const :tag "Background colors are dimmed" :background) - (const :tag "Foreground and background are dimmed" :both)) - :group 'dimmer) - -(make-obsolete-variable - 'dimmer-exclusion-regexp - "`dimmer-exclusion-regexp` is obsolete and has no effect in this session. -The variable has been superseded by `dimmer-buffer-exclusion-regexps`. -See documentation for details." - "v0.4.0") - -(define-obsolete-variable-alias - 'dimmer-exclusion-regexp-list 'dimmer-buffer-exclusion-regexps) -(defcustom dimmer-buffer-exclusion-regexps '("^ \\*Minibuf-[0-9]+\\*$" - "^ \\*Echo.*\\*$") - "List of regular expressions describing buffer names that are never dimmed." - :type '(repeat (choice regexp)) - :group 'dimmer) - -(defcustom dimmer-buffer-exclusion-predicates '() - "List of predicate functions indicating buffers that are never dimmed. - -Functions in the list are called while visiting each available -buffer. If the predicate function returns a truthy value, then -the buffer is not dimmed." - :type '(repeat (choice function)) - :group 'dimmer) - -(define-obsolete-variable-alias - 'dimmer-exclusion-predicates 'dimmer-prevent-dimming-predicates) -(defcustom dimmer-prevent-dimming-predicates '(window-minibuffer-p) - "List of functions which prevent dimmer from altering dimmed buffer set. - -Functions in this list are called in turn with no arguments. If any function -returns a non-nil value, no buffers will be added to or removed from the set -of dimmed buffers." - :type '(repeat (choice function)) - :group 'dimmer) - -(defcustom dimmer-watch-frame-focus-events t - "Should windows be dimmed when all Emacs frame(s) lose focus? -Restart Emacs after changing this configuration." - :type '(boolean) - :group 'dimmer) - -(defcustom dimmer-use-colorspace :cielab - "Colorspace in which dimming calculations are performed. -Choices are :cielab (default), :hsl, or :rgb. - -CIELAB is the default, and in most cases should serve perfectly -well. As a colorspace it attempts to be uniform to the human -eye, meaning the degree of dimming should be roughly the same for -all your foreground colors. - -Bottom line: If CIELAB is working for you, then you don't need to -experiment with the other choices. - -However, interpolating in CIELAB introduces one wrinkle, in that -mathematically it's possible to generate a color that isn't -representable on your RGB display (colors having one or more RGB -channel values < 0.0 or > 1.0). When dimmer finds an -\"impossible\" RGB value like that it simply clamps that value to -fit in the range 0.0 - 1.0. Clamping like this can lead to some -colors looking \"wrong\". If you think the dimmed values look -wrong, then try HSL or RGB instead." - :type '(radio (const :tag "Interpolate in CIELAB 1976" :cielab) - (const :tag "Interpolate in HSL" :hsl) - (const :tag "Interpolate in RGB" :rgb)) - :group 'dimmer) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; configuration - -;;;###autoload -(defun dimmer-configure-company-box () - "Convenience setting for company-box users. -This predicate prevents dimming the buffer you are editing when -company-box pops up a list of completion." - (add-to-list - 'dimmer-prevent-dimming-predicates - (lambda () (string-prefix-p " *company-box-" (buffer-name))))) - -;;;###autoload -(defun dimmer-configure-helm () - "Convenience settings for helm users." - (with-no-warnings - (add-to-list - 'dimmer-exclusion-regexp-list "^\\*[h|H]elm.*\\*$") - (add-to-list - 'dimmer-prevent-dimming-predicates #'helm--alive-p))) - -;;;###autoload -(defun dimmer-configure-hydra () - "Convenience settings for hydra users." - (add-to-list - 'dimmer-exclusion-regexp-list "^ \\*LV\\*$")) - -;;;###autoload -(defun dimmer-configure-magit () - "Convenience settings for magit users." - (add-to-list - 'dimmer-exclusion-regexp-list "^ \\*transient\\*$")) - -;;;###autoload -(defun dimmer-configure-org () - "Convenience settings for org users." - (add-to-list 'dimmer-exclusion-regexp-list "^\\*Org Select\\*$") - (add-to-list 'dimmer-exclusion-regexp-list "^ \\*Agenda Commands\\*$")) - -;;;###autoload -(defun dimmer-configure-posframe () - "Convenience settings for packages depending on posframe. - -Note, packages that use posframe aren't required to be consistent -about how they name their buffers, but many of them tend to -include the words \"posframe\" and \"buffer\" in the buffer's -name. Examples include: - - - \" *ivy-posframe-buffer*\" - - \" *company-posframe-buffer*\" - - \" *flycheck-posframe-buffer*\" - - \" *ddskk-posframe-buffer*\" - -If this setting doesn't work for you, you still have the option -of adding another regular expression to catch more things, or -in some cases you can customize the other package and ensure it -uses a buffer name that fits this pattern." - (add-to-list - 'dimmer-exclusion-regexp-list "^ \\*.*posframe.*buffer.*\\*$")) - -;;;###autoload -(defun dimmer-configure-which-key () - "Convenience settings for which-key-users." - (with-no-warnings - (add-to-list - 'dimmer-exclusion-regexp-list "^ \\*which-key\\*$") - (add-to-list - 'dimmer-prevent-dimming-predicates #'which-key--popup-showing-p))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; implementation - -(defvar dimmer-last-buffer nil - "Identity of the last buffer to be made current.") - -(defvar dimmer-debug-messages 0 - "Control debugging output to *Messages* buffer. -Set 0 to disable all output, 1 for basic output, or a larger -integer for more verbosity.") - -(defvar-local dimmer-buffer-face-remaps nil - "Per-buffer face remappings needed for later clean up.") -;; don't allow major mode change to kill the local variable -(put 'dimmer-buffer-face-remaps 'permanent-local t) - -(defconst dimmer-dimmed-faces (make-hash-table :test 'equal) - "Cache of face names with their computed dimmed values.") - -(defun dimmer-lerp (frac c0 c1) - "Use FRAC to compute a linear interpolation of C0 and C1." - (+ (* c0 (- 1.0 frac)) - (* c1 frac))) - -(defun dimmer-lerp-in-rgb (c0 c1 frac) - "Compute linear interpolation of C0 and C1 in RGB space. -FRAC controls the interpolation." - (apply 'color-rgb-to-hex - (cl-mapcar (apply-partially 'dimmer-lerp frac) c0 c1))) - -(defun dimmer-lerp-in-hsl (c0 c1 frac) - "Compute linear interpolation of C0 and C1 in HSL space. -FRAC controls the interpolation." - ;; Implementation note: We must handle this case carefully to ensure the - ;; hue is interpolated over the "shortest" arc around the color wheel. - (apply 'color-rgb-to-hex - (apply 'color-hsl-to-rgb - (cl-destructuring-bind (h0 s0 l0) - (apply 'color-rgb-to-hsl c0) - (cl-destructuring-bind (h1 s1 l1) - (apply 'color-rgb-to-hsl c1) - (if (> (abs (- h1 h0)) 0.5) - ;; shortest arc "wraps around" - (list (mod (dimmer-lerp (- 1.0 frac) h1 (+ 1.0 h0)) 1.0) - (dimmer-lerp frac s0 s1) - (dimmer-lerp frac l0 l1)) - ;; shortest arc is the natural one - (list (dimmer-lerp frac h0 h1) - (dimmer-lerp frac s0 s1) - (dimmer-lerp frac l0 l1)))))))) - -(defun dimmer-lerp-in-cielab (c0 c1 frac) - "Compute linear interpolation of C0 and C1 in CIELAB space. -FRAC controls the interpolation." - (apply 'color-rgb-to-hex - (cl-mapcar 'color-clamp - (apply 'color-lab-to-srgb - (cl-mapcar (apply-partially 'dimmer-lerp frac) - (apply 'color-srgb-to-lab c0) - (apply 'color-srgb-to-lab c1)))))) - -(defun dimmer-compute-rgb (c0 c1 frac colorspace) - "Compute a \"dimmed\" color via linear interpolation. - -Blends the two colors, C0 and C1, using FRAC to control the -interpolation. When FRAC is 0.0, the result is equal to C0. When -FRAC is 1.0, the result is equal to C1. - -Any other value for FRAC means the result's hue, saturation, and -value will be adjusted linearly so that the color sits somewhere -between C0 and C1. - -The interpolation is performed in a COLORSPACE which is specified -with a symbol, :rgb, :hsl, or :cielab." - (pcase colorspace - (:rgb (dimmer-lerp-in-rgb c0 c1 frac)) - (:hsl (dimmer-lerp-in-hsl c0 c1 frac)) - (:cielab (dimmer-lerp-in-cielab c0 c1 frac)) - (_ (dimmer-lerp-in-cielab c0 c1 frac)))) - -(defun dimmer-cached-compute-rgb (c0 c1 frac colorspace) - "Lookup a \"dimmed\" color value from cache, else compute a value. -This is essentially a memoization of `dimmer-compute-rgb` via a hash -using the arguments C0, C1, FRAC, and COLORSPACE as the key." - (let ((key (format "%s-%s-%f-%s" c0 c1 frac dimmer-use-colorspace))) - (or (gethash key dimmer-dimmed-faces) - (let ((rgb (dimmer-compute-rgb (color-name-to-rgb c0) - (color-name-to-rgb c1) - frac - dimmer-use-colorspace))) - (when rgb - (puthash key rgb dimmer-dimmed-faces) - rgb))))) - -(defun dimmer-face-color (f frac) - "Compute a dimmed version of the foreground color of face F. -If `dimmer-adjust-background-color` is true, adjust the -background color as well. FRAC is the amount of dimming where -0.0 is no change and 1.0 is maximum change. Returns a plist -containing the new foreground (and if needed, new background) -suitable for use with `face-remap-add-relative`." - (let ((fg (face-foreground f)) - (bg (face-background f)) - (def-fg (face-foreground 'default)) - (def-bg (face-background 'default)) - ;; when mode is :both, the perceptual effect is "doubled" - (my-frac (if (eq dimmer-adjustment-mode :both) - (/ frac 2.0) - frac)) - (result '())) - ;; We shift the desired components of F by FRAC amount toward the `default` - ;; color, thereby dimming or desaturating the overall appearance: - ;; * When the `dimmer-adjustment-mode` is `:foreground` we move the - ;; foreground component toward the `default` background. - ;; * When the `dimmer-adjustment-mode` is :background we mofe the - ;; background component of F toward the `default` foreground.` - (when (and (or (eq dimmer-adjustment-mode :foreground) - (eq dimmer-adjustment-mode :both)) - fg (color-defined-p fg) - def-bg (color-defined-p def-bg)) - (setq result - (plist-put result :foreground - (dimmer-cached-compute-rgb fg - def-bg - my-frac - dimmer-use-colorspace)))) - (when (and (or (eq dimmer-adjustment-mode :background) - (eq dimmer-adjustment-mode :both)) - bg (color-defined-p bg) - def-fg (color-defined-p def-fg)) - (setq result - (plist-put result :background - (dimmer-cached-compute-rgb bg - def-fg - my-frac - dimmer-use-colorspace)))) - result)) - -(defun dimmer-filtered-face-list () - "Return a filtered version of `face-list`. -Filtering is needed to exclude faces that shouldn't be dimmed." - ;; `fringe` is problematic because it is shared for all windows, - ;; so for now we just leave it alone. - (remove 'fringe (face-list))) - -(defun dimmer-dim-buffer (buf frac) - "Dim all the faces defined in the buffer BUF. -FRAC controls the dimming as defined in ‘dimmer-face-color’." - (with-current-buffer buf - (dimmer--dbg 1 "dimmer-dim-buffer: BEFORE '%s' (%s)" buf - (alist-get 'default face-remapping-alist)) - (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" - (alist-get 'default dimmer-buffer-face-remaps)) - (unless dimmer-buffer-face-remaps - (dolist (f (dimmer-filtered-face-list)) - (let ((c (dimmer-face-color f frac))) - (when c ; e.g. "(when-let* ((c (...)))" in Emacs 26 - (push (face-remap-add-relative f c) dimmer-buffer-face-remaps))))) - (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" - (alist-get 'default dimmer-buffer-face-remaps)) - (dimmer--dbg 2 "dimmer-dim-buffer: AFTER '%s' (%s)" buf - (alist-get 'default face-remapping-alist)))) - -(defun dimmer-restore-buffer (buf) - "Restore the un-dimmed faces in the buffer BUF." - (with-current-buffer buf - (dimmer--dbg 1 "dimmer-restore-buffer: BEFORE '%s' (%s)" buf - (alist-get 'default face-remapping-alist)) - (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" - (alist-get 'default dimmer-buffer-face-remaps)) - (when dimmer-buffer-face-remaps - (mapc 'face-remap-remove-relative dimmer-buffer-face-remaps) - (setq dimmer-buffer-face-remaps nil)) - (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" - (alist-get 'default dimmer-buffer-face-remaps)) - (dimmer--dbg 2 "dimmer-restore-buffer: AFTER '%s' (%s)" buf - (alist-get 'default face-remapping-alist)))) - -(defun dimmer-filtered-buffer-list () - "Get filtered subset of all visible buffers in all frames." - (let (buffers) - (walk-windows - (lambda (win) - (let* ((buf (window-buffer win)) - (name (buffer-name buf))) - (unless (or (member buf buffers) - (cl-some (lambda (rxp) (string-match-p rxp name)) - dimmer-buffer-exclusion-regexps) - (cl-some (lambda (f) (funcall f buf)) - dimmer-buffer-exclusion-predicates)) - (push buf buffers)))) - nil - t) - (dimmer--dbg 3 "dimmer-filtered-buffer-list: %s" buffers) - buffers)) - -(defun dimmer-process-all () - "Process all buffers and dim or un-dim each." - (dimmer--dbg-buffers 1 "dimmer-process-all") - (let ((selected (current-buffer)) - (ignore (cl-some (lambda (f) (and (fboundp f) (funcall f))) - dimmer-prevent-dimming-predicates))) - (setq dimmer-last-buffer selected) - (unless ignore - (dolist (buf (dimmer-filtered-buffer-list)) - (dimmer--dbg 2 "dimmer-process-all: buf %s" buf) - (if (eq buf selected) - (dimmer-restore-buffer buf) - (dimmer-dim-buffer buf dimmer-fraction)))))) - -(defun dimmer-dim-all () - "Dim all buffers." - (dimmer--dbg-buffers 1 "dimmer-dim-all") - (mapc (lambda (buf) - (dimmer-dim-buffer buf dimmer-fraction)) - (buffer-list))) - -(defun dimmer-restore-all () - "Un-dim all buffers." - (dimmer--dbg-buffers 1 "dimmer-restore-all") - (mapc 'dimmer-restore-buffer (buffer-list))) - -(defun dimmer-command-handler () - "Process all buffers if current buffer has changed." - (dimmer--dbg-buffers 1 "dimmer-command-handler") - (unless (eq (window-buffer) dimmer-last-buffer) - (dimmer-process-all))) - -(defun dimmer-config-change-handler () - "Process all buffers if window configuration has changed." - (dimmer--dbg-buffers 1 "dimmer-config-change-handler") - (dimmer-process-all)) - -(defun dimmer-after-focus-change-handler () - "Handle cases where a frame may have gained or last focus. -Walk the `frame-list` and check the state of each one. If none -of the frames has focus then dim them all. If any frame has -focus then dim the others. Used in Emacs >= 27.0 only." - (dimmer--dbg-buffers 1 "dimmer-after-focus-change-handler") - (let ((focus-out t)) - (with-no-warnings - (dolist (f (frame-list) focus-out) - (setq focus-out (and focus-out (not (frame-focus-state f)))))) - (if focus-out - (dimmer-dim-all) - (dimmer-process-all)))) - -(defun dimmer-manage-frame-focus-hooks (install) - "Manage the frame focus in/out hooks for dimmer. - -When INSTALL is t, install the appropriate hooks to catch focus -events. Otherwise remove the hooks. This function has no effect -when `dimmer-watch-frame-focus-events` is nil." - (when dimmer-watch-frame-focus-events - (if (boundp 'after-focus-change-function) - ;; emacs-version >= 27.0 - (if install - (add-function :before - after-focus-change-function - #'dimmer-after-focus-change-handler) - (remove-function after-focus-change-function - #'dimmer-after-focus-change-handler)) - ;; else emacs-version < 27.0 - (if install - (with-no-warnings - (add-hook 'focus-in-hook #'dimmer-config-change-handler) - (add-hook 'focus-out-hook #'dimmer-dim-all)) - (with-no-warnings - (remove-hook 'focus-in-hook #'dimmer-config-change-handler) - (remove-hook 'focus-out-hook #'dimmer-dim-all)))))) - -;;;###autoload -(define-minor-mode dimmer-mode - "visually highlight the selected buffer" - nil - :lighter "" - :global t - :require 'dimmer - (if dimmer-mode - (progn - (dimmer-manage-frame-focus-hooks t) - (add-hook 'post-command-hook #'dimmer-command-handler) - (add-hook 'window-configuration-change-hook - #'dimmer-config-change-handler)) - (dimmer-manage-frame-focus-hooks nil) - (remove-hook 'post-command-hook #'dimmer-command-handler) - (remove-hook 'window-configuration-change-hook - #'dimmer-config-change-handler) - (dimmer-restore-all))) - -;;;###autoload -(define-obsolete-function-alias 'dimmer-activate 'dimmer-mode) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; debugging - call from *scratch*, ielm, or eshell - -(defun dimmer--debug-face-remapping-alist (name &optional clear) - "Display 'face-remapping-alist' for buffer NAME (or clear if CLEAR)." - (with-current-buffer name - (if clear - (setq face-remapping-alist nil) - face-remapping-alist))) - -(defun dimmer--debug-buffer-face-remaps (name &optional clear) - "Display 'dimmer-buffer-face-remaps' for buffer NAME (or clear if CLEAR)." - (with-current-buffer name - (if clear - (setq dimmer-buffer-face-remaps nil) - dimmer-buffer-face-remaps))) - -(defun dimmer--debug-reset (name) - "Clear 'face-remapping-alist' and 'dimmer-buffer-face-remaps' for NAME." - (dimmer--debug-face-remapping-alist name t) - (dimmer--debug-buffer-face-remaps name t) - (redraw-display)) - -(defun dimmer--dbg (v fmt &rest args) - "Print debug message at verbosity V, filling format string FMT with ARGS." - (when (>= dimmer-debug-messages v) - (apply #'message fmt args))) - -(defun dimmer--dbg-buffers (v label) - "Print debug buffer state at verbosity V and the given LABEL." - (when (>= dimmer-debug-messages v) - (let ((inhibit-message t) - (cb (current-buffer)) - (wb (window-buffer))) - (message "%s: cb '%s' <== lb '%s' %s" label cb dimmer-last-buffer - (if (not (eq cb wb)) - (format "wb '%s' **" wb) - ""))))) - -(provide 'dimmer) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; dimmer.el ends here diff --git a/elpa/dimmer-20200302.2032/dimmer.elc b/elpa/dimmer-20200302.2032/dimmer.elc Binary files differ. diff --git a/elpa/dimmer-20200308.2331/dimmer-autoloads.el b/elpa/dimmer-20200308.2331/dimmer-autoloads.el @@ -0,0 +1,85 @@ +;;; dimmer-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "dimmer" "dimmer.el" (0 0 0 0)) +;;; Generated autoloads from dimmer.el + +(autoload 'dimmer-configure-company-box "dimmer" "\ +Convenience setting for company-box users. +This predicate prevents dimming the buffer you are editing when +company-box pops up a list of completion." nil nil) + +(autoload 'dimmer-configure-helm "dimmer" "\ +Convenience settings for helm users." nil nil) + +(autoload 'dimmer-configure-gnus "dimmer" "\ +Convenience settings for gnus users." nil nil) + +(autoload 'dimmer-configure-hydra "dimmer" "\ +Convenience settings for hydra users." nil nil) + +(autoload 'dimmer-configure-magit "dimmer" "\ +Convenience settings for magit users." nil nil) + +(autoload 'dimmer-configure-org "dimmer" "\ +Convenience settings for org users." nil nil) + +(autoload 'dimmer-configure-posframe "dimmer" "\ +Convenience settings for packages depending on posframe. + +Note, packages that use posframe aren't required to be consistent +about how they name their buffers, but many of them tend to +include the words \"posframe\" and \"buffer\" in the buffer's +name. Examples include: + + - \" *ivy-posframe-buffer*\" + - \" *company-posframe-buffer*\" + - \" *flycheck-posframe-buffer*\" + - \" *ddskk-posframe-buffer*\" + +If this setting doesn't work for you, you still have the option +of adding another regular expression to catch more things, or +in some cases you can customize the other package and ensure it +uses a buffer name that fits this pattern." nil nil) + +(autoload 'dimmer-configure-which-key "dimmer" "\ +Convenience settings for which-key-users." nil nil) + +(defvar dimmer-mode nil "\ +Non-nil if Dimmer mode is enabled. +See the `dimmer-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `dimmer-mode'.") + +(custom-autoload 'dimmer-mode "dimmer" nil) + +(autoload 'dimmer-mode "dimmer" "\ +visually highlight the selected buffer + +If called interactively, enable Dimmer mode if ARG is positive, +and disable it if ARG is zero or negative. If called from Lisp, +also enable the mode if ARG is omitted or nil, and toggle it if +ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(define-obsolete-function-alias 'dimmer-activate 'dimmer-mode) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dimmer" '("dimmer-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; dimmer-autoloads.el ends here diff --git a/elpa/dimmer-20200308.2331/dimmer-pkg.el b/elpa/dimmer-20200308.2331/dimmer-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from /home/jdb/.config/emacs/elpa/dimmer-20200308.2331/dimmer.el -*- no-byte-compile: t -*- +(define-package "dimmer" "20200308.2331" "Visually highlight the selected buffer" '((emacs "25.1")) :commit "2b8b639e55e0e79101f7197264f17429cdcf4669" :keywords '("faces" "editing") :authors '(("Neil Okamoto")) :maintainer '("Neil Okamoto") :url "https://github.com/gonewest818/dimmer.el") diff --git a/elpa/dimmer-20200308.2331/dimmer.el b/elpa/dimmer-20200308.2331/dimmer.el @@ -0,0 +1,621 @@ +;;; dimmer.el --- Visually highlight the selected buffer + +;; Copyright (C) 2017-2020 Neil Okamoto + +;; Filename: dimmer.el +;; Author: Neil Okamoto +;; Version: 0.4.2 +;; Package-Version: 20200308.2331 +;; Package-Requires: ((emacs "25.1")) +;; URL: https://github.com/gonewest818/dimmer.el +;; Keywords: faces, editing +;; +;; This file is NOT part of GNU Emacs. +;; +;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; This module provides a minor mode that indicates which buffer is +;; currently active by dimming the faces in the other buffers. It +;; does this nondestructively, and computes the dimmed faces +;; dynamically such that your overall color scheme is shown in a muted +;; form without requiring you to define what is a "dim" version of +;; every face. +;; +;; `dimmer.el' can be configured to adjust foreground colors (default), +;; background colors, or both. +;; +;; Usage: +;; +;; (require 'dimmer) +;; (dimmer-configure-which-key) +;; (dimmer-configure-helm) +;; (dimmer-mode t) +;; +;; Configuration: +;; +;; By default dimmer excludes the minibuffer and echo areas from +;; consideration, so that most packages that use the minibuffer for +;; interaction will behave as users expect. +;; +;; `dimmer-configure-company-box' is a convenience function for users +;; of company-box. It prevents dimming the buffer you are editing when +;; a company-box popup is displayed. +;; +;; `dimmer-configure-helm' is a convenience function for helm users to +;; ensure helm buffers are not dimmed. +;; +;; `dimmer-configure-gnus' is a convenience function for gnus users to +;; ensure article buffers are not dimmed. +;; +;; `dimmer-configure-hydra' is a convenience function for hydra users to +;; ensure "*LV*" buffers are not dimmed. +;; +;; `dimmer-configure-magit' is a convenience function for magit users to +;; ensure transients are not dimmed. +;; +;; `dimmer-configure-org' is a convenience function for org users to +;; ensure org-mode buffers are not dimmed. +;; +;; `dimmer-configure-posframe' is a convenience function for posframe +;; users to ensure posframe buffers are not dimmed. +;; +;; `dimmer-configure-which-key' is a convenience function for which-key +;; users to ensure which-key popups are not dimmed. +;; +;; Please submit pull requests with configurations for other packages! +;; +;; Customization: +;; +;; `dimmer-adjustment-mode' controls what aspect of the color scheme is adjusted +;; when dimming. Choices are :foreground (default), :background, or :both. +;; +;; `dimmer-fraction' controls the degree to which buffers are dimmed. +;; Range is 0.0 - 1.0, and default is 0.20. Increase value if you +;; like the other buffers to be more dim. +;; +;; `dimmer-buffer-exclusion-regexps' can be used to specify buffers that +;; should never be dimmed. If the buffer name matches any regexp in +;; this list then `dimmer.el' will not dim that buffer. +;; +;; `dimmer-buffer-exclusion-predicates' can be used to specify buffers that +;; should never be dimmed. If any predicate function in this list +;; returns true for the buffer then `dimmer.el' will not dim that buffer. +;; +;; `dimmer-prevent-dimming-predicates' can be used to prevent dimmer from +;; altering the dimmed buffer list. This can be used to detect cases +;; where a package pops up a window temporarily, and we don't want the +;; dimming to change. If any function in this list returns a non-nil +;; value, dimming state will not be changed. +;; +;; `dimmer-watch-frame-focus-events' controls whether dimmer will dim all +;; buffers when Emacs no longer has focus in the windowing system. This +;; is enabled by default. Some users may prefer to set this to nil, and +;; have the dimmed / not dimmed buffers stay as-is even when Emacs +;; doesn't have focus. +;; +;; `dimmer-use-colorspace' allows you to specify what color space the +;; dimming calculation is performed in. In the majority of cases you +;; won't need to touch this setting. See the docstring below for more +;; information. +;; +;;; Code: + +(require 'cl-lib) +(require 'color) +(require 'face-remap) +(require 'seq) +(require 'subr-x) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; customization + +(defgroup dimmer nil + "Highlight the current buffer by dimming the colors on the others." + :prefix "dimmer-" + :group 'convenience + :link '(url-link :tag "GitHub" "https://github.com/gonewest818/dimmer.el")) + +(define-obsolete-variable-alias 'dimmer-percent 'dimmer-fraction) +(defcustom dimmer-fraction 0.20 + "Control the degree to which buffers are dimmed (0.0 - 1.0)." + :type '(float) + :group 'dimmer) + +(defcustom dimmer-adjustment-mode :foreground + "Control what aspect of the color scheme is adjusted when dimming. +Choices are :foreground (default), :background, or :both." + :type '(radio (const :tag "Foreground colors are dimmed" :foreground) + (const :tag "Background colors are dimmed" :background) + (const :tag "Foreground and background are dimmed" :both)) + :group 'dimmer) + +(make-obsolete-variable + 'dimmer-exclusion-regexp + "`dimmer-exclusion-regexp` is obsolete and has no effect in this session. +The variable has been superseded by `dimmer-buffer-exclusion-regexps`. +See documentation for details." + "v0.4.0") + +(define-obsolete-variable-alias + 'dimmer-exclusion-regexp-list 'dimmer-buffer-exclusion-regexps) +(defcustom dimmer-buffer-exclusion-regexps '("^ \\*Minibuf-[0-9]+\\*$" + "^ \\*Echo.*\\*$") + "List of regular expressions describing buffer names that are never dimmed." + :type '(repeat (choice regexp)) + :group 'dimmer) + +(defcustom dimmer-buffer-exclusion-predicates '() + "List of predicate functions indicating buffers that are never dimmed. + +Functions in the list are called while visiting each available +buffer. If the predicate function returns a truthy value, then +the buffer is not dimmed." + :type '(repeat (choice function)) + :group 'dimmer) + +(define-obsolete-variable-alias + 'dimmer-exclusion-predicates 'dimmer-prevent-dimming-predicates) +(defcustom dimmer-prevent-dimming-predicates '(window-minibuffer-p) + "List of functions which prevent dimmer from altering dimmed buffer set. + +Functions in this list are called in turn with no arguments. If any function +returns a non-nil value, no buffers will be added to or removed from the set +of dimmed buffers." + :type '(repeat (choice function)) + :group 'dimmer) + +(defcustom dimmer-watch-frame-focus-events t + "Should windows be dimmed when all Emacs frame(s) lose focus? +Restart Emacs after changing this configuration." + :type '(boolean) + :group 'dimmer) + +(defcustom dimmer-use-colorspace :cielab + "Colorspace in which dimming calculations are performed. +Choices are :cielab (default), :hsl, or :rgb. + +CIELAB is the default, and in most cases should serve perfectly +well. As a colorspace it attempts to be uniform to the human +eye, meaning the degree of dimming should be roughly the same for +all your foreground colors. + +Bottom line: If CIELAB is working for you, then you don't need to +experiment with the other choices. + +However, interpolating in CIELAB introduces one wrinkle, in that +mathematically it's possible to generate a color that isn't +representable on your RGB display (colors having one or more RGB +channel values < 0.0 or > 1.0). When dimmer finds an +\"impossible\" RGB value like that it simply clamps that value to +fit in the range 0.0 - 1.0. Clamping like this can lead to some +colors looking \"wrong\". If you think the dimmed values look +wrong, then try HSL or RGB instead." + :type '(radio (const :tag "Interpolate in CIELAB 1976" :cielab) + (const :tag "Interpolate in HSL" :hsl) + (const :tag "Interpolate in RGB" :rgb)) + :group 'dimmer) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; configuration + +;;;###autoload +(defun dimmer-configure-company-box () + "Convenience setting for company-box users. +This predicate prevents dimming the buffer you are editing when +company-box pops up a list of completion." + (add-to-list + 'dimmer-prevent-dimming-predicates + (lambda () (string-prefix-p " *company-box-" (buffer-name))))) + +;;;###autoload +(defun dimmer-configure-helm () + "Convenience settings for helm users." + (with-no-warnings + (add-to-list + 'dimmer-exclusion-regexp-list "^\\*[h|H]elm.*\\*$") + (add-to-list + 'dimmer-prevent-dimming-predicates #'helm--alive-p))) + +;;;###autoload +(defun dimmer-configure-gnus () + "Convenience settings for gnus users." + (add-to-list + 'dimmer-exclusion-regexp-list "^\\*Article .*\\*$")) + +;;;###autoload +(defun dimmer-configure-hydra () + "Convenience settings for hydra users." + (add-to-list + 'dimmer-exclusion-regexp-list "^ \\*LV\\*$")) + +;;;###autoload +(defun dimmer-configure-magit () + "Convenience settings for magit users." + (add-to-list + 'dimmer-exclusion-regexp-list "^ \\*transient\\*$")) + +;;;###autoload +(defun dimmer-configure-org () + "Convenience settings for org users." + (add-to-list 'dimmer-exclusion-regexp-list "^\\*Org Select\\*$") + (add-to-list 'dimmer-exclusion-regexp-list "^ \\*Agenda Commands\\*$")) + +;;;###autoload +(defun dimmer-configure-posframe () + "Convenience settings for packages depending on posframe. + +Note, packages that use posframe aren't required to be consistent +about how they name their buffers, but many of them tend to +include the words \"posframe\" and \"buffer\" in the buffer's +name. Examples include: + + - \" *ivy-posframe-buffer*\" + - \" *company-posframe-buffer*\" + - \" *flycheck-posframe-buffer*\" + - \" *ddskk-posframe-buffer*\" + +If this setting doesn't work for you, you still have the option +of adding another regular expression to catch more things, or +in some cases you can customize the other package and ensure it +uses a buffer name that fits this pattern." + (add-to-list + 'dimmer-exclusion-regexp-list "^ \\*.*posframe.*buffer.*\\*$")) + +;;;###autoload +(defun dimmer-configure-which-key () + "Convenience settings for which-key-users." + (with-no-warnings + (add-to-list + 'dimmer-exclusion-regexp-list "^ \\*which-key\\*$") + (add-to-list + 'dimmer-prevent-dimming-predicates #'which-key--popup-showing-p))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; implementation + +(defvar dimmer-last-buffer nil + "Identity of the last buffer to be made current.") + +(defvar dimmer-debug-messages 0 + "Control debugging output to *Messages* buffer. +Set 0 to disable all output, 1 for basic output, or a larger +integer for more verbosity.") + +(defvar-local dimmer-buffer-face-remaps nil + "Per-buffer face remappings needed for later clean up.") +;; don't allow major mode change to kill the local variable +(put 'dimmer-buffer-face-remaps 'permanent-local t) + +(defconst dimmer-dimmed-faces (make-hash-table :test 'equal) + "Cache of face names with their computed dimmed values.") + +(defun dimmer-lerp (frac c0 c1) + "Use FRAC to compute a linear interpolation of C0 and C1." + (+ (* c0 (- 1.0 frac)) + (* c1 frac))) + +(defun dimmer-lerp-in-rgb (c0 c1 frac) + "Compute linear interpolation of C0 and C1 in RGB space. +FRAC controls the interpolation." + (apply 'color-rgb-to-hex + (cl-mapcar (apply-partially 'dimmer-lerp frac) c0 c1))) + +(defun dimmer-lerp-in-hsl (c0 c1 frac) + "Compute linear interpolation of C0 and C1 in HSL space. +FRAC controls the interpolation." + ;; Implementation note: We must handle this case carefully to ensure the + ;; hue is interpolated over the "shortest" arc around the color wheel. + (apply 'color-rgb-to-hex + (apply 'color-hsl-to-rgb + (cl-destructuring-bind (h0 s0 l0) + (apply 'color-rgb-to-hsl c0) + (cl-destructuring-bind (h1 s1 l1) + (apply 'color-rgb-to-hsl c1) + (if (> (abs (- h1 h0)) 0.5) + ;; shortest arc "wraps around" + (list (mod (dimmer-lerp (- 1.0 frac) h1 (+ 1.0 h0)) 1.0) + (dimmer-lerp frac s0 s1) + (dimmer-lerp frac l0 l1)) + ;; shortest arc is the natural one + (list (dimmer-lerp frac h0 h1) + (dimmer-lerp frac s0 s1) + (dimmer-lerp frac l0 l1)))))))) + +(defun dimmer-lerp-in-cielab (c0 c1 frac) + "Compute linear interpolation of C0 and C1 in CIELAB space. +FRAC controls the interpolation." + (apply 'color-rgb-to-hex + (cl-mapcar 'color-clamp + (apply 'color-lab-to-srgb + (cl-mapcar (apply-partially 'dimmer-lerp frac) + (apply 'color-srgb-to-lab c0) + (apply 'color-srgb-to-lab c1)))))) + +(defun dimmer-compute-rgb (c0 c1 frac colorspace) + "Compute a \"dimmed\" color via linear interpolation. + +Blends the two colors, C0 and C1, using FRAC to control the +interpolation. When FRAC is 0.0, the result is equal to C0. When +FRAC is 1.0, the result is equal to C1. + +Any other value for FRAC means the result's hue, saturation, and +value will be adjusted linearly so that the color sits somewhere +between C0 and C1. + +The interpolation is performed in a COLORSPACE which is specified +with a symbol, :rgb, :hsl, or :cielab." + (pcase colorspace + (:rgb (dimmer-lerp-in-rgb c0 c1 frac)) + (:hsl (dimmer-lerp-in-hsl c0 c1 frac)) + (:cielab (dimmer-lerp-in-cielab c0 c1 frac)) + (_ (dimmer-lerp-in-cielab c0 c1 frac)))) + +(defun dimmer-cached-compute-rgb (c0 c1 frac colorspace) + "Lookup a \"dimmed\" color value from cache, else compute a value. +This is essentially a memoization of `dimmer-compute-rgb` via a hash +using the arguments C0, C1, FRAC, and COLORSPACE as the key." + (let ((key (format "%s-%s-%f-%s" c0 c1 frac dimmer-use-colorspace))) + (or (gethash key dimmer-dimmed-faces) + (let ((rgb (dimmer-compute-rgb (color-name-to-rgb c0) + (color-name-to-rgb c1) + frac + dimmer-use-colorspace))) + (when rgb + (puthash key rgb dimmer-dimmed-faces) + rgb))))) + +(defun dimmer-face-color (f frac) + "Compute a dimmed version of the foreground color of face F. +If `dimmer-adjust-background-color` is true, adjust the +background color as well. FRAC is the amount of dimming where +0.0 is no change and 1.0 is maximum change. Returns a plist +containing the new foreground (and if needed, new background) +suitable for use with `face-remap-add-relative`." + (let ((fg (face-foreground f)) + (bg (face-background f)) + (def-fg (face-foreground 'default)) + (def-bg (face-background 'default)) + ;; when mode is :both, the perceptual effect is "doubled" + (my-frac (if (eq dimmer-adjustment-mode :both) + (/ frac 2.0) + frac)) + (result '())) + ;; We shift the desired components of F by FRAC amount toward the `default` + ;; color, thereby dimming or desaturating the overall appearance: + ;; * When the `dimmer-adjustment-mode` is `:foreground` we move the + ;; foreground component toward the `default` background. + ;; * When the `dimmer-adjustment-mode` is :background we mofe the + ;; background component of F toward the `default` foreground.` + (when (and (or (eq dimmer-adjustment-mode :foreground) + (eq dimmer-adjustment-mode :both)) + fg (color-defined-p fg) + def-bg (color-defined-p def-bg)) + (setq result + (plist-put result :foreground + (dimmer-cached-compute-rgb fg + def-bg + my-frac + dimmer-use-colorspace)))) + (when (and (or (eq dimmer-adjustment-mode :background) + (eq dimmer-adjustment-mode :both)) + bg (color-defined-p bg) + def-fg (color-defined-p def-fg)) + (setq result + (plist-put result :background + (dimmer-cached-compute-rgb bg + def-fg + my-frac + dimmer-use-colorspace)))) + result)) + +(defun dimmer-filtered-face-list () + "Return a filtered version of `face-list`. +Filtering is needed to exclude faces that shouldn't be dimmed." + ;; `fringe` is problematic because it is shared for all windows, + ;; so for now we just leave it alone. + (remove 'fringe (face-list))) + +(defun dimmer-dim-buffer (buf frac) + "Dim all the faces defined in the buffer BUF. +FRAC controls the dimming as defined in ‘dimmer-face-color’." + (with-current-buffer buf + (dimmer--dbg 1 "dimmer-dim-buffer: BEFORE '%s' (%s)" buf + (alist-get 'default face-remapping-alist)) + (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" + (alist-get 'default dimmer-buffer-face-remaps)) + (unless dimmer-buffer-face-remaps + (dolist (f (dimmer-filtered-face-list)) + (let ((c (dimmer-face-color f frac))) + (when c ; e.g. "(when-let* ((c (...)))" in Emacs 26 + (push (face-remap-add-relative f c) dimmer-buffer-face-remaps))))) + (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" + (alist-get 'default dimmer-buffer-face-remaps)) + (dimmer--dbg 2 "dimmer-dim-buffer: AFTER '%s' (%s)" buf + (alist-get 'default face-remapping-alist)))) + +(defun dimmer-restore-buffer (buf) + "Restore the un-dimmed faces in the buffer BUF." + (with-current-buffer buf + (dimmer--dbg 1 "dimmer-restore-buffer: BEFORE '%s' (%s)" buf + (alist-get 'default face-remapping-alist)) + (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" + (alist-get 'default dimmer-buffer-face-remaps)) + (when dimmer-buffer-face-remaps + (mapc 'face-remap-remove-relative dimmer-buffer-face-remaps) + (setq dimmer-buffer-face-remaps nil)) + (dimmer--dbg 2 "dimmer-buffer-face-remaps: %s" + (alist-get 'default dimmer-buffer-face-remaps)) + (dimmer--dbg 2 "dimmer-restore-buffer: AFTER '%s' (%s)" buf + (alist-get 'default face-remapping-alist)))) + +(defun dimmer-filtered-buffer-list () + "Get filtered subset of all visible buffers in all frames." + (let (buffers) + (walk-windows + (lambda (win) + (let* ((buf (window-buffer win)) + (name (buffer-name buf))) + (unless (or (member buf buffers) + (cl-some (lambda (rxp) (string-match-p rxp name)) + dimmer-buffer-exclusion-regexps) + (cl-some (lambda (f) (funcall f buf)) + dimmer-buffer-exclusion-predicates)) + (push buf buffers)))) + nil + t) + (dimmer--dbg 3 "dimmer-filtered-buffer-list: %s" buffers) + buffers)) + +(defun dimmer-process-all () + "Process all buffers and dim or un-dim each." + (dimmer--dbg-buffers 1 "dimmer-process-all") + (let ((selected (current-buffer)) + (ignore (cl-some (lambda (f) (and (fboundp f) (funcall f))) + dimmer-prevent-dimming-predicates))) + (setq dimmer-last-buffer selected) + (unless ignore + (dolist (buf (dimmer-filtered-buffer-list)) + (dimmer--dbg 2 "dimmer-process-all: buf %s" buf) + (if (eq buf selected) + (dimmer-restore-buffer buf) + (dimmer-dim-buffer buf dimmer-fraction)))))) + +(defun dimmer-dim-all () + "Dim all buffers." + (dimmer--dbg-buffers 1 "dimmer-dim-all") + (mapc (lambda (buf) + (dimmer-dim-buffer buf dimmer-fraction)) + (buffer-list))) + +(defun dimmer-restore-all () + "Un-dim all buffers." + (dimmer--dbg-buffers 1 "dimmer-restore-all") + (mapc 'dimmer-restore-buffer (buffer-list))) + +(defun dimmer-command-handler () + "Process all buffers if current buffer has changed." + (dimmer--dbg-buffers 1 "dimmer-command-handler") + (unless (eq (window-buffer) dimmer-last-buffer) + (dimmer-process-all))) + +(defun dimmer-config-change-handler () + "Process all buffers if window configuration has changed." + (dimmer--dbg-buffers 1 "dimmer-config-change-handler") + (dimmer-process-all)) + +(defun dimmer-after-focus-change-handler () + "Handle cases where a frame may have gained or last focus. +Walk the `frame-list` and check the state of each one. If none +of the frames has focus then dim them all. If any frame has +focus then dim the others. Used in Emacs >= 27.0 only." + (dimmer--dbg-buffers 1 "dimmer-after-focus-change-handler") + (let ((focus-out t)) + (with-no-warnings + (dolist (f (frame-list) focus-out) + (setq focus-out (and focus-out (not (frame-focus-state f)))))) + (if focus-out + (dimmer-dim-all) + (dimmer-process-all)))) + +(defun dimmer-manage-frame-focus-hooks (install) + "Manage the frame focus in/out hooks for dimmer. + +When INSTALL is t, install the appropriate hooks to catch focus +events. Otherwise remove the hooks. This function has no effect +when `dimmer-watch-frame-focus-events` is nil." + (when dimmer-watch-frame-focus-events + (if (boundp 'after-focus-change-function) + ;; emacs-version >= 27.0 + (if install + (add-function :before + after-focus-change-function + #'dimmer-after-focus-change-handler) + (remove-function after-focus-change-function + #'dimmer-after-focus-change-handler)) + ;; else emacs-version < 27.0 + (if install + (with-no-warnings + (add-hook 'focus-in-hook #'dimmer-config-change-handler) + (add-hook 'focus-out-hook #'dimmer-dim-all)) + (with-no-warnings + (remove-hook 'focus-in-hook #'dimmer-config-change-handler) + (remove-hook 'focus-out-hook #'dimmer-dim-all)))))) + +;;;###autoload +(define-minor-mode dimmer-mode + "visually highlight the selected buffer" + nil + :lighter "" + :global t + :require 'dimmer + (if dimmer-mode + (progn + (dimmer-manage-frame-focus-hooks t) + (add-hook 'post-command-hook #'dimmer-command-handler) + (add-hook 'window-configuration-change-hook + #'dimmer-config-change-handler)) + (dimmer-manage-frame-focus-hooks nil) + (remove-hook 'post-command-hook #'dimmer-command-handler) + (remove-hook 'window-configuration-change-hook + #'dimmer-config-change-handler) + (dimmer-restore-all))) + +;;;###autoload +(define-obsolete-function-alias 'dimmer-activate 'dimmer-mode) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; debugging - call from *scratch*, ielm, or eshell + +(defun dimmer--debug-face-remapping-alist (name &optional clear) + "Display 'face-remapping-alist' for buffer NAME (or clear if CLEAR)." + (with-current-buffer name + (if clear + (setq face-remapping-alist nil) + face-remapping-alist))) + +(defun dimmer--debug-buffer-face-remaps (name &optional clear) + "Display 'dimmer-buffer-face-remaps' for buffer NAME (or clear if CLEAR)." + (with-current-buffer name + (if clear + (setq dimmer-buffer-face-remaps nil) + dimmer-buffer-face-remaps))) + +(defun dimmer--debug-reset (name) + "Clear 'face-remapping-alist' and 'dimmer-buffer-face-remaps' for NAME." + (dimmer--debug-face-remapping-alist name t) + (dimmer--debug-buffer-face-remaps name t) + (redraw-display)) + +(defun dimmer--dbg (v fmt &rest args) + "Print debug message at verbosity V, filling format string FMT with ARGS." + (when (>= dimmer-debug-messages v) + (apply #'message fmt args))) + +(defun dimmer--dbg-buffers (v label) + "Print debug buffer state at verbosity V and the given LABEL." + (when (>= dimmer-debug-messages v) + (let ((inhibit-message t) + (cb (current-buffer)) + (wb (window-buffer))) + (message "%s: cb '%s' <== lb '%s' %s" label cb dimmer-last-buffer + (if (not (eq cb wb)) + (format "wb '%s' **" wb) + ""))))) + +(provide 'dimmer) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; dimmer.el ends here diff --git a/elpa/dimmer-20200308.2331/dimmer.elc b/elpa/dimmer-20200308.2331/dimmer.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/dir b/elpa/emms-20200212.1825/dir @@ -1,18 +0,0 @@ -This is the file .../info/dir, which contains the -topmost node of the Info hierarchy, called (dir)Top. -The first time you invoke Info you start off looking at this node. - -File: dir, Node: Top This is the top of the INFO tree - - This (the Directory node) gives a menu of major topics. - Typing "q" exits, "H" lists all Info commands, "d" returns here, - "h" gives a primer for first-timers, - "mEmacs<Return>" visits the Emacs manual, etc. - - In Emacs, you can click mouse button 2 on a menu item or cross reference - to select it. - -* Menu: - -Emacs -* Emms: (emms). The Emacs Multimedia System diff --git a/elpa/emms-20200212.1825/emms-autoloads.el b/elpa/emms-20200212.1825/emms-autoloads.el @@ -1,552 +0,0 @@ -;;; emms-autoloads.el --- automatically extracted autoloads -;; -;;; Code: - -(add-to-list 'load-path (directory-file-name - (or (file-name-directory #$) (car load-path)))) - - -;;;### (autoloads nil "emms" "emms.el" (0 0 0 0)) -;;; Generated autoloads from emms.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms" '("define-emms-" "emms-" "with-current-emms-playlist"))) - -;;;*** - -;;;### (autoloads nil "emms-bookmarks" "emms-bookmarks.el" (0 0 0 -;;;;;; 0)) -;;; Generated autoloads from emms-bookmarks.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-bookmarks" '("emms-bookmarks-"))) - -;;;*** - -;;;### (autoloads nil "emms-browser" "emms-browser.el" (0 0 0 0)) -;;; Generated autoloads from emms-browser.el - -(autoload 'emms-browser "emms-browser" "\ -Launch or switch to the EMMS Browser." t nil) - -(autoload 'emms-smart-browse "emms-browser" "\ -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." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-browser" '("case-fold-string" "emms-"))) - -;;;*** - -;;;### (autoloads nil "emms-cache" "emms-cache.el" (0 0 0 0)) -;;; Generated autoloads from emms-cache.el - -(autoload 'emms-cache-enable "emms-cache" "\ -Enable caching of Emms track data." t nil) - -(autoload 'emms-cache-disable "emms-cache" "\ -Disable caching of Emms track data." t nil) - -(autoload 'emms-cache-toggle "emms-cache" "\ -Toggle caching of Emms track data." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-cache" '("emms-cache"))) - -;;;*** - -;;;### (autoloads nil "emms-compat" "emms-compat.el" (0 0 0 0)) -;;; Generated autoloads from emms-compat.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-compat" '("emms-"))) - -;;;*** - -;;;### (autoloads nil "emms-cue" "emms-cue.el" (0 0 0 0)) -;;; Generated autoloads from emms-cue.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-cue" '("emms-"))) - -;;;*** - -;;;### (autoloads nil "emms-history" "emms-history.el" (0 0 0 0)) -;;; Generated autoloads from emms-history.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-history" '("emms-history-"))) - -;;;*** - -;;;### (autoloads nil "emms-i18n" "emms-i18n.el" (0 0 0 0)) -;;; Generated autoloads from emms-i18n.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-i18n" '("emms-i18n-"))) - -;;;*** - -;;;### (autoloads nil "emms-info" "emms-info.el" (0 0 0 0)) -;;; Generated autoloads from emms-info.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-info" '("emms-info-"))) - -;;;*** - -;;;### (autoloads nil "emms-info-libtag" "emms-info-libtag.el" (0 -;;;;;; 0 0 0)) -;;; Generated autoloads from emms-info-libtag.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-info-libtag" '("emms-info-libtag"))) - -;;;*** - -;;;### (autoloads nil "emms-info-metaflac" "emms-info-metaflac.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-info-metaflac.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-info-metaflac" '("emms-info-metaflac"))) - -;;;*** - -;;;### (autoloads nil "emms-info-mp3info" "emms-info-mp3info.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-info-mp3info.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-info-mp3info" '("emms-info-mp3"))) - -;;;*** - -;;;### (autoloads nil "emms-info-ogginfo" "emms-info-ogginfo.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-info-ogginfo.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-info-ogginfo" '("emms-info-ogginfo"))) - -;;;*** - -;;;### (autoloads nil "emms-info-opusinfo" "emms-info-opusinfo.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-info-opusinfo.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-info-opusinfo" '("emms-info-opusinfo"))) - -;;;*** - -;;;### (autoloads nil "emms-last-played" "emms-last-played.el" (0 -;;;;;; 0 0 0)) -;;; Generated autoloads from emms-last-played.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-last-played" '("emms-last-played-"))) - -;;;*** - -;;;### (autoloads nil "emms-librefm-scrobbler" "emms-librefm-scrobbler.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-librefm-scrobbler.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-librefm-scrobbler" '("emms-librefm-scrobbler-"))) - -;;;*** - -;;;### (autoloads nil "emms-librefm-stream" "emms-librefm-stream.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-librefm-stream.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-librefm-stream" '("emms-librefm-stream"))) - -;;;*** - -;;;### (autoloads nil "emms-lyrics" "emms-lyrics.el" (0 0 0 0)) -;;; Generated autoloads from emms-lyrics.el - -(autoload 'emms-lyrics-enable "emms-lyrics" "\ -Enable displaying emms lyrics." t nil) - -(autoload 'emms-lyrics-disable "emms-lyrics" "\ -Disable displaying emms lyrics." t nil) - -(autoload 'emms-lyrics-toggle "emms-lyrics" "\ -Toggle displaying emms lyrics." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-lyrics" '("emms-lyrics"))) - -;;;*** - -;;;### (autoloads nil "emms-mark" "emms-mark.el" (0 0 0 0)) -;;; Generated autoloads from emms-mark.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-mark" '("emms-mark-"))) - -;;;*** - -;;;### (autoloads nil "emms-metaplaylist-mode" "emms-metaplaylist-mode.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-metaplaylist-mode.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-metaplaylist-mode" '("emms-metaplaylist-mode"))) - -;;;*** - -;;;### (autoloads nil "emms-mode-line" "emms-mode-line.el" (0 0 0 -;;;;;; 0)) -;;; Generated autoloads from emms-mode-line.el - -(autoload 'emms-mode-line-enable "emms-mode-line" "\ -Turn on `emms-mode-line'." t nil) - -(autoload 'emms-mode-line-disable "emms-mode-line" "\ -Turn off `emms-mode-line'." t nil) - -(autoload 'emms-mode-line-toggle "emms-mode-line" "\ -Toggle `emms-mode-line'." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-mode-line" '("emms-mode-line"))) - -;;;*** - -;;;### (autoloads nil "emms-mode-line-icon" "emms-mode-line-icon.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-mode-line-icon.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-mode-line-icon" '("emms-mode-line-icon-"))) - -;;;*** - -;;;### (autoloads nil "emms-player-mpd" "emms-player-mpd.el" (0 0 -;;;;;; 0 0)) -;;; Generated autoloads from emms-player-mpd.el - -(autoload 'emms-player-mpd-clear "emms-player-mpd" "\ -Clear the MusicPD playlist." t nil) - -(autoload 'emms-player-mpd-connect "emms-player-mpd" "\ -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." t nil) - -(autoload 'emms-player-mpd-show "emms-player-mpd" "\ -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. - -\(fn &optional INSERTP CALLBACK)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-player-mpd" '("emms-"))) - -;;;*** - -;;;### (autoloads nil "emms-player-mpg321-remote" "emms-player-mpg321-remote.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-player-mpg321-remote.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-player-mpg321-remote" '("emms-player-mpg321-remote"))) - -;;;*** - -;;;### (autoloads nil "emms-player-mplayer" "emms-player-mplayer.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-player-mplayer.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-player-mplayer" '("emms-player-mplayer-" "mplayer"))) - -;;;*** - -;;;### (autoloads nil "emms-player-mpv" "emms-player-mpv.el" (0 0 -;;;;;; 0 0)) -;;; Generated autoloads from emms-player-mpv.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-player-mpv" '("emms-player-mpv"))) - -;;;*** - -;;;### (autoloads nil "emms-player-simple" "emms-player-simple.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-player-simple.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-player-simple" '("alsaplayer" "define-emms-simple-player" "emms-player-" "fluidsynth" "mikmod" "mpg321" "ogg123" "playsound" "speexdec" "timidity"))) - -;;;*** - -;;;### (autoloads nil "emms-player-vlc" "emms-player-vlc.el" (0 0 -;;;;;; 0 0)) -;;; Generated autoloads from emms-player-vlc.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-player-vlc" '("emms-player-vlc-" "vlc"))) - -;;;*** - -;;;### (autoloads nil "emms-player-xine" "emms-player-xine.el" (0 -;;;;;; 0 0 0)) -;;; Generated autoloads from emms-player-xine.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-player-xine" '("emms-" "xine"))) - -;;;*** - -;;;### (autoloads nil "emms-playing-time" "emms-playing-time.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-playing-time.el - -(autoload 'emms-playing-time-enable-display "emms-playing-time" "\ -Display playing time on mode line." t nil) - -(autoload 'emms-playing-time-disable-display "emms-playing-time" "\ -Remove playing time from mode line." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-playing-time" '("emms-playing-time"))) - -;;;*** - -;;;### (autoloads nil "emms-playlist-limit" "emms-playlist-limit.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-playlist-limit.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-playlist-limit" '("define-emms-playlist-limit" "emms-playlist-limit-"))) - -;;;*** - -;;;### (autoloads nil "emms-playlist-mode" "emms-playlist-mode.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-playlist-mode.el - -(autoload 'emms-playlist-mode "emms-playlist-mode" "\ -A major mode for Emms playlists. -\\{emms-playlist-mode-map}" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-playlist-mode" '("emms"))) - -;;;*** - -;;;### (autoloads nil "emms-playlist-sort" "emms-playlist-sort.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-playlist-sort.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-playlist-sort" '("define-emms-playlist-sort" "emms-"))) - -;;;*** - -;;;### (autoloads nil "emms-score" "emms-score.el" (0 0 0 0)) -;;; Generated autoloads from emms-score.el - -(autoload 'emms-score-enable "emms-score" "\ -Turn on emms-score." t nil) - -(autoload 'emms-score-disable "emms-score" "\ -Turn off emms-score." t nil) - -(autoload 'emms-score-toggle "emms-score" "\ -Toggle emms-score." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-score" '("emms-score"))) - -;;;*** - -;;;### (autoloads nil "emms-setup" "emms-setup.el" (0 0 0 0)) -;;; Generated autoloads from emms-setup.el - -(autoload 'emms-minimalistic "emms-setup" "\ -An Emms setup script. -Invisible playlists and all the basics for playing media." nil nil) - -(autoload 'emms-all "emms-setup" "\ -An Emms setup script. -Everything included in the `emms-minimalistic' setup and adds all -the stable features which come with the Emms distribution." nil nil) - -(autoload 'emms-default-players "emms-setup" "\ -Set `emms-player-list' to `emms-setup-default-player-list'." nil nil) - -(autoload 'emms-devel "emms-setup" nil nil nil) - -(autoload 'emms-standard "emms-setup" nil nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-setup" '("emms-setup-default-player-list"))) - -;;;*** - -;;;### (autoloads nil "emms-show-all" "emms-show-all.el" (0 0 0 0)) -;;; Generated autoloads from emms-show-all.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-show-all" '("emms-show-all"))) - -;;;*** - -;;;### (autoloads nil "emms-source-file" "emms-source-file.el" (0 -;;;;;; 0 0 0)) -;;; Generated autoloads from emms-source-file.el - (autoload 'emms-play-file "emms-source-file" nil t) - (autoload 'emms-add-file "emms-source-file" nil t) - (autoload 'emms-play-directory "emms-source-file" nil t) - (autoload 'emms-add-directory "emms-source-file" nil t) - (autoload 'emms-play-directory-tree "emms-source-file" nil t) - (autoload 'emms-add-directory-tree "emms-source-file" nil t) - (autoload 'emms-play-find "emms-source-file" nil t) - (autoload 'emms-add-find "emms-source-file" nil t) - (autoload 'emms-play-dired "emms-source-file" nil t) - (autoload 'emms-add-dired "emms-source-file" nil t) - -(autoload 'emms-source-file-directory-tree "emms-source-file" "\ -Return a list of all files under DIR that match REGEX. -This function uses `emms-source-file-directory-tree-function'. - -\(fn DIR REGEX)" nil nil) - -(autoload 'emms-source-file-regex "emms-source-file" "\ -Return a regexp that matches everything any player (that supports -files) can play." nil nil) - -(autoload 'emms-locate "emms-source-file" "\ -Search for REGEXP and display the results in a locate buffer - -\(fn REGEXP)" t nil) - (autoload 'emms-play-url "emms-source-file" nil t) - (autoload 'emms-add-url "emms-source-file" nil t) - (autoload 'emms-play-streamlist "emms-source-file" nil t) - (autoload 'emms-add-streamlist "emms-source-file" nil t) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-source-file" '("dire" "emms-" "file" "find" "streamlist" "url"))) - -;;;*** - -;;;### (autoloads nil "emms-source-playlist" "emms-source-playlist.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-source-playlist.el - (autoload 'emms-play-playlist "emms-source-playlist" nil t) - (autoload 'emms-add-playlist "emms-source-playlist" nil t) - (autoload 'emms-play-native-playlist "emms-source-playlist" nil t) - (autoload 'emms-add-native-playlist "emms-source-playlist" nil t) - (autoload 'emms-play-m3u-playlist "emms-source-playlist" nil t) - (autoload 'emms-add-m3u-playlist "emms-source-playlist" nil t) - (autoload 'emms-play-pls-playlist "emms-source-playlist" nil t) - (autoload 'emms-add-pls-playlist "emms-source-playlist" nil t) - (autoload 'emms-play-playlist-file "emms-source-playlist" nil t) - (autoload 'emms-add-playlist-file "emms-source-playlist" nil t) - (autoload 'emms-play-playlist-directory - "emms-source-playlist" nil t) - (autoload 'emms-add-playlist-directory - "emms-source-playlist" nil t) - (autoload 'emms-play-playlist-directory-tree - "emms-source-playlist" nil t) - (autoload 'emms-add-playlist-directory-tree - "emms-source-file" nil t) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-source-playlist" '("emms-" "m3u-playlist" "native-playlist" "playlist" "pls-playlist"))) - -;;;*** - -;;;### (autoloads nil "emms-streams" "emms-streams.el" (0 0 0 0)) -;;; Generated autoloads from emms-streams.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-streams" '("emms-streams"))) - -;;;*** - -;;;### (autoloads nil "emms-tag-editor" "emms-tag-editor.el" (0 0 -;;;;;; 0 0)) -;;; Generated autoloads from emms-tag-editor.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-tag-editor" '("emms-tag-editor-"))) - -;;;*** - -;;;### (autoloads nil "emms-url" "emms-url.el" (0 0 0 0)) -;;; Generated autoloads from emms-url.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-url" '("emms-"))) - -;;;*** - -;;;### (autoloads nil "emms-volume" "emms-volume.el" (0 0 0 0)) -;;; Generated autoloads from emms-volume.el - -(autoload 'emms-volume-raise "emms-volume" "\ -Raise the speaker volume." t nil) - -(autoload 'emms-volume-lower "emms-volume" "\ -Lower the speaker volume." t nil) - -(autoload 'emms-volume-mode-plus "emms-volume" "\ -Raise volume and enable or extend the `emms-volume-minor-mode' timeout." t nil) - -(autoload 'emms-volume-mode-minus "emms-volume" "\ -Lower volume and enable or extend the `emms-volume-minor-mode' timeout." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-volume" '("emms-volume-"))) - -;;;*** - -;;;### (autoloads nil "emms-volume-amixer" "emms-volume-amixer.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-volume-amixer.el - -(autoload 'emms-volume-amixer-change "emms-volume-amixer" "\ -Change amixer master volume by AMOUNT. - -\(fn AMOUNT)" nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-volume-amixer" '("emms-volume-amixer-c"))) - -;;;*** - -;;;### (autoloads nil "emms-volume-mixerctl" "emms-volume-mixerctl.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-volume-mixerctl.el - -(autoload 'emms-volume-mixerctl-change "emms-volume-mixerctl" "\ -Change mixerctl master volume by AMOUNT. - -\(fn AMOUNT)" nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-volume-mixerctl" '("emms-volume-mixerctl-c"))) - -;;;*** - -;;;### (autoloads nil "emms-volume-pulse" "emms-volume-pulse.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emms-volume-pulse.el - -(autoload 'emms-volume-pulse-change "emms-volume-pulse" "\ -Change PulseAudio volume by AMOUNT. - -\(fn AMOUNT)" nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "emms-volume-pulse" '("emms-volume-"))) - -;;;*** - -;;;### (autoloads nil "jack" "jack.el" (0 0 0 0)) -;;; Generated autoloads from jack.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "jack" '("jack-"))) - -;;;*** - -;;;### (autoloads nil "later-do" "later-do.el" (0 0 0 0)) -;;; Generated autoloads from later-do.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "later-do" '("later-do"))) - -;;;*** - -;;;### (autoloads nil nil ("emms-maint.el" "emms-pkg.el" "emms-stream-info.el") -;;;;;; (0 0 0 0)) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; emms-autoloads.el ends here diff --git a/elpa/emms-20200212.1825/emms-bookmarks.el b/elpa/emms-20200212.1825/emms-bookmarks.el @@ -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/elpa/emms-20200212.1825/emms-bookmarks.elc b/elpa/emms-20200212.1825/emms-bookmarks.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-browser.el b/elpa/emms-20200212.1825/emms-browser.el @@ -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/elpa/emms-20200212.1825/emms-browser.elc b/elpa/emms-20200212.1825/emms-browser.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-cache.el b/elpa/emms-20200212.1825/emms-cache.el @@ -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/elpa/emms-20200212.1825/emms-cache.elc b/elpa/emms-20200212.1825/emms-cache.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-compat.el b/elpa/emms-20200212.1825/emms-compat.el @@ -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/elpa/emms-20200212.1825/emms-compat.elc b/elpa/emms-20200212.1825/emms-compat.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-cue.el b/elpa/emms-20200212.1825/emms-cue.el @@ -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/elpa/emms-20200212.1825/emms-cue.elc b/elpa/emms-20200212.1825/emms-cue.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-history.el b/elpa/emms-20200212.1825/emms-history.el @@ -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/elpa/emms-20200212.1825/emms-history.elc b/elpa/emms-20200212.1825/emms-history.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-i18n.el b/elpa/emms-20200212.1825/emms-i18n.el @@ -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/elpa/emms-20200212.1825/emms-i18n.elc b/elpa/emms-20200212.1825/emms-i18n.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-info-libtag.el b/elpa/emms-20200212.1825/emms-info-libtag.el @@ -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/elpa/emms-20200212.1825/emms-info-libtag.elc b/elpa/emms-20200212.1825/emms-info-libtag.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-info-metaflac.el b/elpa/emms-20200212.1825/emms-info-metaflac.el @@ -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/elpa/emms-20200212.1825/emms-info-metaflac.elc b/elpa/emms-20200212.1825/emms-info-metaflac.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-info-mp3info.el b/elpa/emms-20200212.1825/emms-info-mp3info.el @@ -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/elpa/emms-20200212.1825/emms-info-mp3info.elc b/elpa/emms-20200212.1825/emms-info-mp3info.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-info-ogginfo.el b/elpa/emms-20200212.1825/emms-info-ogginfo.el @@ -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/elpa/emms-20200212.1825/emms-info-ogginfo.elc b/elpa/emms-20200212.1825/emms-info-ogginfo.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-info-opusinfo.el b/elpa/emms-20200212.1825/emms-info-opusinfo.el @@ -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/elpa/emms-20200212.1825/emms-info-opusinfo.elc b/elpa/emms-20200212.1825/emms-info-opusinfo.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-info.el b/elpa/emms-20200212.1825/emms-info.el @@ -1,140 +0,0 @@ -;;; emms-info.el --- Retrieving track information - -;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2015 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/elpa/emms-20200212.1825/emms-info.elc b/elpa/emms-20200212.1825/emms-info.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-last-played.el b/elpa/emms-20200212.1825/emms-last-played.el @@ -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/elpa/emms-20200212.1825/emms-last-played.elc b/elpa/emms-20200212.1825/emms-last-played.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-librefm-scrobbler.el b/elpa/emms-20200212.1825/emms-librefm-scrobbler.el @@ -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/elpa/emms-20200212.1825/emms-librefm-scrobbler.elc b/elpa/emms-20200212.1825/emms-librefm-scrobbler.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-librefm-stream.el b/elpa/emms-20200212.1825/emms-librefm-stream.el @@ -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/elpa/emms-20200212.1825/emms-librefm-stream.elc b/elpa/emms-20200212.1825/emms-librefm-stream.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-lyrics.el b/elpa/emms-20200212.1825/emms-lyrics.el @@ -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/elpa/emms-20200212.1825/emms-lyrics.elc b/elpa/emms-20200212.1825/emms-lyrics.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-maint.el b/elpa/emms-20200212.1825/emms-maint.el @@ -1 +0,0 @@ -(add-to-list 'load-path ".") diff --git a/elpa/emms-20200212.1825/emms-maint.elc b/elpa/emms-20200212.1825/emms-maint.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-mark.el b/elpa/emms-20200212.1825/emms-mark.el @@ -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/elpa/emms-20200212.1825/emms-mark.elc b/elpa/emms-20200212.1825/emms-mark.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-metaplaylist-mode.el b/elpa/emms-20200212.1825/emms-metaplaylist-mode.el @@ -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/elpa/emms-20200212.1825/emms-metaplaylist-mode.elc b/elpa/emms-20200212.1825/emms-metaplaylist-mode.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-mode-line-icon.el b/elpa/emms-20200212.1825/emms-mode-line-icon.el @@ -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/elpa/emms-20200212.1825/emms-mode-line-icon.elc b/elpa/emms-20200212.1825/emms-mode-line-icon.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-mode-line.el b/elpa/emms-20200212.1825/emms-mode-line.el @@ -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/elpa/emms-20200212.1825/emms-mode-line.elc b/elpa/emms-20200212.1825/emms-mode-line.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-pkg.el b/elpa/emms-20200212.1825/emms-pkg.el @@ -1,12 +0,0 @@ -(define-package "emms" "20200212.1825" "The Emacs Multimedia System" - '((cl-lib "0.5")) - :keywords - '("emms" "mp3" "mpeg" "multimedia") - :authors - '(("Jorgen Schäfer" . "forcer@forcix.cx")) - :maintainer - '("Jorgen Schäfer" . "forcer@forcix.cx") - :url "http://www.gnu.org/software/emms/") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/elpa/emms-20200212.1825/emms-player-mpd.el b/elpa/emms-20200212.1825/emms-player-mpd.el @@ -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/elpa/emms-20200212.1825/emms-player-mpd.elc b/elpa/emms-20200212.1825/emms-player-mpd.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-player-mpg321-remote.el b/elpa/emms-20200212.1825/emms-player-mpg321-remote.el @@ -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/elpa/emms-20200212.1825/emms-player-mpg321-remote.elc b/elpa/emms-20200212.1825/emms-player-mpg321-remote.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-player-mplayer.el b/elpa/emms-20200212.1825/emms-player-mplayer.el @@ -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/elpa/emms-20200212.1825/emms-player-mplayer.elc b/elpa/emms-20200212.1825/emms-player-mplayer.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-player-mpv.el b/elpa/emms-20200212.1825/emms-player-mpv.el @@ -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/elpa/emms-20200212.1825/emms-player-mpv.elc b/elpa/emms-20200212.1825/emms-player-mpv.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-player-simple.el b/elpa/emms-20200212.1825/emms-player-simple.el @@ -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/elpa/emms-20200212.1825/emms-player-simple.elc b/elpa/emms-20200212.1825/emms-player-simple.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-player-vlc.el b/elpa/emms-20200212.1825/emms-player-vlc.el @@ -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/elpa/emms-20200212.1825/emms-player-vlc.elc b/elpa/emms-20200212.1825/emms-player-vlc.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-player-xine.el b/elpa/emms-20200212.1825/emms-player-xine.el @@ -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/elpa/emms-20200212.1825/emms-player-xine.elc b/elpa/emms-20200212.1825/emms-player-xine.elc Binary files differ. diff --git a/elpa/emms-20200212.1825/emms-playing-time.el b/elpa/emms-20200212.1825/emms-playing-time.el @@ -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 - (