diff options
Diffstat (limited to 'X11/mpd/ncmpcpp/scripts')
| -rwxr-xr-x | X11/mpd/ncmpcpp/scripts/album-art | 248 | ||||
| -rw-r--r-- | X11/mpd/ncmpcpp/scripts/music.png | bin | 0 -> 113344 bytes | |||
| -rwxr-xr-x | X11/mpd/ncmpcpp/scripts/ncmpcpp-art | 22 |
3 files changed, 270 insertions, 0 deletions
diff --git a/X11/mpd/ncmpcpp/scripts/album-art b/X11/mpd/ncmpcpp/scripts/album-art new file mode 100755 index 0000000..d852f34 --- /dev/null +++ b/X11/mpd/ncmpcpp/scripts/album-art | |||
| @@ -0,0 +1,248 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | |||
| 3 | ## Copyright (C) 2020-2021 Aditya Shakya <adi1090x@gmail.com> | ||
| 4 | ## Everyone is permitted to copy and distribute copies of this file under GNU-GPL3 | ||
| 5 | |||
| 6 | ## Cover art script for ncmpcpp | ||
| 7 | |||
| 8 | # SETTINGS | ||
| 9 | music_library="$HOME/Music" | ||
| 10 | padding_top=3 | ||
| 11 | padding_bottom=0 | ||
| 12 | padding_right=0 | ||
| 13 | max_width=40 | ||
| 14 | reserved_playlist_cols=31 | ||
| 15 | reserved_cols_in_percent="false" | ||
| 16 | force_square="true" | ||
| 17 | square_alignment="top" | ||
| 18 | left_aligned="true" | ||
| 19 | padding_left=0 | ||
| 20 | |||
| 21 | # Only set this if the geometries are wrong or ncmpcpp shouts at you to do it. | ||
| 22 | # Visually select/highlight a character on your terminal, zoom in an image | ||
| 23 | # editor and count how many pixels a character's width and height are. | ||
| 24 | font_height= | ||
| 25 | font_width= | ||
| 26 | |||
| 27 | main() { | ||
| 28 | kill_previous_instances >/dev/null 2>&1 | ||
| 29 | find_cover_image >/dev/null 2>&1 | ||
| 30 | display_cover_image 2>/dev/null | ||
| 31 | dunstify -u low --replace=69 -i "$cover_path" "$(mpc current)" | ||
| 32 | detect_window_resizes >/dev/null 2>&1 | ||
| 33 | } | ||
| 34 | |||
| 35 | # ==== Main functions ========================================================= | ||
| 36 | |||
| 37 | kill_previous_instances() { | ||
| 38 | script_name=$(basename "$0") | ||
| 39 | for pid in $(pidof -x "$script_name"); do | ||
| 40 | if [ "$pid" != $$ ]; then | ||
| 41 | kill -15 "$pid" | ||
| 42 | fi | ||
| 43 | done | ||
| 44 | } | ||
| 45 | |||
| 46 | find_cover_image() { | ||
| 47 | |||
| 48 | # First we check if the audio file has an embedded album art | ||
| 49 | ext="$(mpc --format %file% current | sed 's/^.*\.//')" | ||
| 50 | if [ "$ext" = "flac" ]; then | ||
| 51 | # since FFMPEG cannot export embedded FLAC art we use metaflac | ||
| 52 | metaflac --export-picture-to=/tmp/mpd_cover.jpg \ | ||
| 53 | "$(mpc --format "$music_library"/%file% current)" && | ||
| 54 | cover_path="/tmp/mpd_cover.jpg" && return | ||
| 55 | else | ||
| 56 | ffmpeg -y -i "$(mpc --format "$music_library"/%file% | head -n 1)" \ | ||
| 57 | /tmp/mpd_cover.jpg && | ||
| 58 | cover_path="/tmp/mpd_cover.jpg" && return | ||
| 59 | fi | ||
| 60 | |||
| 61 | # If no embedded art was found we look inside the music file's directory | ||
| 62 | album="$(mpc --format %album% current)" | ||
| 63 | file="$(mpc --format %file% current)" | ||
| 64 | album_dir="${file%/*}" | ||
| 65 | album_dir="$music_library/$album_dir" | ||
| 66 | found_covers="$(find "$album_dir" -type d -exec find {} -maxdepth 1 -type f \ | ||
| 67 | -iregex ".*/.*\(${album}\|cover\|folder\|artwork\|front\).*[.]\\(jpe?g\|png\|gif\|bmp\)" \; )" | ||
| 68 | cover_path="$(echo "$found_covers" | head -n1)" | ||
| 69 | if [ -n "$cover_path" ]; then | ||
| 70 | return | ||
| 71 | fi | ||
| 72 | |||
| 73 | # If we still failed to find a cover image, we use the fallback | ||
| 74 | if [ -z "$cover_path" ]; then | ||
| 75 | cover_path="$HOME/.ncmpcpp/scripts/music.png" | ||
| 76 | fi | ||
| 77 | } | ||
| 78 | |||
| 79 | display_cover_image() { | ||
| 80 | compute_geometry | ||
| 81 | |||
| 82 | send_to_ueberzug \ | ||
| 83 | action "add" \ | ||
| 84 | identifier "mpd_cover" \ | ||
| 85 | path "$cover_path" \ | ||
| 86 | x "$ueber_left" \ | ||
| 87 | y "$padding_top" \ | ||
| 88 | height "$ueber_height" \ | ||
| 89 | width "$ueber_width" \ | ||
| 90 | synchronously_draw "True" \ | ||
| 91 | scaler "forced_cover" \ | ||
| 92 | scaling_position_x "0.5" | ||
| 93 | } | ||
| 94 | |||
| 95 | detect_window_resizes() { | ||
| 96 | { | ||
| 97 | trap 'display_cover_image' WINCH | ||
| 98 | while :; do sleep .1; done | ||
| 99 | } & | ||
| 100 | } | ||
| 101 | |||
| 102 | |||
| 103 | # ==== Helper functions ========================================================= | ||
| 104 | |||
| 105 | compute_geometry() { | ||
| 106 | unset LINES COLUMNS # Required in order for tput to work in a script | ||
| 107 | term_lines=$(tput lines) | ||
| 108 | term_cols=$(tput cols) | ||
| 109 | if [ -z "$font_height" ] || [ -z "$font_height" ]; then | ||
| 110 | guess_font_size | ||
| 111 | fi | ||
| 112 | |||
| 113 | ueber_height=$(( term_lines - padding_top - padding_bottom )) | ||
| 114 | # Because Ueberzug uses characters as a unit we must multiply | ||
| 115 | # the line count (height) by the font size ratio in order to | ||
| 116 | # obtain an equivalent width in column count | ||
| 117 | ueber_width=$(( ueber_height * font_height / font_width )) | ||
| 118 | ueber_left=$(( term_cols - ueber_width - padding_right )) | ||
| 119 | |||
| 120 | if [ "$left_aligned" = "true" ]; then | ||
| 121 | compute_geometry_left_aligned | ||
| 122 | else | ||
| 123 | compute_geometry_right_aligned | ||
| 124 | fi | ||
| 125 | |||
| 126 | apply_force_square_setting | ||
| 127 | } | ||
| 128 | |||
| 129 | compute_geometry_left_aligned() { | ||
| 130 | ueber_left=$padding_left | ||
| 131 | max_width_chars=$(( term_cols * max_width / 100 )) | ||
| 132 | if [ "$max_width" != 0 ] && | ||
| 133 | [ $(( ueber_width + padding_right + padding_left )) -gt "$max_width_chars" ]; then | ||
| 134 | ueber_width=$(( max_width_chars - padding_left - padding_right )) | ||
| 135 | fi | ||
| 136 | } | ||
| 137 | |||
| 138 | compute_geometry_right_aligned() { | ||
| 139 | if [ "$reserved_cols_in_percent" = "true" ]; then | ||
| 140 | ueber_left_percent=$(printf "%.0f\n" $(calc "$ueber_left" / "$term_cols" '*' 100)) | ||
| 141 | if [ "$ueber_left_percent" -lt "$reserved_playlist_cols" ]; then | ||
| 142 | ueber_left=$(( term_cols * reserved_playlist_cols / 100 )) | ||
| 143 | ueber_width=$(( term_cols - ueber_left - padding_right )) | ||
| 144 | fi | ||
| 145 | else | ||
| 146 | if [ "$ueber_left" -lt "$reserved_playlist_cols" ]; then | ||
| 147 | ueber_left=$reserved_playlist_cols | ||
| 148 | ueber_width=$(( term_cols - ueber_left - padding_right )) | ||
| 149 | fi | ||
| 150 | |||
| 151 | fi | ||
| 152 | |||
| 153 | if [ "$max_width" != 0 ] && [ "$ueber_width" -gt "$max_width" ]; then | ||
| 154 | ueber_width=$max_width | ||
| 155 | ueber_left=$(( term_cols - ueber_width - padding_right )) | ||
| 156 | fi | ||
| 157 | } | ||
| 158 | |||
| 159 | apply_force_square_setting() { | ||
| 160 | if [ $force_square = "true" ]; then | ||
| 161 | ueber_height=$(( ueber_width * font_width / font_height )) | ||
| 162 | case "$square_alignment" in | ||
| 163 | center) | ||
| 164 | area=$(( term_lines - padding_top - padding_bottom )) | ||
| 165 | padding_top=$(( padding_top + area / 2 - ueber_height / 2 )) | ||
| 166 | ;; | ||
| 167 | bottom) | ||
| 168 | padding_top=$(( term_lines - padding_bottom - ueber_height )) | ||
| 169 | ;; | ||
| 170 | *) ;; | ||
| 171 | esac | ||
| 172 | fi | ||
| 173 | } | ||
| 174 | |||
| 175 | guess_font_size() { | ||
| 176 | # A font width and height estimate is required to | ||
| 177 | # properly compute the cover width (in columns). | ||
| 178 | # We are reproducing the arithmetic used by Ueberzug | ||
| 179 | # to guess font size. | ||
| 180 | # https://github.com/seebye/ueberzug/blob/master/ueberzug/terminal.py#L24 | ||
| 181 | |||
| 182 | guess_terminal_pixelsize | ||
| 183 | |||
| 184 | approx_font_width=$(( term_width / term_cols )) | ||
| 185 | approx_font_height=$(( term_height / term_lines )) | ||
| 186 | |||
| 187 | term_xpadding=$(( ( - approx_font_width * term_cols + term_width ) / 2 )) | ||
| 188 | term_ypadding=$(( ( - approx_font_height * term_lines + term_height ) / 2 )) | ||
| 189 | |||
| 190 | font_width=$(( (term_width - 2 * term_xpadding) / term_cols )) | ||
| 191 | font_height=$(( (term_height - 2 * term_ypadding) / term_lines )) | ||
| 192 | } | ||
| 193 | |||
| 194 | guess_terminal_pixelsize() { | ||
| 195 | # We are re-using the same Python snippet that | ||
| 196 | # Ueberzug utilizes to retrieve terminal window size. | ||
| 197 | # https://github.com/seebye/ueberzug/blob/master/ueberzug/terminal.py#L10 | ||
| 198 | |||
| 199 | python <<END | ||
| 200 | import sys, struct, fcntl, termios | ||
| 201 | |||
| 202 | def get_geometry(): | ||
| 203 | fd_pty = sys.stdout.fileno() | ||
| 204 | farg = struct.pack("HHHH", 0, 0, 0, 0) | ||
| 205 | fretint = fcntl.ioctl(fd_pty, termios.TIOCGWINSZ, farg) | ||
| 206 | rows, cols, xpixels, ypixels = struct.unpack("HHHH", fretint) | ||
| 207 | return "{} {}".format(xpixels, ypixels) | ||
| 208 | |||
| 209 | output = get_geometry() | ||
| 210 | f = open("/tmp/ncmpcpp_geometry.txt", "w") | ||
| 211 | f.write(output) | ||
| 212 | f.close() | ||
| 213 | END | ||
| 214 | |||
| 215 | # ioctl doesn't work inside $() for some reason so we | ||
| 216 | # must use a temporary file | ||
| 217 | term_width=$(awk '{print $1}' /tmp/ncmpcpp_geometry.txt) | ||
| 218 | term_height=$(awk '{print $2}' /tmp/ncmpcpp_geometry.txt) | ||
| 219 | rm "/tmp/ncmpcpp_geometry.txt" | ||
| 220 | |||
| 221 | if ! is_font_size_successfully_computed; then | ||
| 222 | echo "Failed to guess font size, try setting it in `basename $0` settings" | ||
| 223 | fi | ||
| 224 | } | ||
| 225 | |||
| 226 | is_font_size_successfully_computed() { | ||
| 227 | [ -n "$term_height" ] && [ -n "$term_width" ] && | ||
| 228 | [ "$term_height" != "0" ] && [ "$term_width" != "0" ] | ||
| 229 | } | ||
| 230 | |||
| 231 | |||
| 232 | calc() { | ||
| 233 | awk "BEGIN{print $*}" | ||
| 234 | } | ||
| 235 | |||
| 236 | send_to_ueberzug() { | ||
| 237 | old_IFS="$IFS" | ||
| 238 | |||
| 239 | # Ueberzug's "simple parser" uses tab-separated | ||
| 240 | # keys and values so we separate words with tabs | ||
| 241 | # and send the result to the wrapper's FIFO | ||
| 242 | IFS="$(printf "\t")" | ||
| 243 | echo "$*" > "$FIFO_UEBERZUG" | ||
| 244 | |||
| 245 | IFS=${old_IFS} | ||
| 246 | } | ||
| 247 | |||
| 248 | main | ||
diff --git a/X11/mpd/ncmpcpp/scripts/music.png b/X11/mpd/ncmpcpp/scripts/music.png new file mode 100644 index 0000000..3ded333 --- /dev/null +++ b/X11/mpd/ncmpcpp/scripts/music.png | |||
| Binary files differ | |||
diff --git a/X11/mpd/ncmpcpp/scripts/ncmpcpp-art b/X11/mpd/ncmpcpp/scripts/ncmpcpp-art new file mode 100755 index 0000000..38d34c1 --- /dev/null +++ b/X11/mpd/ncmpcpp/scripts/ncmpcpp-art | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | |||
| 3 | ## Copyright (C) 2020-2021 Aditya Shakya <adi1090x@gmail.com> | ||
| 4 | ## Everyone is permitted to copy and distribute copies of this file under GNU-GPL3 | ||
| 5 | |||
| 6 | export FIFO_UEBERZUG="/tmp/mpd-ueberzug-${PPID}" | ||
| 7 | |||
| 8 | cleanup() { | ||
| 9 | rm "$FIFO_UEBERZUG" 2>/dev/null | ||
| 10 | rm /tmp/mpd_cover.jpg 2>/dev/null | ||
| 11 | pkill -P $$ 2>/dev/null | ||
| 12 | pkill album-art | ||
| 13 | } | ||
| 14 | |||
| 15 | pkill -P $$ 2>/dev/null | ||
| 16 | rm "$FIFO_UEBERZUG" 2>/dev/null | ||
| 17 | mkfifo "$FIFO_UEBERZUG" >/dev/null | ||
| 18 | trap cleanup EXIT 2>/dev/null | ||
| 19 | tail --follow "$FIFO_UEBERZUG" | ueberzug layer --silent --parser simple >/dev/null 2>&1 & | ||
| 20 | |||
| 21 | ncmpcpp -c ~/.ncmpcpp/config-art | ||
| 22 | cleanup | ||