diff --git a/README.org b/README.org
index 56525ac..92adc7f 100644
--- a/README.org
+++ b/README.org
@@ -2931,205 +2931,54 @@ See `org-link-parameters' for details about PATH, DESC and FORMAT."
:END:
Listing [[lst:define-org-yt-link-type][define org-yt-link type]] implements code to open the link to the
-following YouTube video [[yt:eaZUZCzaIgw#6s#10s][Extending org-mode to handle YouTube links.]]
+following YouTube video [[yt:eaZUZCzaIgw][Extending org-mode to handle YouTube links]] and the
+following [[https://raw.githubusercontent.com/bitspook/spookmax.d/master/readme.org][Emacs setup]].
+
+Opening [[yt:eaZUZCzaIgw][Extending org-mode to handle YouTube links]] may fail due to a bug in the
+interface between =mpv= and =yt-dlp=. Listing [[lst:set-emms-options][set EMMS options]] indicates how to
+work around this bug at the cost of making the user interface less clean.
+However, the link [[yt:48JlgiBpw_I][Absolute Beginner's Guide to Emacs]] works always.
The following posts provide programming information:
1. [[https://developers.google.com/youtube/v3/docs][YouTube API reference]].
2. [[https://developers.google.com/youtube/iframe_api_reference][YouTube Player API reference for iframe embeds]].
-3. [[https://www.alphr.com/how-to-link-specific-timestamp-youtube/][How to link to a specific timestamp in a YouTube video]].
-
-#+begin_src emacs-lisp -n :exports none :tangle no
-;; https://www.youtube.com/embed/M03bTkQxVUg?start=30&end=120
-
-(org-yt-seconds-to-hms (+ (* 3600 120) (* 60 9) 7))
-(org-yt-seconds-to-hms 3661)
-
-(org-yt-time-to-seconds "")
-(org-yt-time-to-seconds "1")
-(org-yt-time-to-seconds "1:1")
-(org-yt-time-to-seconds "1:1:1")
-(org-yt-time-to-seconds "1h1m1s")
-(org-yt-time-to-seconds "1mX")
-(org-yt-time-to-seconds "1h")
-(org-yt-time-to-seconds "1H1m")
-(org-yt-time-to-seconds "1h1s")
-(org-yt-time-to-seconds "1m1s")
-(org-yt-time-to-seconds "1h1s")
-(org-yt-time-to-seconds "1h1M1s")
-
-(org-yt-format-open-url "WKwZHSbHmPg" "")
-(org-yt-format-open-url "WKwZHSbHmPg" nil)
-(org-yt-format-open-url "WKwZHSbHmPg" '("1m1s"))
-(org-yt-format-open-url "WKwZHSbHmPg" '("0:2:44" "0:2:50"))
-
-(org-yt-open "WKwZHSbHmPg#0:2:44#0:2:50" t)
-
-(org-yt-export "WKwZHSbHmPg#0:2:44#0:2:50" "Title" 'html nil)
-(org-yt-export "WKwZHSbHmPg#0h2m40s#0h2m50s" "Title" 'html nil)
-(org-yt-export "WKwZHSbHmPg#2M40S#2M50S" "Title" 'html nil)
-
-(org-yt-export "WKwZHSbHmPg#0:2:44#0:2:50" "Title" 'latex nil)
-(org-yt-export "WKwZHSbHmPg#0h2m40s#0h2m50s" "Title" 'latex nil)
-(org-yt-export "WKwZHSbHmPg#2M40S#2M50S" "Title" 'latex nil)
-#+end_src
-
-#+caption[Parsing function for the =org-yt= link type]:
-#+caption: Parsing function for the =org-yt= link type.
-#+name: lst:org-yt-parsing
-#+begin_src emacs-lisp -n :results silent
-(defun org-yt-time-to-seconds (text)
- "Convert TEXT of the form `12:34:56' or `12h34m56s' to seconds as integers."
- (let* ((case-fold-search t)
- (hms (< (length (split-string text "[:]"))
- (length (split-string text "[HhMmSs]"))))
- (regexp (if hms
- (rx (opt (group (+ digit) "h"))
- (opt (group (+ digit) "m"))
- (opt (group (+ digit) "s")))
- (rx (opt (group (+ digit)))
- (opt ":" (group (+ digit)))
- (opt ":" (group (+ digit))))))
- (_ (string-match regexp text))
- (md (match-data))
- (found (substring text (pop md) (pop md)))
- (seconds 0)
- lot)
- (if (string< found text)
- (user-error "Found `%s' which is a prefix of `%s'" found text)
- (if hms
- (while md
- (setq lot (substring text (or (pop md) 0) (or (pop md) 0)))
- (cond
- ((or (string-suffix-p "h" lot) (string-suffix-p "H" lot))
- (setq seconds (+ seconds (* 3600 (string-to-number lot)))))
- ((or (string-suffix-p "m" lot) (string-suffix-p "M" lot))
- (setq seconds (+ seconds (* 60 (string-to-number lot)))))
- ((or (string-suffix-p "s" lot) (string-suffix-p "S" lot))
- (setq seconds (+ seconds (string-to-number lot))))))
- (while md (push (string-to-number
- (substring text (or (pop md) 0) (or (pop md) 0)))
- lot))
- (cond
- ((length= lot 1) (setq seconds (car lot)))
- ((length= lot 2) (setq seconds (+ (* 60 (cadr lot))
- (car lot))))
- ((length= lot 3) (setq seconds (+ (* 3600 (caddr lot))
- (* 60 (cadr lot))
- (car lot)))))))
- seconds))
-#+end_src
-
-#+caption[Formatting functions to open =org-yt= links]:
-#+caption: Formatting functions to open =org-yt= links.
-#+name: lst:org-yt-open-formatting
-#+begin_src emacs-lisp -n :results silent
-(defun org-yt-seconds-to-hms (seconds)
- "Convert seconds as integers to text of the form `12h34m56s'."
- (let ((h (/ seconds 3600))
- (m (/ (% seconds 3600) 60))
- (s (% seconds 60)))
- (concat (and (> h 0) (format "%dh" h))
- (if (> h 0)
- (format "%02dm" m)
- (and (> m 0) (format "%dm" m)))
- (if (or (> h 0) (> m 0))
- (format "%02ds" s)
- (format "%ds" s)))))
-
-(defconst org-yt-start
- "https://www.youtube.com/watch?v=%s&t=%s"
- "Format string for `org-yt-format-open-url' to fill in ID and TIMING.")
-
-(defconst org-yt-chunk
- "https://www.youtube.com/embed/%s?autoplay=1&start=%d&end=%d"
- "Format string for `org-yt-format-open-url' to fill in ID and TIMING.")
-
-(defun org-yt-format-open-url (id timing)
- "Convert an \"yt\" type link to an URL for opening."
- (cond
- ((not timing)
- (format org-yt-start id "0s"))
- ((length= timing 1)
- (format org-yt-start id
- (org-yt-seconds-to-hms (org-yt-time-to-seconds (car timing)))))
- ((length= timing 2)
- (format org-yt-chunk id
- (org-yt-time-to-seconds (car timing))
- (org-yt-time-to-seconds (cadr timing))))))
-#+end_src
-
-#+caption[Formatting function for HTML export of =org-yt= links]:
-#+caption: Formatting function for HTML export of =org-yt= links.
-#+name: lst:org-yt-html-export-formatting
-#+begin_src emacs-lisp -n :results silent
-(defconst org-yt-iframe
- ""
- "Format string for `org-yt-iframe' to fill in ID, TIMING, and TITLE.")
-
-(defun org-yt-format-iframe (id timing title)
- "Convert an \"yt\" type link to an inline frame element for export to HTML."
- (format org-yt-iframe id
- (cond
- ((not timing) "")
- ((length= timing 1)
- (format "?start=%d" id (org-yt-time-to-seconds (car timing))))
- ((length= timing 2)
- (format "?start=%d&end=%d"
- (org-yt-time-to-seconds (car timing))
- (org-yt-time-to-seconds (cadr timing)))))
- title))
-#+end_src
#+caption[Define an =org-link= type for =YouTube=]:
#+caption: Define an =org-link= type for =YouTube=.
#+name: lst:define-org-yt-link-type
#+begin_src emacs-lisp -n :results silent
-(defun org-yt-open (path prefix)
- "Open an \"yt\" type link with `browse-url', `emms', or \"mpv\".
-PATH is a string containing the video ID and optional timing information.
-Open the link with `browse-url' if PREFIX else with `emms' or \"mpv\"."
- (let* ((parts (split-string path "[#]+" t))
- (id (car parts))
- (timing (cdr parts))
- (url (org-yt-format-open-url id timing)))
- (cond
- (prefix
- (browse-url url))
- ((require 'emms nil 'noerror)
- (emms-add-url url)
- (with-current-emms-playlist
- (save-excursion
- (emms-playlist-last)
- (emms-playlist-mode-play-current-track))))
- ((executable-find "mpv")
- (let ((display-buffer-alist
- `((,shell-command-buffer-name-async . (display-buffer-no-window)))))
- (async-shell-command (format "\"%s\" \"%s\"" url)))
- (message "Launched mpv with \"%s\"" url))
- (t
- (user-error "Can't open `%s': install `emms' and/or `mpv'" url)))))
+;; https://bitspook.in/blog/extending-org-mode-to-handle-youtube-paths/
+(defun org-yt-emms-open (path)
+ "Open an \"YouTube\" link with `emms' using \"mpv\"."
+ (let ((url (format "https://www.youtube.com/watch?v=%s" path)))
+ (require 'emms nil 'noerror)
+ (emms-add-url url)
+ (with-current-emms-playlist
+ (save-excursion
+ (emms-playlist-last)
+ (emms-playlist-mode-play-current-track)))))
+
+(defun org-yt-url-browse-open (path)
+ "Open an \"YouTube\" link with `url-browse'."
+ (let ((url (format "https://www.youtube.com/watch?v=%s" path)))
+ (browse-url url)))
(defun org-yt-export (path desc backend _)
- "Export an \"yt\" type link."
- (let* ((parts (split-string path "[#]+" t))
- (id (car parts))
- (timing (cdr parts)))
- (pcase backend
+ "Export an \"YouTube\" link."
+ (pcase backend
(`html
- (org-yt-format-iframe id timing desc))
+ (format "" path desc))
(`latex
- (format "\\href{%s}{%s}" (org-yt-format-open-url id timing) desc))
- (_ id))))
+ (format "\\href{https://www.youtube.com/watch?v=%s}{%s}" path desc))
+ (_ path)))
(with-eval-after-load 'ol
- ;; https://bitspook.in/blog/extending-org-mode-to-handle-youtube-paths/
- (org-link-set-parameters "yt"
- :follow #'org-yt-open
- :export #'org-yt-export))
+ (org-link-set-parameters
+ "yt" :follow #'org-yt-emms-open :export #'org-yt-export))
#+end_src
*** [[https://tecosaur.github.io/emacs-config/#translate-capital-keywords][Translate capital keywords (old) to lower case (new)]]