From 7abbee91824debdeb256d47e3e9c46132fd6f2f7 Mon Sep 17 00:00:00 2001
From: itdominator <1itdominator@gmail.com>
Date: Tue, 19 Jul 2022 16:46:38 -0500
Subject: [PATCH 1/4] Addec compilation to binary using Nuitka
---
.../solarfm-0.0.1/SolarFM/create-binary.sh | 17 +++++++++++++++++
.../{solarfm.sh => create-standalone.sh} | 7 +++----
.../SolarFM/solarfm/core/controller_data.py | 2 +-
3 files changed, 21 insertions(+), 5 deletions(-)
create mode 100755 src/versions/solarfm-0.0.1/SolarFM/create-binary.sh
rename src/versions/solarfm-0.0.1/SolarFM/{solarfm.sh => create-standalone.sh} (50%)
diff --git a/src/versions/solarfm-0.0.1/SolarFM/create-binary.sh b/src/versions/solarfm-0.0.1/SolarFM/create-binary.sh
new file mode 100755
index 0000000..2cd29cc
--- /dev/null
+++ b/src/versions/solarfm-0.0.1/SolarFM/create-binary.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# . CONFIG.sh
+
+# set -o xtrace ## To debug scripts
+# set -o errexit ## To exit on error
+# set -o errunset ## To exit if a variable is referenced but not set
+
+
+function main() {
+ cd "$(dirname "")"
+ echo "Working Dir: " $(pwd)
+
+ source "/home/abaddon/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/activate"
+ python -m nuitka --onefile --follow-imports --linux-onefile-icon="/home/abaddon/.config/solarfm/solarfm.png" solarfm/__main__.py -o solarfm.a
+}
+main "$@";
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm.sh b/src/versions/solarfm-0.0.1/SolarFM/create-standalone.sh
similarity index 50%
rename from src/versions/solarfm-0.0.1/SolarFM/solarfm.sh
rename to src/versions/solarfm-0.0.1/SolarFM/create-standalone.sh
index 67de002..ccc97e0 100755
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm.sh
+++ b/src/versions/solarfm-0.0.1/SolarFM/create-standalone.sh
@@ -8,11 +8,10 @@
function main() {
- SCRIPTPATH="$( cd "$(dirname "")" >/dev/null 2>&1 ; pwd -P )"
- cd "${SCRIPTPATH}"
+ cd "$(dirname "")"
echo "Working Dir: " $(pwd)
- source "/home/abaddon/Portable_Apps/py-venvs/flask-apps-venv/venv/bin/activate"
- python ./solarfm
+ source "/home/abaddon/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/activate"
+ python -m nuitka --follow-imports --standalone --linux-onefile-icon="/home/abaddon/.config/solarfm/solarfm.png" solarfm/__main__.py
}
main "$@";
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py
index 6a787f4..4a5e5f8 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller_data.py
@@ -120,7 +120,7 @@ class Controller_Data:
self.warning_color = self.settings.get_warning_color()
self.error_color = self.settings.get_error_color()
- sys.excepthook = self.custom_except_hook
+ # sys.excepthook = self.custom_except_hook
self.window.connect("delete-event", self.tear_down)
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.tear_down)
--
2.27.0
From 3f5664da5b7173b284e71dc90a9011c97a929479 Mon Sep 17 00:00:00 2001
From: itdominator <1itdominator@gmail.com>
Date: Wed, 20 Jul 2022 23:57:06 -0500
Subject: [PATCH 2/4] Updated READNE, added searcher plugin, cleanup
---
README.md | 3 -
plugins/file_properties/__init__.py | 3 +
plugins/file_properties/plugin.py | 2 +-
plugins/searcher/__init__.py | 3 +
plugins/searcher/plugin.py | 281 +++++++++++++++++++++++++++
plugins/searcher/search_dialog.glade | 227 ++++++++++++++++++++++
plugins/template/__init__.py | 3 +
plugins/template/plugin.py | 2 +-
plugins/youtube_download/__init__.py | 3 +
plugins/youtube_download/download.sh | 1 -
plugins/youtube_download/plugin.py | 2 +-
11 files changed, 523 insertions(+), 7 deletions(-)
create mode 100644 plugins/file_properties/__init__.py
create mode 100644 plugins/searcher/__init__.py
create mode 100644 plugins/searcher/plugin.py
create mode 100644 plugins/searcher/search_dialog.glade
create mode 100644 plugins/template/__init__.py
create mode 100644 plugins/youtube_download/__init__.py
diff --git a/README.md b/README.md
index c61ddf6..f405c7f 100644
--- a/README.md
+++ b/README.md
@@ -11,10 +11,7 @@ sudo apt-get install python3.8 wget python3-setproctitle python3-gi ffmpegthumbn
# TODO
-- Add simpleish plugin system to run bash/python scripts.
- Add simpleish preview plugin for various file types.
-- Add simpleish file chmod, chown, stats, etc plugin for file management.
-- Add simpleish search plugin to do recursive search and show.
- Add simpleish bulk-renamer.
- Add a basic favorites manager plugin.
diff --git a/plugins/file_properties/__init__.py b/plugins/file_properties/__init__.py
new file mode 100644
index 0000000..d36fa8c
--- /dev/null
+++ b/plugins/file_properties/__init__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Module
+"""
diff --git a/plugins/file_properties/plugin.py b/plugins/file_properties/plugin.py
index 9236370..5a4b2a4 100644
--- a/plugins/file_properties/plugin.py
+++ b/plugins/file_properties/plugin.py
@@ -2,7 +2,7 @@
import os, threading, subprocess, time, pwd, grp
from datetime import datetime
-# Gtk imports
+# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, Gio
diff --git a/plugins/searcher/__init__.py b/plugins/searcher/__init__.py
new file mode 100644
index 0000000..d36fa8c
--- /dev/null
+++ b/plugins/searcher/__init__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Module
+"""
diff --git a/plugins/searcher/plugin.py b/plugins/searcher/plugin.py
new file mode 100644
index 0000000..ea295eb
--- /dev/null
+++ b/plugins/searcher/plugin.py
@@ -0,0 +1,281 @@
+# Python imports
+import os, multiprocessing, threading, subprocess, inspect, time, json
+from multiprocessing import Manager, Process
+
+# Lib imports
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk, GLib, GObject
+
+# Application imports
+
+
+# NOTE: Threads WILL NOT die with parent's destruction.
+def threaded(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
+ return wrapper
+
+# NOTE: Threads WILL die with parent's destruction.
+def daemon_threaded(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
+ return wrapper
+
+
+
+
+class Manifest:
+ path: str = os.path.dirname(os.path.realpath(__file__))
+ name: str = "Search"
+ author: str = "ITDominator"
+ version: str = "0.0.1"
+ support: str = ""
+ requests: {} = {
+ 'ui_target': "context_menu",
+ 'pass_fm_events': "true",
+ 'bind_keys': [f"{name}||_show_grep_list_page:f"]
+ }
+
+
+
+
+class FilePreviewWidget(Gtk.LinkButton):
+ def __init__(self, path, file):
+ super(FilePreviewWidget, self).__init__()
+ self.set_label(file)
+ self.set_uri(f"file://{path}")
+ self.show_all()
+
+
+class GrepPreviewWidget(Gtk.Box):
+ def __init__(self, path, sub_keys, data):
+ super(GrepPreviewWidget, self).__init__()
+ self.set_orientation(Gtk.Orientation.VERTICAL)
+ self.line_color = "#e0cc64"
+
+
+ _label = '/'.join( path.split("/")[-3:] )
+ title = Gtk.LinkButton.new_with_label(uri=f"file://{path}", label=_label)
+
+ self.add(title)
+ for key in sub_keys:
+ line_num = key
+ text = data[key]
+ box = Gtk.Box()
+ number_label = Gtk.Label()
+ text_view = Gtk.Label(label=text[:-1])
+ label_text = f"{line_num}"
+
+ number_label.set_markup(label_text)
+ number_label.set_margin_left(15)
+ number_label.set_margin_right(5)
+ number_label.set_margin_top(5)
+ number_label.set_margin_bottom(5)
+ text_view.set_margin_top(5)
+ text_view.set_margin_bottom(5)
+ text_view.set_line_wrap(True)
+
+ box.add(number_label)
+ box.add(text_view)
+ self.add(box)
+
+ self.show_all()
+
+
+
+manager = Manager()
+grep_result_set = manager.dict()
+file_result_set = manager.list()
+
+
+class Plugin(Manifest):
+ def __init__(self):
+ self._GLADE_FILE = f"{self.path}/search_dialog.glade"
+ self._builder = None
+ self._search_dialog = None
+
+ self._event_system = None
+ self._event_sleep_time = .5
+ self._event_message = None
+
+ self._active_path = None
+ self._file_list = None
+ self._grep_list = None
+ self._grep_proc = None
+ self._list_proc = None
+
+
+ def get_ui_element(self):
+ self._builder = Gtk.Builder()
+ self._builder.add_from_file(self._GLADE_FILE)
+
+ classes = [self]
+ handlers = {}
+ for c in classes:
+ methods = None
+ try:
+ methods = inspect.getmembers(c, predicate=inspect.ismethod)
+ handlers.update(methods)
+ except Exception as e:
+ print(repr(e))
+
+ self._builder.connect_signals(handlers)
+
+ self._search_dialog = self._builder.get_object("search_dialog")
+ self._grep_list = self._builder.get_object("grep_list")
+ self._file_list = self._builder.get_object("file_list")
+
+ GObject.signal_new("update-file-ui-signal", self._search_dialog, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
+ self._search_dialog.connect("update-file-ui-signal", self._load_file_ui)
+ GObject.signal_new("update-grep-ui-signal", self._search_dialog, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
+ self._search_dialog.connect("update-grep-ui-signal", self._load_grep_ui)
+
+ button = Gtk.Button(label=self.name)
+ button.connect("button-release-event", self._show_grep_list_page)
+ return button
+
+ def set_fm_event_system(self, fm_event_system):
+ self._event_system = fm_event_system
+
+ def run(self):
+ self._module_event_observer()
+
+
+ @daemon_threaded
+ def _show_grep_list_page(self, widget=None, eve=None):
+ self._event_system.push_gui_event([self.name, "get_current_state", ()])
+ self.wait_for_fm_message()
+
+ state = self._event_message
+ self._event_message = None
+
+ GLib.idle_add(self._process_queries, (state))
+
+ def _process_queries(self, state):
+ self._active_path = state.tab.get_current_directory()
+ response = self._search_dialog.run()
+ self._search_dialog.hide()
+
+
+ def _run_find_file_query(self, widget=None, eve=None):
+ if self._list_proc:
+ self._list_proc.terminate()
+ self._list_proc = None
+ time.sleep(.2)
+
+ del file_result_set[:]
+ self.clear_children(self._file_list)
+
+ query = widget.get_text()
+ if query:
+ self._list_proc = multiprocessing.Process(self._do_list_search(self._active_path, query))
+ self._list_proc.start()
+
+ def _do_list_search(self, path, query):
+ self._file_traverse_path(path, query)
+ for target, file in file_result_set:
+ widget = FilePreviewWidget(target, file)
+ self._search_dialog.emit("update-file-ui-signal", (widget))
+
+ def _load_file_ui(self, parent=None, widget=None):
+ self._file_list.add(widget)
+
+ def _file_traverse_path(self, path, query):
+ try:
+ for file in os.listdir(path):
+ target = os.path.join(path, file)
+ if os.path.isdir(target):
+ self._file_traverse_path(target, query)
+ else:
+ if query.lower() in file.lower():
+ file_result_set.append([target, file])
+ except Exception as e:
+ if debug:
+ print("Couldn't traverse to path. Might be permissions related...")
+
+
+ def _run_grep_query(self, widget=None, eve=None):
+ if self._grep_proc:
+ self._grep_proc.terminate()
+ self._grep_proc = None
+ time.sleep(.2)
+
+ grep_result_set.clear()
+ self.clear_children(self._grep_list)
+
+ query = widget.get_text()
+ if query:
+ self._grep_proc = multiprocessing.Process(self._do_grep_search(self._active_path, query))
+ self._grep_proc.start()
+
+ def _do_grep_search(self, path, query):
+ self._grep_traverse_path(path, query)
+
+ keys = grep_result_set.keys()
+ for key in keys:
+ sub_keys = grep_result_set[key].keys()
+ widget = GrepPreviewWidget(key, sub_keys, grep_result_set[key])
+ self._search_dialog.emit("update-grep-ui-signal", (widget))
+
+ def _load_grep_ui(self, parent=None, widget=None):
+ self._grep_list.add(widget)
+
+ def _grep_traverse_path(self, path, query):
+ try:
+ for file in os.listdir(path):
+ target = os.path.join(path, file)
+ if os.path.isdir(target):
+ self._grep_traverse_path(target, query)
+ else:
+ self._search_for_string(target, query)
+ except Exception as e:
+ if debug:
+ print("Couldn't traverse to path. Might be permissions related...")
+
+ def _search_for_string(self, file, query):
+ try:
+ with open(file, 'r') as fp:
+ for i, line in enumerate(fp):
+ if query in line:
+ if f"{file}" in grep_result_set.keys():
+ grep_result_set[f"{file}"][f"{i+1}"] = line
+ else:
+ grep_result_set[f"{file}"] = {}
+ grep_result_set[f"{file}"] = {f"{i+1}": line}
+ except Exception as e:
+ if debug:
+ print("Couldn't read file. Might be binary or other cause...")
+
+
+
+
+ def clear_children(self, widget: type) -> None:
+ ''' Clear children of a gtk widget. '''
+ for child in widget.get_children():
+ widget.remove(child)
+
+ def wait_for_fm_message(self):
+ while not self._event_message:
+ pass
+
+ @daemon_threaded
+ def _module_event_observer(self):
+ while True:
+ time.sleep(self._event_sleep_time)
+ event = self._event_system.read_module_event()
+ if event:
+ try:
+ if event[0] == self.name:
+ target_id, method_target, data = self._event_system.consume_module_event()
+
+ if not method_target:
+ self._event_message = data
+ else:
+ method = getattr(self.__class__, f"{method_target}")
+ if data:
+ data = method(*(self, *data))
+ else:
+ method(*(self,))
+ except Exception as e:
+ print(repr(e))
diff --git a/plugins/searcher/search_dialog.glade b/plugins/searcher/search_dialog.glade
new file mode 100644
index 0000000..47fc1bc
--- /dev/null
+++ b/plugins/searcher/search_dialog.glade
@@ -0,0 +1,227 @@
+
+
+
+
+
+
diff --git a/plugins/template/__init__.py b/plugins/template/__init__.py
new file mode 100644
index 0000000..d36fa8c
--- /dev/null
+++ b/plugins/template/__init__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Module
+"""
diff --git a/plugins/template/plugin.py b/plugins/template/plugin.py
index 294aadc..bc22725 100644
--- a/plugins/template/plugin.py
+++ b/plugins/template/plugin.py
@@ -1,7 +1,7 @@
# Python imports
import os, threading, subprocess, time
-# Gtk imports
+# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
diff --git a/plugins/youtube_download/__init__.py b/plugins/youtube_download/__init__.py
new file mode 100644
index 0000000..d36fa8c
--- /dev/null
+++ b/plugins/youtube_download/__init__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Module
+"""
diff --git a/plugins/youtube_download/download.sh b/plugins/youtube_download/download.sh
index dc6df21..073b354 100755
--- a/plugins/youtube_download/download.sh
+++ b/plugins/youtube_download/download.sh
@@ -10,7 +10,6 @@
function main() {
cd "$(dirname "")"
echo "Working Dir: " $(pwd)
- source "/home/abaddon/Portable_Apps/py-venvs/yt-dlp-venv/venv/bin/activate"
LINK=`xclip -selection clipboard -o`
yt-dlp --write-sub --embed-sub --sub-langs en -o "${1}/%(title)s.%(ext)s" "${LINK}"
diff --git a/plugins/youtube_download/plugin.py b/plugins/youtube_download/plugin.py
index a7a6c44..cd98a37 100644
--- a/plugins/youtube_download/plugin.py
+++ b/plugins/youtube_download/plugin.py
@@ -1,7 +1,7 @@
# Python imports
import os, threading, subprocess, time
-# Gtk imports
+# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
--
2.27.0
From b058dc3667b21897de8e70ab6cac7d96b4f4dffb Mon Sep 17 00:00:00 2001
From: itdominator <1itdominator@gmail.com>
Date: Tue, 9 Aug 2022 20:10:25 -0500
Subject: [PATCH 3/4] Global threading decorators; Endpoint registry creation
---
plugins/vod_thumbnailer/__init__.py | 3 +
plugins/vod_thumbnailer/plugin.py | 173 ++++++++++++++
plugins/vod_thumbnailer/re_thumbnailer.glade | 219 ++++++++++++++++++
.../SolarFM/solarfm/__builtins__.py | 39 +++-
.../solarfm-0.0.1/SolarFM/solarfm/app.py | 2 +-
.../SolarFM/solarfm/core/controller.py | 22 +-
.../core/mixins/exception_hook_mixin.py | 6 +-
.../solarfm/core/mixins/ui/grid_mixin.py | 8 +-
.../mixins/ui/widget_file_action_mixin.py | 6 +-
9 files changed, 444 insertions(+), 34 deletions(-)
create mode 100644 plugins/vod_thumbnailer/__init__.py
create mode 100644 plugins/vod_thumbnailer/plugin.py
create mode 100644 plugins/vod_thumbnailer/re_thumbnailer.glade
diff --git a/plugins/vod_thumbnailer/__init__.py b/plugins/vod_thumbnailer/__init__.py
new file mode 100644
index 0000000..d36fa8c
--- /dev/null
+++ b/plugins/vod_thumbnailer/__init__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Module
+"""
diff --git a/plugins/vod_thumbnailer/plugin.py b/plugins/vod_thumbnailer/plugin.py
new file mode 100644
index 0000000..44deeb2
--- /dev/null
+++ b/plugins/vod_thumbnailer/plugin.py
@@ -0,0 +1,173 @@
+# Python imports
+import os, threading, subprocess, time, inspect, hashlib
+from datetime import datetime
+
+# Gtk imports
+import gi
+gi.require_version('Gtk', '3.0')
+gi.require_version('GdkPixbuf', '2.0')
+from gi.repository import Gtk, GLib, Gio, GdkPixbuf
+
+# Application imports
+
+
+# NOTE: Threads WILL NOT die with parent's destruction.
+def threaded(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
+ return wrapper
+
+# NOTE: Threads WILL die with parent's destruction.
+def daemon_threaded(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
+ return wrapper
+
+
+
+
+class Manifest:
+ path: str = os.path.dirname(os.path.realpath(__file__))
+ name: str = "VOD Thumbnailer"
+ author: str = "ITDominator"
+ version: str = "0.0.1"
+ support: str = ""
+ requests: {} = {
+ 'ui_target': "context_menu",
+ 'pass_fm_events': "true"
+ }
+
+class Plugin(Manifest):
+ def __init__(self):
+ self._GLADE_FILE = f"{self.path}/re_thumbnailer.glade"
+ self._builder = None
+ self._thumbnailer_dialog = None
+ self._thumbnail_preview_img = None
+ self._file_name = None
+ self._file_location = None
+ self._file_hash = None
+ self._state = None
+
+ self._event_system = None
+ self._event_sleep_time = .5
+ self._event_message = None
+
+
+
+ def get_ui_element(self):
+ self._builder = Gtk.Builder()
+ self._builder.add_from_file(self._GLADE_FILE)
+
+ classes = [self]
+ handlers = {}
+ for c in classes:
+ methods = None
+ try:
+ methods = inspect.getmembers(c, predicate=inspect.ismethod)
+ handlers.update(methods)
+ except Exception as e:
+ print(repr(e))
+
+ self._builder.connect_signals(handlers)
+
+ self._thumbnailer_dialog = self._builder.get_object("thumbnailer_dialog")
+ self._file_name = self._builder.get_object("file_name")
+ self._file_location = self._builder.get_object("file_location")
+ self._thumbnail_preview_img = self._builder.get_object("thumbnail_preview_img")
+ self._file_hash = self._builder.get_object("file_hash")
+
+ button = Gtk.Button(label=self.name)
+ button.connect("button-release-event", self._show_thumbnailer_page)
+ return button
+
+ def set_fm_event_system(self, fm_event_system):
+ self._event_system = fm_event_system
+
+ def run(self):
+ self._module_event_observer()
+
+
+
+
+ @threaded
+ def _show_thumbnailer_page(self, widget=None, eve=None):
+ self._event_system.push_gui_event([self.name, "get_current_state", ()])
+ self.wait_for_fm_message()
+
+ state = self._event_message
+ self._event_message = None
+
+ GLib.idle_add(self._process_changes, (state))
+
+ def _process_changes(self, state):
+ self._state = None
+
+ if len(state.selected_files) == 1:
+ if state.selected_files[0].lower().endswith(state.tab.fvideos):
+ self._state = state
+ self._set_ui_data()
+ response = self._thumbnailer_dialog.run()
+ if response in [Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT]:
+ self._thumbnailer_dialog.hide()
+
+
+ def _regenerate_thumbnail(self, widget=None, eve=None):
+ print("Regenerating thumbnail...")
+ file = self._file_name.get_text()
+ dir = self._file_location.get_text()
+ file_hash = self._file_hash.get_text()
+
+ hash_img_pth = f"{self._state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg"
+ try:
+ if os.path.isfile(hash_img_pth):
+ os.remove(hash_img_pth)
+
+ img_pixbuf = self._state.tab.create_icon(dir, file)
+ self._thumbnail_preview_img.set_from_pixbuf(img_pixbuf)
+ except Exception as e:
+ print("Couldn't regenerate thumbnail!")
+
+ def _use_selected_thumbnail(self, widget=None, eve=None):
+ print("_use_selected_thumbnail stub...")
+
+
+ def _set_ui_data(self):
+ uri = self._state.selected_files[0]
+ path = self._state.tab.get_current_directory()
+ parts = uri.split("/")
+
+ file_hash = hashlib.sha256(str.encode(uri)).hexdigest()
+ hash_img_pth = f"{self._state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg"
+ img_pixbuf = GdkPixbuf.Pixbuf.new_from_file(hash_img_pth)
+
+ self._thumbnail_preview_img.set_from_pixbuf(img_pixbuf)
+ self._file_name.set_text(parts[ len(parts) - 1 ])
+ self._file_location.set_text(path)
+ self._file_hash.set_text(file_hash)
+
+
+
+ def wait_for_fm_message(self):
+ while not self._event_message:
+ pass
+
+ @daemon_threaded
+ def _module_event_observer(self):
+ while True:
+ time.sleep(self._event_sleep_time)
+ event = self._event_system.read_module_event()
+ if event:
+ try:
+ if event[0] == self.name:
+ target_id, method_target, data = self._event_system.consume_module_event()
+
+ if not method_target:
+ self._event_message = data
+ else:
+ method = getattr(self.__class__, f"{method_target}")
+ if data:
+ data = method(*(self, *data))
+ else:
+ method(*(self,))
+ except Exception as e:
+ print(repr(e))
diff --git a/plugins/vod_thumbnailer/re_thumbnailer.glade b/plugins/vod_thumbnailer/re_thumbnailer.glade
new file mode 100644
index 0000000..1198dc4
--- /dev/null
+++ b/plugins/vod_thumbnailer/re_thumbnailer.glade
@@ -0,0 +1,219 @@
+
+
+
+
+
+ False
+ 6
+ VOD Thumbnailer
+ True
+ center-on-parent
+ 420
+ True
+ dialog
+ True
+ True
+ center
+
+
+ True
+ False
+ 12
+
+
+ True
+ False
+ end
+
+
+ gtk-cancel
+ True
+ True
+ True
+ False
+ True
+
+
+ True
+ True
+ 0
+
+
+
+
+ False
+ False
+ end
+ 0
+
+
+
+
+ True
+ False
+ vertical
+
+
+ True
+ False
+ gtk-missing-image
+ 6
+
+
+ True
+ True
+ 0
+
+
+
+
+
+
+
+ True
+ False
+ 4
+ 4
+ 2
+ 12
+ 6
+
+
+ True
+ False
+ <b>File _Name:</b>
+ True
+ True
+ file_name
+ 0
+
+
+ GTK_FILL
+
+
+
+
+
+ True
+ True
+ False
+
+
+ 1
+ 2
+
+
+
+
+
+ True
+ False
+ <b>_Location:</b>
+ True
+ True
+ file_location
+ 0
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+
+ True
+ True
+ False
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+
+ Regenerate
+ True
+ True
+ True
+
+
+
+ 1
+ 2
+ 3
+ 4
+
+
+
+
+ Use Selected
+ True
+ True
+ True
+
+
+
+ 3
+ 4
+
+
+
+
+ True
+ False
+ <b>_Thumbnail Hash:</b>
+ True
+ True
+ file_location
+ 0
+
+
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+
+ True
+ True
+ False
+
+
+ 1
+ 2
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+
+ False
+ True
+ 2
+
+
+
+
+ True
+ True
+ 1
+
+
+
+
+
+ cancel_button
+
+
+
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py
index ae1c305..15a4f9d 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py
@@ -1,5 +1,5 @@
# Python imports
-import builtins
+import builtins, threading
# Lib imports
@@ -7,6 +7,21 @@ import builtins
from utils.ipc_server import IPCServer
+# NOTE: Threads will not die with parent's destruction
+def threaded_wrapper(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
+ return wrapper
+
+# NOTE: Insure threads die with parent's destruction
+def daemon_threaded_wrapper(fn):
+ def wrapper(*args, **kwargs):
+ threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
+ return wrapper
+
+
+
+
class EventSystem(IPCServer):
@@ -65,10 +80,32 @@ class EventSystem(IPCServer):
+class EndpointRegistry():
+ def __init__(self):
+ self._endpoints = {}
+
+ def register(self, rule, **options):
+ def decorator(f):
+ _endpoint = options.pop("endpoint", None)
+ self._endpoints[rule] = f
+ return f
+
+ return decorator
+
+ def get_endpoints(self):
+ return self._endpoints
+
+
+
+
# NOTE: Just reminding myself we can add to builtins two different ways...
# __builtins__.update({"event_system": Builtins()})
builtins.app_name = "SolarFM"
builtins.event_system = EventSystem()
+builtins.endpoint_registry = EndpointRegistry()
+builtins.threaded = threaded_wrapper
+builtins.daemon_threaded = daemon_threaded_wrapper
builtins.event_sleep_time = 0.05
builtins.trace_debug = False
builtins.debug = False
+builtins.app_settings = None
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py
index bc414b5..e7b0d5f 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py
@@ -4,9 +4,9 @@ import os, inspect, time
# Lib imports
# Application imports
+from __builtins__ import EventSystem
from utils.settings import Settings
from core.controller import Controller
-from __builtins__ import EventSystem
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py
index 3b7ba50..6ddb4c9 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py
@@ -1,5 +1,5 @@
# Python imports
-import os, gc, threading, time
+import os, gc, time
# Lib imports
import gi
@@ -14,19 +14,6 @@ from .signals.keyboard_signals_mixin import KeyboardSignalsMixin
from .controller_data import Controller_Data
-# NOTE: Threads will not die with parent's destruction
-def threaded(fn):
- def wrapper(*args, **kwargs):
- threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
- return wrapper
-
-# NOTE: Insure threads die with parent's destruction
-def daemon_threaded(fn):
- def wrapper(*args, **kwargs):
- threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
- return wrapper
-
-
class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMixin, Controller_Data):
@@ -177,23 +164,28 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
-
+ @endpoint_registry.register(rule="go_home")
def go_home(self, widget=None, eve=None):
self.builder.get_object("go_home").released()
+ @endpoint_registry.register(rule="refresh_tab")
def refresh_tab(self, widget=None, eve=None):
self.builder.get_object("refresh_tab").released()
+ @endpoint_registry.register(rule="go_up")
def go_up(self, widget=None, eve=None):
self.builder.get_object("go_up").released()
+ @endpoint_registry.register(rule="grab_focus_path_entry")
def grab_focus_path_entry(self, widget=None, eve=None):
self.builder.get_object("path_entry").grab_focus()
+ @endpoint_registry.register(rule="tggl_top_main_menubar")
def tggl_top_main_menubar(self, widget=None, eve=None):
top_main_menubar = self.builder.get_object("top_main_menubar")
top_main_menubar.hide() if top_main_menubar.is_visible() else top_main_menubar.show()
+ @endpoint_registry.register(rule="open_terminal")
def open_terminal(self, widget=None, eve=None):
wid, tid = self.fm_controller.get_active_wid_and_tid()
tab = self.get_fm_window(wid).get_tab_by_id(tid)
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/exception_hook_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/exception_hook_mixin.py
index 81a0b95..660b9b6 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/exception_hook_mixin.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/exception_hook_mixin.py
@@ -1,5 +1,5 @@
# Python imports
-import traceback, threading, time
+import traceback, time
# Lib imports
import gi
@@ -9,10 +9,6 @@ from gi.repository import Gtk, GLib
# Application imports
-def threaded(fn):
- def wrapper(*args, **kwargs):
- threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
- return wrapper
class ExceptionHookMixin:
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/grid_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/grid_mixin.py
index 01ff051..2d3afeb 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/grid_mixin.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/grid_mixin.py
@@ -1,5 +1,5 @@
# Python imports
-import os, threading, subprocess, time
+import os
# Lib imports
import gi
@@ -11,12 +11,6 @@ from gi.repository import Gtk, Gdk, GLib, Gio, GdkPixbuf
# Application imports
-def threaded(fn):
- def wrapper(*args, **kwargs):
- threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
- return wrapper
-
-
# NOTE: Consider trying to use Gtk.TreeView with css that turns it into a grid...
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/widget_file_action_mixin.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/widget_file_action_mixin.py
index 9fc5a83..71a3cc3 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/widget_file_action_mixin.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/mixins/ui/widget_file_action_mixin.py
@@ -1,5 +1,5 @@
# Python imports
-import os, time, threading, shlex
+import os, time, shlex
# Lib imports
import gi
@@ -9,10 +9,6 @@ from gi.repository import Gtk, GObject, GLib, Gio
# Application imports
-def threaded(fn):
- def wrapper(*args, **kwargs):
- threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
- return wrapper
class WidgetFileActionMixin:
--
2.27.0
From bff54995fd116e78bf61b8b361a6e1fb756c35de Mon Sep 17 00:00:00 2001
From: itdominator <1itdominator@gmail.com>
Date: Fri, 12 Aug 2022 22:54:16 -0500
Subject: [PATCH 4/4] Reworked plugin manifest; decoupled event system and ipc
---
plugins/file_properties/__main__.py | 3 +
plugins/file_properties/manifest.json | 12 +++
plugins/file_properties/plugin.py | 16 +---
plugins/searcher/__main__.py | 3 +
plugins/searcher/manifest.json | 13 ++++
plugins/searcher/plugin.py | 20 +----
plugins/template/__main__.py | 3 +
plugins/template/manifest.json | 13 ++++
plugins/template/plugin.py | 18 +----
plugins/vod_thumbnailer/__main__.py | 3 +
plugins/vod_thumbnailer/manifest.json | 12 +++
plugins/vod_thumbnailer/plugin.py | 16 +---
plugins/youtube_download/__main__.py | 3 +
plugins/youtube_download/manifest.json | 12 +++
plugins/youtube_download/plugin.py | 17 +----
.../SolarFM/solarfm/__builtins__.py | 67 ++--------------
.../solarfm-0.0.1/SolarFM/solarfm/app.py | 16 ++--
.../SolarFM/solarfm/core/controller.py | 1 -
.../SolarFM/solarfm/plugins/manifest.py | 76 +++++++++++++++++++
.../SolarFM/solarfm/plugins/plugins.py | 69 ++---------------
.../SolarFM/solarfm/utils/event_system.py | 59 ++++++++++++++
.../SolarFM/solarfm/utils/ipc_server.py | 8 +-
22 files changed, 253 insertions(+), 207 deletions(-)
create mode 100644 plugins/file_properties/__main__.py
create mode 100644 plugins/file_properties/manifest.json
create mode 100644 plugins/searcher/__main__.py
create mode 100644 plugins/searcher/manifest.json
create mode 100644 plugins/template/__main__.py
create mode 100644 plugins/template/manifest.json
create mode 100644 plugins/vod_thumbnailer/__main__.py
create mode 100644 plugins/vod_thumbnailer/manifest.json
create mode 100644 plugins/youtube_download/__main__.py
create mode 100644 plugins/youtube_download/manifest.json
create mode 100644 src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/manifest.py
create mode 100644 src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/event_system.py
diff --git a/plugins/file_properties/__main__.py b/plugins/file_properties/__main__.py
new file mode 100644
index 0000000..a576329
--- /dev/null
+++ b/plugins/file_properties/__main__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Package
+"""
diff --git a/plugins/file_properties/manifest.json b/plugins/file_properties/manifest.json
new file mode 100644
index 0000000..7ba667d
--- /dev/null
+++ b/plugins/file_properties/manifest.json
@@ -0,0 +1,12 @@
+{
+ "manifest": {
+ "name": "Properties",
+ "author": "ITDominator",
+ "version": "0.0.1",
+ "support": "",
+ "requests": {
+ "ui_target": "context_menu",
+ "pass_fm_events": "true"
+ }
+ }
+}
diff --git a/plugins/file_properties/plugin.py b/plugins/file_properties/plugin.py
index 5a4b2a4..a7f6d8e 100644
--- a/plugins/file_properties/plugin.py
+++ b/plugins/file_properties/plugin.py
@@ -25,17 +25,6 @@ def daemon_threaded(fn):
-class Manifest:
- path: str = os.path.dirname(os.path.realpath(__file__))
- name: str = "Properties"
- author: str = "ITDominator"
- version: str = "0.0.1"
- support: str = ""
- requests: {} = {
- 'ui_target': "context_menu",
- 'pass_fm_events': "true"
- }
-
class Properties:
file_uri: str = None
file_name: str = None
@@ -50,8 +39,11 @@ class Properties:
chmod_stat: str = None
-class Plugin(Manifest):
+class Plugin:
def __init__(self):
+ self.path = os.path.dirname(os.path.realpath(__file__))
+ self.name = "Properties" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
+ # where self.name should not be needed for message comms
self._GLADE_FILE = f"{self.path}/file_properties.glade"
self._builder = None
self._properties_dialog = None
diff --git a/plugins/searcher/__main__.py b/plugins/searcher/__main__.py
new file mode 100644
index 0000000..a576329
--- /dev/null
+++ b/plugins/searcher/__main__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Package
+"""
diff --git a/plugins/searcher/manifest.json b/plugins/searcher/manifest.json
new file mode 100644
index 0000000..845a31f
--- /dev/null
+++ b/plugins/searcher/manifest.json
@@ -0,0 +1,13 @@
+{
+ "manifest": {
+ "name": "Search",
+ "author": "ITDominator",
+ "version": "0.0.1",
+ "support": "",
+ "requests": {
+ "ui_target": "context_menu",
+ "pass_fm_events": "true",
+ "bind_keys": ["Search||_show_grep_list_page:f"]
+ }
+ }
+}
diff --git a/plugins/searcher/plugin.py b/plugins/searcher/plugin.py
index ea295eb..4721b32 100644
--- a/plugins/searcher/plugin.py
+++ b/plugins/searcher/plugin.py
@@ -25,21 +25,6 @@ def daemon_threaded(fn):
-class Manifest:
- path: str = os.path.dirname(os.path.realpath(__file__))
- name: str = "Search"
- author: str = "ITDominator"
- version: str = "0.0.1"
- support: str = ""
- requests: {} = {
- 'ui_target': "context_menu",
- 'pass_fm_events': "true",
- 'bind_keys': [f"{name}||_show_grep_list_page:f"]
- }
-
-
-
-
class FilePreviewWidget(Gtk.LinkButton):
def __init__(self, path, file):
super(FilePreviewWidget, self).__init__()
@@ -89,8 +74,11 @@ grep_result_set = manager.dict()
file_result_set = manager.list()
-class Plugin(Manifest):
+class Plugin:
def __init__(self):
+ self.path = os.path.dirname(os.path.realpath(__file__))
+ self.name = "Search" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
+ # where self.name should not be needed for message comms
self._GLADE_FILE = f"{self.path}/search_dialog.glade"
self._builder = None
self._search_dialog = None
diff --git a/plugins/template/__main__.py b/plugins/template/__main__.py
new file mode 100644
index 0000000..a576329
--- /dev/null
+++ b/plugins/template/__main__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Package
+"""
diff --git a/plugins/template/manifest.json b/plugins/template/manifest.json
new file mode 100644
index 0000000..4dcbf47
--- /dev/null
+++ b/plugins/template/manifest.json
@@ -0,0 +1,13 @@
+{
+ "manifest": {
+ "name": "Example Plugin",
+ "author": "John Doe",
+ "version": "0.0.1",
+ "support": "",
+ "requests": {
+ "ui_target": "plugin_control_list",
+ "pass_fm_events": "true",
+ "bind_keys": ["Example Plugin||send_message:f"]
+ }
+ }
+}
diff --git a/plugins/template/plugin.py b/plugins/template/plugin.py
index bc22725..21a5d5b 100644
--- a/plugins/template/plugin.py
+++ b/plugins/template/plugin.py
@@ -24,21 +24,10 @@ def daemon_threaded(fn):
-class Manifest:
- path: str = os.path.dirname(os.path.realpath(__file__))
- name: str = "Example Plugin"
- author: str = "John Doe"
- version: str = "0.0.1"
- support: str = ""
- requests: {} = {
- 'ui_target': "plugin_control_list",
- 'pass_fm_events': "true",
- 'bind_keys': [f"{name}||send_message:f"]
- }
-
-
-class Plugin(Manifest):
+class Plugin:
def __init__(self):
+ self.name = "Example Plugin" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
+ # where self.name should not be needed for message comms
self._event_system = None
self._event_sleep_time = .5
self._event_message = None
@@ -58,7 +47,6 @@ class Plugin(Manifest):
def send_message(self, widget=None, eve=None):
message = "Hello, World!"
- print("here")
self._event_system.push_gui_event([self.name, "display_message", ("warning", message, None)])
diff --git a/plugins/vod_thumbnailer/__main__.py b/plugins/vod_thumbnailer/__main__.py
new file mode 100644
index 0000000..a576329
--- /dev/null
+++ b/plugins/vod_thumbnailer/__main__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Package
+"""
diff --git a/plugins/vod_thumbnailer/manifest.json b/plugins/vod_thumbnailer/manifest.json
new file mode 100644
index 0000000..154bd40
--- /dev/null
+++ b/plugins/vod_thumbnailer/manifest.json
@@ -0,0 +1,12 @@
+{
+ "manifest": {
+ "name": "VOD Thumbnailer",
+ "author": "ITDominator",
+ "version": "0.0.1",
+ "support": "",
+ "requests": {
+ "ui_target": "context_menu",
+ "pass_fm_events": "true"
+ }
+ }
+}
diff --git a/plugins/vod_thumbnailer/plugin.py b/plugins/vod_thumbnailer/plugin.py
index 44deeb2..1fbc4ac 100644
--- a/plugins/vod_thumbnailer/plugin.py
+++ b/plugins/vod_thumbnailer/plugin.py
@@ -26,19 +26,11 @@ def daemon_threaded(fn):
-class Manifest:
- path: str = os.path.dirname(os.path.realpath(__file__))
- name: str = "VOD Thumbnailer"
- author: str = "ITDominator"
- version: str = "0.0.1"
- support: str = ""
- requests: {} = {
- 'ui_target': "context_menu",
- 'pass_fm_events': "true"
- }
-
-class Plugin(Manifest):
+class Plugin:
def __init__(self):
+ self.path = os.path.dirname(os.path.realpath(__file__))
+ self.name = "VOD Thumbnailer" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
+ # where self.name should not be needed for message comms
self._GLADE_FILE = f"{self.path}/re_thumbnailer.glade"
self._builder = None
self._thumbnailer_dialog = None
diff --git a/plugins/youtube_download/__main__.py b/plugins/youtube_download/__main__.py
new file mode 100644
index 0000000..a576329
--- /dev/null
+++ b/plugins/youtube_download/__main__.py
@@ -0,0 +1,3 @@
+"""
+ Pligin Package
+"""
diff --git a/plugins/youtube_download/manifest.json b/plugins/youtube_download/manifest.json
new file mode 100644
index 0000000..554ce1e
--- /dev/null
+++ b/plugins/youtube_download/manifest.json
@@ -0,0 +1,12 @@
+{
+ "manifest": {
+ "name": "Youtube Download",
+ "author": "ITDominator",
+ "version": "0.0.1",
+ "support": "",
+ "requests": {
+ "ui_target": "plugin_control_list",
+ "pass_fm_events": "true"
+ }
+ }
+}
diff --git a/plugins/youtube_download/plugin.py b/plugins/youtube_download/plugin.py
index cd98a37..122cc99 100644
--- a/plugins/youtube_download/plugin.py
+++ b/plugins/youtube_download/plugin.py
@@ -24,21 +24,10 @@ def daemon_threaded(fn):
-class Manifest:
- path: str = os.path.dirname(os.path.realpath(__file__))
- name: str = "Youtube Download"
- author: str = "ITDominator"
- version: str = "0.0.1"
- support: str = ""
- requests: {} = {
- 'ui_target': "plugin_control_list",
- 'pass_fm_events': "true"
-
- }
-
-
-class Plugin(Manifest):
+class Plugin:
def __init__(self):
+ self.name = "Youtube Download" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
+ # where self.name should not be needed for message comms
self._event_system = None
self._event_sleep_time = .5
self._event_message = None
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py
index 15a4f9d..d9a77d8 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/__builtins__.py
@@ -4,16 +4,18 @@ import builtins, threading
# Lib imports
# Application imports
-from utils.ipc_server import IPCServer
+from utils.event_system import EventSystem
-# NOTE: Threads will not die with parent's destruction
+
+
+# NOTE: Threads WILL NOT die with parent's destruction.
def threaded_wrapper(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=False).start()
return wrapper
-# NOTE: Insure threads die with parent's destruction
+# NOTE: Threads WILL die with parent's destruction.
def daemon_threaded_wrapper(fn):
def wrapper(*args, **kwargs):
threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
@@ -22,71 +24,12 @@ def daemon_threaded_wrapper(fn):
-
-
-class EventSystem(IPCServer):
- """ Inheret IPCServerMixin. Create an pub/sub systems. """
-
- def __init__(self):
- super(EventSystem, self).__init__()
-
- # NOTE: The format used is list of ['who', target, (data,)] Where:
- # who is the sender or target ID and is used for context and control flow,
- # method_target is the method to call,
- # data is the method parameters OR message data to give
- # Where data may be any kind of data
- self._gui_events = []
- self._module_events = []
-
-
-
- # Makeshift "events" system FIFO
- def _pop_gui_event(self) -> None:
- if len(self._gui_events) > 0:
- return self._gui_events.pop(0)
- return None
-
- def _pop_module_event(self) -> None:
- if len(self._module_events) > 0:
- return self._module_events.pop(0)
- return None
-
-
- def push_gui_event(self, event: list) -> None:
- if len(event) == 3:
- self._gui_events.append(event)
- return None
-
- raise Exception("Invald event format! Please do: ['sender_id': str, method_target: method, (data,): any]")
-
- def push_module_event(self, event: list) -> None:
- if len(event) == 3:
- self._module_events.append(event)
- return None
-
- raise Exception("Invald event format! Please do: ['target_id': str, method_target: method, (data,): any]")
-
- def read_gui_event(self) -> list:
- return self._gui_events[0] if self._gui_events else None
-
- def read_module_event(self) -> list:
- return self._module_events[0] if self._module_events else None
-
- def consume_gui_event(self) -> list:
- return self._pop_gui_event()
-
- def consume_module_event(self) -> list:
- return self._pop_module_event()
-
-
-
class EndpointRegistry():
def __init__(self):
self._endpoints = {}
def register(self, rule, **options):
def decorator(f):
- _endpoint = options.pop("endpoint", None)
self._endpoints[rule] = f
return f
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py
index e7b0d5f..a0e36e9 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/app.py
@@ -4,31 +4,33 @@ import os, inspect, time
# Lib imports
# Application imports
-from __builtins__ import EventSystem
+from __builtins__ import *
+from utils.ipc_server import IPCServer
from utils.settings import Settings
from core.controller import Controller
-
-class Application(EventSystem):
+class Application(IPCServer):
""" Create Settings and Controller classes. Bind signal to Builder. Inherit from Builtins to bind global methods and classes. """
def __init__(self, args, unknownargs):
+ super(Application, self).__init__()
+
if not trace_debug:
- event_system.create_ipc_listener()
+ self.create_ipc_listener()
time.sleep(0.05)
- if not event_system.is_ipc_alive:
+ if not self.is_ipc_alive:
if unknownargs:
for arg in unknownargs:
if os.path.isdir(arg):
message = f"FILE|{arg}"
- event_system.send_ipc_message(message)
+ self.send_ipc_message(message)
if args.new_tab and os.path.isdir(args.new_tab):
message = f"FILE|{args.new_tab}"
- event_system.send_ipc_message(message)
+ self.send_ipc_message(message)
raise Exception("IPC Server Exists: Will send path(s) to it and close...\nNote: If no fm exists, remove /tmp/solarfm-ipc.sock")
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py
index 6ddb4c9..d476cbf 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/core/controller.py
@@ -43,7 +43,6 @@ class Controller(UIMixin, KeyboardSignalsMixin, IPCSignalsMixin, ExceptionHookMi
def tear_down(self, widget=None, eve=None):
- event_system.send_ipc_message("close server")
self.fm_controller.save_state()
time.sleep(event_sleep_time)
Gtk.main_quit()
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/manifest.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/manifest.py
new file mode 100644
index 0000000..6aa3f0a
--- /dev/null
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/manifest.py
@@ -0,0 +1,76 @@
+# Python imports
+import os, json
+from os.path import join
+
+# Lib imports
+
+# Application imports
+
+
+
+
+class Plugin:
+ path: str = None
+ name: str = None
+ author: str = None
+ version: str = None
+ support: str = None
+ requests:{} = None
+ reference: type = None
+
+
+class ManifestProcessor:
+ def __init__(self, path, builder):
+ manifest = join(path, "manifest.json")
+ if not os.path.exists(manifest):
+ raise Exception("Invalid Plugin Structure: Plugin doesn't have 'manifest.json'. Aboarting load...")
+
+ self._path = path
+ self._builder = builder
+ with open(manifest) as f:
+ data = json.load(f)
+ self._manifest = data["manifest"]
+ self._plugin = self.collect_info()
+
+ def collect_info(self) -> Plugin:
+ plugin = Plugin()
+ plugin.path = self._path
+ plugin.name = self._manifest["name"]
+ plugin.author = self._manifest["author"]
+ plugin.version = self._manifest["version"]
+ plugin.support = self._manifest["support"]
+ plugin.requests = self._manifest["requests"]
+
+ return plugin
+
+ def get_loading_data(self):
+ loading_data = {}
+ requests = self._plugin.requests
+ keys = requests.keys()
+
+ if "ui_target" in keys:
+ if requests["ui_target"] in [
+ "none", "other", "main_Window", "main_menu_bar", "path_menu_bar", "plugin_control_list",
+ "context_menu", "window_1", "window_2", "window_3", "window_4"
+ ]:
+ if requests["ui_target"] == "other":
+ if "ui_target_id" in keys:
+ loading_data["ui_target"] = self._builder.get_object(requests["ui_target_id"])
+ if loading_data["ui_target"] == None:
+ raise Exception('Invalid "ui_target_id" given in requests. Must have one if setting "ui_target" to "other"...')
+ else:
+ raise Exception('Invalid "ui_target_id" given in requests. Must have one if setting "ui_target" to "other"...')
+ else:
+ loading_data["ui_target"] = self._builder.get_object(requests["ui_target"])
+ else:
+ raise Exception('Unknown "ui_target" given in requests.')
+
+ if "pass_fm_events" in keys:
+ if requests["pass_fm_events"] in ["true"]:
+ loading_data["pass_fm_events"] = True
+
+ if "bind_keys" in keys:
+ if isinstance(requests["bind_keys"], list):
+ loading_data["bind_keys"] = requests["bind_keys"]
+
+ return self._plugin, loading_data
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/plugins.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/plugins.py
index 2d547b4..b14a1a9 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/plugins.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/plugins/plugins.py
@@ -8,17 +8,9 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gio
# Application imports
+from .manifest import Plugin, ManifestProcessor
-class Plugin:
- path: str = None
- name: str = None
- author: str = None
- version: str = None
- support: str = None
- requests:{} = None
- reference: type = None
-
class Plugins:
@@ -28,7 +20,7 @@ class Plugins:
self._settings = settings
self._builder = self._settings.get_builder()
self._plugins_path = self._settings.get_plugins_path()
- self._keybindings = self._settings.get_keybindings()
+ self._keybindings = self._settings.get_keybindings()
self._plugins_dir_watcher = None
self._plugin_collection = []
@@ -55,20 +47,18 @@ class Plugins:
for path, folder in [[join(self._plugins_path, item), item] if os.path.isdir(join(self._plugins_path, item)) else None for item in os.listdir(self._plugins_path)]:
try:
- target = join(path, "plugin.py")
+ target = join(path, "plugin.py")
+ manifest = ManifestProcessor(path, self._builder)
+
if not os.path.exists(target):
raise Exception("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
- module = self.load_plugin_module(path, folder, target)
- plugin = self.collect_info(module, path)
- loading_data = self.parse_requests(plugin)
-
+ plugin, loading_data = manifest.get_loading_data()
+ module = self.load_plugin_module(path, folder, target)
self.execute_plugin(module, plugin, loading_data)
except Exception as e:
print(f"Malformed Plugin: Not loading -->: '{folder}' !")
- traceback.print_exc()
- # if debug:
- # traceback.print_exc()
+ traceback.print_exc()
os.chdir(parent_path)
@@ -82,49 +72,6 @@ class Plugins:
return module
- def collect_info(self, module, path) -> Plugin:
- plugin = Plugin()
- plugin.path = module.Manifest.path
- plugin.name = module.Manifest.name
- plugin.author = module.Manifest.author
- plugin.version = module.Manifest.version
- plugin.support = module.Manifest.support
- plugin.requests = module.Manifest.requests
-
- return plugin
-
- def parse_requests(self, plugin):
- loading_data = {}
- requests = plugin.requests
- keys = requests.keys()
-
- if "ui_target" in keys:
- if requests["ui_target"] in [
- "none", "other", "main_Window", "main_menu_bar", "path_menu_bar", "plugin_control_list",
- "context_menu", "window_1", "window_2", "window_3", "window_4"
- ]:
- if requests["ui_target"] == "other":
- if "ui_target_id" in keys:
- loading_data["ui_target"] = self._builder.get_object(requests["ui_target_id"])
- if loading_data["ui_target"] == None:
- raise Exception('Invalid "ui_target_id" given in requests. Must have one if setting "ui_target" to "other"...')
- else:
- raise Exception('Invalid "ui_target_id" given in requests. Must have one if setting "ui_target" to "other"...')
- else:
- loading_data["ui_target"] = self._builder.get_object(requests["ui_target"])
- else:
- raise Exception('Unknown "ui_target" given in requests.')
-
-
- if "pass_fm_events" in keys:
- if requests["pass_fm_events"] in ["true"]:
- loading_data["pass_fm_events"] = True
-
- if "bind_keys" in keys:
- if isinstance(requests["bind_keys"], list):
- loading_data["bind_keys"] = requests["bind_keys"]
-
- return loading_data
def execute_plugin(self, module: type, plugin: Plugin, loading_data: []):
plugin.reference = module.Plugin()
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/event_system.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/event_system.py
new file mode 100644
index 0000000..1dcd7fa
--- /dev/null
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/event_system.py
@@ -0,0 +1,59 @@
+# Python imports
+
+# Lib imports
+
+# Application imports
+
+
+
+
+class EventSystem:
+ """ Inheret IPCServerMixin. Create an pub/sub systems. """
+
+ def __init__(self):
+ # NOTE: The format used is list of ['who', target, (data,)] Where:
+ # who is the sender or target ID and is used for context and control flow,
+ # method_target is the method to call,
+ # data is the method parameters OR message data to give
+ # Where data may be any kind of data
+ self._gui_events = []
+ self._module_events = []
+
+
+ # Makeshift "events" system FIFO
+ def _pop_gui_event(self) -> None:
+ if len(self._gui_events) > 0:
+ return self._gui_events.pop(0)
+ return None
+
+ def _pop_module_event(self) -> None:
+ if len(self._module_events) > 0:
+ return self._module_events.pop(0)
+ return None
+
+
+ def push_gui_event(self, event: list) -> None:
+ if len(event) == 3:
+ self._gui_events.append(event)
+ return None
+
+ raise Exception("Invald event format! Please do: ['sender_id': str, method_target: method, (data,): any]")
+
+ def push_module_event(self, event: list) -> None:
+ if len(event) == 3:
+ self._module_events.append(event)
+ return None
+
+ raise Exception("Invald event format! Please do: ['target_id': str, method_target: method, (data,): any]")
+
+ def read_gui_event(self) -> list:
+ return self._gui_events[0] if self._gui_events else None
+
+ def read_module_event(self) -> list:
+ return self._module_events[0] if self._module_events else None
+
+ def consume_gui_event(self) -> list:
+ return self._pop_gui_event()
+
+ def consume_module_event(self) -> list:
+ return self._pop_module_event()
diff --git a/src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/ipc_server.py b/src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/ipc_server.py
index 5ad037d..3b88c16 100644
--- a/src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/ipc_server.py
+++ b/src/versions/solarfm-0.0.1/SolarFM/solarfm/utils/ipc_server.py
@@ -7,12 +7,6 @@ from multiprocessing.connection import Listener, Client
# Application imports
-def threaded(fn):
- def wrapper(*args, **kwargs):
- threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True).start()
- return wrapper
-
-
class IPCServer:
@@ -36,7 +30,7 @@ class IPCServer:
self._ipc_authkey = None
- @threaded
+ @daemon_threaded
def create_ipc_listener(self) -> None:
if self._conn_type == "socket":
if os.path.exists(self._ipc_address):
--
2.27.0