From d07839b44beb0184a278be916a20ab59ff912f7c Mon Sep 17 00:00:00 2001 From: bryan Date: Wed, 29 May 2019 17:53:24 -0400 Subject: [PATCH] Initial commit --- README.md | 12 ++-- images/icon.svg | 148 ----------------------------------------- images/rdp.svg | 41 ------------ images/ssh.svg | 1 - images/vnc.svg | 23 ------- images/x2goclient.svg | 16 +++++ main.py | 151 ++++++++++++------------------------------ manifest.json | 20 +++--- 8 files changed, 77 insertions(+), 335 deletions(-) delete mode 100644 images/icon.svg delete mode 100644 images/rdp.svg delete mode 100644 images/ssh.svg delete mode 100644 images/vnc.svg create mode 100644 images/x2goclient.svg diff --git a/README.md b/README.md index 31cf1f8..e68c818 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ -# ulauncher-remmina +# ulauncher-x2goclient -🖥 [Ulauncher](https://ulauncher.io) extension for quick access to [Remmina](https://remmina.org) profiles. +🖥 [Ulauncher](https://ulauncher.io) extension for quick access to [x2goclient](https://wiki.x2go.org/doku.php) sessions. -You can enter several queries to match strings in profiles' descriptions (e.g. `r ssh stan`) +You can enter several queries to match strings in sessions' descriptions (e.g. `x ssh stan`) -Some icons from the [Numix project](https://github.com/numixproject) and [Remmina](https://github.com/FreeRDP/Remmina). +Icons from the [Numix project](https://github.com/numixproject). -![ulauncher-remmina extension screenshot](screenshot.png) +Adapted from [ulauncher-remmina](https://github.com/noam09/ulauncher-remmina) by noam09. + +![ulauncher-x2goclient extension screenshot](screenshot.png) diff --git a/images/icon.svg b/images/icon.svg deleted file mode 100644 index 7e15a98..0000000 --- a/images/icon.svg +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/rdp.svg b/images/rdp.svg deleted file mode 100644 index 6520ce4..0000000 --- a/images/rdp.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/ssh.svg b/images/ssh.svg deleted file mode 100644 index 9e64490..0000000 --- a/images/ssh.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/images/vnc.svg b/images/vnc.svg deleted file mode 100644 index c123de0..0000000 --- a/images/vnc.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/x2goclient.svg b/images/x2goclient.svg new file mode 100644 index 0000000..7913dde --- /dev/null +++ b/images/x2goclient.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/main.py b/main.py index 2aa54c5..ee6c0d2 100644 --- a/main.py +++ b/main.py @@ -27,77 +27,69 @@ if os.path.exists(usage_db): # JSON to dict usage_cache = json.loads(raw) -# Initialize items cache and Remmina profiles path -remmina_bin = "" -# Locate Remmina profiles and binary -default_paths = ["{}/.local/share/remmina".format(os.environ.get('HOME')), - "{}/.remmina".format(os.environ.get('HOME'))] -# remmina_profiles_path = "{}/.local/share/remmina".format(os.environ.get('HOME')) -# remmina_profiles_path_alt = "{}/.remmina".format(os.environ.get('HOME')) -remmina_bin = distutils.spawn.find_executable('remmina') -# This extension is useless without remmina -if remmina_bin is None or remmina_bin == "": - logger.error("Remmina executable path could not be determined") +# Initialize items cache and x2goclient sessions file path +x2goclient_bin = "" +# Locate x2goclient profiles and binary +x2go_sessions_path = ["{}/.x2goclient/sessions".format(os.environ.get('HOME'))] +x2goclient_bin = distutils.spawn.find_executable('x2goclient') +# This extension is useless without x2goclient +if x2goclient_bin is None or x2goclient_bin == "": + logger.error("x2goclient executable path could not be determined") exit() -# Check if Remmina profiles directory exists -remmina_profiles_path = None +# Check if x2goclient sessions file exists +x2go_sessions_path_exists = None # Check default paths first -for p in default_paths: - if os.path.isdir(p): - remmina_profiles_path = p +if os.path.isfile(x2go_sessions_path): + x2go_sessions_path_exists = True -class RemminaExtension(Extension): +class x2goclientExtension(Extension): def __init__(self): - super(RemminaExtension, self).__init__() + super(x2goclientExtension, self).__init__() self.subscribe(KeywordQueryEvent, KeywordQueryEventListener()) self.subscribe(ItemEnterEvent, ItemEnterEventListener()) - def list_profiles(self, query): - profiles = [] - items_cache = [] - try: - # Get list of profile files from Remmina directory - for profile in os.listdir(remmina_profiles_path): - if profile.endswith(".remmina"): - profiles.append(os.path.join(remmina_profiles_path, profile)) - # Get sorted list of profiles - temp = profiles - profiles = sorted(temp) - except Exception as e: - logger.error("Failed getting Remmina profile files") - for p in profiles: - base = os.path.basename(p) - title, desc, proto = profile_details(p) + def list_sessions(self, query): + items = [] + with open('/home/bryan/.x2goclient/sessions') as lines: + for line in lines: + if line.startswith('host=') or line.startswith('name='): + line = line.rstrip() + line = line.split('=',1) + item = line[1] + items.append(item) + it_items = iter(items) + sessions = list(zip(it_items, it_items)) + for session in sessions: + host = session[0] + name = session[1] # Search for query inside filename and profile description # Multiple strings can be used to search in description # all() is used to achieve a AND search (include all keywords) keywords = query.split(" ") # if (query in base.lower()) or (query in desc.lower()): - if (query.lower() in base.lower()) or \ - (query.lower() in title.lower()) or \ - all(x.lower() in desc.lower() for x in keywords): - items_cache.append(create_item(title, proto, p, desc, p)) + if (query.lower() in host.lower()) or (query.lower() in name.lower()): + items_cache.append(create_item(host, name)) items_cache = sorted(items_cache, key=sort_by_usage, reverse=True) return items_cache + class KeywordQueryEventListener(EventListener): def on_event(self, event, extension): - global remmina_profiles_path - if extension.preferences["profiles"] is not "" \ - or not remmina_profiles_path: + global x2go_sessions_path + if extension.preferences["sessions"] is not "" or not x2go_sessions_path: # Tilde (~) won't work alone, need expanduser() - remmina_profiles_path = os.path.expanduser(extension.preferences["profiles"]) - # pref_profiles_path = extension.preferences['profiles'] - logger.debug("Remmina profiles path: {}".format(remmina_profiles_path)) + x2go_sessions_path = os.path.expanduser(extension.preferences["sessions"]) + # pref_sessions_path = extension.preferences['sessions'] + logger.debug("x2goclient sessions path: {}".format(x2go_sessions_path)) # Get query term = (event.get_argument() or "").lower() # Display all items when query empty - profiles_list = extension.list_profiles(term) - return RenderResultListAction(profiles_list[:8]) + sessions_list = extension.list_sessions(term) + return RenderResultListAction(sessions_list[:8]) class ItemEnterEventListener(EventListener): @@ -117,16 +109,16 @@ class ItemEnterEventListener(EventListener): # Update usage JSON with open(usage_db, 'w') as db: db.write(json.dumps(usage_cache, indent=2)) - return RunScriptAction('#!/usr/bin/env bash\n{} -c {}\n'.format(remmina_bin, on_enter), None).run() + return RunScriptAction('#!/usr/bin/env bash\n{} --session {}\n'.format(x2goclient_bin, on_enter), None).run() -def create_item(name, icon, keyword, description, on_enter): +def create_item(host, name): return ExtensionResultItem( name=name, - description=description, - icon="images/{}.svg".format(icon), + description=host, + icon="images/x2goclient.svg", on_enter=ExtensionCustomAction( - {"id": on_enter}) + {"id": name}) ) @@ -141,61 +133,6 @@ def sort_by_usage(i): return 0 -def profile_details(profile_path): - if os.path.isfile(profile_path): - with open(profile_path, "r") as f: - # Read profile file lines - lines = f.read().split("\n") - # Initialize strings - desc = name = username = group = proto = "" - # Parse lines for relevant details - for line in lines: - # Profile name - if line.startswith("name="): - elem = line.split("name=") - if len(elem[1]) > 0: - name = elem[1] - # Profile username (optional) - if "username=" in line: - elem = line.split("username=") - # if len(elem) > 1: - if len(elem[0]) == 0 and len(elem[1]) > 0: - username = elem[1] - elif len(elem[0]) > 0 and len(elem[1]) > 0: - username = elem[1] - # Profile server and port - if line.startswith("server="): - elem = line.split("server=") - if len(elem[1]) > 0: - server = elem[1] - # Profile group name - if line.startswith("group="): - elem = line.split("group=") - if len(elem[1]) > 0: - group = elem[1] - # Profile protocol (for different icons) - if line.startswith("protocol="): - elem = line.split("protocol=") - if len(elem[1]) > 0: - proto = elem[1].strip().lower() - else: - pass - if len(username) > 0: - server = "{username}@{server}".format(username=username, - server=server) - if len(proto) > 0: - server = "{proto}://{server}".format(proto=proto, - server=server) - if len(group) > 0: - group = " | {group}".format(group=group) - # Final description string - desc = "{server} {group}".format(server=server, - group=group) - return name, desc, proto - else: - # Default values - return "", "", "rdp" - if __name__ == "__main__": - RemminaExtension().run() + x2goclientExtension().run() diff --git a/manifest.json b/manifest.json index 2b50952..fdfcd3c 100644 --- a/manifest.json +++ b/manifest.json @@ -1,25 +1,25 @@ { "required_api_version": "^2.0.0", - "name": "Remmina", - "description": "Quick access to Remmina profiles", - "developer_name": "noam09", + "name": "x2goclient", + "description": "Quick access to x2goclient sessions", + "developer_name": "cryobry", "icon": "images/icon.svg", "options": { "query_debounce": 0.1 }, "preferences": [ { - "id": "remmina", + "id": "x2goclient", "type": "keyword", - "name": "Remmina", - "description": "Quick access to Remmina profiles", - "default_value": "r" + "name": "x2goclient", + "description": "Quick access to x2goclient sessions", + "default_value": "x" }, { - "id": "profiles", + "id": "sessions", "type": "input", - "name": "Remmina Profiles Directory", - "description": "Where Remmina stores profile configuration files
~/.local/share/remmina and ~/.remmina are checked by default", + "name": "x2goclient sessions file", + "description": "Where x2goclient stores its profile configuration file
~/.x2goclient/sessions is checked by default", "default_value": "" } ]