Last active
May 10, 2024 07:09
-
-
Save gelin/27178bf2a54ba1f416211cef83fcb74a to your computer and use it in GitHub Desktop.
Adds any URL as the Chrome application to the main menu
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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