Add new custom org link "music:ARTIST:TRACK::TIME"
This commit is contained in:
parent
0cc6f8a238
commit
6c24ceffb6
149
config.org
149
config.org
|
@ -3638,6 +3638,155 @@ Saving seconds adds up after all! (but only so much)
|
|||
"Complete xkcd using `+xkcd-stored-info'"
|
||||
(format "xkcd:%d" (+xkcd-select))))
|
||||
#+END_SRC
|
||||
***** Music
|
||||
First, we set up all the necessarily 'utility' functions.
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(after! org
|
||||
(defvar org-music-player 'mpris
|
||||
"Music player type. Curretly only supports mpris.")
|
||||
(defvar org-music-mpris-player "Lollypop"
|
||||
"Name of the mpris player, used in the form org.gnome.MPRIS.")
|
||||
(defvar org-music-track-search-method 'beets
|
||||
"Method to find the track file from the link.")
|
||||
(defvar org-music-beets-db "~/Music/library.db"
|
||||
"Location of the beets DB, when using beets as the `org-music-track-search-method'")
|
||||
|
||||
(defun org-music-get-link (full &optional include-time)
|
||||
"Generate link string for currently playing track, optionally including a time-stamp"
|
||||
(let* ((track-metadata
|
||||
(dbus-get-property :session "org.gnome.Lollypop" "/org/mpris/MediaPlayer2"
|
||||
"org.mpris.MediaPlayer2.Player" "Metadata"))
|
||||
(artist (caar (cadr (assoc "xesam:artist" track-metadata))))
|
||||
(album (car (cadr (assoc "xesam:album" track-metadata))))
|
||||
(track (car (cadr (assoc "xesam:title" track-metadata))))
|
||||
(seconds (when include-time
|
||||
(/ (dbus-get-property :session "org.gnome.Lollypop" "/org/mpris/MediaPlayer2"
|
||||
"org.mpris.MediaPlayer2.Player" "Position") 1000000))))
|
||||
(if full
|
||||
(format "[[music:%s][%s by %s]]" (org-music-format-link artist album track seconds) track artist)
|
||||
(org-music-format-link artist album track seconds))))
|
||||
|
||||
(defun org-music-format-link (artist album track &optional seconds)
|
||||
(let ((artist (replace-regexp-in-string ":" "\\:" artist))
|
||||
(album (replace-regexp-in-string ":" "\\:" album))
|
||||
(track (replace-regexp-in-string ":" "\\:" track)))
|
||||
(if seconds
|
||||
(format "%s:%s::%s" artist track (org-music-seconds-to-time seconds))
|
||||
(format "%s:%s" artist track))))
|
||||
|
||||
(defun org-music-parse-link (link)
|
||||
(let* ((link-dc (->> link
|
||||
(replace-regexp-in-string "\\([^\\\\]\\)\\\\:" "\\1#COLON#")
|
||||
(replace-regexp-in-string "\\`music:" "")
|
||||
(replace-regexp-in-string "\\(::[a-z0-9]*[0-9]\\)\\'" "\\1s")))
|
||||
(link-components (mapcar (lambda (lc) (replace-regexp-in-string "#COLON#" ":" lc))
|
||||
(s-split ":" link-dc)))
|
||||
(artist (nth 0 link-components))
|
||||
(track (nth 1 link-components))
|
||||
(seconds (when (and (> (length link-components) 3)
|
||||
(equal (nth 2 link-components) ""))
|
||||
(org-music-time-to-seconds (nth 3 link-components)))))
|
||||
(list artist track seconds)))
|
||||
|
||||
(defun org-music-seconds-to-time (seconds)
|
||||
"Convert a number of seconds to a nice human duration, e.g. 5m21s.
|
||||
This action is reversed by `org-music-time-to-seconds'."
|
||||
(if (< seconds 60)
|
||||
(format "%ss" seconds)
|
||||
(if (< seconds 3600)
|
||||
(format "%sm%ss" (/ seconds 60) (% seconds 60))
|
||||
(format "%sh%sm%ss" (/ seconds 3600) (/ (% seconds 3600) 60) (% seconds 60)))))
|
||||
|
||||
(defun org-music-time-to-seconds (time-str)
|
||||
"Get the number of seconds in a string produced by `org-music-seconds-to-time'."
|
||||
(let* ((time-components (reverse (s-split "[a-z]" time-str)))
|
||||
(seconds (string-to-number (nth 1 time-components)))
|
||||
(minutes (when (> (length time-components) 2)
|
||||
(string-to-number (nth 2 time-components))))
|
||||
(hours (when (> (length time-components) 3)
|
||||
(string-to-number (nth 3 time-components)))))
|
||||
(+ (* 3600 (or hours 0)) (* 60 (or minutes 0)) seconds)))
|
||||
|
||||
(defun org-music-play-track (artist title &optional seconds)
|
||||
"Play the track specified by ARTIST and TITLE, optionally skipping to SECONDS in."
|
||||
(case org-music-player
|
||||
('mpris (org-music-mpris-play
|
||||
(org-music-find-track-file artist title)
|
||||
seconds))
|
||||
(t (user-error! "The specified music player: %s is not supported" org-music-player))))
|
||||
|
||||
(defun org-music-mpris-play (file &optional seconds)
|
||||
(let ((player (concat "org.gnome." org-music-mpris-player)))
|
||||
(dbus-call-method :session player
|
||||
"/org/mpris/MediaPlayer2" "org.mpris.MediaPlayer2.Player"
|
||||
"OpenUri" (replace-regexp-in-string " " "%20" (rng-file-name-uri file)))
|
||||
(when seconds
|
||||
(let ((track-id (caadr (assoc "mpris:trackid"
|
||||
(dbus-get-property :session
|
||||
player
|
||||
"/org/mpris/MediaPlayer2"
|
||||
"org.mpris.MediaPlayer2.Player"
|
||||
"Metadata")))))
|
||||
(dbus-call-method :session player
|
||||
"/org/mpris/MediaPlayer2" "org.mpris.MediaPlayer2.Player"
|
||||
"SetPosition"
|
||||
:object-path track-id
|
||||
:int64 (round (* seconds 1000000)))))))
|
||||
|
||||
(defun org-music-find-track-file (artist title)
|
||||
(case org-music-track-search-method
|
||||
('beets (org-music-beets-find-file artist title))
|
||||
(t (user-error! "The specified music search method: %s is not supported" org-music-track-search-method))))
|
||||
|
||||
(defun org-music-beets-find-file (artist title)
|
||||
"Find the file correspanding to a given artist and title."
|
||||
(let* ((artist-escaped (replace-regexp-in-string "\"" "\\\"" artist))
|
||||
(title-escaped (replace-regexp-in-string "\"" "\\\"" title))
|
||||
(file
|
||||
(shell-command-to-string
|
||||
(format
|
||||
"sqlite3 '%s' \"SELECT path FROM items WHERE artist IS '%s' AND title IS '%s' COLLATE NOCASE\""
|
||||
(expand-file-name org-music-beets-db) artist-escaped title-escaped))))
|
||||
(if (> (length file) 0)
|
||||
(substring file 0 -1)
|
||||
(user-error! "Could not find '%s' by '%s' in your beets database" title artist)))))
|
||||
#+END_SRC
|
||||
|
||||
Then we integrate this nicely with org-mode
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(after! org
|
||||
(org-link-set-parameters "music"
|
||||
:follow #'org-music-open-fn
|
||||
:export #'org-music-export)
|
||||
|
||||
(defun org-music-open-fn (link)
|
||||
(apply #'org-music-play-track (org-music-parse-link link)))
|
||||
|
||||
(defun org-music-insert-current-track (&optional include-time)
|
||||
"Insert link to currest track, including a timestamp when the universal argument is supplied."
|
||||
(interactive "P")
|
||||
(pp include-time)
|
||||
(insert (org-music-get-link t include-time)))
|
||||
|
||||
(defun org-music-export (path desc backend _com)
|
||||
"Convert xkcd to html/LaTeX form"
|
||||
(let* ((track-info (org-music-parse-link path))
|
||||
(artist (nth 0 track-info))
|
||||
(track (nth 1 track-info))
|
||||
(seconds (nth 2 track-info))
|
||||
(description ))
|
||||
(cond ((org-export-derived-backend-p backend 'html)
|
||||
(if seconds
|
||||
(format "%s seconds into <span style=\"font-style: italic\">%s</span> by %s" seconds track artist)
|
||||
(format "%s by %s" track artist)))
|
||||
((org-export-derived-backend-p backend 'latex)
|
||||
(if seconds
|
||||
(format "%s seconds into \\emph{%s} by %s" seconds track artist)
|
||||
(format "\\emph{%s} by %s" track artist)))
|
||||
(t (if seconds
|
||||
(format "%s seconds into %s by %s" seconds track artist)
|
||||
(format "%s by %s" track artist)))))))
|
||||
#+END_SRC
|
||||
***** YouTube
|
||||
The ~[[yt:...]]~ links preview nicely, but don't export nicely. Thankfully, we can
|
||||
fix that.
|
||||
|
|
Loading…
Reference in a new issue