Skip to content

Instantly share code, notes, and snippets.

@gelin
Last active May 10, 2024 07:09
Show Gist options
  • Save gelin/27178bf2a54ba1f416211cef83fcb74a to your computer and use it in GitHub Desktop.
Save gelin/27178bf2a54ba1f416211cef83fcb74a to your computer and use it in GitHub Desktop.
Adds any URL as the Chrome application to the main menu
#!/usr/bin/env python3
import argparse
import re
import tempfile
import os.path
import subprocess
import urllib.request
import urllib.parse
from PIL import Image
VENDOR = 'chrome'
CHROME = '/opt/google/chrome/google-chrome'
CHROME_PROFILE = 'Default'
def main():
parser = argparse.ArgumentParser(description='Adds some site as the application to the main menu.')
parser.add_argument('url', help='url of the site to be used as the app')
parser.add_argument('--title', default='Chrome App', help='menu item title (default: Chrome App)')
parser.add_argument('--icon', default=None, help='url to the PNG icon for the app (default: None)')
parser.add_argument('--wmclass', default=None, help='WM_CLASS for the app (default: same as url domain)')
args = parser.parse_args()
with tempfile.TemporaryDirectory() as tempdir:
wmclass = args.wmclass if args.wmclass else find_class(args.url)
icon = download_icon(tempdir, args.icon, wmclass)
icon_name = install_icon(icon, wmclass)
desktop_file = create_desktop_file(tempdir, args.url, args.title, icon_name, wmclass)
install_desktop_file(desktop_file)
def find_class(url):
parts = urllib.parse.urlsplit(url)
wmclass = parts.hostname
urlpath = re.sub(r'/$', '', parts.path)
if len(urlpath) > 0:
wmclass += re.sub(r'^/', '__', urlpath).replace('/', '_')
return wmclass
def download_icon(tempdir, icon_url, wmclass):
if icon_url is None:
return None
try:
print('Retrieving', icon_url)
filename = os.path.join(tempdir, '%s-%s.png' % (VENDOR, wmclass))
filename, _ = urllib.request.urlretrieve(icon_url, filename=filename)
return filename
except Exception as e:
print('Failed:', e)
return None
def install_icon(icon_file, wmclass):
if icon_file is None:
return None
try:
icon_name = '%s-%s' % (VENDOR, wmclass)
size = resize_icon(icon_file)
print('Installing', icon_file, 'as', icon_name)
subprocess.run(
['xdg-icon-resource', 'install', '--size', str(size), icon_file, icon_name],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
)
return icon_name
except Exception as e:
print('Failed:', e)
return None
def resize_icon(icon_file):
image = Image.open(icon_file)
actual_size, _ = image.size
best_size = find_icon_size(actual_size)
if best_size != actual_size:
print('Resizing', icon_file, 'to', best_size)
resized = image.resize((best_size, best_size), Image.LANCZOS)
resized.save(icon_file)
return best_size
def find_icon_size(actual_size):
if actual_size >= 256:
return 256
elif actual_size >= 128:
return 128
elif actual_size >= 64:
return 64
elif actual_size >= 32:
return 32
else:
return 16
def create_desktop_file(tempdir, url, title, icon_name, wmclass):
desktop_file = os.path.join(tempdir, '%s-%s.desktop' % (VENDOR, wmclass))
try:
print('Creating', desktop_file)
with open(desktop_file, 'wt') as f:
print('[Desktop Entry]', file=f)
print('Type=Application', file=f)
print('Name=%s' % title, file=f)
if icon_name:
print('Icon=%s' % icon_name, file=f)
print('Exec=%s --profile-directory=%s --app=%s' % (CHROME, CHROME_PROFILE, url), file=f)
print('StartupWMClass=%s' % wmclass, file=f)
print('Terminal=false', file=f)
print('Categories=Network', file=f)
return desktop_file
except Exception as e:
print('Failed:', e)
return None
def install_desktop_file(desktop_file):
if desktop_file is None:
return
try:
print('Installing', desktop_file)
subprocess.run(
['xdg-desktop-menu', 'install', desktop_file],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
)
except Exception as e:
print('Failed:', e)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment