Org Mode: Insert YouTube video with separate captions
| emacsI'm playing around with some ideas for making it easier to post a video with its captions on a webpage or in an Org file so that it's easier to skim or search.
This requires the youtube-dl
command. I'm also learning how to use dash.el
‘s threading macro, so you'll need to install that as well if you want to run it.
(require 'dash) (defun my/msecs-to-timestamp (msecs) "Convert MSECS to string in the format HH:MM:SS.MS." (concat (format-seconds "%02h:%02m:%02s" (/ msecs 1000)) "." (format "%03d" (mod msecs 1000)))) (defun my/org-insert-youtube-video-with-transcript (url) (interactive "MURL: ") (let* ((id (if (string-match "v=\\([^&]+\\)" url) (match-string 1 url) url)) (temp-file (make-temp-name "org-youtube-")) (temp-file-name (concat temp-file ".en.srv1")) data) (when (and (call-process "youtube-dl" nil nil nil "--write-sub" "--write-auto-sub" "--no-warnings" "--sub-lang" "en" "--skip-download" "--sub-format" "srv1" "-o" temp-file (format "https://youtube.com/watch?v=%s" id)) (file-exists-p temp-file-name)) (insert (format "#+begin_export html <iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/%s\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n#+end_export\n" id) "\n" (mapconcat (lambda (o) (format "| [[https://youtube.com/watch?v=%s&t=%ss][%s]] | %s |\n" id (dom-attr o 'start) (my/msecs-to-timestamp (* 1000 (string-to-number (dom-attr o 'start)))) (->> (dom-text o) (replace-regexp-in-string "[ \n]+" " ") (replace-regexp-in-string "'" "'") (replace-regexp-in-string """ "\"")))) (dom-by-tag (xml-parse-file temp-file-name) 'text) "")) (delete-file temp-file-name))))
It makes an embedded Youtube video and a table with captions below it. The Org file doesn't look too bad, either.
I decided to stick to standard Org syntax so that I can read it in Emacs too. With the current implementation, clicking on the timestamps jumps to that position in the video, but on the Youtube website. I haven't coded anything fancy like keeping the embedded video at a fixed position, controlling it from the clicks, or highlighting the current position. It's a start, though!
Here's the output of running it with my talk from the last EmacsConf.
00:00:00.000 | I'm Sacha Chua, and welcome to EmacsConf 2020. |
00:00:04.000 | To kick things off, here are ten cool things |
00:00:07.000 | that people have been working on |
00:00:08.000 | since the conference last year. |
00:00:10.000 | If you want to follow the links |
00:00:11.000 | or if you'd like to add something I've missed, |
00:00:14.000 | add them to the collaborative pad |
00:00:16.000 | if you're watching this live |
00:00:17.000 | or check out the EmacsConf wiki page for this talk. |
… (omitted for brevity)
6 comments
Gahis
2021-04-04T08:25:56ZHi! Thanks for this. I just tried it but got no output. I am on a Org-mode buffer. I do M-x my/org-insert-youtube-video-with-transcript, paste the Youtube video URL, and nothing happens :(
sachac
2021-04-09T02:55:39ZDo you have youtube-dl installed? Does something like "youtube-dl --write-sub --write-auto-sub --sub-lang en --skip-download --sub-format srv1 -o temp YOURVIDEOURL" at the command-line download the subtitle file?
gahis
2021-04-10T11:18:34ZIt works now! Thanks! I must have done something wrong.
NoonianAtall
2021-04-04T12:51:36ZI use Dash a lot, but FYI, Emacs has the built-in macros `thread-first' (i.e. ->) and `thread-last' (i.e. ->>).
sachac
2021-04-09T02:52:09ZOh, that's good to know! Thanks!
Rudi C
2021-06-02T13:42:15ZIs it possible to make the inline links hidden just for the youtube subtree? I generally like to see links completely, but for this purpose they make it impossible to read the table.