aboutsummaryrefslogtreecommitdiffhomepage
path: root/X11/mpd/ncmpcpp/scripts/album-art
diff options
context:
space:
mode:
Diffstat (limited to 'X11/mpd/ncmpcpp/scripts/album-art')
-rwxr-xr-xX11/mpd/ncmpcpp/scripts/album-art248
1 files changed, 248 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
9music_library="$HOME/Music"
10padding_top=3
11padding_bottom=0
12padding_right=0
13max_width=40
14reserved_playlist_cols=31
15reserved_cols_in_percent="false"
16force_square="true"
17square_alignment="top"
18left_aligned="true"
19padding_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.
24font_height=
25font_width=
26
27main() {
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
37kill_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
46find_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
79display_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
95detect_window_resizes() {
96 {
97 trap 'display_cover_image' WINCH
98 while :; do sleep .1; done
99 } &
100}
101
102
103# ==== Helper functions =========================================================
104
105compute_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
129compute_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
138compute_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
159apply_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
175guess_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
194guess_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
200import sys, struct, fcntl, termios
201
202def 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
209output = get_geometry()
210f = open("/tmp/ncmpcpp_geometry.txt", "w")
211f.write(output)
212f.close()
213END
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
226is_font_size_successfully_computed() {
227 [ -n "$term_height" ] && [ -n "$term_width" ] &&
228 [ "$term_height" != "0" ] && [ "$term_width" != "0" ]
229}
230
231
232calc() {
233 awk "BEGIN{print $*}"
234}
235
236send_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
248main