quickshell-rice/quickshell/services/python/launch_app.py

98 lines
3.4 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
import os
import subprocess
import shutil
import re
def get_installed_flatpaks():
"""Returns a list of installed Flatpak application IDs."""
try:
res = subprocess.run(["flatpak", "list", "--app", "--columns=application"], capture_output=True, text=True)
if res.returncode == 0:
return [line.strip() for line in res.stdout.splitlines() if line.strip()]
except Exception:
pass
return []
def launch():
if len(sys.argv) < 2:
return
raw_cmd = sys.argv[1].strip()
if not raw_cmd:
return
# Strip desktop field codes (%u, %U, %f, %F, %i, %c, %k, etc.)
clean_cmd = re.sub(r'%[a-zA-Z]', '', raw_cmd).strip()
# Extract desktop ID and base name
# e.g. "/usr/bin/equibop" -> "equibop", "org.equicord.equibop.desktop" -> "org.equicord.equibop"
base_name = clean_cmd.replace('.desktop', '').strip()
if '/' in base_name:
base_name = os.path.basename(base_name.split()[0]).replace('.desktop', '').strip()
lower_name = base_name.lower()
flatpak_mappings = {
"spotify": "com.spotify.Client",
"feishin": "io.github.jeffvli.feishin",
"zen": "io.github.zen_browser.zen",
"zen-browser": "io.github.zen_browser.zen",
"vesktop": "dev.vencord.Vesktop",
"equibop": "org.equicord.equibop",
"equicord": "org.equicord.equibop",
"vencord": "dev.vencord.Vesktop",
"discord": "com.discordapp.Discord",
"code": "com.visualstudio.code",
"vscodium": "com.vscodium.codium",
"obs": "com.obsproject.Studio",
"steam": "com.valvesoftware.Steam",
"heroic": "com.heroicgameslauncher.hgl"
}
installed_flatpaks = get_installed_flatpaks()
# 1. Flatpak launch check
candidates_flatpak = []
if lower_name in flatpak_mappings:
candidates_flatpak.append(flatpak_mappings[lower_name])
# Match any installed flatpak containing lower_name (e.g. 'equibop' -> 'org.equicord.equibop')
for fp in installed_flatpaks:
fp_lower = fp.lower()
if lower_name in fp_lower or fp_lower.endswith(lower_name):
if fp not in candidates_flatpak:
candidates_flatpak.append(fp)
if lower_name.startswith(("org.", "io.", "com.", "app.", "dev.")):
candidates_flatpak.append(lower_name)
for fp_id in candidates_flatpak:
if fp_id in installed_flatpaks:
subprocess.Popen(["flatpak", "run", fp_id], start_new_session=True)
return
# Fallback check via flatpak info
check = subprocess.run(["flatpak", "info", fp_id], capture_output=True, text=True)
if check.returncode == 0:
subprocess.Popen(["flatpak", "run", fp_id], start_new_session=True)
return
# 2. GTK Desktop launcher check (using clean desktop ID without paths)
if shutil.which("gtk-launch"):
for gtk_id in [base_name, f"{base_name}.desktop", lower_name]:
res = subprocess.run(["gtk-launch", gtk_id], capture_output=True, text=True)
if res.returncode == 0:
return
# 3. Direct binary execution
bin_name = clean_cmd.split()[0]
if shutil.which(bin_name):
subprocess.Popen(clean_cmd, shell=True, start_new_session=True)
return
# 4. Fallback execution
subprocess.Popen(f"{clean_cmd} &", shell=True, start_new_session=True)
if __name__ == '__main__':
launch()