From 44cf90eb363e4c8b2649800272d31321e1c20938 Mon Sep 17 00:00:00 2001 From: SqrtMinusOne Date: Thu, 15 Sep 2022 12:43:32 +0300 Subject: [PATCH] feat(emacs): rdrview & some vosk stuff --- .config/guix/manifests/emacs.scm | 1 + .emacs.d/init.el | 50 ++++++++++++++++++++++----- Emacs.org | 58 +++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/.config/guix/manifests/emacs.scm b/.config/guix/manifests/emacs.scm index 2104d90..f3f0b14 100644 --- a/.config/guix/manifests/emacs.scm +++ b/.config/guix/manifests/emacs.scm @@ -7,6 +7,7 @@ "imagemagick" "yt-dlp" "mpv" + "rdrview" "graphviz" "emacs-emacsql-sqlite3" "python-isort" diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 1a0acb8..5f6f957 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -1567,6 +1567,7 @@ Returns ( . ) or nil." :straight (:host github :repo "SqrtMinusOne/copilot.el" :files ("dist" "*.el")) :commands (copilot-mode) :if (not my/remote-server) + :disabled :init (add-hook 'prog-mode-hook #'copilot-mode) :config @@ -2832,7 +2833,8 @@ Returns ( . ) or nil." (setq-local org-format-latex-options (plist-put org-format-latex-options :scale (* org-present-text-scale my/org-latex-scale 0.5))) - (org-latex-preview '(16)) + ;; (org-latex-preview '(16)) + ;; TODO ^somehow this stucks at running LaTeX^ (setq-local olivetti-body-width 60) (olivetti-mode 1)))) (setq org-present-mode-quit-hook @@ -4654,16 +4656,23 @@ by the `my/elfeed-youtube-subtitles' function." (setq-local subed-mpv-video-file (elfeed-entry-link entry)) (subed-mpv--play subed-mpv-video-file)) +(defvar my/vosk-script-path + "/home/pavel/Code/system-crafting/podcasts-vosk/" + "Path to the `podcasts-vosk' script folder.") + (defun my/invoke-vosk (input output) + "Extract subtitles from audio file. + +INPUT is the audio file, OUTPUT is the part to the resulting SRT file." (interactive (list (read-file-name "Input file: " nil nil t) (read-file-name "SRT file: "))) (let* ((buffer (generate-new-buffer "vosk")) - (default-directory "/home/pavel/Code/system-crafting/podcasts-vosk/") + (default-directory my/vosk-script-path) (proc (start-process "vosk_api" buffer - "/home/pavel/Code/system-crafting/podcasts-vosk/venv/bin/python" + (concat my/vosk-script-path "venv/bin/python") "main.py" "--file-path" input "--model-path" "./model-small" "--save-path" output "--words-per-line" "14"))) (set-process-sentinel @@ -4672,7 +4681,8 @@ by the `my/elfeed-youtube-subtitles' function." (let ((status (process-status process)) (code (process-exit-status process))) (cond ((and (eq status 'exit) (= code 0)) - (message "SRT conversion completed")) + (notifications-notify :body "SRT conversion completed" + :title "Vosk API")) ((or (and (eq status 'exit) (> code 0)) (eq status 'signal)) (let ((err (with-current-buffer (process-buffer process) @@ -4681,10 +4691,11 @@ by the `my/elfeed-youtube-subtitles' function." (user-error "Error in Vosk API: %s" err))))))))) (defun my/get-file-name-from-url (url) + "Extract file name from the URL." (string-match (rx "/" (+ (not "/")) (? "/") eos) url) (let ((match (match-string 0 url))) (unless match - (user-error "No file name found. Somehow")) + (user-error "No file name found. Somehow")) ;; Remove the first / (setq match (substring match 1)) ;; Remove the trailing / @@ -4692,9 +4703,16 @@ by the `my/elfeed-youtube-subtitles' function." (setq match (substring match 0 (1- (length match))))) match)) +(with-eval-after-load 'elfeed + (defvar my/elfeed-vosk-podcast-files-directory + (concat elfeed-db-directory "/podcast-files/"))) + (defun my/elfeed-vosk-get-transcript-new (url srt-path) (let* ((file-name (my/get-file-name-from-url url)) - (file-path (format "/tmp/%s" file-name))) + (file-path (expand-file-name + (concat + my/elfeed-vosk-podcast-files-directory + file-name)))) (message "Download started") (request url :type "GET" @@ -4714,6 +4732,7 @@ by the `my/elfeed-youtube-subtitles' function." (message "Error!: %S" error-thrown)))))) (defun my/elfeed-vosk-get-transcript (entry) + "Retrieve transcript from the current elfeed ENTRY." (interactive (list elfeed-show-entry)) (let ((enclosure (caar (elfeed-entry-enclosures entry)))) (unless enclosure @@ -4722,9 +4741,24 @@ by the `my/elfeed-youtube-subtitles' function." (elfeed-ref-id (elfeed-entry-content entry)) ".srt"))) (if (file-exists-p srt-path) - (find-file-other-window srt-path) + (let ((buffer (find-file-other-window srt-path))) + (with-current-buffer buffer + (setq-local elfeed-show-entry entry))) (my/elfeed-vosk-get-transcript-new enclosure srt-path))))) +(defun my/elfeed-vosk-subed (entry) + (interactive (list elfeed-show-entry)) + (unless entry + (user-error "No entry!")) + (unless (derived-mode-p 'subed-mode) + (user-error "Not subed mode!")) + (setq-local subed-mpv-video-file + (expand-file-name + (concat my/elfeed-vosk-podcast-files-directory + (my/get-file-name-from-url + (caar (elfeed-entry-enclosures entry)))))) + (subed-mpv--play subed-mpv-video-file)) + (unless (or my/is-termux my/remote-server) (let ((mail-file (expand-file-name "mail.el" user-emacs-directory))) (if (file-exists-p mail-file) @@ -5278,8 +5312,8 @@ by the `my/elfeed-youtube-subtitles' function." :commands (pomm pomm-third-time) :init (my-leader-def "ap" #'pomm-third-time) - :config (setq alert-default-style 'libnotify) + :config (pomm-mode-line-mode)) (use-package hledger-mode diff --git a/Emacs.org b/Emacs.org index 35ae344..3f6e6a4 100644 --- a/Emacs.org +++ b/Emacs.org @@ -2361,6 +2361,7 @@ A general-purpose package to run formatters on files. While the most popular for :straight (:host github :repo "SqrtMinusOne/copilot.el" :files ("dist" "*.el")) :commands (copilot-mode) :if (not my/remote-server) + :disabled :init (add-hook 'prog-mode-hook #'copilot-mode) :config @@ -3937,7 +3938,8 @@ Doing presentations with [[https://github.com/rlister/org-present][org-present]] (setq-local org-format-latex-options (plist-put org-format-latex-options :scale (* org-present-text-scale my/org-latex-scale 0.5))) - (org-latex-preview '(16)) + ;; (org-latex-preview '(16)) + ;; TODO ^somehow this stucks at running LaTeX^ (setq-local olivetti-body-width 60) (olivetti-mode 1)))) (setq org-present-mode-quit-hook @@ -6093,6 +6095,10 @@ Now, a function to add a YouTube link with metadata from elfeed to EMMS. *** rdrview [[https://github.com/eafer/rdrview][rdrview]] is a command-line tool to strip webpages from clutter, extracting only parts related to the actual content. It's a standalone port of the corresponding feature of Firefox, called [[https://support.mozilla.org/en-US/kb/firefox-reader-view-clutter-free-web-pages][Reader View]]. +| Guix dependency | +|-----------------| +| rdrview | + It seems like the tool [[https://repology.org/project/rdrview/versions][isn't available]] in a whole lot of package repositories, but it's pretty easy to compile. I've put together a [[https://github.com/SqrtMinusOne/channel-q/blob/master/rdrview.scm][Guix definition]], which /one day/ I'll submit to upstream. **** Integrating rdrview with Emacs @@ -6545,16 +6551,23 @@ Occasionally I want to have a text version of a podcast, for instance to take so In order do do that, I've made a [[https://github.com/SqrtMinusOne/podcasts-vosk][small script]] that uses the [[https://alphacephei.com/vosk/][Vosk speech recognition toolkit]] to extract subtitles from an audio file. Here's a function to invoke that script. #+begin_src emacs-lisp +(defvar my/vosk-script-path + "/home/pavel/Code/system-crafting/podcasts-vosk/" + "Path to the `podcasts-vosk' script folder.") + (defun my/invoke-vosk (input output) + "Extract subtitles from audio file. + +INPUT is the audio file, OUTPUT is the part to the resulting SRT file." (interactive (list (read-file-name "Input file: " nil nil t) (read-file-name "SRT file: "))) (let* ((buffer (generate-new-buffer "vosk")) - (default-directory "/home/pavel/Code/system-crafting/podcasts-vosk/") + (default-directory my/vosk-script-path) (proc (start-process "vosk_api" buffer - "/home/pavel/Code/system-crafting/podcasts-vosk/venv/bin/python" + (concat my/vosk-script-path "venv/bin/python") "main.py" "--file-path" input "--model-path" "./model-small" "--save-path" output "--words-per-line" "14"))) (set-process-sentinel @@ -6563,7 +6576,8 @@ In order do do that, I've made a [[https://github.com/SqrtMinusOne/podcasts-vosk (let ((status (process-status process)) (code (process-exit-status process))) (cond ((and (eq status 'exit) (= code 0)) - (message "SRT conversion completed")) + (notifications-notify :body "SRT conversion completed" + :title "Vosk API")) ((or (and (eq status 'exit) (> code 0)) (eq status 'signal)) (let ((err (with-current-buffer (process-buffer process) @@ -6575,10 +6589,11 @@ In order do do that, I've made a [[https://github.com/SqrtMinusOne/podcasts-vosk In order to use that, we need to download the file first. So here's a function that extracts the file name from the URL: #+begin_src emacs-lisp (defun my/get-file-name-from-url (url) + "Extract file name from the URL." (string-match (rx "/" (+ (not "/")) (? "/") eos) url) (let ((match (match-string 0 url))) (unless match - (user-error "No file name found. Somehow")) + (user-error "No file name found. Somehow")) ;; Remove the first / (setq match (substring match 1)) ;; Remove the trailing / @@ -6589,9 +6604,16 @@ In order to use that, we need to download the file first. So here's a function t Now can use that to save the file and invoke the =my/invoke-vosk= function. #+begin_src emacs-lisp +(with-eval-after-load 'elfeed + (defvar my/elfeed-vosk-podcast-files-directory + (concat elfeed-db-directory "/podcast-files/"))) + (defun my/elfeed-vosk-get-transcript-new (url srt-path) (let* ((file-name (my/get-file-name-from-url url)) - (file-path (format "/tmp/%s" file-name))) + (file-path (expand-file-name + (concat + my/elfeed-vosk-podcast-files-directory + file-name)))) (message "Download started") (request url :type "GET" @@ -6615,6 +6637,7 @@ And the final entrypoint, that opens up the SRT file is it's available, and queu #+begin_src emacs-lisp (defun my/elfeed-vosk-get-transcript (entry) + "Retrieve transcript from the current elfeed ENTRY." (interactive (list elfeed-show-entry)) (let ((enclosure (caar (elfeed-entry-enclosures entry)))) (unless enclosure @@ -6623,10 +6646,27 @@ And the final entrypoint, that opens up the SRT file is it's available, and queu (elfeed-ref-id (elfeed-entry-content entry)) ".srt"))) (if (file-exists-p srt-path) - (find-file-other-window srt-path) + (let ((buffer (find-file-other-window srt-path))) + (with-current-buffer buffer + (setq-local elfeed-show-entry entry))) (my/elfeed-vosk-get-transcript-new enclosure srt-path))))) #+end_src +#+begin_src emacs-lisp +(defun my/elfeed-vosk-subed (entry) + (interactive (list elfeed-show-entry)) + (unless entry + (user-error "No entry!")) + (unless (derived-mode-p 'subed-mode) + (user-error "Not subed mode!")) + (setq-local subed-mpv-video-file + (expand-file-name + (concat my/elfeed-vosk-podcast-files-directory + (my/get-file-name-from-url + (caar (elfeed-entry-enclosures entry)))))) + (subed-mpv--play subed-mpv-video-file)) +#+end_src + ** Internet & Multimedia *** Notmuch My notmuch config now resides in [[file:Mail.org][Mail.org]]. @@ -7422,8 +7462,8 @@ My package for doing Pomodoro timer. :commands (pomm pomm-third-time) :init (my-leader-def "ap" #'pomm-third-time) - :config (setq alert-default-style 'libnotify) + :config (pomm-mode-line-mode)) #+end_src *** hledger @@ -7542,7 +7582,7 @@ Watch out if you are using EXWM. * Guix settings | Guix dependency | Description | |---------------------+-------------------------------| -| emacs-vterm | A vterm package | +| emacs-vterm | The vterm package | | ripgrep | A recursive search tool | | the-silver-searcher | Another recursive search tool |