Category Archives: emacs

Reading these posts, you can probably tell that I really, really like the Emacs text editor.

View my Emacs configuration.

Check out Planet Emacsen to read other Emacs geeks’ blogs. For all things Emacs, check out r/emacs or the EmacsWiki. If you come across an interesting thing you’d like me to include in Emacs News, post it in r/emacs and I’ll probably pick it up the following week.

New to Emacs? Start here:
One-page guide to learning Emacs
One-page guide to learning Emacs keyboard shortcuts

Grabbing the Youtube auto-generated captions is pretty useful when making Emacs News

I’ve been adding Emacs-related videos to my public Emacs News playlist to make it easier to include them when I put together Emacs News every week. I still haven’t had much time to watch things, though. But the code I wrote to convert captions into a table so that they could be used to make notes after a meetup presentation turned out to be handy for Emacs News as well.

Screenshot_20210408_221732.png

Figure 1: With a bit of clicking, Youtube can display translated subtitles and a transcript on the side. I haven’t figured out how to get the transcript translated on Youtube yet.

Screenshot_20210408_221732.png

Figure 2: My Org buffer displays the auto-translated captions, making things easy to skim through.

Then I can jump to sections I’m particularly curious about. Neat!

2021-04-05 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

Org Mode: Insert YouTube video with separate captions

I’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 "&#39;" "'")
                                 (replace-regexp-in-string "&quot;" "\""))))
                  (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.

Screenshot_20210401_234956.png

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)

This is part of my Emacs configuration.

2021-03-29 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

Org2blog: Add a note to the bottom of blog posts exported from my config file

I occasionally post snippets from my Emacs configuration file, drafting the notes directly in my literate config and posting them via org2blog. I figured it might be a good idea to include a link to my config at the end of the posts, but I didn’t want to scatter redundant links in my config file itself. Wouldn’t it be cool if the link could be automatically added whenever I use org2blog to post a subtree from my config file? I think the code below accomplishes that.

(defun my/org-export-filter-body-add-emacs-configuration-link (string backend info)
  (concat string
          (let ((id (org-entry-get-with-inheritance "CUSTOM_ID")))
            (format
             "\n<div class=\"note\">This is part of my <a href=\"https://sachachua.com/dotemacs%s\">Emacs configuration.</a></div>"
             (if id (concat "#" id) "")))))

(use-package org2blog
  :config
  (advice-add 'org2blog-entry-save
              :around
              (lambda (orig-fun &rest args)
                (if (string-match "\\.emacs\\.d/Sacha\\.org" (buffer-file-name))
                    (let ((org-export-filter-body-functions (cons 'my/org-export-filter-body-add-emacs-configuration-link org-export-filter-body-functions)))
                      (apply orig-fun args))
                  (apply orig-fun args)))))
This is part of my Emacs configuration.

2021-03-22 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.