forked from Botspot/pi-apps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
preload
executable file
·321 lines (275 loc) · 11.3 KB
/
preload
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#!/bin/bash
#this generates a yad-friendly app list. This is run every time the gui script is executed.
#if this script detects nothing has changed since last run, then it will echo back the app list that was generated last time.
if [ -z "$DIRECTORY" ];then
DIRECTORY="$(readlink -f "$(dirname "$0")")"
fi
mktimestamps() {
#these directories are checked for changes
checkfiles="${DIRECTORY}/apps
${DIRECTORY}/data/settings
${DIRECTORY}/data/status
${DIRECTORY}/etc
${DIRECTORY}/icons/categories
${DIRECTORY}/preload
${DIRECTORY}/api
${DIRECTORY}/data/category-overrides"
local IFS=$'\n'
for i in $checkfiles
do
printf "$i $(stat -c %Y "${i}" 2>/dev/null) "
if [ -d "$i" ];then
find "$i" -type f -printf '%T@ %p\n' | sort -rn | head -n1
else
printf '\n'
fi
done
}
[ "$1" == source ] && return 0
function error {
echo -e "\e[91m$1\e[39m" 1>&2
exit 1
}
#yad or xlunch format
guimode="$1"
if [ -z "$guimode" ];then
format=yad
elif [[ "$guimode" = xlunch* ]];then
format=xlunch
elif [[ "$guimode" = yad* ]];then
format=yad
elif [ "$guimode" != 'yad' ] && [ "$guimode" != 'xlunch' ];then
error "Unknown list format '$format'!"
fi
#specifies a category to preload (can be left empty to load main page)
prefix="$2"
if [ "$prefix" == '/' ];then
prefix=
fi
#For systems with older versions of yad, the text color column cannot be left blank. This python script determines the default text color from GTK bindings.
if [ -z "${text_color+x}" ] && [ "$format" == yad ];then
#0400 is the latest version
yad_version="$(zcat /usr/share/doc/yad/NEWS.gz | head -n 1 | tr -cd '0123456789\n')"
if [ $yad_version -lt 0400 ]; then
if command -v python3 &>/dev/null; then
python_version="python3"
else
python_version="python2"
fi
export text_color=$(echo "import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
win = Gtk.Window()
vb = Gtk.VBox()
tv = Gtk.TextView()
vb.add(tv)
win.show_all()
style = tv.get_style_context()
textcolor = style.get_color(Gtk.StateType.NORMAL)
print(Gdk.RGBA.to_string(textcolor))
" | $python_version -)
else
export text_color=""
fi
fi
timestampfile="${DIRECTORY}/data/preload/timestamps-$(echo "$prefix" | tr -d '/')"
listfile="${DIRECTORY}/data/preload/LIST-$(echo "$prefix" | tr -d '/')"
mkdir -p "${DIRECTORY}/data/preload"
reloadlist=0
if [ -f "$timestampfile" ];then
#get modified timestamps for files/directories in the pi-apps folder
timestamps="$(mktimestamps)"
if [ "$timestamps" == "$(cat "$timestampfile")" ];then
#if current timestamps and saved timestamps match, then don't reload the list
reloadlist=0
echo "Timestamps match." 1>&2
else
#timestamps don't match, so reload the list
reloadlist=1
echo "Timestamps don't match" 1>&2
#echo -e "original file: $(cat "$timestampfile")\nnew timestamp: $timestamps" 1>&2
fi
else
#timestamp file not found
reloadlist=1
fi
if [ ! -f "$listfile" ] || [ ! -s "$listfile" ];then
echo "list file for $prefix does not exist." 1>&2
reloadlist=1
else
list_length=$(wc -l "$listfile" | awk '{print $1}')
fi
if [ -n "$list_length" ] && [ "$format" == yad ] && (( $list_length % 5 )) ; then
echo "yad lists are a multiple of 5, $prefix does not have a list a multiple of 5 so it may be corrupted and needs regenerating." 1>&2
reloadlist=1
fi
#If updates available, show special Updates category (returned separately to avoid re-preloading after update-check finishes)
if [ -z "$prefix" ] && [ "$format" == yad ] && ([ -s "${DIRECTORY}/data/update-status/updatable-files" ] || [ -s "${DIRECTORY}/data/update-status/updatable-apps" ]);then
#yad format
echo "${DIRECTORY}/icons/categories/Updates.png
Updates
Updates/
Pi-Apps updates are available. Click here to update your apps.
$text_color"
elif [ -z "$prefix" ] && [ "$format" == xlunch ] && ([ -s "${DIRECTORY}/data/update-status/updatable-files" ] || [ -s "${DIRECTORY}/data/update-status/updatable-apps" ]);then
#xlunch format
echo "Updates;${DIRECTORY}/icons/categories/Updates-64.png;:exec "\""echo Updates/"\"""
fi
if [ $reloadlist == 1 ];then
echo "Generating list for '$prefix'..." 1>&2
#for app_prefix_categories() and app_status() functions
if ! command -v app_prefix_category >/dev/null ;then
source "${DIRECTORY}/api"
fi
if [ ! -z "$prefix" ];then
echo "Showing apps within $prefix/" 1>&2
vfiles="$(app_prefix_category "$prefix" | grep . | sort -f | uniq | sed "s+$prefix/++g")" #generate a virtual file system with apps in folders represented as subdirectories
else
vfiles="$(app_prefix_category "" | grep . | sort -f | uniq | grep -v '^hidden/')"
fi
#remove apps within categories - show this layer of stuff only.
vfiles="$(sed 's+/.*+/+g' <<<"$vfiles" | uniq)"
#get list of apps - excluding folders and apps that are incompatible with CPU architecture
APPS="$(grep -v '/' <<<"$vfiles" | list_intersect "$(list_apps cpu_installable)")"
#get list of folders - excluding apps.
DIRS="$(grep '/' <<<"$vfiles" | tr -d '/')"
#shuffle the list if enabled
if [ "$(< "${DIRECTORY}/data/settings/Shuffle App list")" == 'Yes' ];then
APPS="$(echo "$APPS" | shuf)"
DIRS="$(echo "$DIRS" | shuf)"
fi
if [ "$format" == yad ];then
IFS=$'\n'
listfile_tmp="$listfile-$(mktemp -u | sed 's:/tmp/tmp.::g')"
#initial value of listfile: if within a prefix, start with a Back button
if [ ! -z "$prefix" ];then
echo "${DIRECTORY}/icons/back.png
Back
$(dirname "$prefix" | sed 's+^\.$++g')/
Return to the previous location
$text_color" | tee "$listfile_tmp" &>/dev/null
else
echo -n '' > "$listfile_tmp"
fi
declare -A dir_lookup
dir_lookup=( ["Browsers"]="Internet browsers." ["All Apps"]="All Pi-Apps Applications in one long list." ["Appearance"]="Applications and Themes which modify the look and feel of your OS." ["System Management"]="Apps that help you keep track of system resources and general system management." ["Games"]="Games and Emulators" ["Installed"]="All Pi-Apps Apps that you have installed." ["Internet"]="Browsers, Chat Clients, Email Clients, and so much more." ["Multimedia"]="Video playback and creation, audio playback and creation, and streaming alternatives." ["Packages"]="Simple Apps that install directly from APT repos." ["Tools"]="An assortment of helpful programs that don't already fit into another category." ["Terminals"]="Alternative terminal programs built for the modern age as well as to replicate your old vintage computer." ["Programming"]="Code editors, IDEs, and other applications to help you write and make other programs." ["Creative Arts"]="Drawing, Painting, and Photo and Movie Editors" ["Engineering"]="3D Printing slicers, CAD/modeling, and general design software" ["Office"]="Office suites (document and slideshow editors), and other office tools." ["Emulation"]="Applications that help you run non-ARM or non-Linux software." ["Communication"]="Internet messaging, calling, video chatting, and email clients.")
for dir in $DIRS
do
if [ -f "${DIRECTORY}/icons/categories/${dir}.png" ];then
diricon="${DIRECTORY}/icons/categories/${dir}.png"
else
diricon="${DIRECTORY}/icons/categories/default.png"
fi
if [ ! -z "$prefix" ];then
add="$diricon
$dir
$prefix/$dir/
"${dir_lookup["$dir"]}"
$text_color"
else
add="$diricon
$dir
$dir/
"${dir_lookup["$dir"]}"
$text_color"
fi
add="${add//[&]/&}"
echo "$add"
done >> "$listfile_tmp"
#finished preloading categories
#preload apps
for app in $APPS
do
#get installation status of app
unset status
read -r 2>/dev/null status <"${DIRECTORY}/data/status/${app}"
#determine app icon
if [ -f "${DIRECTORY}/apps/${app}/icon-24.png" ];then
add="${DIRECTORY}/apps/${app}/icon-24.png"$'\n'
else
add="${DIRECTORY}/apps/${app}/none-24.png"$'\n'
fi
#rest of list attributes
if [ -z "$status" ];then
read -r 2>/dev/null line <"${DIRECTORY}/apps/${app}/description" || line="Description unavailable"
add+="$app
$prefix/$app
$line"$'\n'
else
read -r 2>/dev/null line <"${DIRECTORY}/apps/${app}/description" || line="Description unavailable"
add+="$app
$prefix/$app
"\("$status"\)" $line"$'\n'
fi
#determine status text-color for app name (green for installed, red for uninstalled, yellow for corrupted)
if [ -z "$status" ];then
add+="$text_color"
elif [ "$status" == installed ];then
add+="#00AA00"
elif [ "$status" == uninstalled ];then
add+="#CC3333"
elif [ "$status" == corrupted ];then
add+="#888800"
elif [ "$status" == disabled ];then
add+="#FF0000"
else
# fallback incase unexpected status
add+="$text_color"
fi
#output finished app lines
add="${add//[&]/&}"
echo "$add"
done >> "$listfile_tmp"
# write to the pipe all at once instead of in breaking chunks. this prevents errors when user clicks the back button too quickly when the list file is still generating
mv "$listfile_tmp" "$listfile"
# specifically use cat here so that all data enters the pipe at once
cat "$listfile"
echo "Finished preload for '$prefix'" 1>&2
#finished preloading apps
elif [ "$format" == xlunch ];then
#XLUNCH list format
listfile_tmp="$listfile-$(mktemp -u | sed 's:/tmp/tmp.::g')"
#initial value of listfile: if within a prefix, start with a Back button, or if on main page start with Updates
if [ ! -z "$prefix" ];then
echo "Back;${DIRECTORY}/icons/back-64.png;:exec "\""echo /"\""" | tee "$listfile_tmp" &>/dev/null
else
echo -n '' > "$listfile_tmp"
fi
IFS=$'\n'
for dir in $DIRS
do
if [ -f "${DIRECTORY}/icons/categories/${dir}-64.png" ];then
diricon="${DIRECTORY}/icons/categories/${dir}-64.png"
else
diricon="${DIRECTORY}/icons/categories/default-64.png"
fi
echo "${dir};${diricon};:exec "\""echo '${prefix}${dir}/'"\"""
done >> "$listfile_tmp"
for app in $APPS
do
if [ -f "${DIRECTORY}/data/status/${app}" ];then
echo "${app} ($(while read line; do echo $line; done 2>/dev/null < "${DIRECTORY}/data/status/${app}" 2>/dev/null));${DIRECTORY}/apps/${app}/icon-64.png;:exec "\""echo '$prefix/${app}'"\"""
else
#status file missing - app has never been installed
echo "${app};${DIRECTORY}/apps/${app}/icon-64.png;:exec "\""echo '$prefix/${app}'"\"""
fi
done >> "$listfile_tmp"
# write to the pipe all at once instead of in breaking chunks. this prevents errors when user clicks the back button too quickly when the list file is still generating
mv "$listfile_tmp" "$listfile"
# specifically use cat here so that all data enters the pipe at once
cat "$listfile"
echo "Finished preload for $prefix" 1>&2
fi
#save timestamps to file too
if [ -z "$timestamps" ];then
timestamps="$(mktimestamps)"
fi
echo "$timestamps" > "$timestampfile"
else
echo "Reading list file for '$prefix'..." 1>&2
# specifically use cat here so that all data enters the pipe at once
cat "$listfile"
fi
#preload all categories in background
"${DIRECTORY}/etc/preload-daemon" "$format" &>/dev/null &