#!/system/bin/sh
# Terminal Magisk Mod Template
# by veez21 @ xda-developers


# Magisk Module ID **
ID="terminal_debloater"

# Detect root
_name=$(basename $0)
ls /data >/dev/null 2>&1 || { echo "$ID needs to run as root!"; echo "type 'su' then '$_name'"; exit 1; }

# Magisk Mod Directory
MOUNTPATH="/data/adb/modules"
MODDIR="$MOUNTPATH/$ID"
[ ! -d $MODDIR ] && { echo "Module not detected!"; exit 1; }

# Load mod-util.sh
. $MODDIR/mod-util.sh || exit $?

# Set Log Files
mount -o remount,rw /cache 2>/dev/null
mount -o rw,remount /cache 2>/dev/null
# > Logs should go in this file
LOG=/data/local/tmp/$ID.log
oldLOG=/data/local/tmp/$ID-old.log
# > Verbose output goes here
VERLOG=/data/local/tmp/$ID-verbose.log
oldVERLOG=/data/local/tmp/$ID-verbose-old.log

# Start Logging verbosely
mv -f $VERLOG $oldVERLOG 2>/dev/null; mv -f $LOG $oldLOG 2>/dev/null
set -x 2>$VERLOG

# Main
# > You can start your MOD here.
# > You can add functions, variables & etc.
# > Rather than editing the default vars above.

help_me() {
  cat << EOF
$MODTITLE $VER($REL)
by $AUTHOR

Usage: $_name
   or: $_name [options]...

Options:
    -nc                              removes ANSI escape codes
    -l [app|priv-app|vendor]         list system apps
    -d [app label|app folder name]   uninstall apps (use $_name -d -h)
    -i [file]                        import config from file
    -e [file]                        export current settings
    -h                               show this message
EOF
exit
}

show_rein=false
use_aapt=false
export PATH=$MODDIR:$PATH
[[ "$(which aapt)" ]] && use_aapt=true
import_file=$CACHELOC/import-debloat.txt
exclude_file=$MODDIR/exclude.list
LISTFILE=$CACHELOC/debloat.list
RESCAN=true
[ -f $SYSTEM2/build.prop ] && SYSTEM=$SYSTEM2

[ $(getenforce) == "Permissive" ] && use_cmd=true || use_cmd=false
[ $ANDROID_SOCKET_adbd ] && use_cmd=true || use_cmd=false

debloat_app() {
  [ "$1" == "n" ] && shift || get_cfg $1
   echo "Uninstalling ${R}${1}${N} ($DIR_APP)" | tr '%_' ' '
  sleep 0.4
  [ ! -d $DIR_APP ] && DIR_APP=$(dumpsys package $PKG | grep "path:" | sed 's/.*path: //;s/\(.*\)\/.*/\1/' 2>/dev/null)
  echo " App Label: ${G}$PKG${N}"
  echo " App Dir: ${G}$DIR_APP${N}"
  [ "$proceed" == "a" ] || {
    echo -n " Proceed? < (y)es | (n)o | (a)ll >: "
    read proceed
  }
  case "$proceed" in
    y|Y|a|A)  mktouch ${MODDIR}${DIR_APP}/.replace ${1}
             $use_aapt && {
             if $(dumpsys package $PKG | grep UPDATED_SYSTEM_APP >/dev/null); then
               echo " - App is updated, uninstall updates in Settings App"
             fi
		     }
			 echo "${R}${1}${N} uninstalled" | tr '%_' ' ';;
	n|N) echo "${R}${1}${N} cancelled" | tr '%_' ' ';;
	*) echo "Invalid!";;
  esac
}

get_cfg() {
  APP_NAME=$(grep -wm1 "=${1}^" $LISTFILE | tr '^=' ' ' | awk '{print $1}')
  DIR_APP=$(grep -wm1 "=${1}^" $LISTFILE | tr '^=' ' ' | awk '{print $2}')
  PKG=$(grep -wm1 "=${1}^" $LISTFILE | tr '^=' ' ' | awk '{print $3}')
  [ $? -gt 0 ] && abort "Package doesn't exist!"
}

get_app_name() {
  apk_dir=$(echo ${1}/${apk_name[$2]})
  if $use_aapt; then
    app_name=$(aapt dump badging $apk_dir 2>>$LOG | grep 'application-label:' 2>/dev/null)
    if [ $? -gt 0 ]; then
      app_name[$2]=${name[$2]}
      return
    fi
    app_name=${app_name#*:}
    app_name[$2]=$(echo $app_name | tr ' ' '%_' | sed "s/'//1;s/\(.*\)'/\1/")
    app_label=$(aapt dump badging $apk_dir | grep package | head -n1)
    app_label=${app_label#*"'"}
    app_label[$2]=${app_label%%"'"*}
  else
    app_name[$2]=${name[$2]}
  fi
}

list_s-app() {
  if [[ "$RESCAN" ]] && [[ "$type" != "$1" ]]; then
    rm $LISTFILE 2>>$LOG; app_name=(); listapp=()
    x=1
    type=$1
    sapp=($(ls $SYSTEM/$type))
    for i in ${sapp[@]}; do
      ProgressBar $x ${#sapp[@]}
      listapp[x]=$SYSTEM2/$type/$i
      if [[ ! -d $MODDIR${listapp[x]} ]]; then
        if ! grep -xqE -e "(app|priv-app|vendor/app)/${i}" $exclude_file; then
          name[x]=${i}
          apk_name[x]="$(basename $(find $SYSTEM/$type/$i -name "*.apk" -type f -mindepth 1))"
          get_app_name ${listapp[x]} $x
          echo "^=${app_name[x]}^=${listapp[x]}^=${app_label[x]}" >> $LISTFILE
          x=$((x+1))
        fi
      fi
    done
    app_name=(); u_app_name=(); xz=0
    for i in $(cat $LISTFILE); do
      u_app_name[xz++]=$(echo $i | tr '^=' ' ' | awk '{print $1}')
    done
    app_name=($(printf '%s\n' "${u_app_name[@]}" | sort -f))
	RESCAN=false
  fi
}

list_unin_app() {
  c=1
  for i in $(find $MODDIR$SYSTEM2 -name ".replace" -type f); do
    unin_app[c]=$(dirname $i)
    name_unin[c]=$(cat $i)
    if [ $? -gt 0 ] || [ -z ${name_unin[c]} ] || [[ ! $(cat $i) ]]; then
      name_unin[c]=$(basename ${unin_app[c]})
    fi
    echo " $c - ${W}${name_unin[c]}${N} ($(basename ${unin_app[c]%/*}))" | tr '_' ' ' | tr '%_' ' '
    c=$((c+1))
  done
}

import_list() {
  [[ "$1" ]] && local import_file=$1
  if [[ -f $import_file ]] && [[ "$(grep_prop debloat.import $import_file)" == 1 ]]; then
    c=1
	for i in $(cat $import_file | grep -vE -e "(#|debloat.import)"); do
	  name[c]=${i%^=*}
	  sys_dir=${i#*^=}
      get_app_name $sys_dir $c
      mktouch $MODDIR$sys_dir/.replace ${app_name[c]}
      echo "${W}${app_name[c]}${N} - Imported"
      c=$((c+1))
    done
  else
    echo "Invalid file"
  fi
}

export_list() {
  [[ "$1" ]] && local import_file=$1
  mktouch $import_file "debloat.import=1"
  for i in $(find $MODDIR/system -name ".replace" -type f); do
    local dir=${i%/*}
	local folder=${dir##*/}
	local name=$(cat $i) || local name=$folder
    echo "$folder^=${dir#*${MODDIR}}" >> $import_file
    echo " $name - Exported" | tr '_' ' ' | tr '%_' ' '
  done
}

menu_list_system_app() {
  clear
  list_s-app $1 2>>$LOG
  clear
  echo "$div"
  title_div "System Apps ($1)"
  echo "$div"
  echo ""
  dir_error=false
  c=1
  for i in $(seq 1 $((${#app_name[@]}-1))); do
    detect_app_dir=$(basename $(grep -wm1 "=${app_name[i]}^" $LISTFILE | tr '^=' ' ' | awk '{print $2}') 2>/dev/null) || dir_error=true
    printf "%b %s\n" " $c - ${W}${app_name[i]}${N}" $([ -n "$detect_app_dir" ]  && echo "(${Bl}$detect_app_dir${N})") | tr '%_' ' '
    c=$((c+1))
  done
  echo ""
  $dir_error && echo " ${R}An error was detected while detecting system apps.${N}"
  echo " ${Bl}To uninstall multiple apps, enter multiple numbers. Example:${N} \"1 ${#app_name[$((${#app_name[@]}/3))]} ${#app_name[$((${#app_name[@]}/2))]}\""
  echo " x - ${Bl}Back to Menu${N}"
  echo " r - ${Bl}Refresh list${N}"
  echo " 0 - ${Bl}Exit${N}"
  echo "$div"
  echo -n "[CHOICE]: "
  read app
  [ "$app" == "x" ] && menu
  [ "$app" == "r" ] && { RESCAN=true; type=null ; menu_list_system_app $1; }
  for i in $app; do
    if [ "$i" -gt "${#listapp[@]}" ] || [ "$i" -lt "0" ] || [ "$i" == "" ] || [ -n "$(echo $i | tr -d '0-9')" ] ; then
      echo "$i - Invalid"; false
    elif [ "$i" == "0" ]; then
      exit
    else
      debloat_app ${app_name[i]}
    fi
  done
  unset proceed
  echo "Reboot to apply changes"
  echo -n "Return to menu? < y | n >: "
  read mchoice
  [ "$mchoice" == "y" ] && menu || exit
}

menu_list_unin_app() {
  clear
  echo "$div"
  title_div "Reinstall"
  echo " You can also just delete your selected
 folders in $MODDIR$SYSTEM2/app or priv-app."
  echo " The apps debloated were reset
 to their factory version."
  echo "$div"
  echo ""
  list_unin_app
  echo ""
  echo " ${Bl}To reinstall multiple apps, enter multiple numbers. Example:${N} \"1 ${#app_name[$((${#app_name[@]}/3))]} ${#app_name[$((${#app_name[@]}/2))]}\""
  echo " x - ${Bl}Back to Menu${N}"
  echo " 0 - ${Bl}Exit${N}"
  echo ""
  echo -n "[CHOICE]: "
  read rein
  [ "$rein" == "x" ] && menu
  for i in $rein; do
    if [ "$i" -gt ${#name_unin[@]} ] || [ "$i" -lt 0 ] || [ "$i" == "" ] || [ -n "$(echo $i | tr -d '0-9')" ] ; then
      echo "Invalid"; false
    elif [ "$i" == "0" ]; then
      exit
    else
      echo "Reinstalling ${G}${name_unin[i]}${N}" | tr '_' ' ' | tr '%_' ' '
      sleep 0.4
      rm -rf ${unin_app[i]}
    fi
  done
  echo "Reboot to apply changes"
  echo -n "Return to menu? < y | n >: "
  read mchoice
  app_name=()
  [ "$mchoice" == "y" ] && menu || exit
}

menu_list_custom_dir() {
  clear
  echo "$div"
  title_div "Custom Debloat Directory"
  echo "$div"
  echo " ${R}EXPERIMENTAL!${N}"
  echo " Enter a directory in $SYSTEM"
  echo " that contains system apps/bloatware"
  echo "$div"
  echo "\n Example: /system/delapp"
  echo " x - ${Bl}Back to Menu${N}"
  echo -n " > "
  read custdir
  [ "$custdir" == "x" ] && menu
  echo -n " Checking if $custdir exists"
  if [ -d "$custdir" ]; then
    echo " - OK"
	echo -n " Checking if $custdir is in $SYSTEM"
	if [ "/$(echo $custdir | awk -F "/" '{print $2}')" == "$SYSTEM" ]; then
	  echo " - OK"
      sleep 1.5
      menu_list_system_app "$(echo $custdir | sed 's/.*\/system\///g')"
	else
	  echo " - Error!"
      echo -n "Return to menu? < y | n >: "
      read mchoice
      [ "$mchoice" == "y" ] && menu || exit
	fi
  else
    echo " - Error!"
    echo -n "Return to menu? < y | n >: "
    read mchoice
    [ "$mchoice" == "y" ] && menu || exit
  fi
}

menu_export_list() {
  clear
  echo "$div"
  title_div "Export Config"
  echo "$div"
  echo " Saves the current debloated apps"
  echo " to a file so it can be imported later/shared"
  echo "$div"
  echo ""
  echo " Enter a directory to save the file"
  echo " or leave it blank to use default ($import_file)"
  echo " Example: /sdcard"
  echo " x - ${Bl}Back to Menu${N}"
  echo -n " > "
  read export_dir
  [ "$export_dir" == "x" ] && menu
  if [[ ! "$export_dir" ]]; then
    echo "Exporting to ${W}$import_file...${N}"
    sleep 0.4
    export_list
    echo "Done"
    echo -n "Return to menu? < y | n >: "
    read mchoice
    [ "$mchoice" == "y" ] && menu || exit
  fi
  echo -n " Checking if $export_dir exists"
  if [[ -d "$export_dir" ]]; then
    echo " - OK"
    echo " Exporting to ${W}$export_dir/import-debloat.txt...${N}"
    sleep 0.4
    export_list $export_dir/import-debloat.txt
    echo "Done"
    echo -n "Return to menu? < y | n >: "
    read mchoice
    [ "$mchoice" == "y" ] && menu || exit
  else
    echo " - Error!"
    echo -n "Return to menu? < y | n >: "
    read mchoice
    [ "$mchoice" == "y" ] && menu || exit
  fi
}

menu_import_list() {
  clear
  echo "$div"
  title_div "Import Config"
  echo "$div"
  echo " Import from a txt file exported from this module"
  echo " ${R}Be careful importing from unknown sources!${N}"
  echo "$div"
  echo ""
  [ -f $import_file ] && echo " ${G}$import_file detected! Leave blank and enter to use it.${N}"
  echo " Enter the directory of the import file"
  echo " Example: /sdcard/import-debloat.txt"
  echo -n " > "
  read import_dir
  [ "$import_dir" == "x" ] && menu
  if [[ -f $import_file ]] && [[ ! "$import_dir" ]]; then
    echo " Importing from ${W}$import_file...${N}"
    sleep 0.4
    import_list
    echo "Done"
    echo -n "Return to menu? < y | n >: "
    read mchoice
    [ "$mchoice" == "y" ] && menu || exit
  fi
  echo -n " Checking if $import_dir exists"
  if [[ -f "$import_dir" ]]; then
    echo " - OK"
    echo " Importing from ${W}$import_dir...${N}"
    sleep 0.4
    import_list $import_dir
    echo "Done"
    echo -n "Return to menu? < y | n >: "
    read mchoice
    [ "$mchoice" == "y" ] && menu || exit
  else
    echo " - Error!"
    echo -n "Return to menu? < y | n >: "
    read mchoice
    [ "$mchoice" == "y" ] && menu || exit
  fi
}

menu() {
  [ -n "$(find $MODDIR$SYSTEM2 -name ".replace" -type f 2>>$LOG)" ] &&  show_rein=true
  mod_head
  echo ""
  [ -d $SYSTEM/app ] && echo " 1 - ${W}System Apps${N}"
  [ -d $SYSTEM/priv-app ] && echo " 2 - ${W}System Priv-Apps${N}"
  [ -d $SYSTEM/vendor/app ] && echo " 3 - ${W}Vendor Apps${N}"
  [ -d $SYSTEM/product/app ] && echo " 4 - ${W}System Product Apps${N}"
  [ -d $SYSTEM/product/priv-app ] && echo " 5 - ${W}System Product Priv-Apps${N}"
  echo " c - ${W}Enter Custom System Apps dir${N}"
  $show_rein && {
    echo " r - ${W}Reinstall Uninstalled Apps${N}"
    echo " e - ${W}Export Config${N}"
  }
  echo " i - ${W}Import Config${N} ($import_file)"
  prandom " d - ${C}Donate${N}"
  echo " 0 - ${Bl}Exit${N}"
  echo ""
  echo -n "[CHOICE]: "
  read choice
  case "$choice" in
    1)  if [ -d $SYSTEM/app ]; then
        menu_list_system_app app
      else
        abort Invalid
      fi;;
    2)  if [ -d $SYSTEM/priv-app ]; then
        menu_list_system_app priv-app
      else
        abort Invalid
      fi;;
    3)  if [ -d $SYSTEM/vendor/app ]; then
        menu_list_system_app vendor/app
      else
        abort Invalid
      fi;;
    4)  if [ -d $SYSTEM/product/app ]; then
        menu_list_system_app product/app
      else
        abort Invalid
      fi;;
    5)  if [ -d $SYSTEM/product/priv-app ]; then
        menu_list_system_app product/priv-app
      else
        abort Invalid
      fi;;
    c|C)  menu_list_custom_dir;;
    r|R)  if $show_rein; then
        menu_list_unin_app
      else
        abort Invalid
      fi;;
    e|E)if $show_rein; then
	    menu_export_list
      else
        abort Invalid
      fi;;
    i|I) menu_import_list;;

    d|D)  am start https://paypal.me/veez21 >/dev/null;;
    logs)  upload_logs;;
    0)  exit;;
    *)  abort Invalid;;
  esac
}

case "$1" in
  -i) shift
    [ -s "$1" ] && { import_list $1; exit; } || abort "Invalid file!";;
  -e) shift
    [ -f "$1" ] && abort "File exists!" || { export_list "$1"; exit; };;
  -l) shift
    [ ! "$1" ] && abort "$(help_me)"
    if [ "$1" == "app" ]; then
      list_s-app app 2>>$LOG
    elif [ "$1" == "priv-app" ]; then
      list_s-app priv-app 2>>$LOG
    elif [ "$1" == "vendor" ]; then
      list_s-app vendor/app 2>>$LOG
    elif [ "$1" == "product/app" ]; then
      list_s-app product/app 2>>$LOG
    elif [ "$1" == "product/priv-app" ]; then
      list_s-app product/priv-app 2>>$LOG
     else
      abort "$(help_me)"
    fi
    c=1
    echo
    for i in $(seq 1 $((${#app_name[@]}-1))); do
      get_cfg ${app_name[i]}
      [ ! "$PKG" ] && PKG="null"
      title_div "App $i"
      echo "Name\t: $(echo $APP_NAME | tr '%_' ' ')\nLabel\t: $PKG\nDirectory\t: $(echo $DIR_APP | sed 's/.*\/system\///g')" | expand -t 10
      c=$((c+1))
    done
	exit;;
  -d) shift
    [ ! "$1" ] && help_me
    [ "$1" == "-h" ] && {
      echo "$_name -d [system app label/s | system app folder/s]\ne.g. \"$_name -d com.google.android.youtube com.android.terminal Velvet LatinIME\"\n"
      echo "To see the list of system apps and its info (its folder name or app label \nin this situation) use \"$_name -l\" "
      exit
    }
    for i in "$@"; do
      [ -d /data/data/$i ] && DIR_APP=$(dumpsys package $i | grep "path:" | sed 's/.*path: //;s/\(.*\)\/.*/\1/') || DIR_APP=$(find $SYSTEM/app $SYSTEM/priv-app $SYSTEM/vendor/app -name $i -type d -mindepth 1)
      [ ! "$DIR_APP" ] && { echo "$i doesn't exist in $SYSTEM"; ok=false; continue; } || {
        [ $(echo $DIR_APP | grep "/system") ] && {
          ok=true
        } || {
          echo "$i is not a system app"
          ok=false
          continue
        }
      }
      [ -f $MODDIR$DIR_APP/.replace ] && echo "$i already uninstalled" && continue
      echo "$i found in $DIR_APP"
      name[0]=${DIR_APP##*/}; apk_name[0]="$(basename $(find $DIR_APP -name "*.apk" -type f -mindepth 1))"; get_app_name $DIR_APP 0; PKG=${app_label[0]}
      debloat_app n ${app_name[0]}
	  unset DIR_APP
    done
    $ok || abort "error: Use \"$_name -d -h\" for help"
    exit;;
  -h|--help) help_me;;
esac

menu
exit $?
