forked from Botspot/pi-apps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi
executable file
·326 lines (260 loc) · 12.4 KB
/
api
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
322
323
324
325
#!/bin/bash
DIRECTORY="$(readlink -f "$(dirname "$0")")"
error() {
echo -e "\e[91m$1\e[39m" 1>&2
exit 1
}
#echo "API script thinks directory is $DIRECTORY" 1>&2
repo_url="$(cat "${DIRECTORY}/etc/git_url" || echo 'https://github.com/Botspot/pi-apps')"
#determine if host system is 64 bit arm64 or 32 bit armhf
if [ ! -z "$(file "$(readlink -f "/sbin/init")" | grep 64)" ];then
arch=64
elif [ ! -z "$(file "$(readlink -f "/sbin/init")" | grep 32)" ];then
arch=32
else
error "Failed to detect OS CPU architecture! Something is very wrong."
fi
list_intersect() { #Outputs only the apps that appear in both stdin and in $1
# change \n to \| | remove last "\|"
grep -x "$(echo "$1" | sed -z 's/\n/\\|/g' | sed -z 's/\\|$/\n/g')"
}
list_subtract() { #Outputs a list of apps from stdin, minus the ones that appear in $1
# change \n to \| | remove last "\|"
grep -vx "$(echo "$1" | sed -z 's/\n/\\|/g' | sed -z 's/\\|$/\n/g')"
}
list_apps() { # $1 can be: installed, uninstalled, corrupted, cpu_installable, hidden, visible, online, online_only, local, local_only
if [ -z "$1" ] || [ "$1" == local ];then
#list all apps
ls "${DIRECTORY}/apps"
elif [ "$1" == all ];then
#combined list of apps, both online and local. Removes duplicate apps from the list.
echo -e "$(list_apps local)\n$(list_apps online)" | sort | uniq
elif [ "$1" == installed ];then
#list installed apps
#list apps| only show ( list of installed apps | remove match string | basename )
list_apps local | list_intersect "$(grep -rx 'installed' "${DIRECTORY}/data/status" | awk -F: '{print $1}' | sed 's!.*/!!')"
elif [ "$1" == corrupted ];then
#list corrupted apps
#list apps|only show ( list of corrupted apps | remove match string | basename )
list_apps local | list_intersect "$(grep -rx 'corrupted' "${DIRECTORY}/data/status" | awk -F: '{print $1}' | sed 's!.*/!!')"
elif [ "$1" == disabled ];then
#list corrupted apps
#list apps|only show ( list of disabled apps | remove match string | basename )
list_apps local | list_intersect "$(grep -rx 'disabled' "${DIRECTORY}/data/status" | awk -F: '{print $1}' | sed 's!.*/!!')"
elif [ "$1" == uninstalled ];then
#list uninstalled apps
#list apps that have a status file containing "uninstalled"
list_apps local | list_intersect "$(grep -rx 'uninstalled' "${DIRECTORY}/data/status" | awk -F: '{print $1}' | sed 's!.*/!!')"
#also list apps that don't have a status file
list_apps local | list_subtract "$(ls "${DIRECTORY}/data/status")"
elif [ "$1" == cpu_installable ];then
#list apps that can be installed on the device's OS architecture (32-bit or 64-bit)
#find all apps that have install-XX script or an install script
find "${DIRECTORY}/apps" -type f \( -name "install-$arch" -o -name "install" \) | sed "s+/install-$arch++g" | sed "s+/install++g" | sed "s+${DIRECTORY}/apps/++g" | sort | uniq
elif [ "$1" == hidden ];then
#list apps that are hidden
cat "${DIRECTORY}/data/categories/structure" | grep '|hidden' | awk -F'|' '{print $1}'
elif [ "$1" == visible ];then
#list apps that are in any other category but 'hidden', and aren't disabled
cat "${DIRECTORY}/data/categories/structure" | grep -v '|hidden' | awk -F'|' '{print $1}' # | list_subtract "$(list_apps disabled)"
elif [ "$1" == online ];then
#list apps that exist on the online git repo
if [ -d "${DIRECTORY}/update/pi-apps/apps" ];then
#if update folder exists, just use that
ls "${DIRECTORY}/update/pi-apps/apps" | grep .
else
#if update folder doesn't exist, then parse github HTML to get a list of online apps. Horrible idea, but it works!
wget -qO- "${repo_url}/tree/master/apps" | grep 'title=".*" data-pjax=' -o | sed 's/title="//g' | sed 's/" data-pjax=//g'
fi
elif [ "$1" == online_only ];then
#list apps that exist only on the git repo, and not locally
list_apps online | list_subtract "$(list_apps local)"
elif [ "$1" == local_only ];then
#list apps that exist only locally, and not on the git repo
list_apps local | list_subtract "$(list_apps online)"
fi
}
app_categories() { #lists all apps in a virtual filesystem based on categories file
#cat "${DIRECTORY}/data/categories/structure" | awk -F'|' '{print $2"/"$1}'
#find apps not in categories file
{
missingapps="$(list_apps | list_subtract "$(cat "${DIRECTORY}/data/categories/structure" | awk -F'|' '{print $1}')")"
if [ ! -z "$missingapps" ];then
PREIFS="$IFS"
IFS=$'\n'
for app in $missingapps ;do
echo "WARNING: $app not found in categories file." 1>&2
if list_apps online | grep -qx "$app" ;then
#if app found online, then use online category line
if [ -z "$onlinestructurefile" ];then
onlinestructurefile="$(wget -qO- 'https://raw.githubusercontent.com/Botspot/pi-apps/master/data/categories/structure')"
fi
if echo "$onlinestructurefile" | grep -q '^'"$app|" ;then
#if line found in online structure file
echo "Putting $app in the $(echo "$onlinestructurefile" | grep '^'"$app|" | awk -F'|' '{print $2}') category." 1>&2
echo "$(echo "$onlinestructurefile" | grep '^'"$app|")" >> "${DIRECTORY}/data/categories/structure"
else
#app exists online, but no structure line found
echo -e "\e[33mHUGE WARNING: the $app exists on github, but no category was found for it on github!\nPlease report this to Botspot.\e[39m" 1>&2
echo "Putting $app in the / category." 1>&2
#put the app in root directory - no category
echo "$app|" >> "${DIRECTORY}/data/categories/structure"
fi
else
#app not found online
echo "Putting $app in the / category." 1>&2
#put the app in root directory - no category
echo "$app|" >> "${DIRECTORY}/data/categories/structure"
fi
done
IFS="$PREIFS"
fi
}
#find apps in categories file that don't exist
{
ghostapps="$(cat "${DIRECTORY}/data/categories/structure" | awk -F'|' '{print $1}' | list_subtract "$(list_apps)")"
if [ ! -z "$ghostapps" ];then
PREIFS="$IFS"
IFS=$'\n'
for app in $ghostapps ;do
echo "WARNING: $app does not exist but it was found in categories file." 1>&2
echo "Removing $app from the categories file..." 1>&2
#put the app in root directory - no category
sed -i "/$app/d" "${DIRECTORY}/data/categories/structure"
done
IFS="$PREIFS"
fi
}
#category file cleaned up past this point
#show normal categories
cat "${DIRECTORY}/data/categories/structure" | grep . | awk -F'|' '{print $2"/"$1}' | sed 's+^/++g'
#show special Installed category
list_apps installed | sed 's+^+Installed/+g'
#show special All Apps category
list_apps cpu_installable | list_intersect "$(list_apps visible)" | sed 's+^+All Apps/+g'
}
usercount() { #Return number of users for specified app. $1 is app name. if empty, all are shown.
clicklist="$(wget -qO- 'https://raw.githubusercontent.com/Botspot/pi-apps-analytics/main/clicklist')"
[ -z "$clicklist" ] && error "usercount: clicklist empty. Likely no internet connection"
if [ -z "$1" ];then
echo "$clicklist"
else
# $1 is app
echo "$clicklist" | grep " $1"'$' | awk '{print $1}' | head -n1
fi
}
text_editor() { #Open user-preferred text editor. $1 is file to open
[ -z "$1" ] && error "text_editor(): no file specified"
#find the best text editor
preferrededitor="$(cat "${DIRECTORY}/data/settings/Preferred text editor")"
#change preferred editor if user-default doesn't exist
if ! command -v "$preferrededitor" >/dev/null;then
preferrededitor=geany
fi
if ! command -v "$preferrededitor" >/dev/null;then
preferrededitor=mousepad
fi
if ! command -v "$preferrededitor" >/dev/null;then
preferrededitor=leafpad
fi
if ! command -v "$preferrededitor" >/dev/null;then
preferrededitor=nano
fi
if [ "$preferrededitor" == nano ];then
#terminal-based text editor
"${DIRECTORY}/etc/terminal-run" "nano "\""$1"\""" "Editing $(basename "$1")"
else
#non-terminal text editor
"$preferrededitor" "$1"
fi
}
script_name() { #returns name of install script(s) for the $1 app. outputs: '', 'install-32', 'install-64', 'install', 'install-32 install-64'
[ -z "$1" ] && error 'script_name: requires an argument'
#ensure $1 is valid app name
[ ! -d "${DIRECTORY}/apps/$1" ] && error "script_name: '$1' is an invalid app name.\n${DIRECTORY}/apps/$1 does not exist."
if [ -f "${DIRECTORY}/apps/$1/install-32" ] && [ ! -f "${DIRECTORY}/apps/$1/install-64" ];then
echo 'install-32'
elif [ -f "${DIRECTORY}/apps/$1/install-64" ] && [ ! -f "${DIRECTORY}/apps/$1/install-32" ];then
echo 'install-64'
elif [ -f "${DIRECTORY}/apps/$1/install-64" ] && [ -f "${DIRECTORY}/apps/$1/install-32" ];then
echo 'install-32 install-64'
elif [ -f "${DIRECTORY}/apps/$1/install" ];then
echo 'install'
else
true
#error "No install script found for the $app app! Please report this to Botspot."
fi
}
script_name_cpu() { #get script name to run based on detected CPU arch
[ -z "$1" ] && error 'script_name_cpu: requires an argument'
#ensure $1 is valid app name
if ! list_apps all | grep -q "$1" ;then
error "script_name_cpu: '$1' is an invalid app name."
fi
#this is used by the updater so we need to check the update folder too
if [ -f "${DIRECTORY}/apps/$1/install-32" ] && [ $arch == 32 ];then
echo 'install-32'
elif [ -f "${DIRECTORY}/apps/$1/install-64" ] && [ $arch == 64 ];then
echo 'install-64'
elif [ -f "${DIRECTORY}/apps/$1/install" ];then
echo 'install'
elif [ -f "${DIRECTORY}/update/pi-apps/apps/$1/install-32" ] && [ $arch == 32 ];then
echo 'install-32'
elif [ -f "${DIRECTORY}/update/pi-apps/apps/$1/install-64" ] && [ $arch == 64 ];then
echo 'install-64'
elif [ -f "${DIRECTORY}/update/pi-apps/apps/$1/install" ];then
echo 'install'
else
true #app not compatible with current arch
fi
}
app_status() { #Gets the $1 app's current status. installed, uninstalled, corrupted, disabled
[ -z "$1" ] && error 'app_status: $1 variable empty!'
if [ -f "${DIRECTORY}/data/status/${1}" ];then
cat "${DIRECTORY}/data/status/${1}"
else
echo 'uninstalled' #if app status file doesn't exist, assume uninstalled
fi
}
will_reinstall() { #return 0 if $1 app will be reinstalled during an update, otherwise return 1.
[ -z "$1" ] && error 'will_reinstall: requires an argument'
#detect which installation script exists and get the hash for that one
scriptname="$(script_name_cpu "$1")"
oldinstallhash=$(sha1sum "${DIRECTORY}/apps/${1}/${scriptname}" | awk '{print $1}')
newinstallhash=$(sha1sum "${DIRECTORY}/update/pi-apps/apps/${1}/${scriptname}" 2>/dev/null | awk '{print $1}')
#if install script was changed #if installed already
if [ "$newinstallhash" != "$oldinstallhash" ] && [ "$(app_status "${1}")" == 'installed' ];then
return 0
else
return 1
fi
}
runonce() { #run command only if it's never been run before. Useful for one-time migration or setting changes.
#Runs a script in the form of stdin
script="$(cat /dev/stdin)"
runonce_hash="$(echo "$script" | sha256sum | awk '{print $1}')"
if grep -qx '^'"$runonce_hash"'$' "${DIRECTORY}/data/runonce_hashes" ;then
#hash found
#echo "runonce: '$script' already run before. Skipping."
true
else
#run the script.
bash <(echo "$script")
#if it succeeds, add the hash to the list to never run it again
if [ $? == 0 ];then
echo "$runonce_hash" >> "${DIRECTORY}/data/runonce_hashes"
echo "'$script' succeeded. Added to list."
else
echo "'$script' failed. Not adding hash to list."
fi
fi
}
#if this script is being run standalone, not sourced
if [[ "$0" == */api ]];then
#if user input a function command, then run it with arguments.
if [ ! -z "$1" ];then
#Keep in mind this could run any command the user wanted, not necessarily exclusively function commands.
"$@"
#"$1" "$2" "$3" "$4" "$5" "$6"
fi
fi