[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/mpv de7a9a6d01 07/12: Merge pull request #23 from efimersp
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/mpv de7a9a6d01 07/12: Merge pull request #23 from efimerspan/feature-listing-commands |
Date: |
Mon, 1 Aug 2022 09:58:52 -0400 (EDT) |
branch: elpa/mpv
commit de7a9a6d01129cb6d84f3d393898afb64ae8899c
Merge: 1d2629ba36 028d85efae
Author: Johann Klähn <johann@jklaehn.de>
Commit: GitHub <noreply@github.com>
Merge pull request #23 from efimerspan/feature-listing-commands
Adds listing interactive functions and other commands
---
mpv.el | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 251 insertions(+)
diff --git a/mpv.el b/mpv.el
index 26f022f0d9..ae6e8a20da 100644
--- a/mpv.el
+++ b/mpv.el
@@ -69,6 +69,21 @@
:type 'number
:group 'mpv)
+(defcustom mpv-entry-format "%s [%s]"
+ "The format of the entries for mpv listing operations."
+ :type 'string
+ :group 'mpv)
+
+(defcustom mpv-current-indicator " *"
+ "The indicator to use for the currently-playing entry."
+ :type 'string
+ :group 'mpv)
+
+(defcustom mpv-loop-indicator " R"
+ "The indicator to use for a looped entry."
+ :type 'string
+ :group 'mpv)
+
(defcustom mpv-on-event-hook nil
"Hook to run when an event message is received.
The hook will be called with the parsed JSON message as its only an
@@ -216,6 +231,213 @@ passes unsolicited event messages to `mpv-on-event-hook'."
;; Recurse to check for further JSON messages.
(mpv--tq-process-buffer tq))))
+(defmacro mpv--with-json (&rest body)
+ "Decode JSON result appropriately from BODY."
+ `(let* ((json-object-type 'alist)
+ (json-array-type 'list)
+ (json-key-type 'symbol)
+ (json-false 'false))
+ ,@body))
+
+(cl-defmacro mpv--with-entry ((var entry list) &body body)
+ "Binds VAR to the ENTRY index of LIST and evaluates BODY with it."
+ `(let ((,var (cl-position ,entry ,list :test #'equal)))
+ ,@body))
+
+(defun mpv-toggle-loop (&optional playlist)
+ "Cycles between 'inf' and 'no' values for the current file,
+or PLAYLIST if provided."
+ (interactive "P")
+ (let ((prop (if playlist
+ "loop-playlist"
+ "loop-file")))
+ (mpv-run-command "cycle-values" prop "inf" "no")
+ (message "Loop [%s]: %s"
+ (cadr (split-string prop "-"))
+ (mpv--with-json
+ (mpv-get-property prop)))))
+
+(defun mpv-toggle-video ()
+ "Cycles video playback state for the current mpv file."
+ (interactive)
+ (mpv-cycle-property "video"))
+
+(defun mpv-show-playlist ()
+ "Shows an interactive completion prompt drawn from the current playlist
entries."
+ (interactive)
+ (completing-read "Playlist entries: "
+ (lambda (string pred action)
+ (if (eq action 'metadata)
+ `(metadata
+ (category . mpv-file)
+ (display-sort-function . ,#'identity))
+ (complete-with-action action
(mpv--get-formatted-playlist) string pred)))))
+
+(defun mpv-show-chapters ()
+ "Presents an interactive completion list drawn from the available chapters
+in the current mpv playback."
+ (interactive)
+ (completing-read "Chapters: "
+ (lambda (string pred action)
+ (if (eq action 'metadata)
+ `(metadata
+ (category . mpv-chapter)
+ (display-sort-function . ,#'identity))
+ (complete-with-action action
(mpv--get-formatted-chapters) string pred)))))
+
+(defun mpv-jump-to-chapter (chapter)
+ "Selects CHAPTER to jump to from list of currently available chapters."
+ (interactive
+ (list (mpv-show-chapters)))
+ (mpv--with-entry
+ (entry chapter (mpv--get-formatted-chapters))
+ (mpv-set-property "chapter" entry)))
+
+(defun mpv-jump-to-file (file)
+ "Selects FILE to jump to from list of available playlist entries."
+ (interactive
+ (list (mpv-show-playlist)))
+ (mpv--with-entry
+ (entry file (mpv--get-formatted-playlist))
+ (mpv-run-command "playlist-play-index" entry)))
+
+(defun mpv-remove-file (file)
+ "Deletes current FILE from the mpv playlist."
+ (interactive
+ (list (mpv-show-playlist)))
+ (mpv--with-entry
+ (entry file (mpv--get-formatted-playlist))
+ (mpv-run-command "playlist-remove" entry)))
+
+(defun mpv-set-chapter-ab-loop (chapter)
+ "Toggles an A-B loop for the timestamps between where CHAPTER is bound."
+ (interactive
+ (list (mpv-show-chapters)))
+ (mpv--with-entry
+ (entry chapter (mpv--get-formatted-chapters))
+ (let* ((current-chapter (nth entry
+ (mpv--with-json
+ (mpv-get-property "chapter-list"))))
+ (current-timestamp (alist-get 'time current-chapter))
+ (title (mpv-get-property (format "chapter-list/%s/title" entry))))
+ (if (eql (mpv-get-property "ab-loop-a") current-timestamp)
+ (progn
+ (mpv-set-property "ab-loop-a" "no")
+ (mpv-set-property "ab-loop-b" "no")
+ (message "Removed A-B loop from chapter \"%s\"" title))
+ (progn
+ (mpv-set-property "ab-loop-a" current-timestamp)
+ (if (eql (mpv-get-property "chapters") (1+ entry))
+ (mpv-set-property "ab-loop-b" (mpv-get-property "duration"))
+ (thread-last
+ (1+ entry)
+ (format "chapter-list/%s/time")
+ (mpv-get-property)
+ (mpv-set-property "ab-loop-b")))
+ (message "Chapter \"%s\" set to A-B loop" title))))))
+
+(defun mpv-set-ab-loop ()
+ "Invokes an A-B loop command in the current mpv playback."
+ (interactive)
+ (mpv-run-command "ab-loop")
+ (cl-flet ((ab-loop-p
+ (point)
+ (or (numberp (mpv-get-property point))
+ (not (string= (mpv-get-property point) "no")))))
+ (cond
+ ((and (not (ab-loop-p "ab-loop-a"))
+ (not (ab-loop-p "ab-loop-b")))
+ (message "Removed A-B loop"))
+ ((and (ab-loop-p "ab-loop-a")
+ (ab-loop-p "ab-loop-b"))
+ (message "Set point B for A-B loop"))
+ ((ab-loop-p "ab-loop-a")
+ (message "Set point A for A-B loop")))))
+
+(defun mpv-chapter-next ()
+ "Jumps to the next chapter in the current playback."
+ (interactive)
+ (if (mpv--with-json
+ (mpv-get-property "chapter-list"))
+ (progn
+ (mpv-run-command "add" "chapter" "1")
+ (run-at-time 1 nil (lambda ()
+ (thread-last
+ (mpv-get-property "chapter")
+ (format "chapter-list/%d/title")
+ (mpv-get-property)
+ (message)))))
+ (error "No chapters available")))
+
+(defun mpv-chapter-prev ()
+ "Jumps to the previous chapter in the current playback."
+ (interactive)
+ (if (mpv--with-json
+ (mpv-get-property "chapter-list"))
+ (progn
+ (mpv-run-command "add" "chapter" "-1")
+ (run-at-time 1 nil (lambda ()
+ (thread-last
+ (mpv-get-property "chapter")
+ (format "chapter-list/%d/title")
+ (mpv-get-property)
+ (message)))))
+ (error "No chapters available")))
+
+(cl-defun mpv--format-entry (title &optional time &key (current nil) (loop-p
nil))
+ "Formats entry for minibuffer display with TITLE, optionally showing a TIME
value.
+Additionally, it sets an indicator for the CURRENT item and/or marks if the
item
+ is currently set to LOOP-P."
+ (concat
+ (if time
+ (format mpv-entry-format
+ title
+ (pcase time
+ ((and n (pred numberp) (guard (< 3600 n)))
+ (format-time-string "%T" n t))
+ ((and n (pred numberp))
+ (format-time-string "%M:%S" n))))
+ title)
+ (and current mpv-current-indicator)
+ (and loop-p mpv-loop-indicator)))
+
+(defun mpv--get-formatted-chapters ()
+ "Builds a formatted list of the available chapters in the current mpv
playback."
+ (if-let* ((chapters (mpv--with-json
+ (mpv-get-property "chapter-list")))
+ (formatted-chapters
+ (cl-loop with counter = 0
+ for chapter in chapters
+ collect (let ((time (alist-get 'time chapter))
+ (title (alist-get 'title chapter)))
+ (cond
+ ((and (= counter (mpv-get-property "chapter"))
+ (eql (mpv-get-property "ab-loop-a")
time))
+ (mpv--format-entry title time :current t
:loop-p t))
+ ((= counter (mpv-get-property "chapter"))
+ (mpv--format-entry title time :current t))
+ ((eql (mpv-get-property "ab-loop-a") time)
+ (mpv--format-entry title time :loop-p t))
+ (t
+ (mpv--format-entry title time))))
+ do (cl-incf counter))))
+ formatted-chapters
+ (error "No chapters available")))
+
+(defun mpv--get-formatted-playlist ()
+ "Builds a formatted list of the current playlist entries."
+ (if-let* ((entries (mpv--with-json
+ (mpv-get-property "playlist")))
+ (formatted-entries
+ (cl-loop for entry in entries
+ collect (let* ((title (or (alist-get 'title entry)
+ (alist-get 'filename entry))))
+ (if (alist-get 'current entry)
+ (mpv--format-entry title nil :current t)
+ (mpv--format-entry title nil))))))
+ formatted-entries
+ (error "No entries in playlist")))
+
;;;###autoload
(defun mpv-play (path)
"Start an mpv process playing the file at PATH.
@@ -226,6 +448,35 @@ See `mpv-start' if you need to pass further arguments and
(interactive "fFile: ")
(mpv-start (expand-file-name path)))
+;;;###autoload
+(defun mpv-enqueue (url &rest args)
+ "Enqueues URL to the current mpv playlist and optionally sets ARGS."
+ (interactive "sURL: ")
+ (if args
+ (mpv-run-command "loadfile" url "append"
+ (string-join
+ (mapcar (lambda (arg)
+ (substring arg 2))
+ args)
+ ","))
+ (mpv-run-command "loadfile" url "append"))
+ (thread-last
+ (mpv-get-property "playlist-count")
+ 1-
+ (format "playlist/%d/filename")
+ (mpv-get-property)
+ (message "Added \"%s\" to the current playlist")))
+
+;;;###autoload
+(defun mpv-quit (watch-later)
+ "Exits the current mpv process. If WATCH-LATER, exits it and stores the
current
+playback position."
+ (interactive
+ (list (yes-or-no-p "Save to watch later?")))
+ (if watch-later
+ (mpv-run-command "quit-watch-later")
+ (mpv-kill)))
+
;;;###autoload
(defun mpv-kill ()
"Kill the mpv process."
- [nongnu] elpa/mpv updated (1d2629ba36 -> 9fc833bf34), ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv 03ca4a6700 02/12: Fixes time formatting, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv 191081e577 03/12: Fixes mpv-quit condition, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv de7a9a6d01 07/12: Merge pull request #23 from efimerspan/feature-listing-commands,
ELPA Syncer <=
- [nongnu] elpa/mpv d9125d8d1d 09/12: Use index as parameters to playlist and chapter functions, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv e10e14ff2b 10/12: Cosmetic changes to docstrings, messages and function signatures, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv 31b630d192 11/12: Rename mpv-entry-format to mpv-entry-with-offset-format, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv a43b1813fc 05/12: Makes listing functions use built-in Emacs completion APIs, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv fb775e339b 08/12: Use format-spec for mpv-entry-format, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv 9fc833bf34 12/12: Rename mpv-enqueue to mpv-playlist-append and simplify, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv e5a6c76612 01/12: Adds listing interactive functions and other commands, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv 331aeb6e26 04/12: Adds completion categories, ELPA Syncer, 2022/08/01
- [nongnu] elpa/mpv 028d85efae 06/12: Notify of AB-loop status upon invocation, ELPA Syncer, 2022/08/01