emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Michael Brand <michael.ch.brand@gmail.com>
To: Org Mode <emacs-orgmode@gnu.org>
Subject: org-player and switch to lexical binding in org.el
Date: Sun, 17 Jan 2016 19:58:38 +0100	[thread overview]
Message-ID: <CALn3zoh+ACSU09eRurfwKjmCnw7i-_0KX7tA2jWqtu=vvQepLQ@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 387 bytes --]

Hi all

release_8.3.3-426-g1f49e9f introduces a regression. The link

    [[file:/dir/audio.mp3::0:12:34]]

results in

    Debugger entered--Lisp error: (void-variable search)
      (org-player-play-file file search)
      [...]
      org-open-file("/dir/audio.mp3" nil nil "0:12:34")
      [...]

I hope it is reproducible after (require 'org-player), org-player.el
attached.

Michael

[-- Attachment #2: org-player.el --]
[-- Type: application/octet-stream, Size: 10372 bytes --]

;;; -*- coding: utf-8-unix -*-
;;; org-player.el - Play audio and video files in org-mode hyperlinks
;;;
;;; Author: Paul Sexton <eeeickythump@gmail.com>
;;; Version: 1.0.0
;;; Repository at http://bitbucket.org/eeeickythump/org-player/
;;;
;;;
;;; Synopsis
;;; ========
;;;
;;; I was learning a language, and wanted to include hyperlinks to audio files
;;; within my org document, and to be able to play each file by clicking on its
;;; link. I wrote the code in this file, which makes org mode use an Emacs
;;; media player library, Bongo, to play audio and video files contained in
;;; 'file:' hyperlinks.
;;;
;;; Installation
;;; ============
;;;
;;; First you will need to install Bongo, which you can download from:
;;; https://github.com/dbrock/bongo
;;;
;;; You will also need to ensure you have an actual media player program
;;; installed, and you need to tell Bongo which program to use to play files. I
;;; have tested org-player with MPlayer, an open source media player which
;;; works well on Windows and Linux. VLC does not work with Bongo on Windows at
;;; the time of writing.
;;;
;;; You can obtain MPlayer from:
;;; http://www.mplayerhq.hu/design7/news.html
;;;
;;; Ensure you have Bongo set up and working. Once this is achieved, installing
;;; org-player is easy - just put the file somewhere in your Emacs load-path
;;; and put (require 'org-player) in your .emacs file.
;;;
;;; Usage
;;; =====
;;;
;;; Clicking on a link such as
;;;
;;;   [[file:/path/to/song.mp3]]
;;;
;;; adds it to the active Bongo playlist and immediately starts playing
;;; it. Playback can be paused, fast-forwarded etc using Bongo commands (see
;;; below).
;;;
;;; Links can also specify track positions. When a link contains a track
;;; position, playback will start at that position in the track. For example:
;;;
;;; [[file:/path/to/song.mp3::2:43]]      Starts playback at 2 min 43 sec.
;;; [[file:/path/to/song.mp3::1:10:45]]   Starts playback at 1 hr 10 min 45 sec.
;;; [[file:/path/to/song.mp3::3m15s]]     Starts playback at 3 min 15 sec.
;;; [[file:/path/to/song.mp3::49s]]       Starts playback at 0 min 49 sec.
;;; [[file:/path/to/song.mp3::1h21m10s]]  Starts playback at 1 hr 21 min 10 sec.
;;;
;;; Controlling playback
;;; ====================
;;;
;;; When Bongo plays a file it puts some icons in the modeline that resemble the
;;; well-known symbols for 'play', 'stop', 'rewind' and so on, and which can be
;;; used to control playback using the mouse. I found these worked erratically when
;;; outside the actual Bongo playlist buffer, so I have instead bound some org-mode
;;; keys (ctrl + numpad keys) to the relevant functions.  These are:
;;;
;;; C-<keypad 0>     pause/resume
;;; C-<keypad .>     stop, or restart playback from beginning
;;; C-<keypad />     show track info
;;; C-<keypad 4>     skip back 10 seconds
;;; C-<keypad 6>     skip forward 10 seconds
;;; C-<keypad 9>     increase volume (requires separate 'volume' library
;;;                  at https://github.com/dbrock/volume-el )
;;; C-<keypad 3>     decrease volume
;;;
;;; Note that these keys (and the modeline icons, if they work) act on the
;;; track that is active in the Bongo playlist. This will always be the last
;;; track that you added by clicking on a link in org-mode, unless you alter
;;; the Bongo playlist outside org mode.
;;;
;;; Also note that these keys are only bound within org mode buffers.
;;;
;;; Notes
;;; =====
;;;
;;; I have only tested this with MP3 files, but it ought to work with
;;; video as well, as both MPlayer and Bongo claim to work with video files.
;;;
;;; Future plans
;;; ============
;;;
;;; If anyone wants to integrate this code with EMMS, another popular Emacs
;;; media player library, contributions would be welcome.


(require 'org)
(require 'bongo)

(defvar org-player-file-extensions-regexp
  (concat "\\." (regexp-opt
                 (append bongo-audio-file-name-extensions
                         bongo-video-file-name-extensions))))

(add-to-list 'org-file-apps
             (cons (concat org-player-file-extensions-regexp "$")
                   '(org-player-play-file file)))

(add-to-list 'org-file-apps
             (cons (concat org-player-file-extensions-regexp
                           "::[0-9]+:[0-9]+\\(:[0-9]+\\|\\)")
                   '(org-player-play-file file search)))

(add-to-list 'org-file-apps
             (cons (concat org-player-file-extensions-regexp
                           "::[0-9]+[HhMmSs]\\([0-9]+[MmSs]\\|\\)\\([0-9]+[MmSs]\\|\\)")
                   '(org-player-play-file file search)))


(defun org-player-string-to-time (str)
  "Understands any of the following formats: MM:SS, HH:MM:SS, NNhNNmNNs,
NNhNNm, NNmNNs, NNh, NNm, NNs."
  (let ((str (substring-no-properties str))
        hours mins secs)
    (cond
     ((string-match "\\([0-9]+\\):\\([0-9]+\\)\\(:[0-9.]+\\|\\)" str)
      (if (string= "" (match-string 3 str)) ; XX:YY
          (setq mins (match-string 1 str)
                secs (match-string 2 str))
        (setq hours (match-string 1 str) ; XX:YY:ZZ
              mins (match-string 2 str)
              secs (subseq (match-string 3 str) 1))))
     ((eq (string-match "[0-9]+[HhMmSs]" str)
          (string-match "\\([0-9]+[Hh]\\|\\)\\([0-9]+[Mm]\\|\\)\\([0-9.]+[Ss]\\|\\)"
                        str))
      (setq hours (match-string 1 str)
            mins (match-string 2 str)
            secs (match-string 3 str))
      (unless (string= "" hours)
        (setq hours (subseq hours 0 (1- (length hours)))))
      (unless (string= "" mins)
        (setq mins (subseq mins 0 (1- (length mins)))))
      (unless (string= "" secs)
        (setq secs (subseq secs 0 (1- (length secs))))))
     (t
      (error "Unrecognised track position specifier: %S" str)))
    (setq hours (if (or (null hours) (string= "" hours))
                    0 (read hours)))
    (setq mins (if (or (null mins) (string= "" mins))
                    0 (read mins)))
    (setq secs (if (or (null secs) (string= "" secs))
                    0 (read secs)))
    (list hours mins secs)))


(defun org-player-play-file (filename &optional pos)
  "POS, if given, is a string that specifies a track position where
playback should begin. This string is taken from the portion of the
hyperlink that follows a double colon. For example:

  [[file:song.mp3::03:22]]
  [[file:song.mp3::1h24m3s]]

See `org-player-string-to-time' for a description of the format of
the POS string."
  (let ((seek (if pos
                  (destructuring-bind (hours mins secs)
                      (org-player-string-to-time pos)
                    (+ secs
                       (* mins 60)
                       (* hours 60 60))))))
    (with-bongo-buffer
      (bongo-insert-file filename)
      (backward-char)
      (org-player-start/stop 'play seek)
      (when seek
        (bongo-seek-to seek)))))


(defun org-player-get-track-info ()
  "Returns a list: (TRACKTITLE ALBUMNAME ARTISTNAME ELAPSEDSECS LENGTHSECS)"
  (with-bongo-buffer
    (let* ((info (bongo-line-infoset))
           (track (cdr (assoc 'track info))))
      (message "%s" info)
      (list (cdr (assoc 'title track))
            (cdr (assoc 'album info))
            (cdr (assoc 'artist info))
            (or (bongo-elapsed-time) 0)
            (or (bongo-total-time) 0)))))


(defun org-player-print-track-info ()
  "Print out some info about the active track, in the minibuffer."
  (interactive)
  (destructuring-bind (title album artist elapsed total)
      (org-player-get-track-info)
    (message "%s" (list title album artist elapsed total))
    (cond
     ((null title)
      (message "No active track."))
     (t
      (message "Track: %s
Album: %s / %s
%s / %s (%d%%) %s"
               title album artist
               (format "%02d:%02d" (floor elapsed 60) (mod elapsed 60))
               (format "%02d:%02d" (floor total 60) (mod total 60))
               (/ (* elapsed 100) total)
               (cond
                ((bongo-paused-p) "(paused)")
                ((bongo-playing-p) "(playing)")
                (t "(stopped)"))
               )))))


(defun org-player-pause/resume ()
  (interactive)
  (destructuring-bind (title album artist elapsed total)
      (org-player-get-track-info)
    (when title
      (message "%02d:%02d/%02d:%02d %s %s (%s / %s)"
               (floor elapsed 60) (mod elapsed 60)
               (floor total 60) (mod total 60)
               (if (bongo-paused-p) "Unpaused:" "Paused:")
               title album artist)))
    (bongo-pause/resume))


(defun org-player-start/stop (&optional force starting-pos)
  (interactive)
  (destructuring-bind (title album artist elapsed total)
      (org-player-get-track-info)
    (when title
      (cond
       ((eq force 'play)
        (bongo-play))
       ((eq force 'stop)
        (bongo-stop))
       (t
        (bongo-start/stop)))
      (let ((msg (format "%02d:%02d/%02d:%02d %s %s (%s / %s)"
                         (floor (or starting-pos 0) 60)
                         (mod (or starting-pos 0) 60)
                         (floor total 60) (mod total 60)
                         (if (bongo-playing-p) "Playing:" "Stopped:")
                         title album artist)))
        (message msg)))))


;; Numpad Ctrl-0: pause/resume
(define-key org-mode-map (kbd "<C-kp-0>") 'org-player-pause/resume)
(define-key org-mode-map (kbd "<C-kp-insert>") 'org-player-pause/resume)
;; Numpad Ctrl-.: stop current track, or restart from beginning if stopped
(define-key org-mode-map (kbd "<C-kp-decimal>") 'org-player-start/stop)
(define-key org-mode-map (kbd "<C-kp-delete>") 'org-player-start/stop)
;; Numpad Ctrl-PgUp, Ctrl-PgDn: raise/lower volume
(define-key org-mode-map (kbd "<C-kp-prior>") 'volume-raise)
(define-key org-mode-map (kbd "<C-kp-next>") 'volume-lower)
(define-key org-mode-map (kbd "<C-kp-9>") 'volume-raise)
(define-key org-mode-map (kbd "<C-kp-3>") 'volume-lower)
;; Numpad Ctrl-left, Ctrl-right: skip back/forward 10 seconds
(define-key org-mode-map (kbd "<C-kp-left>") 'bongo-seek-backward-10)
(define-key org-mode-map (kbd "<C-kp-right>") 'bongo-seek-forward-10)
(define-key org-mode-map (kbd "<C-kp-4>") 'bongo-seek-backward-10)
(define-key org-mode-map (kbd "<C-kp-6>") 'bongo-seek-forward-10)
;; Ctrl-/: show track info
(define-key org-mode-map (kbd "<C-kp-divide>") 'org-player-print-track-info)


(provide 'org-player)

             reply	other threads:[~2016-01-17 18:58 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-17 18:58 Michael Brand [this message]
2016-01-17 20:40 ` org-player and switch to lexical binding in org.el Nicolas Goaziou
2016-01-17 21:02   ` Michael Brand
2016-01-17 21:05   ` Michael Brand
     [not found]     ` <CAK5Vzd2aV7WGGVr=+VF-LCCDCOZXJzUYEnCgbuzgGea4i5BR7Q@mail.gmail.com>
2016-02-07 11:49       ` Michael Brand
2016-01-28 11:37   ` Michael Brand
2016-01-29 13:32     ` Nicolas Goaziou
2016-01-29 20:39       ` Michael Brand
2016-01-30 23:30         ` Nicolas Goaziou
2016-02-01  7:57           ` Michael Brand
2016-02-03 17:33             ` Nicolas Goaziou
2016-02-03 20:41               ` Michael Brand
2016-02-03 20:56                 ` Nicolas Goaziou
2016-02-03 22:02                   ` Michael Brand
2016-02-04  8:36                     ` Nicolas Goaziou
2016-02-04 11:44                       ` Michael Brand
2016-02-04 12:46                         ` Nicolas Goaziou

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CALn3zoh+ACSU09eRurfwKjmCnw7i-_0KX7tA2jWqtu=vvQepLQ@mail.gmail.com' \
    --to=michael.ch.brand@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).