diff --git a/README.org b/README.org index 09cb5d6..0b081db 100644 --- a/README.org +++ b/README.org @@ -40,6 +40,8 @@ Available commands: If called with =C-u=, then tries to fetch the text regardless of the latter. If called with =C-u C-u=, prompts the user to select a matching song. That is helpful when there are multiple songs with similar names, and the top one isn't the right one. + + If called with =C-u C-u C-u=, edit the search query in minibuffer before sending. This is helpful when there is extra information in the song title which prevents the API from finding the song. - ~M-x lyrics-fetcher-show-lyrics-query~ - fetch lyrics by a text query. Modified by =C-u= the same way as ~lyrics-fetcher-show-lyrics~. diff --git a/lyrics-fetcher-genius.el b/lyrics-fetcher-genius.el index 1ce8d31..e2c7203 100644 --- a/lyrics-fetcher-genius.el +++ b/lyrics-fetcher-genius.el @@ -49,7 +49,7 @@ searching \"Song (feat. Artist)\"" :type 'boolean :group 'lyrics-fetcher) -(defun lyrics-fetcher-genius-do-search (track callback &optional sync) +(defun lyrics-fetcher-genius-do-search (track callback &optional sync edit) "Perform a lyrics search on 'genius.com'. Requires `lyrics-fetcher-genius-access-token' to be set. @@ -65,7 +65,11 @@ TRACK should be EMMS-compatible alist or string, take a look at successful, CALLBACK will be called with the result. If SYNC is non-nil, perform request synchronously and ask the -user to pick the matching search result." +user to pick the matching search result. + +When EDIT is non-nil, edit the query in minibuffer before search. +Genius usually struggles to find song if there is extra +information in the title." (lyrics-fetcher--genius-do-query track (lambda (data) @@ -73,9 +77,10 @@ user to pick the matching search result." (lyrics-fetcher--genius-get-data-from-response data 'url sync) callback sync)) - sync)) + sync + edit)) -(defun lyrics-fetcher--genius-do-query (track callback &optional sync) +(defun lyrics-fetcher--genius-do-query (track callback &optional sync edit) "Perform a song search on genius.com. Requires `lyrics-fetcher-genius-access-token' to be set. @@ -86,12 +91,16 @@ successful, CALLBACK will be called with the result. SYNC determines whether the request is synchronous. The parameter is useful when it is necessary to ask the user for something right -after the request." +after the request. + +When EDIT is non-nil, edit the query in minibuffer before search." (when (string-empty-p lyrics-fetcher-genius-access-token) (error "Genius client access token not set!")) (message "Sending a query to genius API...") (request "https://api.genius.com/search" - :params `(("q" . ,(lyrics-fetcher--genius-format-query track)) + :params `(("q" . ,(lyrics-fetcher--genius-maybe-edit-query + (lyrics-fetcher--genius-format-query track) + edit)) ("access_token" . ,lyrics-fetcher-genius-access-token)) :parser 'json-read :sync sync @@ -102,6 +111,12 @@ after the request." (lambda (&key error-thrown &allow-other-keys) (message "Error!: %S" error-thrown))))) +(defun lyrics-fetcher--genius-maybe-edit-query (query edit) + "If EDIT is non-nil, edit QUERY if minibuffer." + (when edit + (read-from-minibuffer "Query: " query)) + query) + (defun lyrics-fetcher--genius-format-query (track) "Format track to genius.com query. @@ -190,7 +205,7 @@ If SYNC is non-nil, the request will be performed synchronously." (lambda (&key error-thrown &allow-other-keys) (message "Error!: %S" error-thrown))))) -(defun lyrics-fetcher-genius-download-cover (track callback folder &optional sync) +(defun lyrics-fetcher-genius-download-cover (track callback folder &optional sync edit) "Downloads album cover of TRACK. Requires `lyrics-fetcher-genius-access-token' to be set and @@ -209,7 +224,9 @@ The file will be saved to FOLDER and will be named CALLBACK will be called with a path to the resulting file. -If SYNC is non-nil, the user will be prompted for a matching song." +If SYNC is non-nil, the user will be prompted for a matching song. + +When EDIT is non-nil, edit the query in minibuffer before search." (lyrics-fetcher--genius-do-query track (lambda (data) @@ -217,7 +234,8 @@ If SYNC is non-nil, the user will be prompted for a matching song." (lyrics-fetcher--genius-get-data-from-response data 'id sync) callback folder)) - sync)) + sync + edit)) (defun lyrics-fetcher--genius-save-album-picture (id callback folder) "Save an album cover of a song of a given ID. diff --git a/lyrics-fetcher.el b/lyrics-fetcher.el index 31b095c..d759be1 100644 --- a/lyrics-fetcher.el +++ b/lyrics-fetcher.el @@ -153,7 +153,7 @@ The function has to take into account that: (substring title 0 (min (length title) 190)))))) ;;;###autoload -(cl-defun lyrics-fetcher-show-lyrics (&optional track &key suppress-open suppress-switch callback force-fetch sync) +(cl-defun lyrics-fetcher-show-lyrics (&optional track &key suppress-open suppress-switch callback force-fetch sync edit) "Show lyrics for TRACK. TRACK can be either a string or an EMMS alist. If TRACK is not @@ -184,7 +184,13 @@ always refetch the lyrics text. If called with \\[universal-argument] \\[universal-argument] or SYNC is non-nil, then ask the user to select a matching song. This may be useful if there are multiple tracks with similar names, and the top -one isn’t the one required." +one isn’t the one required. + +If called with \\[universal-argument] \\[universal-argument] +\\[universal-argument] or EDIT is non-nil, edit the search query +in minibuffer before sending. This is helpful when there is +extra information in the song title which prevents the API from +finding the song." (interactive) (unless track (setq track (funcall lyrics-fetcher-current-track-method))) @@ -196,8 +202,9 @@ one isn’t the one required." ;; and via recursion in asyncronous callbacks, during with ;; `current-prefix-arg' will be unset. So this is necessary ;; to pass the behavior down the recursive calls. - (force-fetch (or force-fetch (member (prefix-numeric-value current-prefix-arg) '(4 16)))) - (sync (or sync (member (prefix-numeric-value current-prefix-arg) '(16))))) + (force-fetch (or force-fetch (member (prefix-numeric-value current-prefix-arg) '(4 16 64)))) + (sync (or sync (member (prefix-numeric-value current-prefix-arg) '(16 64)))) + (edit (or edit (member (prefix-numeric-value current-prefix-arg) '(64))))) (if (and (not force-fetch) (lyrics-fetcher--lyrics-saved-p file-name)) (progn (message "Found fetched lyrics for: %s" song-name) @@ -213,7 +220,8 @@ one isn’t the one required." (lyrics-fetcher--open-lyrics file-name track suppress-switch)) (when callback (funcall callback file-name))) - sync)))) + sync + edit)))) ;;;###autoload (defun lyrics-fetcher-show-lyrics-query (query) @@ -226,18 +234,19 @@ See `lyrics-fetcher-show-lyrics' for behavior." (interactive "sEnter query: ") (lyrics-fetcher-show-lyrics query)) -(cl-defun lyrics-fetcher--fetch-many (tracks &optional &key start force-fetch sync) +(cl-defun lyrics-fetcher--fetch-many (tracks &optional &key start force-fetch sync edit) "Fetch lyrics for every track in the TRACKS list. This function calls itself recursively. START is an indicator of position in the list. -FORCE-FETCH and SYNC are passed to `lyrics-fetcher-show-lyrics'." +FORCE-FETCH, SYNC and EDIT are passed to `lyrics-fetcher-show-lyrics'." (unless start (setq start 0)) (message "Fetching lyrics for %s / %s songs" start (+ start (length tracks))) - (let ((force-fetch (or force-fetch (member (prefix-numeric-value current-prefix-arg) '(4 16)))) - (sync (or sync (member (prefix-numeric-value current-prefix-arg) '(16))))) + (let ((force-fetch (or force-fetch (member (prefix-numeric-value current-prefix-arg) '(4 16 64)))) + (sync (or sync (member (prefix-numeric-value current-prefix-arg) '(16 64)))) + (edit (or edit (member (prefix-numeric-value current-prefix-arg) '(64))))) (unless (seq-empty-p tracks) (lyrics-fetcher-show-lyrics (car tracks) @@ -248,7 +257,8 @@ FORCE-FETCH and SYNC are passed to `lyrics-fetcher-show-lyrics'." (cdr tracks) :start (+ start 1) :force-fetch force-fetch - :sync sync)))))) + :sync sync + :edit edit)))))) ;;; EMMS integration @@ -417,20 +427,21 @@ the same way as `lyrics-fetcher-show-lyrics'." (read-only-mode 1)) ;;; Album cover fetching -(cl-defun lyrics-fetcher--fetch-cover-many (tracks &optional &key start force-fetch sync) +(cl-defun lyrics-fetcher--fetch-cover-many (tracks &optional &key start force-fetch sync edit) "Fetch album covers for every track in the TRACKS list. This functions calls itself recursively. START is an indicator of position in the list. -FORCE-FETCH and SYNC are passed to `lyrics-fetcher--fetch-cover'." +FORCE-FETCH, SYNC and EDIT are passed to `lyrics-fetcher--fetch-cover'." (unless start (setq start 0)) (message "Fetching covers for %s / %s albums" start (+ start (length tracks))) (if (seq-empty-p tracks) (message "Done. Refresh EMMS browser to see the result.") - (let ((force-fetch (or force-fetch (member (prefix-numeric-value current-prefix-arg) '(4 16)))) - (sync (or sync (member (prefix-numeric-value current-prefix-arg) '(16))))) + (let ((force-fetch (or force-fetch (member (prefix-numeric-value current-prefix-arg) '(4 16 64)))) + (sync (or sync (member (prefix-numeric-value current-prefix-arg) '(16 64)))) + (edit (or sync (member (prefix-numeric-value current-prefix-arg) '(64))))) (lyrics-fetcher--fetch-cover (car tracks) :callback @@ -439,11 +450,13 @@ FORCE-FETCH and SYNC are passed to `lyrics-fetcher--fetch-cover'." (cdr tracks) :start (+ start 1) :force-fetch force-fetch - :sync sync)) + :sync sync + :edit edit)) :sync sync - :force-fetch force-fetch)))) + :force-fetch force-fetch + :edit edit)))) -(cl-defun lyrics-fetcher--fetch-cover (track &optional &key callback sync force-fetch) +(cl-defun lyrics-fetcher--fetch-cover (track &optional &key callback sync force-fetch edit) "Fetch cover for a given TRACK. Call CALLBACK with the resulting filename of full cover. @@ -451,7 +464,9 @@ Call CALLBACK with the resulting filename of full cover. If SYNC is non-nil, prompt the user for a matching track. If FORCE-FETCH is non-nil, always fetch regardless of whether the -file exists." +file exists. + +If EDIT is non-nil, edit the query in minibuffer before search." (let ((cover-found (lyrics-fetcher--get-cover-in-directory (f-dirname (cdr (assoc 'name track)))))) (if (and (not force-fetch) cover-found) @@ -468,7 +483,8 @@ file exists." (when callback (funcall callback filename))) (concat (f-dirname (cdr (assoc 'name track))) "/") - sync)))) + sync + edit)))) (defun lyrics-fetcher--get-cover-in-directory (dirname) "Get a path to the large cover file in DIRNAME if one exists."