Compare commits

...

4 Commits

Author SHA1 Message Date
ed12cef7e4 typos fixed 2025-10-16 21:01:42 +02:00
06485fbce7 typo fixed and feature update 2025-10-15 20:38:00 +02:00
214a1cda4c bugfix: playlist list 2025-10-15 15:22:40 +02:00
d13436b963 feat: lyrics support readme and examples 2025-10-15 09:12:02 +02:00
6 changed files with 73 additions and 13 deletions

View File

@@ -12,6 +12,7 @@ Control playback from your terminal while browsing the vast world of music relea
- Handle metadata without touching your audio files - Handle metadata without touching your audio files
- Fast and hackable application with [vim](https://www.vim.org)-like keybindings - Fast and hackable application with [vim](https://www.vim.org)-like keybindings
- Save and load playlists - Save and load playlists
- Lyrics support
🎞️ Screenshot 🎞️ Screenshot
------------- -------------
@@ -19,7 +20,7 @@ Control playback from your terminal while browsing the vast world of music relea
The MusicBrainz database is automatically searched after entering a query. The MusicBrainz database is automatically searched after entering a query.
In the screenshot below, the emoji 🔆 indicates that some tracks of _Mc Solaar_ are available in the local music library. In the screenshot below, the emoji 🔆 indicates that some tracks of _Mc Solaar_ are available in the local music library.
They are played by hitting `<enter>`. They are played by hitting `<enter>`.
![MusicBrainz artist search](//screenshots/search.png) ![MusicBrainz artist search](./screenshots/search.png)
### Browse Local Music Library ### Browse Local Music Library
Here, we fuzzily search an album of _Daft Punk._ Here, we fuzzily search an album of _Daft Punk._
@@ -119,7 +120,7 @@ $ fuzic --decorate ~/Music/Daft\ Punk/Random\ Access\ Memories
Info: Decorating /home/amin/Music/Daft Punk/Random Access Memories as release 5000a285-b67e-4cfc-b54b-2b98f1810d2e Info: Decorating /home/amin/Music/Daft Punk/Random Access Memories as release 5000a285-b67e-4cfc-b54b-2b98f1810d2e
$ fuzic --decorate-as ~/Music/Mc\ Solaar/Prose\ Combat 69e5cf67-7cea-4fe8-9129-9779f0a93d69 $ fuzic --decorate-as ~/Music/Mc\ Solaar/Prose\ Combat 69e5cf67-7cea-4fe8-9129-9779f0a93d69
Info: Decorating /home/amin/Music/Mc Solaar/Prose Combat as the release Prose Combat by MC Solaar Info: Decorating /home/amin/Music/Mc Solaar/Prose Combat as the release Prose Combat by MC Solaar
Info: We discovered the following associatoin: Info: We discovered the following association:
Track 'Aubade' File './01 Aubade.m4a' Track 'Aubade' File './01 Aubade.m4a'
Track 'Obsolète' File './02 Obsolète.m4a' Track 'Obsolète' File './02 Obsolète.m4a'
Track 'Nouveau western' File './03 Nouveau western.m4a' Track 'Nouveau western' File './03 Nouveau western.m4a'
@@ -176,6 +177,28 @@ You may also define the playlist directory using the `PLAYLIST_DIRECTORY` enviro
In `share/playlists` you find example playlists. In `share/playlists` you find example playlists.
Thus, the command `PLAYLIST_DIRECTORY=share/playlists fuzic` launches this application with access to these example playlists. Thus, the command `PLAYLIST_DIRECTORY=share/playlists fuzic` launches this application with access to these example playlists.
📜 Lyrics
---------
By using the key `L` (normal mode), the lyrics of the selected track are displayed.
The lyrics are taken from (in that order)
1. the lyrics stored using `fuzic`, or
2. from the `.lrc` file with the same name as the audio file, or
3. from the audio-file tags (requires `ffprobe`), or
4. from a custom script.
To specify the custom script, you can set the `LYRICS_FETCH_CUSTOM` environment variable to point to an executable.
The executable reads a JSON string on the standard input, and is supposed to print the lyrics (see `share/lyrics/example.sh`).
You may also skip the first three sources and directly make a call to your custom script by using the key `Y` (normal mode).
The key `alt-L` opens the lyrics in a new window using the `EDITOR`.
This requires one of the following terminal emulators (`kitty`, `x-terminal-emulator`, `gnome-terminal`, `xterm`).
If you use another terminal emulator, you may specify the environment variable `EXTERNALEDIT` to hold the string such that
```sh
$ExTERNALEDIT "$file"
```
spawns a text editor with `$file` loaded inside a terminal emulator.
🧭 Planned Features 🧭 Planned Features
------------------- -------------------
The following features are planned: The following features are planned:

25
share/lyrics/example.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/sh
# Example script for `fuzic` to display the lyrics of a track. This script
# reads from stdin a JSON string and stores it in the variable `j`. The
# variable `tj` contains the JSON string of the track.
j="$(cat)"
tj="$(echo "$j" | jq -r '.trackid as $tid | .release.media[].tracks[] | select(.id == $tid)')"
# The following four variables are self-explanatory:
track_name="$(echo "$tj" | jq -r '.title')"
artist_name="$(echo "$tj" | jq -r '."artist-credit" | map([.name, .joinphrase] | join("")) | join("")')"
album_name="$(echo "$j" | jq -r '.release.title')"
duration="$(echo "$tj" | jq -r '.length / 1000 | round')"
# Now, you may call an API to fetch the lyrics for this track,
#
# curl \
# --get \
# --silent \
# --data-urlencode "track_name=$track_name" \
# --data-urlencode "artist_name=$artist_name" \
# --data-urlencode "album_name=$album_name" \
# --data-urlencode "duration=$duration" \
# "$URL"
#
# or simply print a template to write the lyrics yourself:
printf "Lyrics '%s' by '%s' (album: %s, duration: %s seconds)\n" "$track_name" "$artist_name" "$album_name" "$duration"

View File

@@ -443,7 +443,7 @@ case "${1:-}" in
;; ;;
"--playlists") "--playlists")
# List available playlists # List available playlists
stored_playlists stored_playlists | cut -d "$(printf '\t')" -f 1
exit 0 exit 0
;; ;;
"--print-playlist") "--print-playlist")
@@ -474,7 +474,7 @@ GENERAL OPTIONS:
--playlists List stored playlists and exit --playlists List stored playlists and exit
--load-playlist <playlist> Load specified playlist --load-playlist <playlist> Load specified playlist
--print-playlist <playlist> Print specified playlist and exit --print-playlist <playlist> Print specified playlist and exit
--lyrics <release> <mbid> Show lyrics specified track and exit --lyrics <relid> <mbid> Show lyrics of track <mbid> in release <relid> and exit
MANAGE LOCAL MUSIC: MANAGE LOCAL MUSIC:
--decorate <path> Decorate directory containing a tagged release --decorate <path> Decorate directory containing a tagged release

View File

@@ -157,7 +157,7 @@ END { for (i in id) print title[i], id[i], fname[i] }
' "$tmpj" "$tmpf" >"$assocfile" ' "$tmpj" "$tmpf" >"$assocfile"
rm -f "$tmpj" "$tmpf" rm -f "$tmpj" "$tmpf"
# Ask user if this is ok # Ask user if this is ok
info "We discovered the following associatoin:" info "We discovered the following association:"
while IFS= read -r line; do while IFS= read -r line; do
t="$(echo "$line" | cut -d "$(printf '\t')" -f 1)" t="$(echo "$line" | cut -d "$(printf '\t')" -f 1)"
f="$(echo "$line" | cut -d "$(printf '\t')" -f 3)" f="$(echo "$line" | cut -d "$(printf '\t')" -f 3)"

View File

@@ -17,10 +17,9 @@ if [ ! "${LYRICS_LOADED:-}" ]; then
# Custom command to fetch lyrics # Custom command to fetch lyrics
# #
# This command reads from stdin the json object of the track and prints the # This command reads from stdin the json object of the release and prints the
# lyrics. # lyrics of the track.
LYRICS_FETCH_CUSTOM="${LYRICS_FETCH_CUSTOM:-"$JQ '.trackid as \$tid | .release.media[].tracks[] | select(.id == \$tid) | .title'"}" LYRICS_FETCH_CUSTOM="${LYRICS_FETCH_CUSTOM:-""}"
#LYRICS_FETCH_CUSTOM="${LYRICS_FETCH_CUSTOM:-"$JQ '.trackid as \$trid | \"Lyrics for \" + .media[].tracks[] | select(.id == \$trid) | .title'"}"
export LYRICS_FETCH_CUSTOM export LYRICS_FETCH_CUSTOM
export LYRICS_LOADED=1 export LYRICS_LOADED=1
@@ -51,13 +50,21 @@ store_lyrics() {
# #
# @argument $1: MusicBrainz release ID # @argument $1: MusicBrainz release ID
# @argument $2: MusicBrainz track ID # @argument $2: MusicBrainz track ID
#
# The custom script is executed only if the environment variable is set. Else
# the message stored in `$LYRICS_NO_LYRICS` is saved.
store_lyrics_custom() { store_lyrics_custom() {
rlid="${1:-}" rlid="${1:-}"
mbid="${2:-}" mbid="${2:-}"
mb_release "$rlid" | if [ "$LYRICS_FETCH_CUSTOM" ]; then
$JQ --arg mbid "$mbid" '{release: ., trackid: $mbid}' | mb_release "$rlid" |
sh -c "$LYRICS_FETCH_CUSTOM" | $JQ --arg mbid "$mbid" '{release: ., trackid: $mbid}' |
store_lyrics "$mbid" sh -c "$LYRICS_FETCH_CUSTOM" |
store_lyrics "$mbid"
else
echo "$LYRICS_NO_LYRICS" |
store_lyrics "$mbid"
fi
} }
# Print lyrics # Print lyrics

View File

@@ -399,5 +399,10 @@ if [ ! "${THEME_LOADED:-}" ]; then
PLYSTORE_PLAYLIST="${PLYSTORE_PLAYLIST:-"🎼 ${CPURPLE}%f${OFF}"}" PLYSTORE_PLAYLIST="${PLYSTORE_PLAYLIST:-"🎼 ${CPURPLE}%f${OFF}"}"
export TITLE_PLYLST TITLE_PLYLST_STORE PLYSTORE_PLAYLIST export TITLE_PLYLST TITLE_PLYLST_STORE PLYSTORE_PLAYLIST
# Lyrics
# ======
LYRICS_NO_LYRICS="${LYRICS_NO_LYRICS:-"(no lyrics)"}"
export LYRICS_NO_LYRICS
export THEME_LOADED=1 export THEME_LOADED=1
fi fi