emms-help
[Top][All Lists]
Advanced

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

Fetching synchronized lyrics from LRCLIB


From: Daniel Semyonov
Subject: Fetching synchronized lyrics from LRCLIB
Date: Thu, 28 Nov 2024 02:06:17 +0200
User-agent: Gnus/5.13 (Gnus v5.13)

Hi,

For a while I had a some code in my EMMS config for fetching synced
lyrics from LRCLIB (lrclib.net).
The main function can be used both interactively and as a track
initialization function (interactively it fetches lyrics, optionally
overwriting, for the currently playing track).

This service used to be non-free, though the developer promised to free
it at some point in the future.
Well, it turns out this actually happened (in April actually, I didn't
notice), and the server software is now licensed under MIT, so I
separated this code into its own file and integrated it into EMMS (patch
attached).

I think this will be a nice addition to EMMS, should this be added?

Daniel

>From b2b64c7d41e35434fc6ce36228eb4dadb84e43ac Mon Sep 17 00:00:00 2001
From: Daniel Semyonov <daniel@dsemy.com>
Date: Thu, 28 Nov 2024 01:49:13 +0200
Subject: [PATCH] Add an EMMS module for fetching synchronized lyrics from
 LRCLIB

---
 emms-lyrics-lrclib.el | 113 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)
 create mode 100644 emms-lyrics-lrclib.el

diff --git a/emms-lyrics-lrclib.el b/emms-lyrics-lrclib.el
new file mode 100644
index 0000000..272f6cb
--- /dev/null
+++ b/emms-lyrics-lrclib.el
@@ -0,0 +1,113 @@
+;;; 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, try 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).
+With non-nil FORCE, overwrite existing \".lrc\" files.
+With non-nil INTERACTIVE, display messages and confirm overwrite."
+  (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
-- 
2.47.0


reply via email to

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