feat: playlist store
This commit is contained in:
15
README.md
15
README.md
@@ -11,6 +11,7 @@ Control playback from your terminal while browsing the vast world of music relea
|
||||
- Search the MusicBrainz database and discover music artists and releases
|
||||
- Handle metadata without touching your audio files
|
||||
- Fast and hackable application with [vim](https://www.vim.org)-like keybindings
|
||||
- Save and load playlists
|
||||
|
||||
🎞️ Screenshot
|
||||
-------------
|
||||
@@ -86,6 +87,8 @@ GENERAL OPTIONS:
|
||||
--artist <mbid> List release groups of given artist <mbid>
|
||||
--releasegroup <mbid> List releases in given release group <mbid>
|
||||
--release <mbid> Show release given by <mbid>
|
||||
--playlists List stored playlists and exit
|
||||
--load-playlist <playlist> Load specified playlist
|
||||
|
||||
MANAGE LOCAL MUSIC:
|
||||
--decorate <path> Decorate directory containing a tagged release
|
||||
@@ -157,10 +160,20 @@ In the insert mode, triggered using `i`, `a`, or `/`, the keys directly modify t
|
||||
|
||||
Some central keys are `<enter>` to start playback of the selected entry, `<space>` to pause playback, and `ctrl-p` to open the currently loaded playlist.
|
||||
|
||||
📝 Playlist Store
|
||||
-----------------
|
||||
Playlists can be saved, loaded and _shared._
|
||||
To save a playlist, simply press `ctrl-s` when viewing your playlist.
|
||||
To load a playlist, open the playlist store using `ctrl-o` while viewing your playlist.
|
||||
Alternatively, you may start `fuzic` using the command-line parameters `fuzic --load-playlist <playlist>`.
|
||||
Under the hood, a playlist is not more than a sequence of MusicBrainz IDs.
|
||||
This means that `fuzic` users may share their playlists irrespective of the audio file locations and formats.
|
||||
Possibly even more importantly, this means that you can preserve your playlist even if you reorganize your local music library:
|
||||
You can safely share your playlists with your future self.
|
||||
|
||||
🧭 Planned Features
|
||||
-------------------
|
||||
The following features are planned:
|
||||
- saving and loading playlists
|
||||
- cover art and artist images
|
||||
- lyrics support
|
||||
- showing current position in track
|
||||
|
||||
@@ -66,7 +66,7 @@ BEGIN {
|
||||
ds = dur % 60
|
||||
if (ds <= 9)
|
||||
ds = "0"ds
|
||||
if (dh && dm <=9)
|
||||
if (dh && dm <= 9)
|
||||
dm = "0"dm
|
||||
dur = dh ? dh":"dm":"ds : dm":"ds
|
||||
} else {
|
||||
|
||||
97
src/main.sh
97
src/main.sh
@@ -36,6 +36,8 @@ VIEW_LIST_ARTISTS="list-artists"
|
||||
VIEW_LIST_ALBUMS="list-albums"
|
||||
VIEW_SELECT_ARTIST="select-artist"
|
||||
VIEW_PLAYLIST="playlist"
|
||||
VIEW_PLAYLIST_PLAYLISTSTORE="playlist-list"
|
||||
VIEW_PLAYLIST_STORE="playlist-store"
|
||||
VIEW_QUIT="quit"
|
||||
MODE_NORMAL="hidden"
|
||||
MODE_INSERT="show"
|
||||
@@ -50,21 +52,24 @@ MODE_INSERT="show"
|
||||
# Load configuration
|
||||
. "sh/config.sh"
|
||||
|
||||
# Load mpv methods
|
||||
. "sh/mpv.sh"
|
||||
|
||||
# Load query methods
|
||||
. "sh/query.sh"
|
||||
|
||||
# Load playback helper
|
||||
. "sh/playback.sh"
|
||||
# Load local file handling
|
||||
. "sh/local.sh"
|
||||
|
||||
# Load playlist tools
|
||||
. "sh/playlist.sh"
|
||||
|
||||
# Load playback helper
|
||||
. "sh/playback.sh"
|
||||
|
||||
# Load MusicBrainz, Discogs, and wiki methods
|
||||
. "sh/api.sh"
|
||||
|
||||
# Load mpv methods
|
||||
. "sh/mpv.sh"
|
||||
|
||||
# Load preview methods
|
||||
. "sh/preview.sh"
|
||||
|
||||
@@ -74,9 +79,6 @@ MODE_INSERT="show"
|
||||
# Load MusicBrainz wrappers
|
||||
. "sh/mb.sh"
|
||||
|
||||
# Load local file handling
|
||||
. "sh/local.sh"
|
||||
|
||||
# Load list-generating methods
|
||||
. "sh/lists.sh"
|
||||
|
||||
@@ -419,6 +421,11 @@ case "${1:-}" in
|
||||
info "Done"
|
||||
exit 0
|
||||
;;
|
||||
"--playlists")
|
||||
# List available playlists
|
||||
stored_playlists
|
||||
exit 0
|
||||
;;
|
||||
"--help")
|
||||
# Print help string
|
||||
cat <<EOF
|
||||
@@ -433,6 +440,8 @@ GENERAL OPTIONS:
|
||||
--artist <mbid> List release groups of given artist <mbid>
|
||||
--releasegroup <mbid> List releases in given release group <mbid>
|
||||
--release <mbid> Show release given by <mbid>
|
||||
--playlists List stored playlists and exit
|
||||
--load-playlist <playlist> Load specified playlist
|
||||
|
||||
MANAGE LOCAL MUSIC:
|
||||
--decorate <path> Decorate directory containing a tagged release
|
||||
@@ -485,12 +494,22 @@ case "${1:-}" in
|
||||
MODE="$MODE_NORMAL"
|
||||
MBID=""
|
||||
;;
|
||||
"--load-playlist")
|
||||
# We will load and play later
|
||||
VIEW="$VIEW_PLAYLIST"
|
||||
MODE="$MODE_NORMAL"
|
||||
MBID=""
|
||||
;;
|
||||
*)
|
||||
err "Unknown option $1 (see --help)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# For history purpose: previous view is always:
|
||||
LASTVIEW="$VIEW_LIST_ARTISTS"
|
||||
LASTARG=""
|
||||
|
||||
# Start application:
|
||||
# - set title
|
||||
# - check for missing data from MusicBrainz
|
||||
@@ -521,6 +540,9 @@ export LOCKFILE RESULTS PIDFILE
|
||||
# Start mpv
|
||||
mpv_start
|
||||
|
||||
# Playback possible now
|
||||
[ "${1:-}" = "--load-playlist" ] && $0 --playlist "$PLAYLIST_CMD_LOAD" "${2:-}"
|
||||
|
||||
# main loop
|
||||
# states are stored in (in)visible labels
|
||||
#
|
||||
@@ -594,6 +616,63 @@ while true; do
|
||||
LASTVIEW="$VIEW_SELECT_ARTIST"
|
||||
LASTARG="$ARGS"
|
||||
;;
|
||||
"$VIEW_PLAYLIST_STORE")
|
||||
VIEW="$VIEW_PLAYLIST"
|
||||
ARGS=""
|
||||
MBID=""
|
||||
tmpf=$(mktemp)
|
||||
list_playlist | cut -d "$(printf '\t')" -f "3,4" >"$tmpf"
|
||||
# Make sure we store only nonempty playlists
|
||||
[ -s "$tmpf" ] || continue
|
||||
while true; do
|
||||
infonn "Enter playlist name:"
|
||||
read -r playlistname
|
||||
[ "$playlistname" ] || continue
|
||||
case "$playlistname" in
|
||||
*[!a-zA-Z0-9._-]*)
|
||||
info "Please use only alaphnumeric symbols and any of \".-_\" for the playlist name."
|
||||
;;
|
||||
*)
|
||||
f="$PLAYLIST_DIRECTORY/$playlistname"
|
||||
if [ -s "$f" ]; then
|
||||
while true; do
|
||||
infonn "Playlist with name \"$playlistname\" already exists. Do you want to overwrite it? (yes/no)"
|
||||
read -r yn
|
||||
case $yn in
|
||||
"yes" | "no") break ;;
|
||||
*) info "Please answer \"yes\" or \"no\"." ;;
|
||||
esac
|
||||
done
|
||||
[ "$yn" = "yes" ] || continue
|
||||
fi
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
mv "$tmpf" "$f"
|
||||
;;
|
||||
"$VIEW_PLAYLIST_PLAYLISTSTORE")
|
||||
sel=$(
|
||||
stored_playlists | $FZF \
|
||||
--border=double \
|
||||
--border-label="$TITLE_PLYLST_LIST" \
|
||||
--margin="2%,10%" \
|
||||
--bind="$KEYS_I_NORMAL:" \
|
||||
--bind="$KEYS_DOWN:down" \
|
||||
--bind="$KEYS_UP:up" \
|
||||
--bind="$KEYS_HALFPAGE_DOWN:half-page-down" \
|
||||
--bind="$KEYS_HALFPAGE_UP:half-page-up" \
|
||||
--bind="$KEYS_OUT,$KEYS_QUIT:accept" \
|
||||
--bind="$KEYS_KEYBINDINGS:preview:$0 --show-keybindings $VIEW_PLAYLIST_PLAYLISTSTORE" \
|
||||
--bind="$KEYS_SCROLL_PREVIEW_DOWN:preview-down" \
|
||||
--bind="$KEYS_SCROLL_PREVIEW_UP:preview-up" \
|
||||
--bind="$KEYS_PREVIEW_CLOSE:hide-preview" \
|
||||
--bind="$KEYS_PLAYLISTSTORE_SELECT:transform:[ {1} ] && $0 --playlist $PLAYLIST_CMD_LOAD {1} && echo accept" \
|
||||
--bind="$KEYS_PLAYLISTSTORE_DELETE:transform:[ {1} ] && rm \"$PLAYLIST_DIRECTORY/{r1}\" && echo \"reload($0 --playlists\)\"" \
|
||||
--wrap-sign="" || true
|
||||
)
|
||||
VIEW="$VIEW_PLAYLIST"
|
||||
;;
|
||||
"$VIEW_PLAYLIST")
|
||||
sel=$(
|
||||
list_playlist | $FZF \
|
||||
@@ -637,6 +716,8 @@ while true; do
|
||||
--bind="$KEYS_PLAYLIST_SHUFFLE:execute-silent($0 --playlist $PLAYLIST_CMD_SHUFFLE)+$FZF_RELOAD_PLAYLIST" \
|
||||
--bind="$KEYS_PLAYLIST_UNSHUFFLE:execute-silent($0 --playlist $PLAYLIST_CMD_UNSHUFFLE)+$FZF_RELOAD_PLAYLIST" \
|
||||
--bind="$KEYS_PLAYLIST_GOTO_RELEASE:print($VIEW_RELEASE)+accept" \
|
||||
--bind="$KEYS_PLAYLIST_STORE:print($VIEW_PLAYLIST_STORE)+print("")+print($LASTVIEW)+print($LASTARG)+accept" \
|
||||
--bind="$KEYS_PLAYLIST_OPEN_STORE:print($VIEW_PLAYLIST_PLAYLISTSTORE)+print("")+print($LASTVIEW)+print($LASTARG)+accept" \
|
||||
--preview-window="hidden" \
|
||||
--wrap-sign="" \
|
||||
--delimiter="\t" \
|
||||
|
||||
@@ -87,7 +87,10 @@
|
||||
# - KEYS_PLAYLIST_GOTO_RELEASE: Jump to release or selected entry
|
||||
# - KEYS_PLAYLIST_STORE: Store current playlist as file
|
||||
# - KEYS_PLAYLIST_LOAD: Load playlist from file
|
||||
# - KEYS_PLAYLIST_QUIT: Quit playlist view
|
||||
#
|
||||
# Playlist store (here, we don't have a `normal` mode):
|
||||
# - KEYS_PLAYLISTSTORE_SELECT: Use selected playlist
|
||||
# - KEYS_PLAYLISTSTORE_DELETE: Delete stored playlist
|
||||
|
||||
if [ ! "${KEYS_LOADED:-}" ]; then
|
||||
# Mode selection:
|
||||
@@ -199,11 +202,17 @@ if [ ! "${KEYS_LOADED:-}" ]; then
|
||||
KEYS_PLAYLIST_UNSHUFFLE="${KEYS_PLAYLIST_UNSHUFFLE:-"S"}"
|
||||
KEYS_PLAYLIST_GOTO_RELEASE="${KEYS_PLAYLIST_GOTO_RELEASE:-"ctrl-g"}"
|
||||
KEYS_PLAYLIST_STORE="${KEYS_PLAYLIST_STORE:-"ctrl-s"}"
|
||||
KEYS_PLAYLIST_LOAD="${KEYS_PLAYLIST_LOAD:-"ctrl-o"}"
|
||||
KEYS_PLAYLIST_OPEN_STORE="${KEYS_PLAYLIST_LOAD:-"ctrl-o"}"
|
||||
KEYS_PLAYLIST_DELETE="${KEYS_PLAYLIST_DELETE:-"del"}"
|
||||
export KEYS_PLAYLIST_RELOAD KEYS_PLAYLIST_REMOVE KEYS_PLAYLIST_UP \
|
||||
KEYS_PLAYLIST_DOWN KEYS_PLAYLIST_CLEAR KEYS_PLAYLIST_CLEAR_ABOVE \
|
||||
KEYS_PLAYLIST_CLEAR_BELOW KEYS_PLAYLIST_SHUFFLE KEYS_PLAYLIST_UNSHUFFLE \
|
||||
KEYS_PLAYLIST_GOTO_RELEASE KEYS_PLAYLIST_STORE KEYS_PLAYLIST_LOAD
|
||||
KEYS_PLAYLIST_GOTO_RELEASE KEYS_PLAYLIST_STORE KEYS_PLAYLIST_OPEN_STORE
|
||||
|
||||
# Playlist store (here, we don't have a `normal` mode):
|
||||
KEYS_PLAYLISTSTORE_SELECT="${KEYS_PLAYLISTSTORE_SELECT:-"enter"}"
|
||||
KEYS_PLAYLISTSTORE_DELETE="${KEYS_PLAYLISTSTORE_DELETE:-"del"}"
|
||||
export KEYS_PLAYLISTSTORE_SELECT KEYS_PLAYLISTSTORE_DELETE
|
||||
|
||||
export KEYS_LOADED=1
|
||||
fi
|
||||
@@ -297,7 +306,8 @@ print_keybindings() {
|
||||
"$KEYS_PLAYLIST_CLEAR_ABOVE" "Remove all tracks above" \
|
||||
"$KEYS_PLAYLIST_CLEAR_BELOW" "Remove all tracks below" \
|
||||
"$KEYS_PLAYLIST_SHUFFLE" "Shuffle" \
|
||||
"$KEYS_PLAYLIST_UNSHUFFLE" "Undo shuffle"
|
||||
"$KEYS_PLAYLIST_UNSHUFFLE" "Undo shuffle" \
|
||||
"$KEYS_PLAYLIST_OPEN_STORE" "Manage stored playlists"
|
||||
__keybindinggroup_from_args "Playback" \
|
||||
"$KEYS_PLAY,$KEYS_N_PLAY" "Play selected item" \
|
||||
"$KEYS_QUEUE,$KEYS_N_QUEUE" "Queue selected item" \
|
||||
@@ -313,6 +323,22 @@ print_keybindings() {
|
||||
"$KEYS_N_YANK" "Copy MusicBrainz track ID" \
|
||||
"$KEYS_YANK_CURRENT" "Copy MusicBrainz release ID"
|
||||
;;
|
||||
"$VIEW_PLAYLIST_PLAYLISTSTORE")
|
||||
__keybindinggroup_from_args "Previews" \
|
||||
"$KEYS_SCROLL_PREVIEW_DOWN" "Scroll preview down" \
|
||||
"$KEYS_SCROLL_PREVIEW_UP" "Scroll preview up" \
|
||||
"$KEYS_KEYBINDINGS" "Show these keybindings" \
|
||||
"$KEYS_PREVIEW_CLOSE" "Close preview window"
|
||||
__keybindinggroup_from_args "Navigation" \
|
||||
"$KEYS_DOWN" "Down" \
|
||||
"$KEYS_UP" "Up" \
|
||||
"$KEYS_HALFPAGE_DOWN" "Down half a page" \
|
||||
"$KEYS_HALFPAGE_UP" "Up half a page" \
|
||||
"$KEYS_OUT,$KEYS_QUIT" "Leave playlist store"
|
||||
__keybindinggroup_from_args "Playlist store" \
|
||||
"$KEYS_PLAYLISTSTORE_SELECT" "Load playlist" \
|
||||
"$KEYS_PLAYLISTSTORE_DELETE" "Delete playlist"
|
||||
;;
|
||||
*)
|
||||
__keybindinggroup_from_args "Switch between modes" \
|
||||
"$KEYS_I_NORMAL" "Swtich to normal mode (insert)" \
|
||||
|
||||
@@ -43,51 +43,6 @@ __playback_cmd_from_key() {
|
||||
case ",$KEYS_N_SEEK_BACKWARD," in *",$key,"*) echo "$PLAYBACK_CMD_SEEK_BACKWARD" && return ;; esac
|
||||
}
|
||||
|
||||
# Generate playlist from MB release ID and path to decoration
|
||||
#
|
||||
# @argument $1: MusicBrainz release ID
|
||||
# @argument $2: Path to decoration file
|
||||
# @argument $3: MusicBrainz track ID to select (optional)
|
||||
__generate_playlist() {
|
||||
printf "#EXTM3U\n"
|
||||
dir="$(dirname "$2")"
|
||||
mb_release "$1" |
|
||||
$JQ \
|
||||
--slurpfile decofile "$2" \
|
||||
--arg base "$dir" \
|
||||
--arg deco "$2" \
|
||||
--arg tid "${3:-}" \
|
||||
'$decofile[].tracks as $filenames |
|
||||
. |
|
||||
.id as $rid |
|
||||
.media |
|
||||
length as $l |
|
||||
.[] |
|
||||
.position as $pos |
|
||||
.tracks |
|
||||
if ($tid == "") then . else map(select(.id == $tid)) end |
|
||||
map({
|
||||
t: [
|
||||
$rid,
|
||||
.id,
|
||||
$l,
|
||||
$pos,
|
||||
.number,
|
||||
.length,
|
||||
.title,
|
||||
(."artist-credit" | map([.name, .joinphrase] | join("")) | join("")),
|
||||
$deco
|
||||
] | join("\t"),
|
||||
length: (.length // 0 / 1000 | round | tostring),
|
||||
$pos,
|
||||
number: .number,
|
||||
file: $filenames[.id]
|
||||
}) |
|
||||
map(if(.number | type == "string" and test("^[0-9]+$")) then .number |= tonumber else . end) |
|
||||
sort_by([.pos, .number]) |
|
||||
map("#EXTINF:" + .length + "," + .t + "\n" + $base + "/" + .file)[]'
|
||||
}
|
||||
|
||||
# Main playback method
|
||||
#
|
||||
# @argument $1: view
|
||||
@@ -122,10 +77,10 @@ playback() {
|
||||
rpath="$(echo "$line" | cut -d "$(printf '\t')" -f 5)"
|
||||
[ "$rpath" ] || continue
|
||||
if [ ! "$queue" ]; then
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_play_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_play_list >/dev/null
|
||||
queue=1
|
||||
else
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
fi
|
||||
done
|
||||
queue=1
|
||||
@@ -138,15 +93,15 @@ playback() {
|
||||
rpath="$(echo "$line" | cut -d "$(printf '\t')" -f 5)"
|
||||
[ "$rpath" ] || continue
|
||||
if [ ! "${queue:-}" ]; then
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_play_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_play_list >/dev/null
|
||||
queue=1
|
||||
else
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
fi
|
||||
done
|
||||
;;
|
||||
"$VIEW_RELEASEGROUP") __generate_playlist "$mbid" "$path" | mpv_play_list >/dev/null ;;
|
||||
"$VIEW_RELEASE") __generate_playlist "$mbid_current" "$path" "$mbid" | mpv_play_list >/dev/null ;;
|
||||
"$VIEW_RELEASEGROUP") generate_playlist "$mbid" "$path" | mpv_play_list >/dev/null ;;
|
||||
"$VIEW_RELEASE") generate_playlist "$mbid_current" "$path" "$mbid" | mpv_play_list >/dev/null ;;
|
||||
"$VIEW_PLAYLIST") mpv_play_index $((FZF_POS - 1)) >/dev/null ;;
|
||||
esac
|
||||
;;
|
||||
@@ -164,7 +119,7 @@ playback() {
|
||||
rmbid="$(echo "$line" | cut -d "$(printf '\t')" -f 4)"
|
||||
rpath="$(echo "$line" | cut -d "$(printf '\t')" -f 5)"
|
||||
[ "$rpath" ] || continue
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
done
|
||||
done
|
||||
;;
|
||||
@@ -174,12 +129,12 @@ playback() {
|
||||
rmbid="$(echo "$line" | cut -d "$(printf '\t')" -f 4)"
|
||||
rpath="$(echo "$line" | cut -d "$(printf '\t')" -f 5)"
|
||||
[ "$rpath" ] || continue
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_queue_list >/dev/null
|
||||
done
|
||||
;;
|
||||
"$VIEW_RELEASEGROUP") __generate_playlist "$mbid" "$path" | mpv_queue_list >/dev/null ;;
|
||||
"$VIEW_RELEASE") __generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_list >/dev/null ;;
|
||||
"$VIEW_PLAYLIST") __generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_list >/dev/null ;;
|
||||
"$VIEW_RELEASEGROUP") generate_playlist "$mbid" "$path" | mpv_queue_list >/dev/null ;;
|
||||
"$VIEW_RELEASE") generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_list >/dev/null ;;
|
||||
"$VIEW_PLAYLIST") generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_list >/dev/null ;;
|
||||
esac
|
||||
;;
|
||||
"$PLAYBACK_CMD_QUEUE_NEXT")
|
||||
@@ -196,7 +151,7 @@ playback() {
|
||||
rmbid="$(echo "$line" | cut -d "$(printf '\t')" -f 4)"
|
||||
rpath="$(echo "$line" | cut -d "$(printf '\t')" -f 5)"
|
||||
[ "$rpath" ] || continue
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_queue_next_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_queue_next_list >/dev/null
|
||||
done
|
||||
done
|
||||
;;
|
||||
@@ -206,12 +161,12 @@ playback() {
|
||||
rmbid="$(echo "$line" | cut -d "$(printf '\t')" -f 4)"
|
||||
rpath="$(echo "$line" | cut -d "$(printf '\t')" -f 5)"
|
||||
[ "$rpath" ] || continue
|
||||
__generate_playlist "$rmbid" "$rpath" | mpv_queue_next_list >/dev/null
|
||||
generate_playlist "$rmbid" "$rpath" | mpv_queue_next_list >/dev/null
|
||||
done
|
||||
;;
|
||||
"$VIEW_RELEASEGROUP") __generate_playlist "$mbid" "$path" | mpv_queue_next_list >/dev/null ;;
|
||||
"$VIEW_RELEASE") __generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_next_list >/dev/null ;;
|
||||
"$VIEW_PLAYLIST") __generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_next_list >/dev/null ;;
|
||||
"$VIEW_RELEASEGROUP") generate_playlist "$mbid" "$path" | mpv_queue_next_list >/dev/null ;;
|
||||
"$VIEW_RELEASE") generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_next_list >/dev/null ;;
|
||||
"$VIEW_PLAYLIST") generate_playlist "$mbid_current" "$path" "$mbid" | mpv_queue_next_list >/dev/null ;;
|
||||
esac
|
||||
;;
|
||||
"$PLAYBACK_CMD_TOGGLE_PLAYBACK") mpv_toggle_pause ;;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# This files provides an interface to manipulate the playlist. The available
|
||||
# commands are defined in the following variables.
|
||||
if [ ! "${PLAYLIST_LOADED:-}" ]; then
|
||||
# Playlist commands
|
||||
PLAYLIST_CMD_REMOVE="rm"
|
||||
PLAYLIST_CMD_UP="up"
|
||||
PLAYLIST_CMD_DOWN="down"
|
||||
@@ -11,13 +12,101 @@ if [ ! "${PLAYLIST_LOADED:-}" ]; then
|
||||
PLAYLIST_CMD_CLEAR_BELOW="clear-below"
|
||||
PLAYLIST_CMD_SHUFFLE="shuffle"
|
||||
PLAYLIST_CMD_UNSHUFFLE="unshuffle"
|
||||
PLAYLIST_CMD_LOAD="load"
|
||||
export PLAYLIST_CMD_REMOVE PLAYLIST_CMD_UP PLAYLIST_CMD_DOWN \
|
||||
PLAYLIST_CMD_CLEAR PLAYLIST_CMD_CLEAR_ABOVE PLAYLIST_CMD_CLEAR_BELOW \
|
||||
PLAYLIST_CMD_SHUFFLE PLAYLIST_CMD_UNSHUFFLE
|
||||
PLAYLIST_CMD_SHUFFLE PLAYLIST_CMD_UNSHUFFLE PLAYLIST_CMD_LOAD
|
||||
|
||||
# Storage and loading of playlists
|
||||
PLAYLIST_DIRECTORY="$LOCALDATADIR/playlists"
|
||||
[ -d "$PLAYLIST_DIRECTORY" ] || mkdir -p "$PLAYLIST_DIRECTORY"
|
||||
export PLAYLIST_DIRECTORY
|
||||
|
||||
export PLAYLIST_LOADED=1
|
||||
fi
|
||||
|
||||
# List stored playlists
|
||||
#
|
||||
# This prints the names of the stored playlists.
|
||||
stored_playlists() {
|
||||
find "$PLAYLIST_DIRECTORY" -mindepth 1 -maxdepth 1 -type f -printf '%f\n' |
|
||||
sort
|
||||
}
|
||||
|
||||
# Generate playlist from MB release ID and path to decoration
|
||||
#
|
||||
# @argument $1: MusicBrainz release ID
|
||||
# @argument $2: Path to decoration file
|
||||
# @argument $3: MusicBrainz track ID to select (optional)
|
||||
generate_playlist() {
|
||||
printf "#EXTM3U\n"
|
||||
dir="$(dirname "$2")"
|
||||
mb_release "$1" |
|
||||
$JQ \
|
||||
--slurpfile decofile "$2" \
|
||||
--arg base "$dir" \
|
||||
--arg deco "$2" \
|
||||
--arg tid "${3:-}" \
|
||||
'$decofile[].tracks as $filenames |
|
||||
. |
|
||||
.id as $rid |
|
||||
.media |
|
||||
length as $l |
|
||||
.[] |
|
||||
.position as $pos |
|
||||
.tracks |
|
||||
if ($tid == "") then . else map(select(.id == $tid)) end |
|
||||
map({
|
||||
t: [
|
||||
$rid,
|
||||
.id,
|
||||
$l,
|
||||
$pos,
|
||||
.number,
|
||||
.length,
|
||||
.title,
|
||||
(."artist-credit" | map([.name, .joinphrase] | join("")) | join("")),
|
||||
$deco
|
||||
] | join("\t"),
|
||||
length: (.length // 0 / 1000 | round | tostring),
|
||||
$pos,
|
||||
number: .number,
|
||||
file: $filenames[.id]
|
||||
}) |
|
||||
map(if(.number | type == "string" and test("^[0-9]+$")) then .number |= tonumber else . end) |
|
||||
sort_by([.pos, .number]) |
|
||||
map("#EXTINF:" + .length + "," + .t + "\n" + $base + "/" + .file)[]'
|
||||
}
|
||||
|
||||
# Generate playlist content from stored playlist
|
||||
#
|
||||
# @argument $1: Playlist file
|
||||
generate_playlist_stored() {
|
||||
f="${1:-}"
|
||||
[ -s "$f" ] || return
|
||||
tab="$(printf '\t')"
|
||||
PLAYLISTSTART="#EXTM3U"
|
||||
printf "%s\n" "$PLAYLISTSTART"
|
||||
awk -F '\t' \
|
||||
-v rfile="$LOCALDATA_RELEASES" \
|
||||
'BEGIN {
|
||||
OFS="\t"
|
||||
while ((getline < rfile) == 1)
|
||||
release[$1] = $2
|
||||
close(rfile)
|
||||
}
|
||||
{
|
||||
if (release[$1])
|
||||
print $1, release[$1], $2
|
||||
}' <"$f" |
|
||||
while IFS= read -r line; do
|
||||
rid=$(echo "$line" | cut -d "$tab" -f 1)
|
||||
path=$(echo "$line" | cut -d "$tab" -f 2)
|
||||
tid=$(echo "$line" | cut -d "$tab" -f 3)
|
||||
generate_playlist "$rid" "$path" "$tid"
|
||||
done | grep -v "^$PLAYLISTSTART$"
|
||||
}
|
||||
|
||||
# Run playback commands
|
||||
#
|
||||
# @argument $1: playlist command
|
||||
@@ -43,5 +132,10 @@ playlist() {
|
||||
;;
|
||||
"$PLAYLIST_CMD_SHUFFLE") mpv_playlist_shuffle ;;
|
||||
"$PLAYLIST_CMD_UNSHUFFLE") mpv_playlist_unshuffle ;;
|
||||
"$PLAYLIST_CMD_LOAD")
|
||||
f="$PLAYLIST_DIRECTORY/${2:-}"
|
||||
[ -s "$f" ] || return
|
||||
generate_playlist_stored "$f" | mpv_play_list >/dev/null
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ if [ ! "${THEME_LOADED:-}" ]; then
|
||||
# <<duration>> string Track duration
|
||||
PLYLST_FMT="${PLYLST_FMT:-"<<playing>>\t<<title>>\t<<artist>>\t<<duration>>"}"
|
||||
PLYLST_FMT_CNT=$(($(printf "$PLYLST_FMT" | tr -cd '\t' | wc -c) + 1))
|
||||
PLYLST_FMT_RIGHTALIGN="${PLYLST_FMT_RIGHTALIGN:-"1,4"}"
|
||||
PLYLST_FMT_RIGHTALIGN="${PLYLST_FMT_RIGHTALIGN:-"1"}"
|
||||
PLYLST_FMT_PLAYING_YES="${PLYLST_FMT_PLAYING_YES:-"👉"}"
|
||||
PLYLST_FMT_PLAYING_NO="${PLYLST_FMT_PLAYING_NO:-""}"
|
||||
PLYLST_FMT_TITLE="${PLYLST_FMT_TITLE:-"${CTITLE}%s${OFF}"}"
|
||||
@@ -390,7 +390,8 @@ if [ ! "${THEME_LOADED:-}" ]; then
|
||||
# Playlist title
|
||||
# ==============
|
||||
TITLE_PLYLST="${TITLE_PLYLST:-" 🎶 ${CARTIST}Playlist${OFF} "}"
|
||||
export TITLE_PLYLST
|
||||
TITLE_PLYLST_LIST="${TITLE_PLYLST_LIST:-" 🎶 ${CARTIST}Stored Playlists${OFF} "}"
|
||||
export TITLE_PLYLST TITLE_PLYLST_LIST
|
||||
|
||||
export THEME_LOADED=1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user