develop #11
| @@ -115,9 +115,7 @@ class Plugin(PluginBase): | |||||||
|         hash_img_pth  = f"{self._fm_state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg" |         hash_img_pth  = f"{self._fm_state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg" | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             os.remove(hash_img_pth) if os.path.isfile(hash_img_pth) else ... |             self._fm_state.tab.create_video_thumbnail(f"{dir}/{file}", f"{scrub_percent}%", True) | ||||||
|  |  | ||||||
|             self._fm_state.tab.create_thumbnail(dir, file, f"{scrub_percent}%") |  | ||||||
|             preview_pixbuf = GdkPixbuf.Pixbuf.new_from_file(hash_img_pth) |             preview_pixbuf = GdkPixbuf.Pixbuf.new_from_file(hash_img_pth) | ||||||
|             self._thumbnail_preview_img.set_from_pixbuf(preview_pixbuf) |             self._thumbnail_preview_img.set_from_pixbuf(preview_pixbuf) | ||||||
|  |  | ||||||
| @@ -135,8 +133,7 @@ class Plugin(PluginBase): | |||||||
|         uri            = self._fm_state.uris[0] |         uri            = self._fm_state.uris[0] | ||||||
|         path           = self._fm_state.tab.get_current_directory() |         path           = self._fm_state.tab.get_current_directory() | ||||||
|         parts          = uri.split("/") |         parts          = uri.split("/") | ||||||
|  |         file_hash      = self._fm_state.tab.fast_hash(uri) | ||||||
|         file_hash      = hashlib.sha256(str.encode(uri)).hexdigest() |  | ||||||
|         hash_img_pth   = f"{self._fm_state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg" |         hash_img_pth   = f"{self._fm_state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg" | ||||||
|         preview_pixbuf = GdkPixbuf.Pixbuf.new_from_file(hash_img_pth) |         preview_pixbuf = GdkPixbuf.Pixbuf.new_from_file(hash_img_pth) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| # Python imports | # Python imports | ||||||
| import argparse | import argparse | ||||||
| import faulthandler | import faulthandler | ||||||
|  | import locale | ||||||
| import traceback | import traceback | ||||||
| from setproctitle import setproctitle | from setproctitle import setproctitle | ||||||
|  |  | ||||||
| @@ -20,6 +21,8 @@ from app import Application | |||||||
|  |  | ||||||
| def run(): | def run(): | ||||||
|     try: |     try: | ||||||
|  |         locale.setlocale(locale.LC_NUMERIC, 'C') | ||||||
|  |  | ||||||
|         setproctitle(f"{app_name}") |         setproctitle(f"{app_name}") | ||||||
|         faulthandler.enable()  # For better debug info |         faulthandler.enable()  # For better debug info | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,16 +12,18 @@ class PluginBaseException(Exception): | |||||||
|  |  | ||||||
|  |  | ||||||
| class PluginBase: | class PluginBase: | ||||||
|     def __init__(self): |     def __init__(self, **kwargs): | ||||||
|  |         super().__init__(**kwargs) | ||||||
|  |  | ||||||
|         self.name               = "Example Plugin"  # NOTE: Need to remove after establishing private bidirectional 1-1 message bus |         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 |                                                     #       where self.name should not be needed for message comms | ||||||
|  |  | ||||||
|         self._builder           = None |         self._builder           = None | ||||||
|         self._ui_objects        = None |         self._ui_objects        = None | ||||||
|         self._fm_state          = None |         self._fm_state          = None | ||||||
|         self._event_system      = None |         self._event_system      = None | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     def set_fm_event_system(self, fm_event_system): |     def set_fm_event_system(self, fm_event_system): | ||||||
|         """ |         """ | ||||||
|             Requests Key:  'pass_fm_events': "true" |             Requests Key:  'pass_fm_events': "true" | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| # Python imports | # Python imports | ||||||
|  | import os | ||||||
| import hashlib | import hashlib | ||||||
| from os.path import isfile | from os.path import isfile | ||||||
|  |  | ||||||
| @@ -34,31 +35,30 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | |||||||
|             if file.lower().endswith(self.fmeshs):               # 3D Mesh icon |             if file.lower().endswith(self.fmeshs):               # 3D Mesh icon | ||||||
|                 ... |                 ... | ||||||
|             if file.lower().endswith(self.fvideos):              # Video icon |             if file.lower().endswith(self.fvideos):              # Video icon | ||||||
|                 thumbnl = self.create_thumbnail(dir, file, full_path) |                 thumbnl = self.create_video_thumbnail(full_path) | ||||||
|             elif file.lower().endswith(self.fimages):            # Image Icon |             elif file.lower().endswith(self.fimages):            # Image Icon | ||||||
|                 thumbnl = self.create_scaled_image(full_path) |                 thumbnl = self.create_scaled_image(full_path) | ||||||
|             elif file.lower().endswith( (".blend",) ):           # Blender icon |             elif file.lower().endswith( (".blend",) ):           # Blender icon | ||||||
|                 thumbnl = self.create_blender_thumbnail(dir, file, full_path) |                 thumbnl = self.create_blender_thumbnail(full_path) | ||||||
|             elif full_path.lower().endswith( ('.desktop',) ):    # .desktop file parsing |             elif full_path.lower().endswith( ('.desktop',) ):    # .desktop file parsing | ||||||
|                 thumbnl = self.parse_desktop_files(full_path) |                 thumbnl = self.find_thumbnail_from_desktop_file(full_path) | ||||||
|  |  | ||||||
|             if not thumbnl: |             if not thumbnl: | ||||||
|                 thumbnl = self.get_system_thumbnail(full_path, self.sys_icon_wh[0]) |                 thumbnl = self.get_system_thumbnail(full_path, self.sys_icon_wh[0]) | ||||||
|  |  | ||||||
|             if not thumbnl: |             if not thumbnl: | ||||||
|                 thumbnl = self.return_generic_icon() |                 thumbnl = self.get_generic_icon() | ||||||
|  |  | ||||||
|             return thumbnl |             return thumbnl | ||||||
|         except Exception: |         except Exception: | ||||||
|             ... |             ... | ||||||
|  |  | ||||||
|         return self.return_generic_icon() |         return self.get_generic_icon() | ||||||
|  |  | ||||||
|     def create_blender_thumbnail(self, dir, file, full_path=None): |     def create_blender_thumbnail(self, full_path): | ||||||
|         try: |         try: | ||||||
|             file_hash     = hashlib.sha256(str.encode(full_path)).hexdigest() |             path_exists, hash_img_path = self.generate_hash_and_path(full_path) | ||||||
|             hash_img_path = f"{self.ABS_THUMBS_PTH}/{file_hash}.png" |             if not path_exists: | ||||||
|             if not isfile(hash_img_path): |  | ||||||
|                 self.generate_blender_thumbnail(full_path, hash_img_path) |                 self.generate_blender_thumbnail(full_path, hash_img_path) | ||||||
|  |  | ||||||
|             return self.create_scaled_image(hash_img_path, self.video_icon_wh) |             return self.create_scaled_image(hash_img_path, self.video_icon_wh) | ||||||
| @@ -68,11 +68,14 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | |||||||
|  |  | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
|     def create_thumbnail(self, dir, file, full_path=None, scrub_percent = "65%"): |     def create_video_thumbnail(self, full_path, scrub_percent = "65%", replace=False): | ||||||
|         try: |         try: | ||||||
|             file_hash     = hashlib.sha256(str.encode(full_path)).hexdigest() |             path_exists, hash_img_path = self.generate_hash_and_path(full_path) | ||||||
|             hash_img_path = f"{self.ABS_THUMBS_PTH}/{file_hash}.jpg" |             if path_exists and replace: | ||||||
|             if not isfile(hash_img_path): |                 os.remove(hash_img_path) | ||||||
|  |                 path_exists = False | ||||||
|  |  | ||||||
|  |             if not path_exists: | ||||||
|                 self.generate_video_thumbnail(full_path, hash_img_path, scrub_percent) |                 self.generate_video_thumbnail(full_path, hash_img_path, scrub_percent) | ||||||
|  |  | ||||||
|             return self.create_scaled_image(hash_img_path, self.video_icon_wh) |             return self.create_scaled_image(hash_img_path, self.video_icon_wh) | ||||||
| @@ -103,18 +106,6 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | |||||||
|  |  | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
|     def image2pixbuf(self, full_path, wxh): |  | ||||||
|         """Convert Pillow image to GdkPixbuf""" |  | ||||||
|         im   = PImage.open(full_path) |  | ||||||
|         data = im.tobytes() |  | ||||||
|         data = GLib.Bytes.new(data) |  | ||||||
|         w, h = im.size |  | ||||||
|  |  | ||||||
|         pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(data, GdkPixbuf.Colorspace.RGB, |  | ||||||
|                                                             False, 8, w, h, w * 3) |  | ||||||
|  |  | ||||||
|         return pixbuf.scale_simple(wxh[0], wxh[1], 2) # BILINEAR = 2 |  | ||||||
|  |  | ||||||
|     def create_from_file(self, full_path): |     def create_from_file(self, full_path): | ||||||
|         try: |         try: | ||||||
|             return GdkPixbuf.Pixbuf.new_from_file(full_path) |             return GdkPixbuf.Pixbuf.new_from_file(full_path) | ||||||
| @@ -137,5 +128,41 @@ class Icon(DesktopIconMixin, VideoIconMixin, MeshsIconMixin): | |||||||
|  |  | ||||||
|         return None |         return None | ||||||
|  |  | ||||||
|     def return_generic_icon(self): |     def get_generic_icon(self): | ||||||
|         return GdkPixbuf.Pixbuf.new_from_file(self.DEFAULT_ICON) |         return GdkPixbuf.Pixbuf.new_from_file(self.DEFAULT_ICON) | ||||||
|  |  | ||||||
|  |     def generate_hash_and_path(self, full_path): | ||||||
|  |         file_hash     = self.fast_hash(full_path) | ||||||
|  |         hash_img_path = f"{self.ABS_THUMBS_PTH}/{file_hash}.jpg" | ||||||
|  |         path_exists   = True if isfile(hash_img_path) else False | ||||||
|  |  | ||||||
|  |         return path_exists, hash_img_path | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def fast_hash(self, filename, hash_factory=hashlib.md5, chunk_num_blocks=128, i=1): | ||||||
|  |         h = hash_factory() | ||||||
|  |         with open(filename,'rb') as f: | ||||||
|  |             f.seek(0, 2) | ||||||
|  |             mid = int(f.tell() / 2) | ||||||
|  |             f.seek(mid, 0) | ||||||
|  |  | ||||||
|  |             while chunk := f.read(chunk_num_blocks*h.block_size): | ||||||
|  |                 h.update(chunk) | ||||||
|  |                 if (i == 12): | ||||||
|  |                     break | ||||||
|  |  | ||||||
|  |                 i += 1 | ||||||
|  |  | ||||||
|  |         return h.hexdigest() | ||||||
|  |  | ||||||
|  |     def image2pixbuf(self, full_path, wxh): | ||||||
|  |         """Convert Pillow image to GdkPixbuf""" | ||||||
|  |         im   = PImage.open(full_path) | ||||||
|  |         data = im.tobytes() | ||||||
|  |         data = GLib.Bytes.new(data) | ||||||
|  |         w, h = im.size | ||||||
|  |  | ||||||
|  |         pixbuf = GdkPixbuf.Pixbuf.new_from_bytes(data, GdkPixbuf.Colorspace.RGB, | ||||||
|  |                                                             False, 8, w, h, w * 3) | ||||||
|  |  | ||||||
|  |         return pixbuf.scale_simple(wxh[0], wxh[1], 2) # BILINEAR = 2 | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ from .xdg.DesktopEntry import DesktopEntry | |||||||
|  |  | ||||||
|  |  | ||||||
| class DesktopIconMixin: | class DesktopIconMixin: | ||||||
|     def parse_desktop_files(self, full_path): |     def find_thumbnail_from_desktop_file(self, full_path): | ||||||
|         try: |         try: | ||||||
|             xdgObj        = DesktopEntry(full_path) |             xdgObj        = DesktopEntry(full_path) | ||||||
|             icon          = xdgObj.getIcon() |             icon          = xdgObj.getIcon() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user