Emacs Lisp
Table of Contents
- 1. Switch to vterm buffer
- 2. Select new
lsswitches for current Dired buffer - 3. Read YouTube video top comments in a buffer using
yt-dlp - 4. Decode encoded paths
- 5. QR code of clipboard content
- 6. Return the channel name associated with
CHANNEL-ID - 7. Compare Elfeed and FreshRSS feeds
- 8. Parse FreshRSS XML file to show filters
- 9. List active file watchers
- 10. Search and go to the nearest link or image in
elfeed-show-mode
1. Switch to vterm buffer
(defun alan-vterm () "Switch to an existing vterm session or create one based on the current buffer directory." (interactive) (if (file-remote-p default-directory) (let ((remote-host (file-remote-p default-directory))) (string-match "/ssh:\\([^:]+\\):" remote-host) (setq remote-host (match-string 1 remote-host)) (setq remote-host-buffer (concat "*" remote-host "*")) (if (get-buffer remote-host-buffer) (pop-to-buffer-same-window remote-host-buffer) ;; Set current buffer directory to localhost path to ;; prevent TRAMP connecting with `term' (let ((default-directory (getenv "HOME"))) (vterm remote-host-buffer) (with-current-buffer remote-host-buffer (evil-local-mode -1) (setq-local show-trailing-whitespace nil) (vterm-send-string (concat "ssh " remote-host)) (vterm-send-return))))) (let ((host-buffer (concat "*" system-name "*"))) (if (get-buffer host-buffer) (pop-to-buffer-same-window host-buffer) (let ((default-directory (getenv "HOME"))) (vterm host-buffer) (with-current-buffer host-buffer (evil-local-mode -1) (setq-local show-trailing-whitespace nil)))))))
2. Select new ls switches for current Dired buffer
(defun alan-dired-sort () "Select new `ls' switches for current Dired buffer." (interactive) (let* ((switches '(("Access" . "-lhAtu") ("Modification" . "-lhAtc") ("Creation" . "-lhAt --time=creation") ("Extension" . "-lhAtX") ("Name (default)" . "-lhav --group-directories-first") ("Size" . "-lhAS"))) (selected-switches (completing-read "Sort by: " (mapcar #'car switches)))) (dired-sort-other (cdr (assoc selected-switches switches)))))
3. Read YouTube video top comments in a buffer using yt-dlp
# ~/.config/yt-dlp/comments.conf - yt-dlp(1) --skip-download --write-comments --print-to-file "after_filter:%(comments)j" "/tmp/comments.json" --no-write-info-json --parse-metadata "video::(?P<comments>)" --extractor-args "youtube:comment_sort=top,max_comments=5,5,2,2"
(defun alan-read-video-comments (video-id) (interactive (list (read-from-minibuffer "VideoID: "))) (require 'json) (message "Fetching comments... [ID:%s]" video-id) (let* ((comments "/tmp/comments.json") (cmd `(,(executable-find "yt-dlp") "--config-locations" ,(expand-file-name "~/.config/yt-dlp/comments.conf") ,(format "https://www.youtube-nocookie.com/embed/%s" video-id))) (exit-status (apply #'call-process (car cmd) nil nil nil (cdr cmd)))) (if (zerop exit-status) (let ((buf (get-buffer-create (format "*Video comments from [ID:%s], %s*" video-id (format-time-string "%c")))) (data (json-read-file comments))) (with-current-buffer buf (mapcar (lambda (comment) (let* ((parent (alist-get 'parent comment)) (text (alist-get 'text comment)) (like (alist-get 'like_count comment)) (author (alist-get 'author comment)) (type (if (string= parent "root") "comment" "reply"))) (insert (format " ---- %s from %s (%s likes) ----\n%s\n\n" type author like text)))) data)) (pop-to-buffer-same-window buf) (goto-char (point-min)))) (when (file-exists-p comments) (delete-file comments))))
4. Decode encoded paths
(url-unhex-string (url-filename (url-generic-parse-url ENCODED-PATH)))
5. QR code of clipboard content
(defun alan-yank-to-qrcode () (interactive) (let ((buf (get-buffer-create "*qrcode*")) (recent-kill (with-temp-buffer (yank) (buffer-string)))) (with-current-buffer buf (call-process "/usr/bin/python3-qr" nil buf nil "--ascii" recent-kill) (while (search-backward " " nil t) (replace-match " " nil t)) (pop-to-buffer-same-window buf))))
6. Return the channel name associated with CHANNEL-ID
(defun alan-elfeed-return-channel-name (channel-id) "Return the channel name associated with CHANNEL-ID." (let ((channel-name nil)) (with-temp-buffer (insert-file-contents-literally (locate-user-emacs-file "lisp/alan-feeds.el")) (goto-char (point-min)) (while (re-search-forward (format "channel_id=%s.+$" channel-id) nil t) (let ((line (match-string 0))) (when (string-match ".+?;\s\\(.+\\)$" line) (setq channel-name (match-string 1 line)))))) (when channel-name channel-name)))
7. Compare Elfeed and FreshRSS feeds
(defun alan-elfeed-freshrss-compare-feeds () "Compare feeds with FreshRSS." (interactive) (if-let* ((freshrss-xml-file (directory-files "~/downloads/" t "^feeds_.+?\\.xml$"))) (let ((freshrss-feeds-list (xml-query-all '(body outline outline [type "rss"] :xmlUrl) (car (xml-parse-file (car freshrss-xml-file))))) (elfeed-feeds-list (elfeed-feed-list))) (dolist (f freshrss-feeds-list) (unless (member f elfeed-feeds-list) (if (string-match-p "channel_id=" f) (let* ((channel-id (cadr (string-split f "="))) (channel-name (alan-elfeed-return-channel-name channel-id))) (message "FRESHRSS ONLY: %s -- %s" f channel-name)) (message "FRESHRSS ONLY: %s" f)))) (dolist (e elfeed-feeds-list) (unless (member e freshrss-feeds-list) (if (string-match-p "channel_id=" e) (let* ((channel-id (cadr (string-split e "="))) (channel-name (alan-elfeed-return-channel-name channel-id))) (message "ELFEED ONLY: %s -- %s" e channel-name)) (message "ELFEED ONLY: %s" e)))) (pop-to-buffer-same-window "*Messages*")) (user-error "FreshRSS feeds XML file not found")))
8. Parse FreshRSS XML file to show filters
(defun alan-elfeed-freshrss-show-filters () "Parse FreshRSS XML file to show filters." (interactive) (if-let* ((xml-file (car (directory-files "~/downloads/" t "^feeds_.+?\\.xml$")))) (let* ((feeds (xml-query-all '(body outline outline [type "rss"]) (car (xml-parse-file xml-file)))) (filters (mapcar (lambda (feed) (let ((a (cadr feed))) (list (assoc-default 'text a) (assoc-default 'frss:filtersActionRead a)))) feeds))) (pop-to-buffer-same-window (format "*FreshRSS filters: %s*" (format-time-string "%c"))) (dolist (f filters) (unless (null (cadr f)) (insert (format "\n%s\n%s\n%s\n" (car f) (make-string (length (car f)) ?-) (cadr f))))) (local-set-key "q" #'kill-buffer) (read-only-mode 1)) (user-error "FreshRSS XML file not found")))
9. List active file watchers
(maphash (lambda (_key value) (message "%s" value)) file-notify-descriptors)
10. Search and go to the nearest link or image in elfeed-show-mode
;; [2025-07-06 dim.] (use-package shr :bind (:map shr-map ("<backtab>" . alan-shr-previous-link) ("TAB" . alan-shr-next-link)) :config (defun alan-shr-search-link (&optional forward) "Search and go to the nearest link or image in `elfeed-show-mode'." (let* ((search-function (if forward #'text-property-search-forward #'text-property-search-backward)) (url-match (save-excursion (funcall search-function 'shr-url nil nil t))) (url-position (when url-match (prop-match-beginning url-match))) (img-match (save-excursion (funcall search-function 'image-url nil nil t))) (img-position (when img-match (prop-match-beginning img-match))) (target-position nil) (target-property nil)) (cond ((and url-position img-position) (let ((img-is-closer (if forward (> url-position img-position) (< url-position img-position)))) (setq target-position (if img-is-closer img-position url-position)) (setq target-property (if img-is-closer 'image-url 'shr-url)))) (url-position (setq target-position url-position) (setq target-property 'help-echo)) (img-position (setq target-position img-position) (setq target-property 'image-url))) (if target-position (progn (goto-char target-position) (message "%s" (get-text-property (point) target-property))) (message (format "No %s link" (if forward "next" "previous")))))) (defun alan-shr-next-link () "Skip to the next link or image." (interactive) (alan-shr-search-link t)) (defun alan-shr-previous-link () "Skip to the previous link or image." (interactive) (alan-shr-search-link nil)))