#!/bin/bash set -a #export all functions and variables for child processes like runonce() DIRECTORY="$(readlink -f "$(dirname "$0")")" function error { echo -e "\e[91m$1\e[39m" exit 1 } #for the text_editor(), runonce() and app_status() functions source "${DIRECTORY}/api" || error "failed to source ${DIRECTORY}/api" if ! command -v yad &>/dev/null;then error "YAD needs to be installed to run pi-apps." fi echo '|‾‾‾‾\(‾) /‾\ | |‾) |‾| / ⧋ \ |‾'\''‾‾\|‾'\''‾‾\/‾‾‾| | ‾_/| | |‾‾‾| / ‾‾‾ \| |‾) | |‾) \ ‾‾\ |_|‾ |_| ‾‾‾ /_/‾‾‾\_\ .‾_/| .‾_/|‾‾ / |_|‾ |_|‾ ‾‾‾ ' #check for updates in background "${DIRECTORY}/updater" &>/dev/null & #Variable 1 is used to view the details of the specified app if [ ! -z "$1" ];then output="$1" fi #mark wine and box86 as installed, if twisteros runonce <<"EOF" if [ -f /usr/local/bin/twistver ] && command -v wine >/dev/null ;then echo 'disabled' > "${DIRECTORY}/data/status/Wine (x86)" fi if [ -f /usr/local/bin/twistver ] && command -v box86 >/dev/null ;then echo 'disabled' > "${DIRECTORY}/data/status/Box86" fi EOF #move some apps to the new multimedia category runonce <<"EOF" "${DIRECTORY}/etc/categoryedit" "Chromium Widevine" Multimedia >/dev/null "${DIRECTORY}/etc/categoryedit" "FreeTube" Multimedia >/dev/null "${DIRECTORY}/etc/categoryedit" "Sonic Pi 3.2" Multimedia >/dev/null "${DIRECTORY}/etc/categoryedit" "TBOPlayer" Multimedia >/dev/null "${DIRECTORY}/etc/categoryedit" "WACUP (new WinAmp)" Multimedia >/dev/null "${DIRECTORY}/etc/categoryedit" "YouTubuddy" Multimedia >/dev/null "${DIRECTORY}/etc/categoryedit" "OBS Studio" Multimedia >/dev/null #move some apps to tools category "${DIRECTORY}/etc/categoryedit" 'Snapdrop' Tools >/dev/null "${DIRECTORY}/etc/categoryedit" 'Node.js' Tools >/dev/null EOF #re-run install script on twistos lite to re-show some previously hidden apps runonce <<"EOF" if [ -f /usr/local/bin/twistver ] && [[ "$(twistver)" != 'Twister OS version'* ]];then "${DIRECTORY}/install" fi EOF #remove old apps and migrate chromium downgrading apps to the new "Chromium Downgrade" app runonce <<"EOF" rm -rf "${DIRECTORY}/apps/Back to Chromium v86" rm -rf "${DIRECTORY}/apps/Back to Chromium v78" rm -rf "${DIRECTORY}/apps/FreeCAD (precompiled)" rm -rf "${DIRECTORY}/apps/Chromium Media Edition" rm -rf "${DIRECTORY}/apps/Cordless" rm -rf "${DIRECTORY}/apps/Retropie" rm -rf "${DIRECTORY}/apps/Turbo Scratch" mv -f "${DIRECTORY}/data/status/Turbo Scratch" "${DIRECTORY}/data/status/Turbowarp" if [ "$(cat "${DIRECTORY}/data/status/Back to Chromium v78" 2>/dev/null)" == installed ] || [ "$(cat "${DIRECTORY}/data/status/Back to Chromium v86" 2>/dev/null)" == installed ];then echo "installed" > "${DIRECTORY}/data/status/Downgrade Chromium" fi EOF #rename xlunch setting to xlunch-dark runonce <<"EOF" if [ "$(cat "${DIRECTORY}/data/settings/App List Style")" == xlunch ];then echo 'xlunch-dark' > "${DIRECTORY}/data/settings/App List Style" fi EOF #for old installs prior to having categories, re-run install script runonce <<"EOF" if [ ! -e "${DIRECTORY}/data/categories" ];then "${DIRECTORY}/install" fi EOF #remove old mcpi repo runonce <<"EOF" if [ -f /etc/apt/sources.list.d/mcpi-revival.list ] && [ "$(cat /etc/apt/sources.list.d/mcpi-revival.list)" == 'deb [trusted=yes] https://mcpirevival.tk/mcpi-packages buster main' ];then echo 'deb [trusted=yes] https://mcpi-revival.github.io/mcpi-packages/ buster main' | sudo tee /etc/apt/sources.list.d/mcpi-revival.list fi EOF install() { app="$1" #one app name per line #terminal title text linecount="$(echo "$app" | wc -l)" if [ $linecount -eq 1 ];then title="Installing $app" elif [ $linecount -lt 4 ];then title="Installing $(echo -n "$app" | tr '\n' '|' | sed 's/|/, /g')" else title="Installing $linecount apps" fi "${DIRECTORY}/etc/terminal-run" ' if "'"${DIRECTORY}/manage"'" multi-install "'"$app"'" ; then echo -e "\nClosing in 30 seconds." sleep 30 else echo -e "\nClose this window to exit." read enter #technically you could press Enter to exit. fi ' "$title" sleep 1 while ps -C manage &>/dev/null;do sleep 0.1; done #re-preload all categories in background "${DIRECTORY}/etc/preload-daemon" "$format" &>/dev/null & } uninstall() { app="$1" #one app name per line #terminal title text linecount="$(echo "$app" | wc -l)" if [ $linecount -eq 1 ];then title="Uninstalling $app" elif [ $linecount -lt 4 ];then title="Uninstalling $(echo -n "$app" | tr '\n' '|' | sed 's/|/, /g')" else title="Uninstalling $linecount apps" fi "${DIRECTORY}/etc/terminal-run" ' if "'"${DIRECTORY}/manage"'" multi-uninstall "'"$app"'" ; then echo -e "\nClosing in 30 seconds." sleep 30 else echo -e "\nClose this window to exit." read enter #technically you could press Enter to exit. fi ' "$title" sleep 1 while ps -C manage &>/dev/null;do sleep 0.1; done #re-preload all categories in background "${DIRECTORY}/etc/preload-daemon" "$format" &>/dev/null & } motd="$(echo -e "$(wget -qO- https://raw.githubusercontent.com/Botspot/pi-apps-announcements/main/message | shuf -n 1)")" #app list mode. Allowed values: 'yad', 'xlunch' guimode="$(cat "${DIRECTORY}/data/settings/App List Style")" [ -z "$guimode" ] && guimode=yad #mode=yad prefix='' while true;do LIST="$("${DIRECTORY}/preload" $guimode "$prefix")" #LIST="$(cat "${DIRECTORY}/data/preload/LIST")" #echo "$LIST" #if output is not empty then assume button pressed was Details button=0 while [ -z "$output" ];do if [ "$guimode" == yad ];then if [ -z "$prefix" ];then buttons=("--button=!${DIRECTORY}/icons/install.png!Install:4" \ "--button=!${DIRECTORY}/icons/uninstall.png!Uninstall:2" \ "--button=!${DIRECTORY}/icons/info.png!View more about the selected software:0" ) else buttons=("--button=!${DIRECTORY}/icons/back.png!Back:3" \ "--button=!${DIRECTORY}/icons/install.png!Install:4" \ "--button=!${DIRECTORY}/icons/uninstall.png!Uninstall:2" \ "--button=!${DIRECTORY}/icons/info.png!Details:0" ) fi output="$(echo -e "$LIST" | yad --center --title='Pi-Apps'"$([ ! -z "$prefix" ] && echo ": $(echo "$prefix" | tr '/' '>')")" --width=310 --height=400 --no-headers \ --text="$([ -z "$prefix" ] && echo "$motd" || echo "Viewing $(echo "$prefix" | tr '/' '>') category")" --image="${DIRECTORY}/icons/logo-64.png" --image-on-top \ --list --multiple --separator='\n' --window-icon="${DIRECTORY}/icons/logo.png" \ --column=:IMG --column=:IMG --column=Name --column=Sysname:HD --column=tip:HD \ --print-column=4 --tooltip-column=5 \ "${buttons[@]}" \ )" button=$? #get exit code to determine which button was pressed echo "Button: ${button}" if [ $button -eq 252 ];then #if window manager x was pressed exit 0 fi if [ "$button" == 3 ];then #back button break fi if [ -z "$output" ];then echo "output variable empty!" yad --center --title='Pi-Apps' --width=310 \ --window-icon="${DIRECTORY}/icons/logo.png" \ --text="Mind reading is not supported. (You didn"\'"t select an App)" \ --button=OK:0 fi elif [[ "$guimode" == xlunch* ]];then if [ ! -d "${DIRECTORY}/xlunch" ] || [ ! -f /usr/bin/xlunch ];then #uninstall xlunch first sudo rm -rf /etc/xlunch /usr/share/xlunch /usr/bin/xlunch /usr/bin/genentries /usr/bin/updateentries /usr/bin/genentries.desktop.sh /usr/share/icons/hicolor/48x48/apps/xlunch_ghost.png /usr/share/icons/hicolor/48x48/apps/xlunch.png /usr/share/applications/genentries.desktop #signal files rm -f /tmp/xlunchfailed /tmp/xlunchfinished /tmp/terminalexit echo '' > /tmp/terminalexit "${DIRECTORY}/etc/terminal-run" " function error { echo -e "\""\e[91m$1\e[39m"\"" echo 'Close this terminal to exit.' echo '' > /tmp/xlunchfailed sleep infinity } trap 'echo "\"""\"" > /tmp/terminalexit' EXIT rm -f /tmp/terminalexit sudo rm -rf /usr/bin/xlunch "\""$DIRECTORY/xlunch"\"" 2>/dev/null sudo apt install -y libimlib2-dev libx11-dev || error 'APT failed to install libimlib2-dev and libx11-dev packages!' cd "\""$DIRECTORY"\"" git clone https://github.com/Tomas-M/xlunch || error 'Failed to clone xlunch repository!' cd "\""$DIRECTORY/xlunch"\"" echo 'Running make...' echo "\"""\$"(cat '${DIRECTORY}/xlunch/Makefile' | grep -v 'genentries \|cp -r svgicons/')"\"" > '${DIRECTORY}/xlunch/Makefile' make -j8 || error 'make command failed!' echo 'Running sudo make install...' sudo make install || error 'sudo make install failed!' sudo rm -f /usr/share/applications/genentries.desktop cd $HOME if [ ! -f /usr/bin/xlunch ];then error 'xlunch should be installed now, but /usr/bin/xlunch does not exist!' fi echo '' > /tmp/xlunchfinished " 'Compiling xlunch...' #if terminal doesn't start in 3 seconds, then /tmp/terminalexit will exist. sleep 3 #check for an exit status code from the running terminal while true; do if [ -f /tmp/xlunchfinished ];then echo "xlunch finished installing." break elif [ -f /tmp/xlunchfailed ];then #revert back to yad echo 'yad' > "{DIRECTORY}/data/settings/App List Style" error "xlunch failed to compile!" elif [ -f /tmp/terminalexit ];then #revert back to yad echo 'yad' > "{DIRECTORY}/data/settings/App List Style" #if terminal doesn't start in 3 seconds, then /tmp/terminalexit will exist. error "The xlunch compilation terminal exited prematurely." else sleep 1 fi done fi #xlunch compiled screen_width="$(xdpyinfo | grep 'dimensions:' | tr 'x' '\n' | tr ' ' '\n' | sed -n 7p)" screen_height="$(xdpyinfo | grep 'dimensions:' | tr 'x' '\n' | tr ' ' '\n' | sed -n 8p)" height=700 width=800 xposition=$(((screen_width/2)-(width/2))) yposition=$(((screen_height/2)-(height/2))) if false;then scrot -a "$((xposition+1)),$((yposition+33)),${width},${height}" blur.png #blur_init.png convert -blur 10x5 ~/blur.png ~/blur.png fi if [ ! -z "$prefix" ] && ! echo "$LIST" | grep -q 'Back;' ;then echo "Adding back button to xlunch..." LIST="Back;${DIRECTORY}/icons/back-64.png;./ $LIST" LIST="$(echo "$LIST" | grep .)" fi if [ -z "$prefix" ];then searchbox="Search: " else searchbox="Viewing $(echo "$prefix" | tr '/' '>'). Search: " fi if [ "$guimode" == xlunch-light-3d ];then #light mode output="$(echo -e "$LIST" | xlunch -WoCS -s 64 --bc e0e0e000 --tc 000000 --pc 6060ffff --hc ffffff50 \ -p "$searchbox" -a -c $([ $width -lt 550 ] && echo 1 || echo 2) --title "Pi-Apps: Raspberry Pi app store" \ --icon "${DIRECTORY}/icons/logo.png" --scrollbarcolor ffffff40 --scrollindicatorcolor 0000ff80 \ --width $width --height $height --xposition $xposition --yposition $yposition \ --button "${DIRECTORY}/icons/logo-3d.png;;$((($width/2)-(300/2))),0;pi-apps-homepage1" \ -g "${DIRECTORY}/icons/background-3d.png" )" elif [ "$guimode" == xlunch-dark-3d ];then #dark mode, 3d opaque version output="$(echo -e "$LIST" | xlunch -WoCS -s 64 --bc 2F313600 --tc DCDDDE --pc ffffffa0 --hc ffffff30 \ -p "$searchbox" -a -c $([ $width -lt 550 ] && echo 1 || echo 2) --title "Pi-Apps: Raspberry Pi app store" \ --icon "${DIRECTORY}/icons/logo.png" --scrollbarcolor ffffff20 --scrollindicatorcolor ffffff40 \ --width $width --height $height --xposition $xposition --yposition $yposition \ --button "${DIRECTORY}/icons/logo-3d-dark.png;;$((($width/2)-(300/2))),0;pi-apps-homepage1" \ -g "${DIRECTORY}/icons/background-3d-dark.png" )" else #dark mode, transparent version output="$(echo -e "$LIST" | xlunch -WoCS -s 64 --bc 000000A0 --tc ffffffff --pc 6060ffff --hc 60606010 \ -p "$searchbox" -a -c $([ $width -lt 550 ] && echo 1 || echo 2) --title "Pi-Apps: Raspberry Pi app store" \ --icon "${DIRECTORY}/icons/logo.png" --scrollbarcolor ffffff40 --scrollindicatorcolor 0000ff80 \ --width $width --height $height --xposition $xposition --yposition $yposition \ --button "${DIRECTORY}/icons/logo-128-trans.png;;$((($width/2)-(128/2))),0;pi-apps-homepage1" \ --button "${DIRECTORY}/icons/logo-trans.png;;$([ -z "$prefix" ] && echo '45' || echo '65'),$([ -z "$prefix" ] && echo '10' || echo '0');pi-apps-homepage1" #-g ~/blur.png )" fi button=0 if [ -z "$output" ];then error "xlunch did not report any selected apps!" fi #homepage button if [ "$output" == 'pi-apps-homepage1' ];then chromium-browser https://github.com/Botspot/pi-apps & output='' fi else error "Unrecognized app list style '$guimode'!" fi output="$(echo "$output" | grep .)" echo "Output: ${output}EOO" done #output variable populated case $button in 1) echo "User exited." exit 0 ;; 3) echo "Back" prefix="$(dirname "$prefix" | tr -d '.')" ;; 0) echo "Details" if echo "$output" | grep -q '/' ;then #folder if [ "$output" == './' ];then echo "Back" prefix="$(dirname "$prefix" | tr -d '.')" else prefix="$prefix/$output" prefix="${prefix::-1}" prefix="$(echo "$prefix" | sed 's+^/++')" fi echo "Prefix is $prefix" output='' else #app output="$(echo "$output" | head -n1)" if [ -f "${DIRECTORY}/data/installed-packages/${output}" ] && [ ! -z "$(cat "${DIRECTORY}/data/installed-packages/${output}")" ];then installedpackages=" This app installed these packages: $(cat "${DIRECTORY}/data/installed-packages/${output}" | sort | uniq | tr '\n' ' ')" else installedpackages='' fi #text below the app icon description="$(cat "${DIRECTORY}/apps/${output}/description" || echo 'Description unavailable')$installedpackages" #text to the right of the app icon abovetext="$output - Current status: $(echo "$(app_status "${output}")" | sed 's/corrupted/corrupted (installation failed)/g' | sed 's/disabled/disabled (installation is prevented on your system)/g')" if [ -f "${DIRECTORY}/apps/${output}/website" ];then #show website if it exists abovetext="$abovetext - Website: $(cat "${DIRECTORY}/apps/${output}/website" | head -n1)" fi if [ -z "$clicklist" ];then source "${DIRECTORY}/api" clicklist="$(usercount)" fi usercount="$(echo "$clicklist" | grep " $output"'$' | awk '{print $1}' | head -n1)" if [ ! -z "$usercount" ] && [ "$usercount" -gt 20 ];then abovetext="$abovetext - $(printf "%'d" "$usercount") users" if [ "$usercount" -ge 1500 ] && [ "$usercount" -lt 10000 ];then #if a lot of users, add an exclamation point! abovetext="${abovetext}!" elif [ "$usercount" -ge 10000 ];then #if a crazy number of users, add two exclamation points! abovetext="${abovetext}!!" fi fi #array holding various buttons that may be passed to yad whichbutton=() if [ "$(cat "${DIRECTORY}/data/settings/Show Edit button")" == 'Yes' ];then #if edit button enabled, show it whichbutton+=("--button=Edit!${DIRECTORY}/icons/edit.png!Make changes to the app:8") fi if [ -f "${DIRECTORY}/apps/${output}/credits" ];then #if credits file exists, display credits button whichbutton+=("--button=Credits!!See who made the app and who put it on Pi-Apps:10") fi #display buttons based on app's status file if [ "$(app_status "${output}")" == 'installed' ];then #if installed, display uninstall button whichbutton+=("--button=!${DIRECTORY}/icons/uninstall.png:2") elif [ "$(app_status "${output}")" == 'uninstalled' ];then #if uninstalled, display install button whichbutton+=("--button=!${DIRECTORY}/icons/install.png:4") elif [ "$(app_status "${output}")" == 'disabled' ];then #if disabled, display no buttons whichbutton+=("--button=Enable!!Force this app to install on your system."$'\n'"This app was disabled for a reason so if you enable it..."$'\n'"YOU HAVE BEEN WARNED.:12") else #if app status is 'corrupted', and a log file exists for this app, then display a button to view the log file if [ "$(app_status "${output}")" == 'corrupted' ];then logfile="$(ls "$DIRECTORY/logs"/* -t | grep "fail-${output}" | head -n1)" if [ ! -z "$logfile" ];then whichbutton+=("--button=Errors!${DIRECTORY}/icons/log-file.png!$output failed to $(echo "$(basename "$logfile")" | awk -F'-' '{print $1}'). Click this button to view the error output saved in the log file.:14") fi fi #if status is corrupted or unknown, then show both buttons whichbutton+=("--button=!${DIRECTORY}/icons/uninstall.png:2" "--button=!${DIRECTORY}/icons/install.png:4") fi echo "$description" | yad --text-info --fontname=12 --wrap --show-uri --text="$(echo "$abovetext" | sed 's/&/&/g')" \ --image="${DIRECTORY}/apps/${output}/icon-64.png" --image-on-top \ --title="Details of ${output}" --window-icon="${DIRECTORY}/icons/logo.png" --center --width=700 --height=300 \ --button=Back!"${DIRECTORY}/icons/back.png":0 \ --button=Scripts!"${DIRECTORY}/icons/shellscript.png"!"Feel free to see how an app is installed!"$'\n'"Perfect for learning or troubleshooting.":6 \ "${whichbutton[@]}" button=$? #get exit code to determine which button was pressed echo "Button: ${button}" case $button in 0) echo 'Back' #do nothing, as user requested to go back #clear app var output='' ;; 4) app="$output" install "$app" ;; 2) app="$output" uninstall "$app" ;; 6) app="$output" #determine path to app's install script if [ -f "${DIRECTORY}/apps/${app}/install-${arch}" ];then install_script="${DIRECTORY}/apps/${app}/install-${arch}" elif [ -f "${DIRECTORY}/apps/${app}/install" ];then install_script="${DIRECTORY}/apps/${app}/install" fi uninstall_script="${DIRECTORY}/apps/${app}/uninstall" text_editor "$uninstall_script" & sleep 0.1 text_editor "$install_script" & ;; 8) echo "edit $output" "${DIRECTORY}/createapp" "$output" ;; 10) echo "credits of $output" cat "${DIRECTORY}/apps/${output}/credits" | yad --text-info --fontname=12 --wrap \ --image="${DIRECTORY}/apps/${output}/icon-64.png" --image-on-top \ --title="Credits of ${output}" --window-icon="${DIRECTORY}/icons/logo.png" --center --width=700 --height=300 \ --button=Close!"${DIRECTORY}/icons/exit.png":0 ;; 12) echo "Enabling $output..." app="$output" #remove status file containing 'disabled' rm -f "${DIRECTORY}/data/status/${app}" ;; 14) echo "Viewing error log of $output..." echo "Log filepath: $logfile" "${DIRECTORY}/etc/viewlog" "$logfile" ;; *) error 'unknown button. Exiting now.' exit 1 ;; esac fi ;; 2) #uninstall if ! echo "$output" | grep -q '/' ;then uninstall "$output" #clear output var to prompt main window to open next else motd="Sorry, you can't uninstall folders." prefix='' fi output='' ;; 4) #install if ! echo "$output" | grep -q '/' ;then install "$output" #clear output var to prompt main window to open next else motd="Sorry, you can"\'"t install folders." prefix='' fi output='' ;; *) error "Unknown button: $button" ;; esac done