I sometimes keep YouTube links in my Org mode files. They are often links to lectures which I don’t usually watch in one sitting. One trouble I always have is remembering the point where I stopped watching last time and starting there.
Obviously, I decided to write some Elisp to ease that task a bit. Given the time, I want to add a query parameter to the URL (or replace one that’s already there).
This task is fairly easy, though there are a few cases to consider. First of all, the suitable parameter may already be there or not. Then, YouTube links come in two forms (maybe more, I don’t really know) – a shorter one and a longer one. Finally, it would be nice to be able to supply the time either as a number of seconds (possibly with an s
suffix) or as a m:ss
-type string.
Another potentially difficult thing is making sure that the point is on an URL (and finding the places where the link starts and ends). This, however, is a solved problem thanks to the thingatpt
package.
So, let’s bind all this together. The following function asks the user for the time (it also accepts a prefix argument – as the number of seconds) and sets the time parameter in the link.
(require 'thingatpt) (defun yt-set-time (time) "Set TIME in the YouTube link at point. TIME is number of seconds if called from Lisp, and a string if called interactively. Supported formats: - seconds - minutes:seconds - number of seconds with the \"s\" suffix." (interactive (list (if current-prefix-arg (prefix-numeric-value current-prefix-arg) (read-string "Time: ")))) (let ((url (thing-at-point-url-at-point))) (if (and url (string-match (format "^%s" (regexp-opt '("https://www.youtube.com/" "https://youtu.be/") "\\(?:")) url)) (let* ((bounds (thing-at-point-bounds-of-url-at-point)) (time-present-p (string-match "t=[0-9]+" url)) (question-mark-present-p (string-search "?" url)) (seconds (cond ((numberp time) time) ((string-match "^\\([0-9]+\\):\\([0-9]\\{2\\}\\)$" time) (+ (* 60 (string-to-number (match-string 1 time))) (string-to-number (match-string 2 time)))) ((string-match "^\\([0-9]+\\)s?$" time) (string-to-number (match-string 1 time))) (t (error "Wrong argument format")))) (new-url (if time-present-p (replace-regexp-in-string "t=[0-9]+" (format "t=%i" seconds) url) (concat url (if question-mark-present-p "&" "?") (format "t=%i" seconds))))) (delete-region (car bounds) (cdr bounds)) (insert new-url)) (error "Not on a Youtube link"))))