Files
f0ckm-uploader/install.sh
2026-08-13 22:02:18 +02:00

310 lines
13 KiB
Bash
Executable File

#!/bin/bash
# Configuration directories
INSTALL_DIR="$HOME/.local/bin"
APP_DIR="$HOME/.local/share/applications"
SERVICE_MENU_DIR="$HOME/.local/share/kio/servicemenus"
LEGACY_SERVICE_MENU_DIR="$HOME/.local/share/kservices5/ServiceMenus"
# Check dependencies
echo "Checking dependencies..."
MISSING_OPTIONAL=()
if ! command -v python3 &>/dev/null; then
echo "Error: Python 3 is required but not found on your system."
exit 1
fi
if ! python3 -c "import PySide6" &>/dev/null; then
echo "PySide6 is not installed. Attempting automatic installation..."
if command -v pip3 &>/dev/null; then
pip3 install PySide6 || pip3 install --break-system-packages PySide6 || true
elif command -v pip &>/dev/null; then
pip install PySide6 || pip install --break-system-packages PySide6 || true
elif command -v dnf &>/dev/null; then
echo "Installing python3-pyside6 via dnf..."
sudo dnf install -y python3-pyside6 || true
elif command -v apt-get &>/dev/null; then
echo "Installing python3-pyside6 via apt..."
sudo apt-get update && sudo apt-get install -y python3-pyside6 || true
elif command -v pacman &>/dev/null; then
echo "Installing python-pyside6 via pacman..."
sudo pacman -S --noconfirm python-pyside6 || true
elif command -v zypper &>/dev/null; then
echo "Installing python3-pyside6 via zypper..."
sudo zypper install -y python3-pyside6 || true
fi
fi
if ! python3 -c "import PySide6" &>/dev/null; then
echo "Warning: Could not automatically install PySide6. Please install 'PySide6' via pip or package manager."
fi
if ! command -v spectacle &>/dev/null; then
MISSING_OPTIONAL+=("spectacle (KDE screenshot capture tool)")
fi
if ! command -v ffmpeg &>/dev/null; then
MISSING_OPTIONAL+=("ffmpeg (Video notification thumbnail generator)")
fi
# Check Qt6 / KF6 Purpose plugin build requirements
HAS_QT6_MOC=false
for m in /usr/lib/qt6/moc /usr/lib/qt6/libexec/moc /usr/libexec/qt6/moc /usr/lib64/qt6/libexec/moc /usr/lib/qt6/bin/moc moc-qt6 moc; do
if [ -x "$m" ] || command -v "$m" &>/dev/null; then
bin_path="$m"
[ -x "$m" ] || bin_path="$(command -v "$m")"
ver="$("$bin_path" -v 2>&1 || true)"
if [[ "$ver" =~ moc\ 6\. ]] || [[ "$ver" =~ Qt\ 6\. ]] || [[ "$ver" =~ 6\.[0-9]+ ]]; then
HAS_QT6_MOC=true
break
fi
fi
done
HAS_PURPOSE_HDR=false
for h in /usr/include/KF6/Purpose /usr/include/purpose; do
if [ -d "$h" ]; then
HAS_PURPOSE_HDR=true
break
fi
done
if [ "$HAS_QT6_MOC" = false ] || [ "$HAS_PURPOSE_HDR" = false ]; then
MISSING_OPTIONAL+=("qt6-base & kf6-purpose (KDE Gwenview Share Menu integration)")
fi
if [ ${#MISSING_OPTIONAL[@]} -gt 0 ]; then
echo ""
echo "--------------------------------------------------------"
echo " Notice: Optional dependencies missing:"
for dep in "${MISSING_OPTIONAL[@]}"; do
echo " - $dep"
done
echo ""
echo " To install missing dependencies:"
if command -v pacman &>/dev/null; then
echo " Arch Linux: sudo pacman -S python-pyside6 spectacle ffmpeg qt6-base kf6-purpose kf6-kcoreaddons"
elif command -v dnf &>/dev/null; then
echo " Fedora: sudo dnf install python3-pyside6 spectacle ffmpeg qt6-qtbase-devel kf6-purpose-devel kf6-kcoreaddons-devel"
elif command -v apt-get &>/dev/null; then
echo " Debian/Ubuntu: sudo apt install python3-pyside6 spectacle ffmpeg qt6-base-dev libkf6purpose-dev libkf6kcoreaddons-dev"
else
echo " Arch Linux: sudo pacman -S python-pyside6 spectacle ffmpeg qt6-base kf6-purpose kf6-kcoreaddons"
echo " Fedora: sudo dnf install python3-pyside6 spectacle ffmpeg qt6-qtbase-devel kf6-purpose-devel kf6-kcoreaddons-devel"
echo " Debian/Ubuntu: sudo apt install python3-pyside6 spectacle ffmpeg qt6-base-dev libkf6purpose-dev libkf6kcoreaddons-dev"
fi
echo "--------------------------------------------------------"
echo ""
fi
# Create necessary directories
mkdir -p "$INSTALL_DIR" "$APP_DIR" "$SERVICE_MENU_DIR" "$LEGACY_SERVICE_MENU_DIR"
# Clean legacy kde-uploader names
rm -f "$INSTALL_DIR/kde-uploader" "$INSTALL_DIR/kde-uploader-gui"
rm -f "$APP_DIR/kde-uploader.desktop" "$APP_DIR/kde-uploader-gui.desktop"
rm -f "$SERVICE_MENU_DIR/kde-uploader-servicemenu.desktop" "$LEGACY_SERVICE_MENU_DIR/kde-uploader-servicemenu.desktop"
rm -f "$HOME/.config/autostart/kde-uploader-gui.desktop"
# 1. Install the scripts
cp uploader.sh "$INSTALL_DIR/f0ckm-uploader"
chmod +x "$INSTALL_DIR/f0ckm-uploader"
cp gui.py "$INSTALL_DIR/f0ckm-uploader-gui"
chmod +x "$INSTALL_DIR/f0ckm-uploader-gui"
mkdir -p "$HOME/.local/share/icons/hicolor/scalable/apps"
mkdir -p "$HOME/.local/share/pixmaps"
# Generate multi-resolution PNG icons (32x32, 48x48, 64x64, 128x128, 256x256) for KRunner search compatibility
python3 -c '
import os
from PySide6.QtGui import QImage, QPainter
from PySide6.QtSvg import QSvgRenderer
try:
renderer = QSvgRenderer("icon_app.svg")
sizes = [32, 48, 64, 128, 256]
for sz in sizes:
dir_path = f"'$HOME'/.local/share/icons/hicolor/{sz}x{sz}/apps"
os.makedirs(dir_path, exist_ok=True)
img = QImage(sz, sz, QImage.Format_ARGB32)
img.fill(0)
p = QPainter(img)
renderer.render(p)
p.end()
img.save(os.path.join(dir_path, "f0ckm-uploader.png"))
img_48 = QImage(48, 48, QImage.Format_ARGB32)
img_48.fill(0)
p = QPainter(img_48)
renderer.render(p)
p.end()
img_48.save("'$HOME'/.local/share/pixmaps/f0ckm-uploader.png")
except Exception as e:
pass
' &> /dev/null
if [ -f icon_app.svg ]; then
cp icon_app.svg "$INSTALL_DIR/icon_app.svg"
cp icon_app.svg "$HOME/.local/share/icons/hicolor/scalable/apps/f0ckm-uploader.svg"
elif [ -f icon.svg ]; then
cp icon.svg "$HOME/.local/share/icons/hicolor/scalable/apps/f0ckm-uploader.svg"
fi
if [ -f icon.svg ]; then
cp icon.svg "$INSTALL_DIR/icon.svg"
fi
if [ -f icon_light.svg ]; then
cp icon_light.svg "$INSTALL_DIR/icon_light.svg"
fi
if [ -f .env ]; then
cp .env "$INSTALL_DIR/.env"
fi
# Clean up any stale auto-generated desktop entries
rm -f "$APP_DIR/net.local.spectacle_uploader.sh.desktop"
ICON_PATH="f0ckm-uploader"
# 2. Install standard application entry (for Spectacle - hidden from main menu)
sed -e "s|__EXEC_PATH__|$INSTALL_DIR/f0ckm-uploader-gui --spectacle|g" -e "s|__ICON_PATH__|$ICON_PATH|g" f0ckm-uploader.desktop > "$APP_DIR/f0ckm-uploader.desktop"
chmod +x "$APP_DIR/f0ckm-uploader.desktop"
# 3. Install the GUI application entry (visible in main menu)
sed -e "s|__EXEC_PATH__|$INSTALL_DIR/f0ckm-uploader-gui|g" -e "s|__ICON_PATH__|$ICON_PATH|g" f0ckm-uploader-gui.desktop > "$APP_DIR/f0ckm-uploader-gui.desktop"
chmod +x "$APP_DIR/f0ckm-uploader-gui.desktop"
update-desktop-database "$APP_DIR" &> /dev/null
xdg-mime default f0ckm-uploader-gui.desktop x-scheme-handler/f0ckm x-scheme-handler/f0ckm-uploader &> /dev/null || true
gtk-update-icon-cache -f -t "$HOME/.local/share/icons/hicolor" &> /dev/null || true
kbuildsycoca6 --noincremental &> /dev/null || kbuildsycoca5 --noincremental &> /dev/null || true
# 4. Install KDE Service Menu entry (for Dolphin)
sed "s|__EXEC_PATH__|$INSTALL_DIR/f0ckm-uploader-gui --upload|g" f0ckm-uploader-servicemenu.desktop > "$SERVICE_MENU_DIR/f0ckm-uploader-servicemenu.desktop"
chmod +x "$SERVICE_MENU_DIR/f0ckm-uploader-servicemenu.desktop"
sed "s|__EXEC_PATH__|$INSTALL_DIR/f0ckm-uploader-gui --upload|g" f0ckm-uploader-servicemenu.desktop > "$LEGACY_SERVICE_MENU_DIR/f0ckm-uploader-servicemenu.desktop"
chmod +x "$LEGACY_SERVICE_MENU_DIR/f0ckm-uploader-servicemenu.desktop"
# 5. Build and install KDE Purpose plugin (for Gwenview / KDE Share menu)
if [ -f "purpose_plugin/build_plugin.sh" ]; then
echo "Building KDE Purpose plugin for Gwenview Share Menu..."
bash purpose_plugin/build_plugin.sh purpose_plugin &> /dev/null || true
if [ -f "purpose_plugin/f0ckmpurposeplugin.so" ]; then
PURPOSE_USER_DIR64="$HOME/.local/lib64/qt6/plugins/kf6/purpose"
PURPOSE_USER_DIR32="$HOME/.local/lib/qt6/plugins/kf6/purpose"
mkdir -p "$PURPOSE_USER_DIR64" "$PURPOSE_USER_DIR32"
cp "purpose_plugin/f0ckmpurposeplugin.so" "$PURPOSE_USER_DIR64/f0ckmpurposeplugin.so"
cp "purpose_plugin/f0ckmpurposeplugin.so" "$PURPOSE_USER_DIR32/f0ckmpurposeplugin.so"
if [ -w "/usr/lib/qt6/plugins/kf6/purpose" ]; then
cp "purpose_plugin/f0ckmpurposeplugin.so" "/usr/lib/qt6/plugins/kf6/purpose/f0ckmpurposeplugin.so" &>/dev/null || true
elif [ -w "/usr/lib64/qt6/plugins/kf6/purpose" ]; then
cp "purpose_plugin/f0ckmpurposeplugin.so" "/usr/lib64/qt6/plugins/kf6/purpose/f0ckmpurposeplugin.so" &>/dev/null || true
elif sudo -n true 2>/dev/null; then
sudo cp "purpose_plugin/f0ckmpurposeplugin.so" "/usr/lib/qt6/plugins/kf6/purpose/f0ckmpurposeplugin.so" &>/dev/null || true
sudo cp "purpose_plugin/f0ckmpurposeplugin.so" "/usr/lib64/qt6/plugins/kf6/purpose/f0ckmpurposeplugin.so" &>/dev/null || true
fi
ENV_DIR="$HOME/.config/environment.d"
mkdir -p "$ENV_DIR"
cat << 'ENVCONF' > "$ENV_DIR/10-qt-plugins.conf"
QT_PLUGIN_PATH="${HOME}/.local/lib64/qt6/plugins:${HOME}/.local/lib/qt6/plugins:/usr/lib64/qt6/plugins:/usr/lib/qt6/plugins"
ENVCONF
PLASMA_ENV_DIR="$HOME/.config/plasma-workspace/env"
mkdir -p "$PLASMA_ENV_DIR"
cat << 'PLASMAENV' > "$PLASMA_ENV_DIR/10-qt-plugins.sh"
export QT_PLUGIN_PATH="${HOME}/.local/lib64/qt6/plugins:${HOME}/.local/lib/qt6/plugins:${QT_PLUGIN_PATH}:/usr/lib64/qt6/plugins:/usr/lib/qt6/plugins"
PLASMAENV
chmod +x "$PLASMA_ENV_DIR/10-qt-plugins.sh"
echo " -> Gwenview / KDE Share Menu plugin installed (Upload to f0ckm)"
fi
fi
# 6. Migrate config to config.json if not present
CONFIG_DIR="$HOME/.config/f0ckm-uploader"
CONFIG_FILE="$CONFIG_DIR/config.json"
if [ ! -f "$CONFIG_FILE" ]; then
mkdir -p "$CONFIG_DIR"
# Fallback to the default key in script if no config file is found
cat <<EOF > "$CONFIG_FILE"
{
"api_url": "",
"api_key": "",
"default_rating": "",
"default_tags": "",
"default_is_oc": false,
"enable_notifications": true,
"show_progress_dialog": true,
"autostart": false
}
EOF
echo "Initial configuration created at $CONFIG_FILE"
fi
# 7. Ensure autostart state matches config.json
python3 -c '
import json, os
try:
cfg_path = os.path.expanduser("~/.config/f0ckm-uploader/config.json")
if os.path.exists(cfg_path):
with open(cfg_path, "r", encoding="utf-8") as f:
cfg = json.load(f)
autostart = cfg.get("autostart", False)
autostart_dir = os.path.expanduser("~/.config/autostart")
autostart_path = os.path.join(autostart_dir, "f0ckm-uploader-gui.desktop")
if autostart:
os.makedirs(autostart_dir, exist_ok=True)
exec_path = os.path.expanduser("~/.local/bin/f0ckm-uploader-gui")
content = f"""[Desktop Entry]
Type=Application
Name=f0ckm Uploader GUI
Comment=System tray GUI and settings for f0ckm Uploader
Exec={exec_path}
Icon=f0ckm-uploader
Terminal=false
Categories=Utility;Network;
StartupNotify=false
X-GNOME-Autostart-enabled=true
"""
with open(autostart_path, "w", encoding="utf-8") as f:
f.write(content)
os.chmod(autostart_path, 0o755)
print(f"Synced autostart desktop entry: {autostart_path}")
else:
if os.path.exists(autostart_path):
os.remove(autostart_path)
print(f"Removed autostart desktop entry: {autostart_path}")
except Exception as e:
print(f"Warning: could not sync autostart entry: {e}")
'
echo ""
echo "========================================================"
echo " f0ckm Uploader Installation Complete!"
echo "========================================================"
echo " -> Executable installed: $INSTALL_DIR/f0ckm-uploader-gui"
echo " -> Dolphin context menu registered (Right-click file -> Actions -> Upload to f0ckm)"
echo " -> Gwenview / KDE Share menu integration enabled (Upload to f0ckm)"
echo " -> Spectacle screenshot export integration enabled"
echo " -> Browser extension helper API ready on http://127.0.0.1:18739"
echo "========================================================"
echo ""
# Launch GUI to prompt for API settings if API key or URL is not configured yet
python3 -c '
import json, os
cfg_path = os.path.expanduser("~/.config/f0ckm-uploader/config.json")
if os.path.exists(cfg_path):
with open(cfg_path) as f:
cfg = json.load(f)
if not cfg.get("api_url") or not cfg.get("api_key"):
print("[!] API Key or URL not configured yet.")
print(" Launching f0ckm Uploader GUI Settings for initial setup...")
os.system("'$INSTALL_DIR'/f0ckm-uploader-gui &")
' || true