main.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import os
  2. import json
  3. import logging
  4. import distutils.spawn
  5. from ulauncher.api.client.Extension import Extension
  6. from ulauncher.api.client.EventListener import EventListener
  7. from ulauncher.api.shared.event import KeywordQueryEvent, ItemEnterEvent
  8. from ulauncher.api.shared.item.ExtensionResultItem import ExtensionResultItem
  9. from ulauncher.api.shared.item.SmallResultItem import SmallResultItem
  10. from ulauncher.api.shared.action.RenderResultListAction import RenderResultListAction
  11. from ulauncher.api.shared.action.RunScriptAction import RunScriptAction
  12. from ulauncher.api.shared.action.ExtensionCustomAction import ExtensionCustomAction
  13. logging.basicConfig()
  14. logger = logging.getLogger(__name__)
  15. global usage_cache
  16. usage_cache = {}
  17. # Usage tracking
  18. script_directory = os.path.dirname(os.path.realpath(__file__))
  19. usage_db = os.path.join(script_directory, "usage.json")
  20. if os.path.exists(usage_db):
  21. with open(usage_db, 'r') as db:
  22. # Read JSON string
  23. raw = db.read()
  24. # JSON to dict
  25. usage_cache = json.loads(raw)
  26. # Initialize items cache and x2goclient sessions file path
  27. x2goclient_bin = ""
  28. # Locate x2goclient profiles and binary
  29. x2go_sessions_path = "{}/.x2goclient/sessions".format(os.environ.get('HOME'))
  30. x2goclient_bin = distutils.spawn.find_executable('x2goclient')
  31. # This extension is useless without x2goclient
  32. if x2goclient_bin is None or x2goclient_bin == "":
  33. logger.error("x2goclient executable path could not be determined")
  34. exit()
  35. # Check if x2goclient sessions file exists
  36. x2go_sessions_path_exists = None
  37. # Check default paths first
  38. if os.path.exists(x2go_sessions_path):
  39. x2go_sessions_path_exists = True
  40. class x2goclientExtension(Extension):
  41. def __init__(self):
  42. super(x2goclientExtension, self).__init__()
  43. self.subscribe(KeywordQueryEvent, KeywordQueryEventListener())
  44. self.subscribe(ItemEnterEvent, ItemEnterEventListener())
  45. def list_sessions(self, query):
  46. items = []
  47. items_cache = []
  48. with open('/home/bryan/.x2goclient/sessions') as lines:
  49. for line in lines:
  50. if line.startswith('['):
  51. item = line.rstrip()
  52. items.append(item[1:-1])
  53. if line.startswith('host=') or line.startswith('name='):
  54. line = line.rstrip()
  55. line = line.split('=',1)
  56. item = line[1]
  57. items.append(item)
  58. it_items = iter(items)
  59. sessions = list(zip(it_items, it_items, it_items))
  60. for session in sessions:
  61. seid = session[0]
  62. host = session[1]
  63. name = session[2]
  64. # Search for query inside filename and profile description
  65. keywords = query.split(" ")
  66. # if (query in base.lower()) or (query in desc.lower()):
  67. if (query.lower() in host.lower()) or (query.lower() in name.lower()):
  68. items_cache.append(create_item(seid, host, name))
  69. items_cache = sorted(items_cache, key=sort_by_usage, reverse=True)
  70. return items_cache
  71. class KeywordQueryEventListener(EventListener):
  72. def on_event(self, event, extension):
  73. global x2go_sessions_path
  74. if extension.preferences["sessions"] is not "" or not x2go_sessions_path:
  75. # Tilde (~) won't work alone, need expanduser()
  76. x2go_sessions_path = os.path.expanduser(extension.preferences["sessions"])
  77. # pref_sessions_path = extension.preferences['sessions']
  78. logger.debug("x2goclient sessions path: {}".format(x2go_sessions_path))
  79. # Get query
  80. term = (event.get_argument() or "").lower()
  81. # Display all items when query empty
  82. sessions_list = extension.list_sessions(term)
  83. return RenderResultListAction(sessions_list[:8])
  84. class ItemEnterEventListener(EventListener):
  85. def on_event(self, event, extension):
  86. global usage_cache
  87. # Get query
  88. data = event.get_data()
  89. on_enter = data["id"]
  90. # The profilefile name is the ID
  91. base = os.path.basename(on_enter)
  92. b = os.path.splitext(base)[0]
  93. # Check usage and increment
  94. if b in usage_cache:
  95. usage_cache[b] = usage_cache[b]+1
  96. else:
  97. usage_cache[b] = 1
  98. # Update usage JSON
  99. with open(usage_db, 'w') as db:
  100. db.write(json.dumps(usage_cache, indent=2))
  101. return RunScriptAction('#!/usr/bin/env bash\n{} --sessionid={}\n'.format(x2goclient_bin, on_enter), None).run()
  102. def create_item(seid, host, name):
  103. return ExtensionResultItem(
  104. name=name,
  105. description=host,
  106. icon="images/x2goclient.svg",
  107. on_enter=ExtensionCustomAction(
  108. {"id": seid})
  109. )
  110. def sort_by_usage(i):
  111. global usage_cache
  112. # Convert item name to ID format
  113. j = i._name.lower()
  114. # Return score according to usage
  115. if j in usage_cache:
  116. return usage_cache[j]
  117. # Default is 0 (no usage rank / unused)
  118. return 0
  119. if __name__ == "__main__":
  120. x2goclientExtension().run()