mirror of
https://github.com/SqrtMinusOne/dotfiles.git
synced 2025-12-10 19:23:03 +03:00
feat(emacs): emms
This commit is contained in:
parent
d209886abc
commit
bd3743e3a3
2 changed files with 288 additions and 78 deletions
240
.emacs.d/init.el
240
.emacs.d/init.el
|
|
@ -138,6 +138,8 @@
|
|||
(evil-collection-init
|
||||
'(eww
|
||||
proced
|
||||
emms
|
||||
calendar
|
||||
dired
|
||||
debug
|
||||
guix
|
||||
|
|
@ -2733,6 +2735,152 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer."
|
|||
(evil-collection-define-key 'normal 'elfeed-show-mode-map
|
||||
"gm" #'my/elfeed-open-mpv))
|
||||
|
||||
(use-package emms
|
||||
:straight t
|
||||
:commands (emms-smart-browse emms-browser)
|
||||
:init
|
||||
(my-leader-def
|
||||
:infix "as"
|
||||
"s" 'emms-smart-browse
|
||||
"b" 'emms-browser
|
||||
"p" 'emms-pause
|
||||
"q" 'emms-stop
|
||||
"h" 'emms-previous
|
||||
"l" 'emms-next
|
||||
"u" 'emms-player-mpd-connect)
|
||||
:config
|
||||
(require 'emms-setup)
|
||||
(require 'emms-player-mpd)
|
||||
(emms-all)
|
||||
;; MPD setup
|
||||
(setq emms-source-file-default-directory (expand-file-name "~/Music/"))
|
||||
(add-to-list 'emms-info-functions 'emms-info-mpd)
|
||||
(add-to-list 'emms-player-list 'emms-player-mpd)
|
||||
(setq emms-player-mpd-server-name "localhost")
|
||||
(setq emms-player-mpd-server-port "6600")
|
||||
(setq emms-player-mpd-music-directory "~/Music")
|
||||
(emms-player-mpd-connect)
|
||||
;; Clear MPD playlist on clearing EMMS playlist
|
||||
;; IDK if this is fine for MPD playlists, I don't use them anyhow
|
||||
(add-hook 'emms-playlist-cleared-hook 'emms-player-mpd-clear)
|
||||
(defun emms-info-mpd-process (track info)
|
||||
(dolist (data info)
|
||||
(let ((name (car data))
|
||||
(value (cdr data)))
|
||||
(setq name (cond ((string= name "artist") 'info-artist)
|
||||
((string= name "albumartist") 'info-albumartist)
|
||||
((string= name "composer") 'info-composer)
|
||||
((string= name "performer") 'info-performer)
|
||||
((string= name "title") 'info-title)
|
||||
((string= name "album") 'info-album)
|
||||
((string= name "track") 'info-tracknumber)
|
||||
((string= name "disc") 'info-discnumber)
|
||||
((string= name "date") 'info-year)
|
||||
((string= name "genre") 'info-genre)
|
||||
((string= name "time")
|
||||
(setq value (string-to-number value))
|
||||
'info-playing-time)
|
||||
(t nil)))
|
||||
(when name
|
||||
(emms-track-set track name value)))))
|
||||
(defun emms-player-mpd-get-alists (info)
|
||||
"Turn the given parsed INFO from MusicPD into an list of alists.
|
||||
|
||||
The list will be in reverse order."
|
||||
(when (and info
|
||||
(null (car info)) ; no error has occurred
|
||||
(cdr info)) ; data exists
|
||||
(let ((alists nil)
|
||||
(alist nil)
|
||||
cell)
|
||||
(dolist (line (cdr info))
|
||||
(when (setq cell (emms-player-mpd-parse-line line))
|
||||
(if (member (car cell) '("file" "directory" "playlist"))
|
||||
(setq alists (cons alist alists)
|
||||
alist (list cell))
|
||||
(setq alist (cons cell alist)))))
|
||||
(when alist
|
||||
(setq alists (cons alist alists)))
|
||||
alists))))
|
||||
|
||||
(with-eval-after-load 'emms-browser
|
||||
(evil-collection-define-key 'normal 'emms-browser-mode-map
|
||||
"q" 'quit-window))
|
||||
|
||||
(with-eval-after-load 'emms
|
||||
(evil-collection-define-key 'normal 'emms-playlist-mode-map
|
||||
"q" 'quit-window))
|
||||
|
||||
(defun my/toggle-shr-use-fonts ()
|
||||
"Toggle the shr-use-fonts variable in buffer"
|
||||
(interactive)
|
||||
(setq-local shr-use-fonts (not shr-use-fonts)))
|
||||
|
||||
(my-leader-def "aw" 'eww)
|
||||
|
||||
(general-define-key
|
||||
:keymaps 'eww-mode-map
|
||||
"+" 'text-scale-increase
|
||||
"-" 'text-scale-decrease)
|
||||
|
||||
(my-leader-def "ai" #'erc-tls)
|
||||
|
||||
(use-package erc-hl-nicks
|
||||
:hook (erc-mode . erc-hl-nicks-mode)
|
||||
:straight t)
|
||||
|
||||
(setq erc-server "sqrtminusone.xyz")
|
||||
(setq erc-port 1984)
|
||||
(setq erc-nick "sqrtminusone")
|
||||
(setq erc-user-full-name "Pavel Korytov")
|
||||
(setq erc-track-shorten-start 8)
|
||||
|
||||
(setq erc-kill-buffer-on-part t)
|
||||
|
||||
(use-package znc
|
||||
:straight t
|
||||
:after (erc))
|
||||
|
||||
(use-package google-translate
|
||||
:straight t
|
||||
:functions (my-google-translate-at-point google-translate--search-tkk)
|
||||
:custom
|
||||
(google-translate-backend-method 'curl)
|
||||
:config
|
||||
(require 'facemenu)
|
||||
(defun google-translate--search-tkk ()
|
||||
"Search TKK."
|
||||
(list 430675 2721866130))
|
||||
(defun my-google-translate-at-point()
|
||||
"reverse translate if prefix"
|
||||
(interactive)
|
||||
(if current-prefix-arg
|
||||
(google-translate-at-point)
|
||||
(google-translate-at-point-reverse)))
|
||||
(setq google-translate-translation-directions-alist
|
||||
'(("en" . "ru")
|
||||
("ru" . "en"))))
|
||||
|
||||
(my-leader-def
|
||||
"atp" 'google-translate-at-point
|
||||
"atP" 'google-translate-at-point-reverse
|
||||
"atq" 'google-translate-query-translate
|
||||
"atQ" 'google-translate-query-translate-reverse
|
||||
"att" 'google-translate-smooth-translate)
|
||||
|
||||
(use-package elcord
|
||||
:straight t
|
||||
:if (and (or
|
||||
(string= (system-name) "indigo")
|
||||
(string= (system-name) "eminence"))
|
||||
(not my/slow-ssh))
|
||||
:config
|
||||
(elcord-mode)
|
||||
(add-to-list 'elcord-boring-buffers-regexp-list
|
||||
(rx bos (+ num) "-" (+ num) "-" (+ num) ".org" eos))
|
||||
(add-to-list 'elcord-boring-buffers-regexp-list
|
||||
(rx bos (= 14 num) "-" (* not-newline) ".org" eos)))
|
||||
|
||||
(use-package tldr
|
||||
:straight t
|
||||
:commands (tldr)
|
||||
|
|
@ -2754,23 +2902,8 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer."
|
|||
(setq Man-width-max 180)
|
||||
(my-leader-def "hM" 'man)
|
||||
|
||||
(my-leader-def "ai" #'erc-tls)
|
||||
|
||||
(use-package erc-hl-nicks
|
||||
:hook (erc-mode . erc-hl-nicks-mode)
|
||||
:straight t)
|
||||
|
||||
(setq erc-server "sqrtminusone.xyz")
|
||||
(setq erc-port 1984)
|
||||
(setq erc-nick "sqrtminusone")
|
||||
(setq erc-user-full-name "Pavel Korytov")
|
||||
(setq erc-track-shorten-start 8)
|
||||
|
||||
(setq erc-kill-buffer-on-part t)
|
||||
|
||||
(use-package znc
|
||||
:straight t
|
||||
:after (erc))
|
||||
(evil-collection-define-key 'normal 'Info-mode-map
|
||||
(kbd "RET") 'Info-follow-nearest-node)
|
||||
|
||||
(use-package docker
|
||||
:straight t
|
||||
|
|
@ -2821,32 +2954,16 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer."
|
|||
(kbd "C-k") 'evil-window-up
|
||||
(kbd "C-j") 'evil-window-down))
|
||||
|
||||
(use-package google-translate
|
||||
:straight t
|
||||
:functions (my-google-translate-at-point google-translate--search-tkk)
|
||||
:custom
|
||||
(google-translate-backend-method 'curl)
|
||||
:config
|
||||
(require 'facemenu)
|
||||
(defun google-translate--search-tkk ()
|
||||
"Search TKK."
|
||||
(list 430675 2721866130))
|
||||
(defun my-google-translate-at-point()
|
||||
"reverse translate if prefix"
|
||||
(interactive)
|
||||
(if current-prefix-arg
|
||||
(google-translate-at-point)
|
||||
(google-translate-at-point-reverse)))
|
||||
(setq google-translate-translation-directions-alist
|
||||
'(("en" . "ru")
|
||||
("ru" . "en"))))
|
||||
(my-leader-def "ah" 'proced)
|
||||
(add-hook 'proced-mode-hook (lambda ()
|
||||
(visual-line-mode -1)
|
||||
(setq-local truncate-lines t)))
|
||||
|
||||
(my-leader-def
|
||||
"atp" 'google-translate-at-point
|
||||
"atP" 'google-translate-at-point-reverse
|
||||
"atq" 'google-translate-query-translate
|
||||
"atQ" 'google-translate-query-translate-reverse
|
||||
"att" 'google-translate-smooth-translate)
|
||||
(use-package guix
|
||||
:straight t
|
||||
:commands (guix)
|
||||
:init
|
||||
(my-leader-def "ag" 'guix))
|
||||
|
||||
(use-package pomidor
|
||||
:straight t
|
||||
|
|
@ -2865,22 +2982,12 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer."
|
|||
(kbd "RET") #'pomidor-stop
|
||||
(kbd "M-RET") #'pomidor-break))
|
||||
|
||||
(defun my/toggle-shr-use-fonts ()
|
||||
"Toggle the shr-use-fonts variable in buffer"
|
||||
(interactive)
|
||||
(setq-local shr-use-fonts (not shr-use-fonts)))
|
||||
(setq calendar-date-style 'iso) ;; YYYY/mm/dd
|
||||
(setq calendar-week-start-day 1)
|
||||
(setq calendar-time-display-form '(24-hours ":" minutes))
|
||||
|
||||
(my-leader-def "aw" 'eww)
|
||||
|
||||
(general-define-key
|
||||
:keymaps 'eww-mode-map
|
||||
"+" 'text-scale-increase
|
||||
"-" 'text-scale-decrease)
|
||||
|
||||
(my-leader-def "ah" 'proced)
|
||||
(add-hook 'proced-mode-hook (lambda ()
|
||||
(visual-line-mode -1)
|
||||
(setq-local truncate-lines t)))
|
||||
(setq calendar-latitude 59.9375)
|
||||
(setq calendar-longitude 30.308611)
|
||||
|
||||
(use-package screenshot
|
||||
:straight (:repo "tecosaur/screenshot" :host github :files ("screenshot.el"))
|
||||
|
|
@ -2906,22 +3013,3 @@ then it takes a second \\[keyboard-quit] to abort the minibuffer."
|
|||
:action (lambda (elem)
|
||||
(setq zone-programs (vector (cdr elem)))
|
||||
(zone))))
|
||||
|
||||
(use-package elcord
|
||||
:straight t
|
||||
:if (and (or
|
||||
(string= (system-name) "indigo")
|
||||
(string= (system-name) "eminence"))
|
||||
(not my/slow-ssh))
|
||||
:config
|
||||
(elcord-mode)
|
||||
(add-to-list 'elcord-boring-buffers-regexp-list
|
||||
(rx bos (+ num) "-" (+ num) "-" (+ num) ".org" eos))
|
||||
(add-to-list 'elcord-boring-buffers-regexp-list
|
||||
(rx bos (= 14 num) "-" (* not-newline) ".org" eos)))
|
||||
|
||||
(use-package guix
|
||||
:straight t
|
||||
:commands (guix)
|
||||
:init
|
||||
(my-leader-def "ag" 'guix))
|
||||
|
|
|
|||
126
Emacs.org
126
Emacs.org
|
|
@ -221,11 +221,14 @@ As with other files in the repo, parts prefixed with (OFF) are not used but kept
|
|||
- [[#open-emacs-config][Open Emacs config]]
|
||||
- [[#open-magit-for-yadm][Open Magit for yadm]]
|
||||
- [[#open-a-dotfile][Open a dotfile]]
|
||||
- [[#internet][Internet]]
|
||||
- [[#internet--multimedia][Internet & Multimedia]]
|
||||
- [[#notmuch][Notmuch]]
|
||||
- [[#elfeed][Elfeed]]
|
||||
- [[#some-additions][Some additions]]
|
||||
- [[#youtube][YouTube]]
|
||||
- [[#emms][EMMS]]
|
||||
- [[#some-keybindings][Some keybindings]]
|
||||
- [[#fixes][Fixes]]
|
||||
- [[#eww][EWW]]
|
||||
- [[#erc][ERC]]
|
||||
- [[#google-translate][Google Translate]]
|
||||
|
|
@ -503,6 +506,7 @@ I don't enable the entire package, just the modes I need.
|
|||
(evil-collection-init
|
||||
'(eww
|
||||
proced
|
||||
emms
|
||||
calendar
|
||||
dired
|
||||
debug
|
||||
|
|
@ -4059,7 +4063,7 @@ Open a file managed by yadm.
|
|||
(general-define-key "C-c f" 'my/open-yadm-file)
|
||||
(my-leader-def "cf" 'my/open-yadm-file)
|
||||
#+end_src
|
||||
** Internet
|
||||
** Internet & Multimedia
|
||||
*** Notmuch
|
||||
My notmuch config now resides in [[file:Mail.org][Mail.org]].
|
||||
|
||||
|
|
@ -4178,6 +4182,124 @@ And a function to open YouTube link from elfeed
|
|||
(evil-collection-define-key 'normal 'elfeed-show-mode-map
|
||||
"gm" #'my/elfeed-open-mpv))
|
||||
#+end_src
|
||||
*** EMMS
|
||||
EMMS is the Emacs Multi-Media System. I am currently trying to control MPD from Emacs with its help.
|
||||
|
||||
References:
|
||||
- [[https://www.gnu.org/software/emms/manual/][EMMS Manual]]
|
||||
- [[https://www.youtube.com/watch?v=xTVN8UDScqk][Uncle Dave's video]]
|
||||
|
||||
#+begin_src emacs-lisp :noweb yes
|
||||
(use-package emms
|
||||
:straight t
|
||||
:commands (emms-smart-browse emms-browser)
|
||||
:init
|
||||
(my-leader-def
|
||||
:infix "as"
|
||||
"s" 'emms-smart-browse
|
||||
"b" 'emms-browser
|
||||
"p" 'emms-pause
|
||||
"q" 'emms-stop
|
||||
"h" 'emms-previous
|
||||
"l" 'emms-next
|
||||
"u" 'emms-player-mpd-connect)
|
||||
:config
|
||||
(require 'emms-setup)
|
||||
(require 'emms-player-mpd)
|
||||
(emms-all)
|
||||
;; MPD setup
|
||||
(setq emms-source-file-default-directory (expand-file-name "~/Music/"))
|
||||
(add-to-list 'emms-info-functions 'emms-info-mpd)
|
||||
(add-to-list 'emms-player-list 'emms-player-mpd)
|
||||
(setq emms-player-mpd-server-name "localhost")
|
||||
(setq emms-player-mpd-server-port "6600")
|
||||
(setq emms-player-mpd-music-directory "~/Music")
|
||||
(emms-player-mpd-connect)
|
||||
;; Clear MPD playlist on clearing EMMS playlist
|
||||
;; IDK if this is fine for MPD playlists, I don't use them anyhow
|
||||
(add-hook 'emms-playlist-cleared-hook 'emms-player-mpd-clear)
|
||||
<<emms-fixes>>)
|
||||
#+end_src
|
||||
**** Some keybindings
|
||||
#+begin_src emacs-lisp
|
||||
(with-eval-after-load 'emms-browser
|
||||
(evil-collection-define-key 'normal 'emms-browser-mode-map
|
||||
"q" 'quit-window))
|
||||
|
||||
(with-eval-after-load 'emms
|
||||
(evil-collection-define-key 'normal 'emms-playlist-mode-map
|
||||
"q" 'quit-window))
|
||||
#+end_src
|
||||
**** Fixes
|
||||
Some fixes until I submit a patch.
|
||||
|
||||
For some reason EMMS doesn't fetch =albumartist= from MPD. Overriding this function fixes that.
|
||||
|
||||
#+begin_src emacs-lisp :tangle no :noweb-ref emms-fixes
|
||||
(defun emms-info-mpd-process (track info)
|
||||
(dolist (data info)
|
||||
(let ((name (car data))
|
||||
(value (cdr data)))
|
||||
(setq name (cond ((string= name "artist") 'info-artist)
|
||||
((string= name "albumartist") 'info-albumartist)
|
||||
((string= name "composer") 'info-composer)
|
||||
((string= name "performer") 'info-performer)
|
||||
((string= name "title") 'info-title)
|
||||
((string= name "album") 'info-album)
|
||||
((string= name "track") 'info-tracknumber)
|
||||
((string= name "disc") 'info-discnumber)
|
||||
((string= name "date") 'info-year)
|
||||
((string= name "genre") 'info-genre)
|
||||
((string= name "time")
|
||||
(setq value (string-to-number value))
|
||||
'info-playing-time)
|
||||
(t nil)))
|
||||
(when name
|
||||
(emms-track-set track name value)))))
|
||||
#+end_src
|
||||
|
||||
Also, =emms-player-mpd-get-alists= has an interesting bug. This function parses the response to =listallinfo=, which looks something like this:
|
||||
#+begin_example
|
||||
tag1: value1
|
||||
tag2: value2
|
||||
...
|
||||
tag1: value1'
|
||||
tag2: value2'
|
||||
#+end_example
|
||||
|
||||
This structure has to be converted to list of alists, which looks like:
|
||||
#+begin_example
|
||||
(("tag1" . "value1"
|
||||
"tag2" . "value2")
|
||||
("tag1" . "value1'"
|
||||
("tag2" . "value2'")))
|
||||
#+end_example
|
||||
|
||||
The original implementation creates a new alist whenever it encounters a tag it has already put in the current alist. Which doesn't work too well if some tags don't repeat, if the order is messed up, etc.
|
||||
|
||||
Fortunately, according to the [[https://mpd.readthedocs.io/en/latest/protocol.html#command-lsinfo][protocol specification]], each new record has to start with =file=, =directory= or =playlist=. I've overridden the function with that in mind and it fixed the import, at least in my case.
|
||||
|
||||
#+begin_src emacs-lisp :tangle no :noweb-ref emms-fixes
|
||||
(defun emms-player-mpd-get-alists (info)
|
||||
"Turn the given parsed INFO from MusicPD into an list of alists.
|
||||
|
||||
The list will be in reverse order."
|
||||
(when (and info
|
||||
(null (car info)) ; no error has occurred
|
||||
(cdr info)) ; data exists
|
||||
(let ((alists nil)
|
||||
(alist nil)
|
||||
cell)
|
||||
(dolist (line (cdr info))
|
||||
(when (setq cell (emms-player-mpd-parse-line line))
|
||||
(if (member (car cell) '("file" "directory" "playlist"))
|
||||
(setq alists (cons alist alists)
|
||||
alist (list cell))
|
||||
(setq alist (cons cell alist)))))
|
||||
(when alist
|
||||
(setq alists (cons alist alists)))
|
||||
alists)))
|
||||
#+end_src
|
||||
*** EWW
|
||||
Emacs built-in web browser. +I wonder if anyone actually uses it.+
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue