338 lines
12 KiB
Bash
338 lines
12 KiB
Bash
#!/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
|
|
|
|
# if the timestamp in the settings folder has changed, we need to unset the text_color variable since the GTK_THEME may have changed and we need to re-generate it
|
|
timestamp_settings="$( cat ${DIRECTORY}/data/preload/timestamps- | grep "^${DIRECTORY}/data/settings" )"
|
|
timestamps="$(mktimestamps)"
|
|
echo "$timestamps" | grep -q "$timestamp_settings" || unset text_color
|
|
|
|
#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
|
|
#the GTK_THEME may not be current depending on when the API script was last sourced
|
|
#to avoid setting the text to the wrong color, check it again now right
|
|
#set the system GTK theme for yad windows
|
|
guimode="$(cat "${DIRECTORY}/data/settings/App List Style" 2>/dev/null || echo yad-default)"
|
|
if [ "$guimode" == yad-default ];then
|
|
export GTK_THEME=''
|
|
elif [[ "$guimode" = yad* ]];then
|
|
export GTK_THEME=${guimode//yad-/}
|
|
elif [ "$guimode" == xlunch-light-3d ];then
|
|
export GTK_THEME=''
|
|
elif [ "$guimode" == xlunch-dark-3d ];then
|
|
export GTK_THEME=Adwaita-dark
|
|
elif [ "$guimode" == xlunch-dark ];then
|
|
export GTK_THEME=Adwaita-dark
|
|
fi
|
|
export text_color=$(echo "import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gtk
|
|
from gi.repository import Gdk
|
|
tv = Gtk.TextView()
|
|
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 Artian-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/
|
|
Artian-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 Artian-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 Artian-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}/icons/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}"));${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 &
|