samedi 8 novembre 2025

Exemple script AppImage Manager v9 GUI avec Zenity + Sync cloud + scheduling fait avec ChatGPT OpenAI

 #!/usr/bin/env bash

# ============================================================

# đź§© AppImage Manager - GUI avec Zenity + Sync cloud + scheduling

# Version : 9.0 : appimage-manager-9.sh

# Auteur : ChatGPT (OpenAI)

# Licence : MIT

# ============================================================


set -euo pipefail

IFS=$'\n\t'


# --- Paths & Globals ---

INSTALL_DIR="$HOME/Applications"

DESKTOP_DIR="$HOME/.local/share/applications"

CONFIG_DIR="$HOME/.config/appimage-manager"

LOG_DIR="$HOME/.local/share/appimage-manager/logs"

BACKUP_DIR="$HOME/.local/share/appimage-manager/backups"

LOG_FILE="$LOG_DIR/appimage-manager.log"

CLOUD_CFG="$CONFIG_DIR/cloud.conf"

SYSTEMD_UNIT_DIR="$HOME/.config/systemd/user"   # user systemd units

SELF_PATH="$(readlink -f "$0")"


CURRENT_VERSION="9.0"

REPO_URL="https://raw.githubusercontent.com/tonpseudo/appimage-manager/main/appimage-manager-gui.sh"  # <-- replace with your repo raw url if desired


mkdir -p "$INSTALL_DIR" "$DESKTOP_DIR" "$CONFIG_DIR" "$LOG_DIR" "$BACKUP_DIR" "$SYSTEMD_UNIT_DIR"


# --- Helpers ---

log() {

  local TIMESTAMP

  TIMESTAMP="$(date '+%Y-%m-%d %H:%M:%S')"

  echo "[$TIMESTAMP] $1" | tee -a "$LOG_FILE" >/dev/null

}


# --- Dependency check ---

required_cmds=(zenity wget curl jq tar desktop-file-validate)

for cmd in "${required_cmds[@]}"; do

  if ! command -v "$cmd" &>/dev/null; then

    echo "Erreur : '$cmd' n'est pas installĂ©. Installez-le d'abord (ex: sudo apt install zenity wget curl jq tar desktop-file-utils)" >&2

    zenity --error --text="Erreur : '$cmd' n'est pas installĂ©. Installez-le d'abord (ex: sudo apt install zenity wget curl jq tar desktop-file-utils)"

    exit 1

  fi

done


# rclone optional

if command -v rclone &>/dev/null; then

  RCLONE_AVAILABLE=1

else

  RCLONE_AVAILABLE=0

fi


# --- Auto-update for manager ---

check_for_update() {

  if ! command -v curl &>/dev/null; then return; fi

  local LATEST

  LATEST=$(curl -fsSL "$REPO_URL" 2>/dev/null | grep -m1 "Version :" | awk '{print $3}' || true)

  if [[ -n "$LATEST" && "$LATEST" != "$CURRENT_VERSION" ]]; then

    if zenity --question --title="Mise Ă  jour disponible" --text="Version $LATEST disponible. Mettre Ă  jour ?" ; then

      TMP=$(mktemp)

      wget -qO "$TMP" "$REPO_URL"

      sudo cp "$TMP" "$SELF_PATH"

      sudo chmod +x "$SELF_PATH"

      log "Manager updated $CURRENT_VERSION -> $LATEST"

      zenity --info --text="Mise Ă  jour effectuĂ©e. Relance du gestionnaire..."

      exec "$SELF_PATH"

    fi

  fi

}


# --- create .desktop shortcut for appimage ---

create_shortcut() {

  local APP_NAME="$1"

  local APP_PATH="$INSTALL_DIR/${APP_NAME}.AppImage"

  local ICON_PATH="$INSTALL_DIR/${APP_NAME}.png"


  if [[ -x "$APP_PATH" ]]; then

    # try extract icon

    if "$APP_PATH" --appimage-extract &>/dev/null; then

      ICON_FILE=$(find squashfs-root -type f \( -iname '*.png' -o -iname '*.svg' \) | head -n1 || true)

      [[ -n "$ICON_FILE" ]] && cp "$ICON_FILE" "$ICON_PATH"

      rm -rf squashfs-root

    fi

  fi


  cat >"$DESKTOP_DIR/${APP_NAME}.desktop" <<EOF

[Desktop Entry]

Name=${APP_NAME}

Exec=${APP_PATH}

Icon=${ICON_PATH:-$APP_PATH}

Type=Application

Categories=Utility;

Comment=AppImage: ${APP_NAME}

Terminal=false

EOF


  desktop-file-validate "$DESKTOP_DIR/${APP_NAME}.desktop" || true

  chmod +x "$DESKTOP_DIR/${APP_NAME}.desktop"

  update-desktop-database "$DESKTOP_DIR" &>/dev/null || true

  log "Shortcut created: ${APP_NAME}"

}


# --- Install from GitHub releases (auto find AppImage asset) ---

install_from_github() {

  local REPO APP_URL APP_NAME

  REPO=$(zenity --entry --title="Installation depuis GitHub" --text="DĂ©pĂ´t GitHub (ex: obsidianmd/obsidian-releases) :") || return

  zenity --info --text="Recherche de la dernière release pour $REPO..."

  API="https://api.github.com/repos/${REPO}/releases/latest"

  APP_URL=$(curl -s "$API" | jq -r '.assets[] | select(.name|test("AppImage$")) | .browser_download_url' | head -n1 || true)


  if [[ -z "$APP_URL" || "$APP_URL" == "null" ]]; then

    zenity --error --text="Aucune AppImage trouvĂ©e pour $REPO"

    log "install_from_github: no AppImage for $REPO"

    return

  fi


  APP_NAME=$(basename "$APP_URL" | sed 's/\.AppImage$//; s/[^a-zA-Z0-9._-]//g')

  wget -q --show-progress -O "$INSTALL_DIR/${APP_NAME}.AppImage" "$APP_URL"

  chmod +x "$INSTALL_DIR/${APP_NAME}.AppImage"

  create_shortcut "$APP_NAME"

  log "Installed $APP_NAME from GitHub ($REPO)"

  zenity --info --text="✅ $APP_NAME installĂ©."

}


# --- Install via direct URL ---

install_manual() {

  local NAME URL

  NAME=$(zenity --entry --title="Installation manuelle" --text="Nom de l'application :") || return

  URL=$(zenity --entry --title="Installation manuelle" --text="URL directe de l'AppImage :") || return

  wget -q --show-progress -O "$INSTALL_DIR/${NAME}.AppImage" "$URL"

  chmod +x "$INSTALL_DIR/${NAME}.AppImage"

  create_shortcut "$NAME"

  log "Installed $NAME from URL"

  zenity --info --text="✅ $NAME installĂ©."

}


# --- Update AppImage (AppImageUpdate) ---

update_appimage() {

  local NAME APP_PATH TMP_UPD

  NAME=$(zenity --entry --title="Mise Ă  jour" --text="Nom de l'application Ă  mettre Ă  jour :") || return

  APP_PATH="$INSTALL_DIR/${NAME}.AppImage"

  if [[ ! -f "$APP_PATH" ]]; then

    zenity --error --text="Application introuvable."

    return

  fi

  zenity --info --text="Mise Ă  jour en cours pour $NAME..."

  TMP_UPD=$(mktemp)

  wget -qO "$TMP_UPD" "https://github.com/AppImage/AppImageUpdate/releases/latest/download/appimageupdatetool-x86_64.AppImage"

  chmod +x "$TMP_UPD"

  "$TMP_UPD" "$APP_PATH" || zenity --warning --text="Mise Ă  jour non supportĂ©e pour cette AppImage"

  rm -f "$TMP_UPD"

  log "Updated $NAME"

  zenity --info --text="✅ Mise Ă  jour terminĂ©e pour $NAME"

}


# --- Remove AppImage ---

remove_appimage() {

  local NAME

  NAME=$(zenity --entry --title="DĂ©sinstallation" --text="Nom de l'application Ă  supprimer :") || return

  rm -f "$INSTALL_DIR/${NAME}.AppImage" "$INSTALL_DIR/${NAME}.png" "$DESKTOP_DIR/${NAME}.desktop"

  update-desktop-database "$DESKTOP_DIR" &>/dev/null || true

  log "Removed $NAME"

  zenity --info --text="✅ $NAME supprimĂ©."

}


# --- List installed AppImages ---

list_appimages() {

  local LIST

  LIST=$(ls "$INSTALL_DIR"/*.AppImage 2>/dev/null | xargs -n1 basename | sed 's/\.AppImage$//' || true)

  if [[ -z "$LIST" ]]; then

    zenity --info --text="Aucune AppImage installĂ©e."

  else

    zenity --list --title="AppImages installĂ©es" --column="Nom" $LIST

  fi

}


# --- Logging viewer ---

show_logs() {

  touch "$LOG_FILE"

  zenity --text-info --title="Logs AppImage Manager" --filename="$LOG_FILE" --width=900 --height=500 || true

}


# --- Local backup ---

backup_all() {

  local BACKUP_FILE="$BACKUP_DIR/appimage-backup-$(date +%Y%m%d_%H%M%S).tar.gz"

  # create tar with relative paths under $HOME for safe restore

  tar -C "$HOME" -czf "$BACKUP_FILE" "$(realpath --relative-to="$HOME" "$INSTALL_DIR")" "$(realpath --relative-to="$HOME" "$DESKTOP_DIR")" "$(realpath --relative-to="$HOME" "$LOG_DIR")"

  log "Created backup $BACKUP_FILE"

  zenity --info --text="✅ Sauvegarde créée : $BACKUP_FILE"

}


# --- Restore backup ---

restore_backup() {

  local FILE

  FILE=$(zenity --file-selection --title="Choisir une sauvegarde (.tar.gz)" --file-filter="Archives | *.tar.gz") || return

  tar -xzf "$FILE" -C "$HOME"

  log "Restored backup from $FILE"

  zenity --info --text="✅ Restauration terminĂ©e."

}


# --- Cloud configuration (rclone remote name + optional remote path) ---

configure_cloud() {

  if [[ $RCLONE_AVAILABLE -eq 0 ]]; then

    if ! zenity --question --title="rclone manquant" --text="rclone n'est pas installĂ©. Voulez-vous l'installer maintenant ?" ; then

      return

    fi

    curl https://rclone.org/install.sh | sudo bash

    if ! command -v rclone &>/dev/null; then

      zenity --error --text="Impossible d'installer rclone automatiquement. Installez-le manuellement." ; return

    fi

    RCLONE_AVAILABLE=1

  fi


  zenity --info --text="Configurez d'abord un remote via : rclone config\nCrĂ©ez un remote (ex: mydrive)."

  local REMOTE REMOTE_PATH

  REMOTE=$(zenity --entry --title="Nom du remote rclone" --text="Entrez le nom du remote (ex: mydrive) :") || return

  REMOTE_PATH=$(zenity --entry --title="Chemin distant" --text="Entrez le chemin distant Ă  utiliser (ex: AppImage-Backups) :") || return

  cat > "$CLOUD_CFG" <<EOF

REMOTE=${REMOTE}

REMOTE_PATH=${REMOTE_PATH}

EOF

  log "Cloud configured: ${REMOTE}:${REMOTE_PATH}"

  zenity --info --text="✅ Configuration cloud enregistrĂ©e : ${REMOTE}:${REMOTE_PATH}"

}


# --- Sync latest backup to cloud ---

sync_backup_to_cloud() {

  if [[ $RCLONE_AVAILABLE -eq 0 ]]; then

    zenity --error --text="rclone n'est pas installĂ©. Configurez rclone d'abord." ; return

  fi

  if [[ ! -f "$CLOUD_CFG" ]]; then

    zenity --error --text="Configuration cloud absente. Configurez-la d'abord." ; return

  fi

  source "$CLOUD_CFG"

  local LATEST

  LATEST=$(ls -1t "$BACKUP_DIR"/appimage-backup-*.tar.gz 2>/dev/null | head -n1 || true)

  if [[ -z "$LATEST" ]]; then

    zenity --error --text="Aucune sauvegarde locale trouvĂ©e. CrĂ©ez-en une d'abord." ; return

  fi

  zenity --info --text="Envoi de $LATEST vers ${REMOTE}:${REMOTE_PATH} ..."

  log "Cloud sync: $LATEST -> ${REMOTE}:${REMOTE_PATH}"

  rclone copy "$LATEST" "${REMOTE}:${REMOTE_PATH}" --progress || {

    zenity --error --text="Erreur pendant la synchronisation cloud. Voir logs."

    log "Cloud sync failed for $LATEST"

    return

  }

  zenity --info --text="✅ Synchronisation terminĂ©e."

  log "Cloud sync completed: $LATEST"

}


# --- Cron scheduling (weekly) ---

enable_weekly_cron() {

  local CMD="$SELF_PATH --auto-backup"

  # add if not exists

  (crontab -l 2>/dev/null | grep -v -F "$CMD" || true; echo "30 3 * * 0 $CMD") | crontab -

  log "Weekly cron enabled"

  zenity --info --text="✅ Sauvegarde hebdomadaire (cron) activĂ©e (dimanche 03:30)."

}


disable_weekly_cron() {

  local CMD="$SELF_PATH --auto-backup"

  crontab -l 2>/dev/null | grep -v -F "$CMD" | crontab -

  log "Weekly cron disabled"

  zenity --info --text="✅ Sauvegarde hebdomadaire (cron) dĂ©sactivĂ©e."

}


# --- Systemd user timer support (optional) ---

install_systemd_timer() {

  # create service and timer in user systemd

  cat > "$SYSTEMD_UNIT_DIR/appimage-manager-backup.service" <<EOF

[Unit]

Description=AppImage Manager backup service


[Service]

Type=oneshot

ExecStart=${SELF_PATH} --auto-backup

EOF


  cat > "$SYSTEMD_UNIT_DIR/appimage-manager-backup.timer" <<EOF

[Unit]

Description=Run AppImage Manager backup weekly


[Timer]

OnCalendar=weekly

Persistent=true


[Install]

WantedBy=timers.target

EOF


  systemctl --user daemon-reload

  systemctl --user enable --now appimage-manager-backup.timer

  log "Systemd user timer installed & started"

  zenity --info --text="✅ Systemd timer installĂ© et activĂ© (user)."

}


remove_systemd_timer() {

  systemctl --user disable --now appimage-manager-backup.timer || true

  rm -f "$SYSTEMD_UNIT_DIR/appimage-manager-backup.service" "$SYSTEMD_UNIT_DIR/appimage-manager-backup.timer"

  systemctl --user daemon-reload

  log "Systemd user timer removed"

  zenity --info --text="✅ Systemd timer supprimĂ©."

}


# --- Non interactive backup mode for cron/systemd: --auto-backup ---

if [[ "${1:-}" == "--auto-backup" ]]; then

  backup_all

  # sync if cloud configured

  if [[ -f "$CLOUD_CFG" && $RCLONE_AVAILABLE -eq 1 ]]; then

    source "$CLOUD_CFG"

    LATEST=$(ls -1t "$BACKUP_DIR"/appimage-backup-*.tar.gz 2>/dev/null | head -n1 || true)

    if [[ -n "$LATEST" ]]; then

      rclone copy "$LATEST" "${REMOTE}:${REMOTE_PATH}"

      log "Auto backup & sync completed: $LATEST"

    else

      log "Auto backup: no backup file to sync"

    fi

  fi

  exit 0

fi


# --- Initial check for update (non-blocking) ---

check_for_update &>/dev/null || true


# --- GUI menu loop ---

while true; do

  CHOICE=$(zenity --list --title="đź§© AppImage Manager v$CURRENT_VERSION" \

    --column="Action" --width=620 --height=550 \

    "Installer depuis GitHub" \

    "Installer via URL directe" \

    "Mettre Ă  jour une AppImage" \

    "Supprimer une AppImage" \

    "Lister les AppImages installĂ©es" \

    "CrĂ©er une sauvegarde complète (local)" \

    "Restaurer une sauvegarde" \

    "Configurer la synchronisation cloud (rclone)" \

    "Envoyer la dernière sauvegarde vers le cloud" \

    "Activer sauvegarde hebdomadaire (cron)" \

    "DĂ©sactiver sauvegarde hebdomadaire (cron)" \

    "Installer systemd timer (user)" \

    "Supprimer systemd timer (user)" \

    "Afficher l'historique (logs)" \

    "Mettre Ă  jour le gestionnaire lui-mĂŞme" \

    "Quitter") || exit 0


  case "$CHOICE" in

    "Installer depuis GitHub") install_from_github ;;

    "Installer via URL directe") install_manual ;;

    "Mettre Ă  jour une AppImage") update_appimage ;;

    "Supprimer une AppImage") remove_appimage ;;

    "Lister les AppImages installĂ©es") list_appimages ;;

    "CrĂ©er une sauvegarde complète (local)") backup_all ;;

    "Restaurer une sauvegarde") restore_backup ;;

    "Configurer la synchronisation cloud (rclone)") configure_cloud ;;

    "Envoyer la dernière sauvegarde vers le cloud") sync_backup_to_cloud ;;

    "Activer sauvegarde hebdomadaire (cron)") enable_weekly_cron ;;

    "DĂ©sactiver sauvegarde hebdomadaire (cron)") disable_weekly_cron ;;

    "Installer systemd timer (user)") install_systemd_timer ;;

    "Supprimer systemd timer (user)") remove_systemd_timer ;;

    "Afficher l'historique (logs)") show_logs ;;

    "Mettre Ă  jour le gestionnaire lui-mĂŞme") check_for_update ;;

    "Quitter") log "Manager closed by user"; exit 0 ;;

  esac

done


Aucun commentaire:

Enregistrer un commentaire

Archives du blog