التعامل مع تطبيقات الصوت في i3wm

في سطح المكتب كتبت هذا البرنامج متوافقاً مع i3block لطباعة معلومات مقطع الصوت الذي يعمل حالياً على MPD أو مع غيره من المشغلات الصوتية / المرئية.

المشغلات المدعومة:

  • مشغلات MPD أو المتوافق معها كـMopidy.
  • VLC, SMPlayer, audacious, bmp, xmms2 باستخدام playerctl.
  • YouTube صوتي باستخدام mps-youtube و playerctl.
  • YouTube باستخدام SMTube و playerctl.
  • مشغل Spotify باستخدام playerctl ولكن الحساب المجاني لا يدعم الانتقال خلال الملف الصوتي تقديماً وتأخيراً.

الميزات:

  • نمطي عرض، عادي، ومختصر عند امتلاء الشريط.
  • عرض زمن التشغيل، اسم الملف، اسم المغني، الألبوم، عام الإصدار.
  • تشغيل / إيقاف مؤقت بالضغط على الشريط بالزر الأيسر للفأرة.
  • عند التعرف على كلمات الأغنية، يعرض ذلك عند الضغط على الشريط بالزر الأيمن للفأرة.
  • استخدام دولاب الفأرة للتقدم / التراجع بزمن تشغيل الملف.

إعدادات الإضافة للشريط في ملف i3blocks config

1
2
3
4
5
[music]
command=$HOME/scripts/i3blocks/music
interval=1
label=
markup=pango

ثم تفعيل الشريط (مع تغيير الإعداد بما يناسب) في إعداد ~/.i3/config، لاحظ استدعاء خط FontAwesome الذي ينبغي أن يكون منصباً على الجهاز حتى يعرض الأيقونات.

1
2
3
4
5
6
7
8
9
10
bar {
position top
font pango:DejaVu Sans Mono 8, FontAwesome 8
output $monitor_primary
tray_output none
workspace_buttons yes
strip_workspace_numbers yes
binding_mode_indicator yes
status_command i3blocks -c $HOME/.config/i3blocks/config-top
}

إعدادات أزرار الوسائط في ملف الإعدادات ~/.i3/config

1
2
3
4
5
6
7
8
9
10
11
12
# زر التشغيل يشغل / يوقف آنياً
bindsym XF86AudioPlay exec "$HOME/scripts/i3blocks/music toggle"
# Ctrl+زر التشغيل يوقف المشغّل
bindsym Ctrl+XF86AudioPlay exec "$HOME/scripts/i3blocks/music stop"
# زر السابق يؤخر الملف الحالي لـ10 ثوان
bindsym XF86AudioPrev exec "$HOME/scripts/i3blocks/music seek-"
# Ctrl+زر السابق يشغل الملف السابق
bindsym Ctrl+XF86AudioPrev exec "$HOME/scripts/i3blocks/music prev"
# زر التالي يقدم الملف الحالي لـ10 ثوان
bindsym XF86AudioNext exec "$HOME/scripts/i3blocks/music seek+"
# Ctrl+زر الحالي يشغل الملف الحالي
bindsym Ctrl+XF86AudioNext exec "$HOME/scripts/i3blocks/music next"

البرنامج، محفوظاً حسب ما مرّ بإعداد ملف i3blocks config وله صلاحيات التشغيل

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#!/bin/bash
MPD_PASSWORD=/dev/null
MPD_SERVER=localhost
MPC="mpc -h $MPD_PASSWORD@$MPD_SERVER"

convertsecs() {
((h=${1}/3600))
((m=(${1}%3600)/60))
((s=${1}%60))
if [[ $h -gt 0 ]]; then
printf "%02d:%02d:%02d\n" $h $m $s
else
printf "%02d:%02d\n" $m $s

fi
}

function show_lyrics() {
lyrics=`$HOME/scripts/lyrics "$title" "$artist"`

if [[ ! $lyrics ]]; then
return
fi

if [[ $1 == "notify" ]]; then
notify-send "$lyrics"
elif [[ $1 == "echo" ]]; then
echo "$lyrics"
fi
}

# الأولوية لـMPD قبل أي مشغّل
status=`$MPC status | grep -E '\[.+?\]' | awk '{print $1}'`
s_status=`playerctl status`
if [[ $status == '[playing]' ]]; then
PLAYER=mpd
elif [[ $status == '[paused]' ]]; then
if [[ $s_status == "Playing" ]]; then
PLAYER=playerctl
else
PLAYER=mpd
fi
elif [[ $s_status == "Playing" || $s_status == "Paused" ]]; then
PLAYER=playerctl
else
echo -n ""
fi

if [[ $PLAYER == mpd ]]; then
if [[ $status == '[playing]' ]]; then
status=
elif [[ $status == '[paused]' ]]; then
status=
fi

position=`$MPC -f %position% | sed -n 2p | awk '{print $3}'`

text="$status ($position) "

file_name=`$MPC -f %file% | head -n1`
file_name=${file_name##*/}
file_name=${file_name%.*}

artist=`$MPC -f %artist% | head -n1`

title=`$MPC -f %title% | head -n1`

album=`$MPC -f %album% | head -n1`

date=`$MPC -f %date% | head -n1`

volume=`$MPC -f %position% | sed -n 3p | awk '{print $2}'`

case $BLOCK_BUTTON in
1 ) $MPC toggle;;
3 ) show_lyrics "notify";;
4 ) $MPC seek +10;;
5 ) $MPC seek -10;;
esac

elif [[ $PLAYER == playerctl ]]; then

status=`playerctl status`

if [[ $status == 'Playing' ]]; then
status=
elif [[ $status == 'Paused' ]]; then
status=
fi


position=`playerctl metadata`
regex="'(.{1,5}):length'"
if [[ $position =~ $regex ]]; then
position=`playerctl metadata ${BASH_REMATCH[1]}:length`
position=${position%.*}
position=$((position/1000000))
position=`convertsecs $position`

fi

current_position=`playerctl position`
current_position=$(echo "$current_position"|bc)
current_position=${current_position%%.*}
current_position=`convertsecs $current_position`

text="$status ($current_position/$position) "

artist=`playerctl metadata artist`

title=`playerctl metadata title`

album=`playerctl metadata album`

date=`playerctl metadata xesam:contentCreated`
volume=$(echo "`playerctl volume`*100"|bc)
volume=${volume%%.*}%

case $BLOCK_BUTTON in
1 ) playerctl play-pause;;
3 ) show_lyrics "notify";;
4 ) playerctl position 10+;;
5 ) playerctl position 10-;;
esac
fi

if [[ $artist ]]; then
text="$text <span foreground=\"#C0C000\">"`echo "$artist" | recode utf8..html`"</span>"
fi

if [[ $artist && $title ]]; then
text="$text, <span foreground=\"#E54C62\">"`echo "$title " | recode utf8..html`"</span>"
elif [[ $title ]]; then
text="$text <span foreground=\"#E54C62\">"`echo "$title " | recode utf8..html`"</span>"
fi

if [[ $album ]]; then
text="$text (<span foreground=\"#00E0E0\">"`echo "$album " | recode utf8..html`"</span>)"
fi

if [[ $date && $date != '0' ]]; then
text="$text [<span foreground=\"#C0C0C0\">"`echo "$date " | recode utf8..html`"</span>]"
fi

if [[ !$artist && !$title && !$album && !$date ]]; then
text="$text<span foreground=\"#E54C62\">"`echo "$file_name " | recode utf8..html`"</span>"
fi


if [[ $PLAYER == playerctl && `playerctl -l | head -n1` =~ "mps-youtube" ]]; then
text="$text <span foreground=\"#cd201f\"></span>"
fi

if [[ $volume ]]; then
if [[ ${volume%?} -le 5 ]]; then
volume=" ${volume}"
elif [[ ${volume%?} -le 50 ]]; then
volume=" ${volume}"
else
volume=" ${volume}"
fi

text="$text | $volume"
fi

if [[ ${#title} -ge 20 ]]; then
short_text=`echo -n $title | awk '{print substr($0,2,20)}'`
short_text="($position) $status $short_text..."
fi

# إن لم يكن هناك أي ملف من أي مشغّل، حاول بدء المشغّل
function toggle() {
if [[ $PLAYER == mpd || `playerctl status 2>&1` == "Connection to player failed: No players found" ]]; then
$MPC toggle
elif [[ $PLAYER == playerctl || `mpc 2>&1` == "mpd error: Connection refused" ]]; then
playerctl play-pause
fi
}

function stop() {
if [[ $PLAYER == mpd ]]; then
$MPC stop
elif [[ $PLAYER == playerctl ]]; then
playerctl stop
fi
}

function seek() {
if [[ $PLAYER == mpd ]]; then
$MPC seek ${1}10
elif [[ $PLAYER == playerctl ]]; then
playerctl position 10${1}
fi
}

function next() {
if [[ $PLAYER == mpd ]]; then
$MPC next
elif [[ $PLAYER == playerctl ]]; then
playerctl next
fi
}

function prev() {
if [[ $PLAYER == mpd ]]; then
$MPC prev
elif [[ $PLAYER == playerctl ]]; then
playerctl previous
fi
}

case $1 in
toggle )
toggle;;
stop)
stop;;
seek-)
seek "-";;
seek+)
seek "+";;
next)
next;;
prev)
prev;;
lyrics)
show_lyrics "echo";;
esac

echo $text
echo $short_text