2022-10-10 Adding timestamps to youtube links

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"))))

CategoryEnglish, CategoryBlog, CategoryEmacs