Add files via upload
This commit is contained in:
152
config/rmpc/config.ron
Normal file
152
config/rmpc/config.ron
Normal file
@@ -0,0 +1,152 @@
|
||||
#![enable(implicit_some)]
|
||||
#![enable(unwrap_newtypes)]
|
||||
#![enable(unwrap_variant_newtypes)]
|
||||
(
|
||||
address: "127.0.0.1:6600",
|
||||
cache_dir: Some("/tmp/rmpc/cache"),
|
||||
lyrics_dir: Some("~/Музыка/mpd"),
|
||||
password: None,
|
||||
theme: "gruvbox",
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
volume_step: 5,
|
||||
max_fps: 30,
|
||||
scrolloff: 0,
|
||||
wrap_navigation: false,
|
||||
enable_mouse: true,
|
||||
status_update_interval_ms: 1000,
|
||||
select_current_song_on_change: false,
|
||||
browser_column_widths: [20, 38, 42],
|
||||
album_art: (
|
||||
method: Auto,
|
||||
max_size_px: (width: 900, height: 900),
|
||||
disabled_protocols: ["http://", "https://"],
|
||||
vertical_align: Top,
|
||||
horizontal_align: Center,
|
||||
),
|
||||
keybinds: (
|
||||
global: {
|
||||
":": CommandMode,
|
||||
",": VolumeDown,
|
||||
"s": Stop,
|
||||
".": VolumeUp,
|
||||
"<Tab>": NextTab,
|
||||
"<S-Tab>": PreviousTab,
|
||||
"1": SwitchToTab("Queue"),
|
||||
"2": SwitchToTab("Artists"),
|
||||
"3": SwitchToTab("Albums"),
|
||||
"4": SwitchToTab("Search"),
|
||||
"5": SwitchToTab("Directories"),
|
||||
"6": SwitchToTab("Lyrics"),
|
||||
"q": Quit,
|
||||
">": NextTrack,
|
||||
"p": TogglePause,
|
||||
"<": PreviousTrack,
|
||||
"f": SeekForward,
|
||||
"z": ToggleRepeat,
|
||||
"x": ToggleRandom,
|
||||
"c": ToggleConsume,
|
||||
"v": ToggleSingle,
|
||||
"b": SeekBack,
|
||||
"~": ShowHelp,
|
||||
"I": ShowCurrentSongInfo,
|
||||
"O": ShowOutputs,
|
||||
"P": ShowDecoders,
|
||||
},
|
||||
navigation: {
|
||||
"k": Up,
|
||||
"j": Down,
|
||||
"h": Left,
|
||||
"l": Right,
|
||||
"<Up>": Up,
|
||||
"<Down>": Down,
|
||||
"<Left>": Left,
|
||||
"<Right>": Right,
|
||||
"<C-k>": PaneUp,
|
||||
"<C-j>": PaneDown,
|
||||
"<C-h>": PaneLeft,
|
||||
"<C-l>": PaneRight,
|
||||
"<C-u>": UpHalf,
|
||||
"N": PreviousResult,
|
||||
"a": Add,
|
||||
"A": AddAll,
|
||||
"r": Rename,
|
||||
"n": NextResult,
|
||||
"g": Top,
|
||||
"<Space>": Select,
|
||||
"<C-Space>": InvertSelection,
|
||||
"G": Bottom,
|
||||
"<CR>": Confirm,
|
||||
"i": FocusInput,
|
||||
"J": MoveDown,
|
||||
"<C-d>": DownHalf,
|
||||
"/": EnterSearch,
|
||||
"<C-c>": Close,
|
||||
"<Esc>": Close,
|
||||
"K": MoveUp,
|
||||
"D": Delete,
|
||||
},
|
||||
queue: {
|
||||
"D": DeleteAll,
|
||||
"<CR>": Play,
|
||||
"<C-s>": Save,
|
||||
"a": AddToPlaylist,
|
||||
"d": Delete,
|
||||
"i": ShowInfo,
|
||||
"C": JumpToCurrent,
|
||||
},
|
||||
),
|
||||
search: (
|
||||
case_sensitive: false,
|
||||
mode: Contains,
|
||||
tags: [
|
||||
(value: "any", label: "Any Tag"),
|
||||
(value: "artist", label: "Artist"),
|
||||
(value: "album", label: "Album"),
|
||||
(value: "title", label: "Title"),
|
||||
(value: "filename", label: "Filename"),
|
||||
(value: "genre", label: "Genre"),
|
||||
(value: "albumartist", label: "Featured"),
|
||||
],
|
||||
),
|
||||
artists: (
|
||||
album_display_mode: SplitByDate,
|
||||
album_sort_by: Date,
|
||||
),
|
||||
tabs: [
|
||||
(
|
||||
name: "Queue",
|
||||
pane: Split(
|
||||
direction: Horizontal,
|
||||
panes: [(size: "20%", pane: Pane(AlbumArt)), (size: "80%", pane: Pane(Queue))],
|
||||
),
|
||||
),
|
||||
(
|
||||
name: "Artists",
|
||||
pane: Pane(Artists),
|
||||
),
|
||||
(
|
||||
name: "Albums",
|
||||
pane: Pane(Albums),
|
||||
),
|
||||
(
|
||||
name: "Search",
|
||||
pane: Pane(Search),
|
||||
),
|
||||
(
|
||||
name: "Directories",
|
||||
pane: Pane(Directories),
|
||||
),
|
||||
(
|
||||
name: "Lyrics",
|
||||
pane: Split(
|
||||
direction: Vertical,
|
||||
panes: [(size: "25%", pane: Pane(AlbumArt)), (size: "70%", pane: Pane(Lyrics), vertical_align: Bottom)],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
8
config/rmpc/increment_play_count
Executable file
8
config/rmpc/increment_play_count
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
sticker=$(rmpc sticker get "$FILE" "playCount" | jq -r '.value')
|
||||
if [ -z "$sticker" ]; then
|
||||
rmpc sticker set "$FILE" "playCount" "1"
|
||||
else
|
||||
rmpc sticker set "$FILE" "playCount" "$((sticker + 1))"
|
||||
fi
|
||||
26
config/rmpc/inspect_log.sh
Executable file
26
config/rmpc/inspect_log.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
LOGFILE="$HOME/.mpd/log"
|
||||
OUTFILE="$HOME/.config/rmpc/genre_counts.txt"
|
||||
TMPFILE="$(mktemp)"
|
||||
|
||||
# Extract and accumulate genres to tmpfile
|
||||
grep "player: played" "$LOGFILE" | while read -r line; do
|
||||
filepath=$(echo "$line" | sed -n 's/.*player: played "\(.*\)"/\1/p')
|
||||
fullpath="$HOME/Music/mpd/$filepath"
|
||||
|
||||
if [ -f "$fullpath" ]; then
|
||||
genre=$(eyeD3 --no-color "$fullpath" | grep "genre:" | sed -E 's/.*genre: (.*) \(id.*/\1/')
|
||||
IFS=';'
|
||||
for g in $genre; do
|
||||
clean_genre=$(echo "$g" | xargs)
|
||||
[ -n "$clean_genre" ] && echo "$clean_genre" >> "$TMPFILE"
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# Count and sort genres
|
||||
sort "$TMPFILE" | uniq -c | sort -k1 -nr | awk '{ $1=$1; print substr($0, index($0,$2)) " " $1 }' > "$OUTFILE"
|
||||
|
||||
rm "$TMPFILE"
|
||||
echo "✅ Genre frequency list saved to $OUTFILE"
|
||||
26
config/rmpc/notify
Executable file
26
config/rmpc/notify
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Directory where to store temporary data
|
||||
TMP_DIR="/tmp/rmpc"
|
||||
|
||||
# Ensure the directory is created
|
||||
mkdir -p "$TMP_DIR"
|
||||
|
||||
# Where to temporarily store the album art received from rmpc
|
||||
ALBUM_ART_PATH="$TMP_DIR/notification_cover"
|
||||
|
||||
# Path to fallback album art if no album art is found by rmpc/mpd
|
||||
# Change this to your needs
|
||||
DEFAULT_ALBUM_ART_PATH="$TMP_DIR/default_album_art.jpg"
|
||||
|
||||
# Save album art of the currently playing song to a file
|
||||
if ! rmpc albumart --output "$ALBUM_ART_PATH"; then
|
||||
# Use default album art if rmpc returns non-zero exit code
|
||||
ALBUM_ART_PATH="${DEFAULT_ALBUM_ART_PATH}"
|
||||
fi
|
||||
|
||||
MSG_TITLE=$(urlencode "$TITLE")
|
||||
MSG_ARTIST=$(urlencode "$ARTIST")
|
||||
|
||||
# Integrates with hammerspoon, but use whatever terminal notifier you have set up.
|
||||
#open "hammerspoon://canvasNotify?line1=$TITLE&line2=$ARTIST&duration=3"
|
||||
153
config/rmpc/themes/gruvbox.ron
Normal file
153
config/rmpc/themes/gruvbox.ron
Normal file
@@ -0,0 +1,153 @@
|
||||
#![enable(implicit_some)]
|
||||
#![enable(unwrap_newtypes)]
|
||||
#![enable(unwrap_variant_newtypes)]
|
||||
(
|
||||
default_album_art_path: None,
|
||||
show_song_table_header: true,
|
||||
draw_borders: true,
|
||||
browser_column_widths: [20, 38, 42],
|
||||
background_color: "#282828",
|
||||
text_color: "#ebdbb2",
|
||||
header_background_color: None,
|
||||
modal_background_color: "#1d2021",
|
||||
tab_bar: (
|
||||
enabled: true,
|
||||
active_style: (fg: "#282828", bg: "#fabd2f", modifiers: "Bold"),
|
||||
inactive_style: (),
|
||||
),
|
||||
highlighted_item_style: (fg: "#fe8019", modifiers: "Bold"),
|
||||
current_item_style: (fg: "#282828", bg: "#d79921", modifiers: "Bold"),
|
||||
borders_style: (fg: "#504945"),
|
||||
highlight_border_style: (fg: "#fabd2f"),
|
||||
symbols: (song: "", dir: "", marker: " ", ellipsis: "..."),
|
||||
progress_bar: (
|
||||
symbols: ["", "", " "],
|
||||
track_style: (fg: "#3c3836"),
|
||||
elapsed_style: (fg: "#d65d0e"),
|
||||
thumb_style: (fg: "#b22222", bg: "#3c3836"),
|
||||
),
|
||||
scrollbar: (
|
||||
symbols: ["│", "█", "▲", "▼"],
|
||||
track_style: (),
|
||||
ends_style: (),
|
||||
thumb_style: (fg: "#fabd2f"),
|
||||
),
|
||||
song_table_format: [ // view in the queue
|
||||
(
|
||||
prop: (kind: Property(Artist),
|
||||
default: (kind: Text("Unknown"))
|
||||
),
|
||||
width: "15%",
|
||||
),
|
||||
(
|
||||
prop: (kind: Property(Title),
|
||||
default: (kind: Text("Unknown"))
|
||||
),
|
||||
width: "55%",
|
||||
),
|
||||
(
|
||||
prop: (kind: Property(Album), style: (fg: "white"),
|
||||
default: (kind: Text("Unknown Album"), style: (fg: "white"))
|
||||
),
|
||||
width: "20%",
|
||||
),
|
||||
(
|
||||
prop: (kind: Sticker("playCount"), default: (kind: Text("0"))),
|
||||
width: "9",
|
||||
alignment: Right,
|
||||
label: "Playcount"
|
||||
),
|
||||
(
|
||||
prop: (kind: Property(Duration),
|
||||
default: (kind: Text("-"))
|
||||
),
|
||||
width: "10%",
|
||||
alignment: Right,
|
||||
),
|
||||
],
|
||||
layout: Split(
|
||||
direction: Vertical,
|
||||
panes: [
|
||||
(
|
||||
pane: Pane(Header),
|
||||
size: "2",
|
||||
),
|
||||
(
|
||||
pane: Pane(Tabs),
|
||||
size: "3",
|
||||
),
|
||||
(
|
||||
pane: Pane(TabContent),
|
||||
size: "100%",
|
||||
),
|
||||
(
|
||||
pane: Pane(ProgressBar),
|
||||
size: "1",
|
||||
),
|
||||
],
|
||||
),
|
||||
header: (
|
||||
rows: [
|
||||
(
|
||||
left: [
|
||||
(kind: Text("["), style: (fg: "#fabd2f", modifiers: "Bold")),
|
||||
(kind: Property(Status(StateV2(playing_label: "Playing", paused_label: "Paused", stopped_label: "Stopped"))), style: (fg: "#fabd2f", modifiers: "Bold")),
|
||||
(kind: Text("]"), style: (fg: "#fabd2f", modifiers: "Bold"))
|
||||
],
|
||||
center: [
|
||||
(kind: Property(Song(Title)), style: (modifiers: "Bold"),
|
||||
default: (kind: Text("No Song"), style: (modifiers: "Bold"))
|
||||
)
|
||||
],
|
||||
right: [
|
||||
(kind: Property(Widget(Volume)), style: (fg: "#b8bb28"))
|
||||
]
|
||||
),
|
||||
(
|
||||
left: [
|
||||
(kind: Property(Status(Elapsed))),
|
||||
(kind: Text(" / ")),
|
||||
(kind: Property(Status(Duration))),
|
||||
(kind: Text(" (")),
|
||||
(kind: Property(Status(Bitrate))),
|
||||
(kind: Text(" kbps)"))
|
||||
],
|
||||
center: [
|
||||
(kind: Property(Song(Artist)), style: (fg: "#fabd2f", modifiers: "Bold"),
|
||||
default: (kind: Text("Unknown"), style: (fg: "#fabd2f", modifiers: "Bold"))
|
||||
),
|
||||
(kind: Text(" - ")),
|
||||
(kind: Property(Song(Album)),
|
||||
default: (kind: Text("Unknown Album"))
|
||||
)
|
||||
],
|
||||
right: [
|
||||
(
|
||||
kind: Property(Widget(States(
|
||||
active_style: (fg: "#ebdbb2", modifiers: "Bold"),
|
||||
separator_style: (fg: "#a89984")))
|
||||
),
|
||||
style: (fg: "#a89984")
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
),
|
||||
browser_song_format: [
|
||||
(
|
||||
kind: Group([
|
||||
(kind: Property(Track)), // track #
|
||||
(kind: Text(" ")),
|
||||
])
|
||||
),
|
||||
(
|
||||
kind: Group([
|
||||
(kind: Property(Artist)),
|
||||
(kind: Text(" - ")),
|
||||
(kind: Property(Title)),
|
||||
]),
|
||||
default: (kind: Property(Filename))
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
109
config/rmpc/utils/fetch_album_lyrics.sh
Executable file
109
config/rmpc/utils/fetch_album_lyrics.sh
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Usage: fetch_album_lyrics_simple.sh "/path/to/Artist/Album"
|
||||
# Example: fetch_album_lyrics_simple.sh "$HOME/Music/mpd/Anderson .Paak/Ventura"
|
||||
|
||||
LRCLIB_API="https://lrclib.net/api/get"
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: $0 \"/path/to/Artist/Album\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ALBUM_DIR="$1"
|
||||
if [ ! -d "$ALBUM_DIR" ]; then
|
||||
echo "Error: '$ALBUM_DIR' is not a directory."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARTIST="$(basename "$(dirname "$ALBUM_DIR")")"
|
||||
ALBUM="$(basename "$ALBUM_DIR")"
|
||||
|
||||
# Try to fetch synced lyrics (only the [mm:ss.xx] lines) for a given title
|
||||
# Arguments:
|
||||
# $1 = artist
|
||||
# $2 = album
|
||||
# $3 = title_to_try
|
||||
# Returns stdout = JSON .syncedLyrics (or "null"/empty)
|
||||
get_lyrics_for() {
|
||||
local artist="$1"
|
||||
local album="$2"
|
||||
local title_try="$3"
|
||||
|
||||
curl -sG \
|
||||
--data-urlencode "artist_name=${artist}" \
|
||||
--data-urlencode "track_name=${title_try}" \
|
||||
--data-urlencode "album_name=${album}" \
|
||||
"$LRCLIB_API" \
|
||||
| jq -r '.syncedLyrics'
|
||||
}
|
||||
|
||||
# Attempt a single fetch:
|
||||
# 1) Try with TITLE_RAW (may include “(feat ...)”)
|
||||
# 2) If that yields "" or "null", strip “(…)" and retry
|
||||
# 3) If still no lyrics, give up
|
||||
# 4) If we do get lyrics, write them verbatim to the .lrc file
|
||||
#
|
||||
# Arguments:
|
||||
# $1 = ARTIST
|
||||
# $2 = ALBUM
|
||||
# $3 = TITLE_RAW
|
||||
# $4 = OUTPUT_LRC_FILE (full path, e.g. /.../Song.lrc)
|
||||
fetch_for_plain() {
|
||||
local artist="$1"
|
||||
local album="$2"
|
||||
local title_try="$3"
|
||||
local out_lrc="$4"
|
||||
|
||||
# 1. First-pass lookup
|
||||
local lyrics
|
||||
lyrics="$(get_lyrics_for "$artist" "$album" "$title_try")"
|
||||
|
||||
# 2. If empty or "null", try stripping "(...)" from title
|
||||
if [ -z "$lyrics" ] || [ "$lyrics" == "null" ]; then
|
||||
local stripped
|
||||
stripped="$(echo "$title_try" | sed -E 's/ *\([^)]*\)//g')"
|
||||
if [ "$stripped" != "$title_try" ]; then
|
||||
title_try="$stripped"
|
||||
lyrics="$(get_lyrics_for "$artist" "$album" "$title_try")"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3. If still empty/null → skip
|
||||
if [ -z "$lyrics" ] || [ "$lyrics" == "null" ]; then
|
||||
echo "✗ No lyrics for: \"$title_try\""
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 4. Write only the synced‐lyrics lines (timestamps + text)
|
||||
# We drop any existing [ar:], [al:], [ti:] lines from the API payload,
|
||||
# but typically lrclib returns only timestamped lines anyway.
|
||||
echo "$lyrics" | sed -E '/^\[(ar|al|ti):/d' > "$out_lrc"
|
||||
echo "✔ Saved lyrics: $(basename "$out_lrc")"
|
||||
return 0
|
||||
}
|
||||
|
||||
echo "▶ Fetching lyrics for all .mp3 in: $ALBUM_DIR"
|
||||
echo " Artist: $ARTIST"
|
||||
echo " Album: $ALBUM"
|
||||
echo
|
||||
|
||||
shopt -s nullglob
|
||||
for mp3 in "$ALBUM_DIR"/*.mp3; do
|
||||
TITLE_RAW="$(basename "$mp3" .mp3)"
|
||||
LRC_FILE="${mp3%.mp3}.lrc"
|
||||
|
||||
if [ -f "$LRC_FILE" ]; then
|
||||
echo "– Skipping \"$TITLE_RAW\" (already have .lrc)"
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! fetch_for_plain "$ARTIST" "$ALBUM" "$TITLE_RAW" "$LRC_FILE"; then
|
||||
# a failure just prints the “No lyrics for…” message and moves on
|
||||
continue
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Done."
|
||||
38
config/rmpc/utils/tag_genres.sh
Executable file
38
config/rmpc/utils/tag_genres.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <path-to-album-directory>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DIR="$1"
|
||||
|
||||
cd "$DIR" || { echo "❌ Failed to navigate to $DIR"; exit 1; }
|
||||
|
||||
# Get all mp3s sorted by eyeD3 track number
|
||||
FILES=()
|
||||
while IFS= read -r line; do
|
||||
FILES+=("$line")
|
||||
done < <(
|
||||
for f in *.mp3; do
|
||||
track_num=$(eyeD3 "$f" 2>/dev/null | grep -i "^track:" | awk '{print $2}' | cut -d/ -f1)
|
||||
printf "%03d|%s\n" "${track_num:-999}" "$f"
|
||||
done | sort | cut -d'|' -f2
|
||||
)
|
||||
|
||||
for file in "${FILES[@]}"; do
|
||||
[[ -f "$file" ]] || continue
|
||||
|
||||
echo ""
|
||||
echo "🎵 Now tagging: $file"
|
||||
eyeD3 "$file" | grep -Ei "title:|track:|genre:"
|
||||
|
||||
read -rp "Enter genre(s) for this track (comma-separated): " genre
|
||||
|
||||
if [[ -n "$genre" ]]; then
|
||||
eyeD3 --genre="$genre" "$file"
|
||||
echo "✅ Set genre to: $genre"
|
||||
else
|
||||
echo "⏭️ Skipped (no genre entered)"
|
||||
fi
|
||||
done
|
||||
38
config/rmpc/utils/tag_music.sh
Executable file
38
config/rmpc/utils/tag_music.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
ARTIST="Anderson .Paak"
|
||||
ALBUM="Oxnard"
|
||||
DIR="$HOME/Music/mpd/Anderson .Paak/Oxnard"
|
||||
|
||||
declare -a TRACKS=(
|
||||
"The Chase (feat. Kadhja Bonet)"
|
||||
"Headlow (feat. Norelle)"
|
||||
"Tints (feat. Kendrick Lamar)"
|
||||
"Who R U?"
|
||||
"6 Summers"
|
||||
"Saviers Road"
|
||||
"Smile⧸Petty (feat. Sonyae Elise)"
|
||||
"Mansa Musa (feat. Dr. Dre & Cocoa Sarai)"
|
||||
"Brother's Keeper (feat. Pusha T)"
|
||||
"Anywhere (feat. Snoop Dogg & The Last Artful, Dodgr)"
|
||||
"Trippy (feat. J. Cole)"
|
||||
"Cheers (feat. Q-Tip)"
|
||||
"Sweet Chick (feat. BJ The Chicago Kid)"
|
||||
"Left To Right"
|
||||
)
|
||||
|
||||
cd "$DIR" || { echo "❌ Failed to navigate to $DIR"; exit 1; }
|
||||
|
||||
# Iterate over the tracks and apply metadata
|
||||
for i in "${!TRACKS[@]}"; do
|
||||
track_num=$((i + 1))
|
||||
title="${TRACKS[$i]}"
|
||||
filename="$title.mp3"
|
||||
|
||||
if [[ -f "$filename" ]]; then
|
||||
echo "✅ Tagging: $filename"
|
||||
eyeD3 -a "$ARTIST" -A "$ALBUM" -t "$title" -n "$track_num" "$filename"
|
||||
else
|
||||
echo "⚠️ File not found: $filename"
|
||||
fi
|
||||
done
|
||||
Reference in New Issue
Block a user