emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/emms a84ebc7984: Add an EMMS module for fetching synchr


From: ELPA Syncer
Subject: [elpa] externals/emms a84ebc7984: Add an EMMS module for fetching synchronized lyrics from LRCLIB
Date: Wed, 27 Nov 2024 21:58:04 -0500 (EST)

branch: externals/emms
commit a84ebc7984725a64177a70656a7860b1bf3f4d93
Author: Daniel Semyonov <daniel@dsemy.com>
Commit: Daniel Semyonov <daniel@dsemy.com>

    Add an EMMS module for fetching synchronized lyrics from LRCLIB
---
 doc/emms.texinfo      |  22 ++++++++++
 emms-lyrics-lrclib.el | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 136 insertions(+)

diff --git a/doc/emms.texinfo b/doc/emms.texinfo
index 43d474dd9e..e7d1300ec4 100644
--- a/doc/emms.texinfo
+++ b/doc/emms.texinfo
@@ -2735,6 +2735,24 @@ To add this feature we invoke:
 (emms-lyrics 1)
 @end lisp
 
+Synchronized lyrics files can be obtained manually from various
+sources, or fetched automatically for new tracks from an LRCLIB server
+(@url{https://lrclib.net}) by adding the following function to
+@var{emms-track-initialize-functions}:
+
+@defun emms-lyrics-lrclib-get &optional track force interactive
+Search for synchronized lyrics for @var{track} through LRCLIB’s API.
+If @var{track} is omitted or nil, use the selected track in the
+current playlist.
+When used as a track initialization function, @var{track} is set to
+the track being initialized.
+The lyrics are saved in an ``.lrc'' file alongside the track, unless
+the file already exists (in which case the search isn’t performed).
+When called interactively (non-nil INTERACTIVE), display informative
+messages, and with prefix argument FORCE, ask to overwrite existing
+``.lrc'' files.
+@end defun
+
 There are a number of variables we can set to define the way that
 `emms-lyrics' behaves, we can set these directly or by using the
 Customize feature in Emacs.
@@ -2770,6 +2788,10 @@ Non-nil value will enable lyrics scrolling.
 Interval between scroller timers. The shorter, the faster.
 @end defvr
 
+@defvr {User Option} emms-lyrics-lrclib-url
+Base URL for LRCLIB API requests.
+@end defvr
+
 We can control `emms-lyrics' with the help of the following functions:
 
 @defun emms-lyrics-start
diff --git a/emms-lyrics-lrclib.el b/emms-lyrics-lrclib.el
new file mode 100644
index 0000000000..d862913de7
--- /dev/null
+++ b/emms-lyrics-lrclib.el
@@ -0,0 +1,114 @@
+;;; emms-lyrics-lrclib.el --- Fetch synchronized lyrics through LRCLIB -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Free Software Foundation, Inc.
+
+;; Author: Daniel Semyonov <daniel@dsemy.com>
+
+;; This file is part of EMMS.
+
+;; EMMS is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; EMMS is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with EMMS; see the file COPYING. If not, write to the Free
+;; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+;; MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; This file provides a command/track initialization function which
+;; automatically fetches synchronized lyrics for tracks (the current
+;; track interactively) through an LRCLIB server.
+
+;;; Code:
+
+(require 'emms-lyrics)
+(require 'emms-later-do)
+
+(defgroup emms-lyrics-lrclib nil
+  "EMMS module for fetching synchronized lyrics through LRCLIB servers."
+  :group 'emms-lyrics
+  :prefix "emms-lyrics-lrclib-")
+
+(defcustom emms-lyrics-lrclib-url "https://lrclib.net/api/";
+  "Base URL for LRCLIB API requests."
+  :type 'string)
+
+(defconst emms-lyrics-lrclib-max-requests 250
+  "Maximum number of concurrent requests to LRCLIB.")
+
+(defvar emms-lyrics-lrclib-requests 0
+  "Current number of concurrent requests to LRCLIB.")
+
+(defun emms-lyrics-lrclib-encode-name (name)
+  "Encode (artist/album/track) NAME for an LRCLIB search."
+  (and (stringp name) (string-replace " " "+" name)))
+
+(defun emms-lyrics-lrclib-parse (_ file track interactive)
+  "Parse and save synced lyrics in FILE.
+If TRACK is the selected track in the current playlist, catch up.
+When INTERACTIVE is non-nil, display messages and confirm overwrite."
+  (unwind-protect
+      (progn
+        (search-forward "\n\n")
+        (let* ((p (json-parse-buffer))
+               (lyrics (and (hash-table-p p) (gethash "syncedLyrics" p))))
+          (if (not (stringp lyrics))
+              (when interactive (message "No lyrics found"))
+            (or
+             (and (file-exists-p file) interactive
+                  (not (y-or-n-p
+                        (format "Overwrite existing file (\"%s\")?" file))))
+             (with-temp-file file
+               (insert (gethash "syncedLyrics" p))
+               (when interactive
+                 (message "Saves synced lyrics at \"%s\"" file))
+               (and (boundp 'emms-lyrics-display-p)
+                    emms-lyrics-display-p emms-player-playing-p
+                    (equal track (emms-playlist-current-selected-track))
+                    (emms-lyrics-catchup file)))))))
+    (setq emms-lyrics-lrclib-requests (1- emms-lyrics-lrclib-requests))))
+
+;;;###autoload
+(defun emms-lyrics-lrclib-get (&optional track force interactive)
+  "Search for synchronized lyrics for TRACK through LRCLIB's API.
+If TRACK is omitted or nil, use the selected track in the current playlist.
+The lyrics are saved in an \".lrc\" file alongside the track, unless the
+file already exists (in which case the search isn't performed).
+When called interactively (non-nil INTERACTIVE), display informative
+messages, and with prefix argument FORCE, ask to overwrite existing
+\".lrc\" files."
+  (interactive (list nil current-prefix-arg t))
+  (if (> emms-lyrics-lrclib-requests emms-lyrics-lrclib-max-requests)
+      (emms-later-do #'emms-lyrics-lrclib-get track force interactive)
+    (when-let* ((track (or track (emms-playlist-current-selected-track)))
+                ((eq (emms-track-type track) 'file))
+                (file (emms-track-name track))
+                (lrc (replace-regexp-in-string "\\.[^.]+\\'" ".lrc" file))
+                ((or force (not (file-exists-p lrc))))
+                ((file-writable-p lrc))
+                (title (emms-lyrics-lrclib-encode-name
+                        (emms-track-get track 'info-title)))
+                (artist (emms-lyrics-lrclib-encode-name
+                         (emms-track-get track 'info-artist)))
+                (album (emms-lyrics-lrclib-encode-name
+                        (emms-track-get track 'info-album)))
+                (time (emms-track-get track 'info-playing-time)))
+      (setq emms-lyrics-lrclib-requests (1+ emms-lyrics-lrclib-requests))
+      (when interactive (message "Searching for lyrics..."))
+      (url-retrieve
+       (url-encode-url
+        (format "%sget?artist_name=%s&track_name=%s&album_name=%s&duration=%d"
+                emms-lyrics-lrclib-url artist title album time))
+       #'emms-lyrics-lrclib-parse (list lrc track interactive)))))
+
+(provide 'emms-lyrics-lrclib)
+
+;;; emms-lyrics-lrclib.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]