summaryrefslogtreecommitdiff
path: root/ar/.local/bin
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-25 20:51:27 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-25 20:51:27 +0900
commit6bd7c20f25dbee51d61ef22b21e3831d64e82a05 (patch)
treef2fff1f0c8795126bca05bb66c0f12ead4e47fcd /ar/.local/bin
parentf2ed278aee005b0a3f0a33233c55f0026cfd2aad (diff)
modified playlists/entire.m3u, modified bin/dmenudelmusic, modified bin/qndl, modified Music/.music.txt
Diffstat (limited to 'ar/.local/bin')
-rwxr-xr-xar/.local/bin/dmenudelmusic7
-rwxr-xr-xar/.local/bin/qndl56
2 files changed, 48 insertions, 15 deletions
diff --git a/ar/.local/bin/dmenudelmusic b/ar/.local/bin/dmenudelmusic
index 91beeac..91994fb 100755
--- a/ar/.local/bin/dmenudelmusic
+++ b/ar/.local/bin/dmenudelmusic
@@ -4,8 +4,11 @@ music_dir="${XDG_MUSIC_DIR:-${HOME}/Music}"
music_txt="${music_dir}/.music.txt"
playlist_dir="${XDG_CONFIG_HOME:-${HOME}/.config}/mpd/playlists"
-# Select the relative path (so we can find the actual file in subdirectories)
-selected_relpath=$(cd "$music_dir" && find . -type f | sed 's|^\./||' | dmenu -i -l 20 -p "Select a file to delete:") || exit 1
+# 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"
diff --git a/ar/.local/bin/qndl b/ar/.local/bin/qndl
index cc61690..6cf3053 100755
--- a/ar/.local/bin/qndl
+++ b/ar/.local/bin/qndl
@@ -7,7 +7,9 @@
# ---------------------------------------------------------------------------
notify() {
- notify-send "$1" "$2"
+ # `--` ends option parsing so titles/bodies that look like flags (e.g. URLs
+ # containing "-A...") aren't misread as notify-send options.
+ notify-send -- "$1" "$2"
}
die() {
@@ -16,8 +18,10 @@ die() {
}
get_cookies() {
+ # yt-dlp doesn't have a native 'librewolf' option but reads its cookies as
+ # a Firefox-style profile when given --cookies-from-browser firefox.
case "${BROWSER:-}" in
- *firefox*) printf 'firefox' ;;
+ *firefox* | *librewolf*) printf 'firefox' ;;
esac
}
@@ -110,17 +114,18 @@ enqueue() {
_quoted_args="$_quoted_args '${_escaped}'"
done
- _ytdl_cmd="yt-dlp${_quoted_args} '$(printf '%s' "$_url" | sed "s/'/'\\\\''/g")'"
+ # `--` ends option parsing so URLs whose video ID starts with '-' aren't treated as flags.
+ _ytdl_cmd="yt-dlp${_quoted_args} -- '$(printf '%s' "$_url" | sed "s/'/'\\\\''/g")'"
_idnum="$(tsp bash -c "$_ytdl_cmd")"
pkill -RTMIN+16 "${STATUSBAR:-dwmblocks}"
# tsp -D runs next job only if dependency succeeded (exit 0)
# Success notification — runs only if download succeeds
- tsp -D "$_idnum" notify-send "✅ ${_dl_type} download complete:" "$_url"
+ tsp -D "$_idnum" notify-send -- "✅ ${_dl_type} download complete:" "$_url"
# Failure notification — waits for job, checks its exit status
- tsp bash -c 'tsp -w "$1"; _exit=$(tsp -i "$1" | sed -n "s/.*exit code //p"); [ -n "$_exit" ] && [ "$_exit" != "0" ] && notify-send "❌ Failed to download:" "$2"' -- "$_idnum" "$_url"
+ tsp bash -c 'tsp -w "$1"; _exit=$(tsp -i "$1" | sed -n "s/.*exit code //p"); [ -n "$_exit" ] && [ "$_exit" != "0" ] && notify-send -- "❌ Failed to download:" "$2"' -- "$_idnum" "$_url"
if [ "$_dl_type" = "music" ]; then
tsp -D "$_idnum" bash -c "mpc update --wait && find '$_music_dir' -name '*.mp3' | sed 's|$_music_dir/||' | sort > '$HOME/.config/mpd/playlists/entire.m3u'"
@@ -177,7 +182,9 @@ download_music() {
_url="$1"
_output_dir="${XDG_MUSIC_DIR:-$HOME/Music}"
_archive="${XDG_DOTFILES_DIR:-$HOME/.dotfiles}/global/Music/.music.txt"
+ _titles="${XDG_DOTFILES_DIR:-$HOME/.dotfiles}/global/Music/.music_titles.txt"
_format="${_output_dir}/%(artists.0|Unknown Artist)s/%(album|Unknown Album)s/%(title)s.%(ext)s"
+ _title_fmt="$(printf '%%(id)s\t%%(artists.0|Unknown Artist)s - %%(title)s')"
_pl_result="$(handle_playlist "$_url" "music" "$_output_dir" "$_format")"
_pl_flag="$(printf '%s' "$_pl_result" | head -n 1)"
@@ -192,6 +199,7 @@ download_music() {
--audio-format mp3 \
--audio-quality 0 \
--download-archive "$_archive" \
+ --print-to-file "$_title_fmt" "$_titles" \
--output "$_fmt"
}
@@ -251,30 +259,51 @@ download_video() {
restore_archive() {
_output_dir="${XDG_MUSIC_DIR:-$HOME/Music}"
_archive="${XDG_DOTFILES_DIR:-$HOME/.dotfiles}/global/Music/.music.txt"
+ _titles="${XDG_DOTFILES_DIR:-$HOME/.dotfiles}/global/Music/.music_titles.txt"
_format="${_output_dir}/%(artists.0|Unknown Artist)s/%(album|Unknown Album)s/%(title)s.%(ext)s"
[ ! -f "$_archive" ] && die "⛔ Archive not found" "$_archive"
- _ids="$(awk '{print $2}' "$_archive")"
- _total="$(printf '%s\n' "$_ids" | wc -l | tr -d ' ')"
+ # Build dmenu lines: "Artist - Title [VIDEOID]" if title is cached, else "[VIDEOID]"
+ # Archive uses space ("youtube ID"); titles file uses tab ("ID<TAB>title").
+ if [ -f "$_titles" ]; then
+ _display="$(awk '
+ NR==FNR {
+ tab = index($0, "\t")
+ if (tab > 0) titles[substr($0, 1, tab-1)] = substr($0, tab+1)
+ next
+ }
+ {
+ sp = index($0, " ")
+ if (sp == 0) next
+ id = substr($0, sp+1)
+ if (id == "") next
+ if (id in titles) print titles[id] " [" id "]"
+ else print "[" id "]"
+ }
+ ' "$_titles" "$_archive")"
+ else
+ _display="$(awk '$2 != "" { print "[" $2 "]" }' "$_archive")"
+ fi
+ _total="$(printf '%s\n' "$_display" | grep -c .)"
- _choice="$(printf 'all\n%s' "$_ids" | dmenu -i -l 20 -p 'Restore which video ID?')"
+ _choice="$(printf 'all\n%s' "$_display" | dmenu -i -l 20 -p "Restore which song? ($_total total)")"
[ -z "$_choice" ] && return 0
if [ "$_choice" = "all" ]; then
- _selected="$_ids"
+ _selected="$(awk '$2 != "" { print $2 }' "$_archive")"
else
- _selected="$_choice"
+ # Extract video ID from trailing "[VIDEOID]" (11-char YouTube id, anchored at end)
+ _selected="$(printf '%s' "$_choice" | sed -n 's/.*\[\([A-Za-z0-9_-]\{11\}\)\][[:space:]]*$/\1/p')"
+ [ -z "$_selected" ] && die "⛔ Could not parse video ID from selection" "$_choice"
fi
_sel_total="$(printf '%s\n' "$_selected" | grep -c .)"
+ notify "⏳ Queueing $_sel_total restore(s)" "via tsp"
_tmpfile="$(mktemp)"
printf '%s\n' "$_selected" >"$_tmpfile"
- _n=0
while IFS= read -r _id; do
[ -z "$_id" ] && continue
- _n=$((_n + 1))
- notify "⏳ Restoring ($_n/$_sel_total)" "$_id"
enqueue "music" "https://www.youtube.com/watch?v=$_id" \
--no-playlist \
--extract-audio \
@@ -283,6 +312,7 @@ restore_archive() {
--output "$_format"
done <"$_tmpfile"
rm -f "$_tmpfile"
+ notify "✅ All $_sel_total job(s) queued" "tsp will process them sequentially"
}
# ---------------------------------------------------------------------------