From b0027edf5f367f76558ef3778d89fb1c089d0142 Mon Sep 17 00:00:00 2001 From: Noam Date: Wed, 5 Sep 2018 11:59:05 +0300 Subject: [PATCH] v0.0.2 - Added sorting by usage --- .gitignore | 3 ++- README.md | 2 +- main.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 61846a6..417e965 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *tmp* -*.gvd* \ No newline at end of file +*.gvd* +usage.json diff --git a/README.md b/README.md index 3ea6bff..31cf1f8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ulauncher-remmina -🖥 Ulauncher extension for quick access to [Remmina](https://remmina.org) profiles. +🖥 [Ulauncher](https://ulauncher.io) extension for quick access to [Remmina](https://remmina.org) profiles. You can enter several queries to match strings in profiles' descriptions (e.g. `r ssh stan`) diff --git a/main.py b/main.py index 250491f..860b5ed 100644 --- a/main.py +++ b/main.py @@ -1,17 +1,32 @@ import os +import json import logging import distutils.spawn from ulauncher.api.client.Extension import Extension from ulauncher.api.client.EventListener import EventListener -from ulauncher.api.shared.event import KeywordQueryEvent +from ulauncher.api.shared.event import KeywordQueryEvent, ItemEnterEvent from ulauncher.api.shared.item.ExtensionResultItem import ExtensionResultItem from ulauncher.api.shared.item.SmallResultItem import SmallResultItem from ulauncher.api.shared.action.RenderResultListAction import RenderResultListAction from ulauncher.api.shared.action.RunScriptAction import RunScriptAction +from ulauncher.api.shared.action.ExtensionCustomAction import ExtensionCustomAction logging.basicConfig() logger = logging.getLogger(__name__) +global usage_cache +usage_cache = {} + +# Usage tracking +script_directory = os.path.dirname(os.path.realpath(__file__)) +usage_db = os.path.join(script_directory, 'usage.json') +if os.path.exists(usage_db): + with open(usage_db, 'r') as db: + # Read JSON string + raw = db.read() + # JSON to dict + usage_cache = json.loads(raw) + # Initialize items cache and Remmina profiles path remmina_bin = '' # Locate Remmina profiles and binary @@ -32,6 +47,7 @@ def __init__(self): super(RemminaExtension, self).__init__() self.subscribe(KeywordQueryEvent, KeywordQueryEventListener()) + self.subscribe(ItemEnterEvent, ItemEnterEventListener()) def list_profiles(self, query): profiles = [] @@ -59,6 +75,7 @@ def list_profiles(self, query): if (query in base.lower()) or all(x in desc for x in keywords): items_cache.append(create_item(title, proto, p, desc, p)) + items_cache = sorted(items_cache, key=sort_by_usage, reverse=True) return items_cache @@ -69,7 +86,28 @@ def on_event(self, event, extension): # Display all items when query empty profiles_list = extension.list_profiles(term) - return RenderResultListAction(profiles_list) + return RenderResultListAction(profiles_list[:8]) + + +class ItemEnterEventListener(EventListener): + def on_event(self, event, extension): + global usage_cache + # Get query + data = event.get_data() + on_enter = data['id'] + # The profilefile name is the ID + base = os.path.basename(on_enter) + b = os.path.splitext(base)[0] + # Check usage and increment + if b in usage_cache: + usage_cache[b] = usage_cache[b]+1 + else: + usage_cache[b] = 1 + # 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() def create_item(name, icon, keyword, description, on_enter): @@ -77,8 +115,20 @@ def create_item(name, icon, keyword, description, on_enter): name=name, description=description, icon='images/{}.svg'.format(icon), - on_enter=RunScriptAction('#!/usr/bin/env bash\n{} -c {}\n'.format(remmina_bin, on_enter), None) - ) + on_enter=ExtensionCustomAction( + {'id': on_enter}) + ) + + +def sort_by_usage(i): + global usage_cache + # Convert item name to ID format + j = i._name.lower() + # Return score according to usage + if j in usage_cache: + return usage_cache[j] + # Default is 0 (no usage rank / unused) + return 0 def profile_details(profile_path):