diff options
Diffstat (limited to 'emms-source-file.el')
-rw-r--r-- | emms-source-file.el | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/emms-source-file.el b/emms-source-file.el new file mode 100644 index 0000000..2be6538 --- /dev/null +++ b/emms-source-file.el @@ -0,0 +1,314 @@ +;;; emms-source-file.el --- EMMS sources from the filesystem. + +;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, +;; 2009 Free Software Foundation, Inc. + +;; Author: Jorgen Schäfer <forcer@forcix.cx> +;; Keywords: emms, mp3, mpeg, multimedia + +;; This file is part of EMMS. + +;; EMMS is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; EMMS is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with EMMS; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +;; Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; This file contains a track source for EMMS that is based on the +;; file system. You can retrieve single files or whole directories. +;; Also, this file offers the commands to play from these sources. + +;;; Code: + +;; Version control +(defvar emms-source-file-version "0.2 $Revision: 1.30 $" + "emms-source-file.el version string") +;; $Id: emms-source-file.el,v 1.30 2005/08/11 06:16:15 yonirabkin Exp $ + +;;; User Customization + +(require 'emms) +(require 'dired) +(require 'locate) +(eval-when-compile + (condition-case nil + (require 'locate) + (error nil))) +(require 'dired) + +(defgroup emms-source-file nil + "*Sources for EMMS that use the file system." + :prefix "emms-source-file-" + :group 'emms-source) + +(defcustom emms-source-file-default-directory nil + "*The default directory to look for media files." + :type '(choice (const :tag "None" nil) file) + :group 'emms-source-file) + +(defcustom emms-source-file-directory-tree-function + 'emms-source-file-directory-tree-internal + "*A function to call that searches in a given directory all files +that match a given regex. DIR and REGEX are the only arguments passed +to this function. +You have two build-in options: +`emms-source-file-directory-tree-internal' will work always, but might +be slow. +`emms-source-file-directory-tree-find' will work only if you have GNU +find, but it's faster." + :type 'function + :options '(emms-source-file-directory-tree-internal + emms-source-file-directory-tree-find) + :group 'emms-source-file) + +(defcustom emms-source-file-exclude-regexp + (concat "\\`\\(#.*#\\|.*,v\\|.*~\\|\\.\\.?\\|\\.#.*\\|,.*\\)\\'\\|" + "/\\(CVS\\|RCS\\|\\.arch-ids\\|{arch}\\|,.*\\|\\.svn\\|" + "_darcs\\)\\(/\\|\\'\\)") + "A regexp matching files to be ignored when adding directories. + +You should set case-fold-search to nil before using this regexp +in code." + :type 'regexp + :group 'emms-source-file) + +(defcustom emms-source-file-gnu-find "find" + "*The program name for GNU find." + :type 'string + :group 'emms-source-file) + +(defcustom emms-source-file-directory-hint-p t + "*When non-nil, guess the directory based on a track at point." + :type 'boolean + :group 'emms-source-file) + +;; The `read-directory-name' function is not available in Emacs 21. +(defalias 'emms-read-directory-name + (if (fboundp 'read-directory-name) + #'read-directory-name + #'read-file-name)) + +(defun emms-source-file-directory-hint () + (if (and emms-source-file-directory-hint-p + emms-playlist-buffer-p + (emms-playlist-track-at)) + (let ((name (emms-track-get (emms-playlist-track-at) 'name)) + (type (emms-track-get (emms-playlist-track-at) 'type))) + (when (eq type 'file) + (file-name-directory name))) + emms-source-file-default-directory)) + + +;;; Sources + +;;;###autoload (autoload 'emms-play-file "emms-source-file" nil t) +;;;###autoload (autoload 'emms-add-file "emms-source-file" nil t) +(define-emms-source file (file) + "An EMMS source for a single file - either FILE, or queried from the +user." + (interactive (list (read-file-name "Play file: " + (emms-source-file-directory-hint) + emms-source-file-default-directory + t))) + (if (file-directory-p file) + (emms-source-directory file) + (emms-playlist-insert-track + (emms-track 'file (expand-file-name file))))) + +;;;###autoload (autoload 'emms-play-directory "emms-source-file" nil t) +;;;###autoload (autoload 'emms-add-directory "emms-source-file" nil t) +(define-emms-source directory (dir) + "An EMMS source for a whole directory tree - either DIR, or queried +from the user." + (interactive (list + (emms-read-directory-name "Play directory: " + (emms-source-file-directory-hint) + emms-source-file-default-directory + t))) + (mapc (lambda (file) + (unless (or (let ((case-fold-search nil)) + (string-match emms-source-file-exclude-regexp file)) + (file-directory-p file)) + (emms-playlist-insert-track + (emms-track 'file (expand-file-name file))))) + (directory-files dir t (emms-source-file-regex)))) + +;;;###autoload (autoload 'emms-play-directory-tree "emms-source-file" nil t) +;;;###autoload (autoload 'emms-add-directory-tree "emms-source-file" nil t) +(define-emms-source directory-tree (dir) + "An EMMS source for multiple directory trees - either DIR, or the +value of `emms-source-file-default-directory'." + (interactive (list + (emms-read-directory-name "Play directory tree: " + (emms-source-file-directory-hint) + emms-source-file-default-directory + t))) + (let ((files (emms-source-file-directory-tree (expand-file-name dir) + (emms-source-file-regex))) + (case-fold-search nil)) + (emms-playlist-ensure-playlist-buffer) + (mapc (lambda (file) + (unless (string-match emms-source-file-exclude-regexp file) + (funcall emms-playlist-insert-track-function + (emms-track 'file file)))) + files))) + +;;;###autoload (autoload 'emms-play-find "emms-source-file" nil t) +;;;###autoload (autoload 'emms-add-find "emms-source-file" nil t) +(define-emms-source find (dir regex) + "An EMMS source that will find files in DIR or +`emms-source-file-default-directory' that match REGEX." + (interactive (list + (emms-read-directory-name "Find in directory: " + emms-source-file-default-directory + emms-source-file-default-directory + t) + (read-from-minibuffer "Find files matching: "))) + (mapc (lambda (file) + (unless (let ((case-fold-search nil)) + (string-match emms-source-file-exclude-regexp file)) + (emms-playlist-insert-track + (emms-track 'file file)))) + (emms-source-file-directory-tree (expand-file-name dir) regex))) + +;;;###autoload (autoload 'emms-play-dired "emms-source-file" nil t) +;;;###autoload (autoload 'emms-add-dired "emms-source-file" nil t) +(define-emms-source dired () + "Return all marked files of a dired buffer" + (interactive) + (mapc (lambda (file) + (if (file-directory-p file) + (emms-source-directory-tree file) + (emms-source-file file))) + (with-current-buffer emms-source-old-buffer + (dired-get-marked-files)))) + + +;;; Helper functions + +;;;###autoload +(defun emms-source-file-directory-tree (dir regex) + "Return a list of all files under DIR that match REGEX. +This function uses `emms-source-file-directory-tree-function'." + (message "Building playlist...") + (let ((pl (sort (funcall emms-source-file-directory-tree-function + dir + regex) + 'string<))) + (message "Building playlist...done") + pl)) + +(defun emms-source-file-directory-tree-internal (dir regex) + "Return a list of all files under DIR that match REGEX. +This function uses only emacs functions, so it might be a bit slow." + (let ((files '()) + (dirs (list dir))) + (while dirs + (cond + ((file-directory-p (car dirs)) + (if (or (string-match "/\\.\\.?$" (car dirs)) + (let ((symlink (file-symlink-p (car dirs)))) + (and symlink + (string-equal dir (substring symlink 0 (string-width dir)))))) + (setq dirs (cdr dirs)) + (setq dirs + (condition-case nil + (append (cdr dirs) + (directory-files (car dirs) + t nil t)) + (error + (cdr dirs)))))) + ((string-match regex (car dirs)) + (setq files (cons (car dirs) files) + dirs (cdr dirs))) + (t + (setq dirs (cdr dirs))))) + files)) + +(defun emms-source-file-directory-tree-find (dir regex) + "Return a list of all files under DIR that match REGEX. +This function uses the external find utility. The name for GNU find +may be supplied using `emms-source-file-gnu-find'." + (with-temp-buffer + (call-process emms-source-file-gnu-find + nil t nil + "-L" ; follow symlinks + (expand-file-name dir) + "-type" "f" + "-iregex" (concat ".*\\(" regex "\\).*")) + (delete "" + (split-string (buffer-substring (point-min) + (point-max)) + "\n")))) + +(defmacro emms-with-excluded-directories (directory-list &rest body) + "Run BODY while excluding DIRECTORY-LIST." + `(let ((emms-source-file-exclude-regexp + (concat (or ,emms-source-file-exclude-regexp "") + "\\|\\(" + (or (regexp-opt ,directory-list) "") + "\\)"))) + ,@body)) + +;;;###autoload +(defun emms-source-file-regex () + "Return a regexp that matches everything any player (that supports +files) can play." + (mapconcat (lambda (player) + (or (emms-player-get player 'regex) + "")) + emms-player-list + "\\|")) + +;; emms-locate should be part of a once to be emms-dired, with maybe +;; file rename after tag functions and so on, but till then i park it +;; here... :) + +;;;###autoload +(defun emms-locate (regexp) + "Search for REGEXP and display the results in a locate buffer" + (interactive "sRegexp to search for: ") + (require 'locate) + (save-window-excursion + (set-buffer (get-buffer-create "*EMMS Find*")) + (locate-mode) + (erase-buffer) + (mapc (lambda (elt) (insert (cdr (assoc 'name elt)) "\n")) + (emms-source-find emms-source-file-default-directory regexp)) + (locate-do-setup regexp)) + (and (not (string-equal (buffer-name) "*EMMS Find*")) + (switch-to-buffer-other-window "*EMMS Find*")) + (run-hooks 'dired-mode-hook) + (dired-next-line 2)) + +;; Strictly speaking, this does not belong in this file (URLs are not +;; real files), but it's close enough :-) + +;;;###autoload (autoload 'emms-play-url "emms-source-file" nil t) +;;;###autoload (autoload 'emms-add-url "emms-source-file" nil t) +(define-emms-source url (url) + "An EMMS source for an URL - for example, for streaming." + (interactive "sPlay URL: ") + (emms-playlist-insert-track (emms-track 'url url))) + +;;;###autoload (autoload 'emms-play-streamlist "emms-source-file" nil t) +;;;###autoload (autoload 'emms-add-streamlist "emms-source-file" nil t) +(define-emms-source streamlist (streamlist) + "An EMMS source for streaming playlists (usually URLs ending in .pls)." + (interactive "sPlay streamlist URL: ") + (emms-playlist-insert-track (emms-track 'streamlist streamlist))) + + +(provide 'emms-source-file) +;;; emms-source-file.el ends here |