diff options
Diffstat (limited to 'ar/.local/bin')
| -rwxr-xr-x | ar/.local/bin/dmenudelmusic | 14 | ||||
| -rwxr-xr-x | ar/.local/bin/emojiupdate | 2 | ||||
| -rw-r--r--[-rwxr-xr-x] | ar/.local/bin/qndl | 90 | ||||
| -rwxr-xr-x | ar/.local/bin/setmonitors | 2 | ||||
| -rwxr-xr-x | ar/.local/bin/v2m | 24 |
5 files changed, 41 insertions, 91 deletions
diff --git a/ar/.local/bin/dmenudelmusic b/ar/.local/bin/dmenudelmusic index fce8db2..c28130a 100755 --- a/ar/.local/bin/dmenudelmusic +++ b/ar/.local/bin/dmenudelmusic @@ -8,7 +8,7 @@ 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. +# substring 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 @@ -45,12 +45,18 @@ remove_id_from() { } if remove_id_from "$music_txt" && remove_id_from "$music_titles"; then - # Remove the relative path from playlists (-F avoids regex pitfalls with [], (), etc.) + # 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 - grep -Fv "$selected_relpath" "$playlist" > "${playlist}.tmp" && mv "${playlist}.tmp" "$playlist" - sed -i '/^$/d' "$playlist" + _pl_tmp="$(mktemp)" || continue + grep -Fv "$selected_relpath" "$playlist" | sed '/^$/d' > "$_pl_tmp" + cat "$_pl_tmp" > "$playlist" + rm -f "$_pl_tmp" fi done diff --git a/ar/.local/bin/emojiupdate b/ar/.local/bin/emojiupdate index 666d7d2..59cad1c 100755 --- a/ar/.local/bin/emojiupdate +++ b/ar/.local/bin/emojiupdate @@ -29,7 +29,7 @@ awk ' { print } ' "$input_file" >"$temp_file" -# Extract + VS16 제거 +# Extract + strip VS16 awk -F'#' ' { if (NF >= 2) { diff --git a/ar/.local/bin/qndl b/ar/.local/bin/qndl index 5cc8783..b9d8fa7 100755..100644 --- a/ar/.local/bin/qndl +++ b/ar/.local/bin/qndl @@ -31,6 +31,17 @@ normalize_url() { printf '%s' "$1" | sed 's|\.sooplive\.com/|.sooplive.co.kr/|' } +to_music_url() { + # Route YouTube links through music.youtube.com. The YouTube Music frontend + # yields cleaner song metadata (album/track/artist) than the plain video + # page. Non-YouTube URLs and already-music.youtube.com links pass through + # untouched; youtu.be short links are expanded to a watch?v= form. + printf '%s' "$1" | sed -E ' + s#^(https?://)?(www\.|m\.)?youtube\.com/#https://music.youtube.com/# + s#^(https?://)?youtu\.be/([A-Za-z0-9_-]+).*#https://music.youtube.com/watch?v=\2# + ' +} + get_url() { for _arg in "$@"; do case "$_arg" in @@ -81,10 +92,6 @@ get_type() { printf 'kill' return 0 ;; - -d | --delete | d | delete) - printf 'delete' - return 0 - ;; *) printf '%s' "$_arg" return 0 @@ -264,7 +271,7 @@ handle_playlist() { # --------------------------------------------------------------------------- download_music() { - _url="$1" + _url="$(to_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" @@ -283,6 +290,7 @@ download_music() { --extract-audio \ --audio-format mp3 \ --audio-quality 0 \ + --parse-metadata "%(release_date,upload_date)s:%(meta_date)s" \ --download-archive "$_archive" \ --print-to-file "$_title_fmt" "$_titles" \ --output "$_fmt" @@ -486,79 +494,18 @@ restore_archive() { else _t="" fi - enqueue "music" "https://www.youtube.com/watch?v=$_id" "${_t:-$_id}" \ + enqueue "music" "https://music.youtube.com/watch?v=$_id" "${_t:-$_id}" \ --no-playlist \ --extract-audio \ --audio-format mp3 \ --audio-quality 0 \ + --parse-metadata "%(release_date,upload_date)s:%(meta_date)s" \ --output "$_format" done <"$_tmpfile" rm -f "$_tmpfile" notify "✅ All $_sel_total job(s) queued" "tsp will process them sequentially" } -delete_archive() { - command -v fzf >/dev/null 2>&1 || die "⛔ fzf not installed" "Install fzf to use qndl -d." - - _archive="${XDG_DOTFILES_DIR:-$HOME/.dotfiles}/global/Music/.music.txt" - _titles="${XDG_DOTFILES_DIR:-$HOME/.dotfiles}/global/Music/.music_titles.txt" - - [ ! -f "$_archive" ] && die "⛔ Archive not found" "$_archive" - - # fzf input: <id>\t<display>. --with-nth hides column 1, cut grabs it back. - if [ -f "$_titles" ]; then - _entries="$(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) printf "%s\t%s [%s]\n", id, titles[id], id - else printf "%s\t[%s]\n", id, id - } - ' "$_titles" "$_archive")" - else - _entries="$(awk '$2 != "" { printf "%s\t[%s]\n", $2, $2 }' "$_archive")" - fi - - [ -z "$_entries" ] && die "⛔ Archive is empty" "Nothing to delete." - - _selected="$(printf '%s\n' "$_entries" | - fzf -m \ - --with-nth=2.. \ - --delimiter='\t' \ - --prompt='Delete: ' \ - --header='TAB to mark multiple, Enter to confirm' | - cut -f1)" - - [ -z "$_selected" ] && return 0 - - _ids_file="$(mktemp)" - printf '%s\n' "$_selected" >"$_ids_file" - - # YouTube IDs have no whitespace, so default FS works for both files. - # Archive lines: "youtube <ID>" → drop where $2 matches. - # Titles lines: "<ID>\t<title>" → drop where $1 matches. - _new_archive="$(mktemp)" - awk 'NR==FNR { drop[$1]=1; next } !($2 in drop)' "$_ids_file" "$_archive" >"$_new_archive" && - mv "$_new_archive" "$_archive" - - if [ -f "$_titles" ]; then - _new_titles="$(mktemp)" - awk 'NR==FNR { drop[$1]=1; next } !($1 in drop)' "$_ids_file" "$_titles" >"$_new_titles" && - mv "$_new_titles" "$_titles" - fi - - _count="$(printf '%s\n' "$_selected" | grep -c .)" - rm -f "$_ids_file" - - notify "🗑️ Removed $_count archive entry/entries" "from .music.txt and .music_titles.txt" -} # --------------------------------------------------------------------------- # Listing & Cancellation @@ -692,9 +639,6 @@ main() { restore) restore_archive ;; - delete) - delete_archive - ;; list) list_queue ;; @@ -702,10 +646,10 @@ main() { kill_job ;; "") - die "⛔ No type specified" "Provide: music, video, restore, delete, list, or kill." + die "⛔ No type specified" "Provide: music, video, restore, list, or kill." ;; *) - die "⛔ Invalid type: $_type" "Recognized types: music, video, restore, delete, list, kill." + die "⛔ Invalid type: $_type" "Recognized types: music, video, restore, list, kill." ;; esac } diff --git a/ar/.local/bin/setmonitors b/ar/.local/bin/setmonitors index 76dabb8..287d785 100755 --- a/ar/.local/bin/setmonitors +++ b/ar/.local/bin/setmonitors @@ -9,7 +9,7 @@ edp_cfg="--mode 1920x1080 --rotate normal --scale 1.0x1.0 --dpi 82" hdmi_cfg="--mode 1920x1080 --rotate normal --scale 1.0x1.0 --dpi 82" dp_cfg="--mode 2560x1600 --rotate normal --scale 1.0x1.0 --dpi 192" -# EDID 미감지 시 (640x480에 갇힌 경우) 1920x1080 폴백 적용 +# When EDID is not detected (stuck at 640x480), apply a 1920x1080 fallback if xrandr -q | grep " connected" | grep -q "640x480+"; then xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync 2>/dev/null for output in $(xrandr -q | grep -w "connected" | cut -d ' ' -f 1); do diff --git a/ar/.local/bin/v2m b/ar/.local/bin/v2m index eda5d86..b2f0510 100755 --- a/ar/.local/bin/v2m +++ b/ar/.local/bin/v2m @@ -1,38 +1,38 @@ #!/bin/bash -# 동영상에서 MP3 추출 스크립트 +# Extract MP3 audio from a video file if [ $# -eq 0 ]; then - echo "사용법: video2mp3 <입력파일> [출력파일]" - echo "예시: video2mp3 video.mp4" - echo "예시: video2mp3 video.mp4 audio.mp3" + echo "Usage: video2mp3 <input_file> [output_file]" + echo "Example: video2mp3 video.mp4" + echo "Example: video2mp3 video.mp4 audio.mp3" exit 1 fi INPUT="$1" -# 파일 존재 확인 +# Check that the file exists if [ ! -f "$INPUT" ]; then - echo "오류: 파일을 찾을 수 없습니다: $INPUT" + echo "Error: file not found: $INPUT" exit 1 fi -# 출력 파일명 설정 +# Determine the output filename if [ $# -eq 2 ]; then OUTPUT="$2" else - # 입력 파일에서 확장자를 제거하고 .mp3 추가 + # Strip the extension from the input file and append .mp3 OUTPUT="${INPUT%.*}.mp3" fi -echo "변환 중: $INPUT -> $OUTPUT" +echo "Converting: $INPUT -> $OUTPUT" -# ffmpeg로 mp3 추출 (고품질: 320kbps) +# Extract mp3 with ffmpeg (high quality: 320kbps) ffmpeg -i "$INPUT" -vn -acodec libmp3lame -b:a 320k "$OUTPUT" if [ $? -eq 0 ]; then - echo "✓ 완료: $OUTPUT" + echo "✓ Done: $OUTPUT" else - echo "✗ 오류 발생" + echo "✗ An error occurred" exit 1 fi |
