#!/bin/sh music_dir="${XDG_MUSIC_DIR:-${HOME}/Music}" dotfiles_dir="${XDG_DOTFILES_DIR:-${HOME}/.dotfiles}" music_txt="${dotfiles_dir}/global/Music/.music.txt" music_titles="${dotfiles_dir}/global/Music/.music_titles.txt" playlist_dir="${XDG_CONFIG_HOME:-${HOME}/.config}/mpd/playlists" # Select the relative path. Sort the list so "first match" semantics in dmenu # are deterministic — otherwise filesystem order is unstable and typing a # substring (e.g. "성시경") can return whichever file find walked first. # `-not -path '*/.*'` skips hidden files (.music.txt, etc.); name filter limits to audio. selected_relpath=$(cd "$music_dir" && find . -type f -not -path '*/.*' \( -name '*.mp3' -o -name '*.m4a' -o -name '*.opus' -o -name '*.flac' -o -name '*.wav' -o -name '*.webm' \) | sed 's|^\./||' | LC_ALL=C.UTF-8 sort | dmenu -i -l 20 -p "Select a file to delete:") || exit 1 [ -n "$selected_relpath" ] || exit 1 selected_file="$music_dir/$selected_relpath" selected_filename=${selected_relpath##*/} [ -f "$selected_file" ] || { notify-send "❌ File not found: $selected_relpath" exit 1 } # Extracting YouTube video ID video_id=$(strings "$selected_file" | grep 'watch?v=' | sed 's/.*watch?v=\([a-zA-Z0-9_-]*\).*/\1/' | head -1) [ -n "$video_id" ] || { notify-send "❌ No YouTube video ID found in file: $selected_filename" exit 1 } # Confirmation dialog confirm=$(printf "Yes\nNo" | dmenu -i -p "Delete $selected_relpath and update mpc?") [ "$confirm" = "Yes" ] || { notify-send "❌ Operation cancelled." exit 0 } # Remove video_id line from .music.txt and .music_titles.txt (fixed-string match) remove_id_from() { _file="$1" [ -f "$_file" ] || return 0 _tmp="$(mktemp)" || return 1 grep -Fv "$video_id" "$_file" >"$_tmp" && mv "$_tmp" "$_file" } if remove_id_from "$music_txt" && remove_id_from "$music_titles"; then # Remove the relative path from every playlist (entire.m3u + genre lists like # jpop/kpop/pop). -F avoids regex pitfalls with [], (), etc. # These .m3u files are symlinks into the dotfiles repo, so write the result # back with `cat > "$playlist"` (which follows the symlink) instead of # `mv`/`sed -i`, both of which would replace the symlink with a plain file. for playlist in "$playlist_dir"/*.m3u; do [ -e "$playlist" ] || continue if grep -Fq "$selected_relpath" "$playlist"; then _pl_tmp="$(mktemp)" || continue grep -Fv "$selected_relpath" "$playlist" | sed '/^$/d' > "$_pl_tmp" cat "$_pl_tmp" > "$playlist" rm -f "$_pl_tmp" fi done # Delete the actual music file if rm "$selected_file"; then mpc update >/dev/null notify-send " Success to delete:" "$selected_relpath" else notify-send "❌ Failed to remove file: $selected_file" fi else notify-send "❌ An error occurred." fi