Updated VOD Thumbnailer, added icon gen logic #6
@@ -35,6 +35,7 @@ class Plugin:
 | 
				
			|||||||
        self._builder               = None
 | 
					        self._builder               = None
 | 
				
			||||||
        self._thumbnailer_dialog    = None
 | 
					        self._thumbnailer_dialog    = None
 | 
				
			||||||
        self._thumbnail_preview_img = None
 | 
					        self._thumbnail_preview_img = None
 | 
				
			||||||
 | 
					        self._scrub_step            = None
 | 
				
			||||||
        self._file_name             = None
 | 
					        self._file_name             = None
 | 
				
			||||||
        self._file_location         = None
 | 
					        self._file_location         = None
 | 
				
			||||||
        self._file_hash             = None
 | 
					        self._file_hash             = None
 | 
				
			||||||
@@ -63,6 +64,7 @@ class Plugin:
 | 
				
			|||||||
        self._builder.connect_signals(handlers)
 | 
					        self._builder.connect_signals(handlers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._thumbnailer_dialog    = self._builder.get_object("thumbnailer_dialog")
 | 
					        self._thumbnailer_dialog    = self._builder.get_object("thumbnailer_dialog")
 | 
				
			||||||
 | 
					        self._scrub_step            = self._builder.get_object("scrub_step")
 | 
				
			||||||
        self._file_name             = self._builder.get_object("file_name")
 | 
					        self._file_name             = self._builder.get_object("file_name")
 | 
				
			||||||
        self._file_location         = self._builder.get_object("file_location")
 | 
					        self._file_location         = self._builder.get_object("file_location")
 | 
				
			||||||
        self._thumbnail_preview_img = self._builder.get_object("thumbnail_preview_img")
 | 
					        self._thumbnail_preview_img = self._builder.get_object("thumbnail_preview_img")
 | 
				
			||||||
@@ -99,40 +101,44 @@ class Plugin:
 | 
				
			|||||||
                self._state = state
 | 
					                self._state = state
 | 
				
			||||||
                self._set_ui_data()
 | 
					                self._set_ui_data()
 | 
				
			||||||
                response   = self._thumbnailer_dialog.run()
 | 
					                response   = self._thumbnailer_dialog.run()
 | 
				
			||||||
                if response in [Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT]:
 | 
					                if response in [Gtk.ResponseType.CLOSE, Gtk.ResponseType.DELETE_EVENT]:
 | 
				
			||||||
                    self._thumbnailer_dialog.hide()
 | 
					                    self._thumbnailer_dialog.hide()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _regenerate_thumbnail(self, widget=None, eve=None):
 | 
					    def _regenerate_thumbnail(self, widget=None, eve=None):
 | 
				
			||||||
        print("Regenerating thumbnail...")
 | 
					        scrub_percent = int(self._scrub_step.get_value())
 | 
				
			||||||
        file      = self._file_name.get_text()
 | 
					        file          = self._file_name.get_text()
 | 
				
			||||||
        dir       = self._file_location.get_text()
 | 
					        dir           = self._file_location.get_text()
 | 
				
			||||||
        file_hash = self._file_hash.get_text()
 | 
					        file_hash     = self._file_hash.get_text()
 | 
				
			||||||
 | 
					        hash_img_pth  = f"{self._state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        hash_img_pth = f"{self._state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg"
 | 
					 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if os.path.isfile(hash_img_pth):
 | 
					            os.remove(hash_img_pth) if os.path.isfile(hash_img_pth) else ...
 | 
				
			||||||
                os.remove(hash_img_pth)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            img_pixbuf = self._state.tab.create_icon(dir, file)
 | 
					            self._state.tab.create_thumbnail(dir, file, f"{scrub_percent}%")
 | 
				
			||||||
            self._thumbnail_preview_img.set_from_pixbuf(img_pixbuf)
 | 
					            preview_pixbuf = GdkPixbuf.Pixbuf.new_from_file(hash_img_pth)
 | 
				
			||||||
 | 
					            self._thumbnail_preview_img.set_from_pixbuf(preview_pixbuf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            img_pixbuf = self._state.tab.create_scaled_image(hash_img_pth)
 | 
				
			||||||
 | 
					            tree_pth   = self._state.icon_grid.get_selected_items()[0]
 | 
				
			||||||
 | 
					            itr        = self._state.store.get_iter(tree_pth)
 | 
				
			||||||
 | 
					            pixbuff    = self._state.store.get(itr, 0)[0]
 | 
				
			||||||
 | 
					            self._state.store.set(itr, 0, img_pixbuf)
 | 
				
			||||||
        except Exception as e:
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            print(repr(e))
 | 
				
			||||||
            print("Couldn't regenerate thumbnail!")
 | 
					            print("Couldn't regenerate thumbnail!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _use_selected_thumbnail(self, widget=None, eve=None):
 | 
					 | 
				
			||||||
        print("_use_selected_thumbnail stub...")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _set_ui_data(self):
 | 
					    def _set_ui_data(self):
 | 
				
			||||||
        uri          = self._state.selected_files[0]
 | 
					        uri            = self._state.selected_files[0]
 | 
				
			||||||
        path         = self._state.tab.get_current_directory()
 | 
					        path           = self._state.tab.get_current_directory()
 | 
				
			||||||
        parts        = uri.split("/")
 | 
					        parts          = uri.split("/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        file_hash    = hashlib.sha256(str.encode(uri)).hexdigest()
 | 
					        file_hash      = hashlib.sha256(str.encode(uri)).hexdigest()
 | 
				
			||||||
        hash_img_pth = f"{self._state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg"
 | 
					        hash_img_pth   = f"{self._state.tab.ABS_THUMBS_PTH}/{file_hash}.jpg"
 | 
				
			||||||
        img_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(img_pixbuf)
 | 
					        self._thumbnail_preview_img.set_from_pixbuf(preview_pixbuf)
 | 
				
			||||||
        self._file_name.set_text(parts[ len(parts) - 1 ])
 | 
					        self._file_name.set_text(parts[ len(parts) - 1 ])
 | 
				
			||||||
        self._file_location.set_text(path)
 | 
					        self._file_location.set_text(path)
 | 
				
			||||||
        self._file_hash.set_text(file_hash)
 | 
					        self._file_hash.set_text(file_hash)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,13 @@
 | 
				
			|||||||
<!-- Generated with glade 3.38.2 -->
 | 
					<!-- Generated with glade 3.38.2 -->
 | 
				
			||||||
<interface>
 | 
					<interface>
 | 
				
			||||||
  <requires lib="gtk+" version="3.16"/>
 | 
					  <requires lib="gtk+" version="3.16"/>
 | 
				
			||||||
 | 
					  <object class="GtkAdjustment" id="scrub_step_adjuster">
 | 
				
			||||||
 | 
					    <property name="lower">1</property>
 | 
				
			||||||
 | 
					    <property name="upper">100</property>
 | 
				
			||||||
 | 
					    <property name="value">65</property>
 | 
				
			||||||
 | 
					    <property name="step-increment">1</property>
 | 
				
			||||||
 | 
					    <property name="page-increment">10</property>
 | 
				
			||||||
 | 
					  </object>
 | 
				
			||||||
  <object class="GtkDialog" id="thumbnailer_dialog">
 | 
					  <object class="GtkDialog" id="thumbnailer_dialog">
 | 
				
			||||||
    <property name="can-focus">False</property>
 | 
					    <property name="can-focus">False</property>
 | 
				
			||||||
    <property name="border-width">6</property>
 | 
					    <property name="border-width">6</property>
 | 
				
			||||||
@@ -26,7 +33,7 @@
 | 
				
			|||||||
            <property name="layout-style">end</property>
 | 
					            <property name="layout-style">end</property>
 | 
				
			||||||
            <child>
 | 
					            <child>
 | 
				
			||||||
              <object class="GtkButton" id="cancel_button">
 | 
					              <object class="GtkButton" id="cancel_button">
 | 
				
			||||||
                <property name="label">gtk-cancel</property>
 | 
					                <property name="label">gtk-close</property>
 | 
				
			||||||
                <property name="visible">True</property>
 | 
					                <property name="visible">True</property>
 | 
				
			||||||
                <property name="can-focus">True</property>
 | 
					                <property name="can-focus">True</property>
 | 
				
			||||||
                <property name="can-default">True</property>
 | 
					                <property name="can-default">True</property>
 | 
				
			||||||
@@ -66,14 +73,55 @@
 | 
				
			|||||||
              </packing>
 | 
					              </packing>
 | 
				
			||||||
            </child>
 | 
					            </child>
 | 
				
			||||||
            <child>
 | 
					            <child>
 | 
				
			||||||
              <placeholder/>
 | 
					              <object class="GtkBox">
 | 
				
			||||||
 | 
					                <property name="visible">True</property>
 | 
				
			||||||
 | 
					                <property name="can-focus">False</property>
 | 
				
			||||||
 | 
					                <property name="orientation">vertical</property>
 | 
				
			||||||
 | 
					                <child>
 | 
				
			||||||
 | 
					                  <object class="GtkLabel">
 | 
				
			||||||
 | 
					                    <property name="visible">True</property>
 | 
				
			||||||
 | 
					                    <property name="can-focus">False</property>
 | 
				
			||||||
 | 
					                    <property name="margin-start">5</property>
 | 
				
			||||||
 | 
					                    <property name="label" translatable="yes">New Thumbnail Scrub Step: </property>
 | 
				
			||||||
 | 
					                  </object>
 | 
				
			||||||
 | 
					                  <packing>
 | 
				
			||||||
 | 
					                    <property name="expand">False</property>
 | 
				
			||||||
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
 | 
					                    <property name="position">0</property>
 | 
				
			||||||
 | 
					                  </packing>
 | 
				
			||||||
 | 
					                </child>
 | 
				
			||||||
 | 
					                <child>
 | 
				
			||||||
 | 
					                  <object class="GtkScale" id="scrub_step">
 | 
				
			||||||
 | 
					                    <property name="visible">True</property>
 | 
				
			||||||
 | 
					                    <property name="can-focus">True</property>
 | 
				
			||||||
 | 
					                    <property name="margin-start">5</property>
 | 
				
			||||||
 | 
					                    <property name="margin-end">5</property>
 | 
				
			||||||
 | 
					                    <property name="adjustment">scrub_step_adjuster</property>
 | 
				
			||||||
 | 
					                    <property name="show-fill-level">True</property>
 | 
				
			||||||
 | 
					                    <property name="round-digits">1</property>
 | 
				
			||||||
 | 
					                    <property name="digits">0</property>
 | 
				
			||||||
 | 
					                    <property name="value-pos">right</property>
 | 
				
			||||||
 | 
					                    <signal name="value-changed" handler="_regenerate_thumbnail" swapped="no"/>
 | 
				
			||||||
 | 
					                  </object>
 | 
				
			||||||
 | 
					                  <packing>
 | 
				
			||||||
 | 
					                    <property name="expand">True</property>
 | 
				
			||||||
 | 
					                    <property name="fill">True</property>
 | 
				
			||||||
 | 
					                    <property name="position">1</property>
 | 
				
			||||||
 | 
					                  </packing>
 | 
				
			||||||
 | 
					                </child>
 | 
				
			||||||
 | 
					              </object>
 | 
				
			||||||
 | 
					              <packing>
 | 
				
			||||||
 | 
					                <property name="expand">False</property>
 | 
				
			||||||
 | 
					                <property name="fill">True</property>
 | 
				
			||||||
 | 
					                <property name="position">1</property>
 | 
				
			||||||
 | 
					              </packing>
 | 
				
			||||||
            </child>
 | 
					            </child>
 | 
				
			||||||
            <child>
 | 
					            <child>
 | 
				
			||||||
              <object class="GtkTable" id="general_table">
 | 
					              <object class="GtkTable" id="general_table">
 | 
				
			||||||
                <property name="visible">True</property>
 | 
					                <property name="visible">True</property>
 | 
				
			||||||
                <property name="can-focus">False</property>
 | 
					                <property name="can-focus">False</property>
 | 
				
			||||||
                <property name="border-width">4</property>
 | 
					                <property name="border-width">4</property>
 | 
				
			||||||
                <property name="n-rows">4</property>
 | 
					                <property name="n-rows">3</property>
 | 
				
			||||||
                <property name="n-columns">2</property>
 | 
					                <property name="n-columns">2</property>
 | 
				
			||||||
                <property name="column-spacing">12</property>
 | 
					                <property name="column-spacing">12</property>
 | 
				
			||||||
                <property name="row-spacing">6</property>
 | 
					                <property name="row-spacing">6</property>
 | 
				
			||||||
@@ -136,34 +184,6 @@
 | 
				
			|||||||
                    <property name="y-options"/>
 | 
					                    <property name="y-options"/>
 | 
				
			||||||
                  </packing>
 | 
					                  </packing>
 | 
				
			||||||
                </child>
 | 
					                </child>
 | 
				
			||||||
                <child>
 | 
					 | 
				
			||||||
                  <object class="GtkButton">
 | 
					 | 
				
			||||||
                    <property name="label" translatable="yes">Regenerate</property>
 | 
					 | 
				
			||||||
                    <property name="visible">True</property>
 | 
					 | 
				
			||||||
                    <property name="can-focus">True</property>
 | 
					 | 
				
			||||||
                    <property name="receives-default">True</property>
 | 
					 | 
				
			||||||
                    <signal name="released" handler="_regenerate_thumbnail" swapped="no"/>
 | 
					 | 
				
			||||||
                  </object>
 | 
					 | 
				
			||||||
                  <packing>
 | 
					 | 
				
			||||||
                    <property name="left-attach">1</property>
 | 
					 | 
				
			||||||
                    <property name="right-attach">2</property>
 | 
					 | 
				
			||||||
                    <property name="top-attach">3</property>
 | 
					 | 
				
			||||||
                    <property name="bottom-attach">4</property>
 | 
					 | 
				
			||||||
                  </packing>
 | 
					 | 
				
			||||||
                </child>
 | 
					 | 
				
			||||||
                <child>
 | 
					 | 
				
			||||||
                  <object class="GtkButton">
 | 
					 | 
				
			||||||
                    <property name="label" translatable="yes">Use Selected</property>
 | 
					 | 
				
			||||||
                    <property name="visible">True</property>
 | 
					 | 
				
			||||||
                    <property name="can-focus">True</property>
 | 
					 | 
				
			||||||
                    <property name="receives-default">True</property>
 | 
					 | 
				
			||||||
                    <signal name="released" handler="_use_selected_thumbnail" swapped="no"/>
 | 
					 | 
				
			||||||
                  </object>
 | 
					 | 
				
			||||||
                  <packing>
 | 
					 | 
				
			||||||
                    <property name="top-attach">3</property>
 | 
					 | 
				
			||||||
                    <property name="bottom-attach">4</property>
 | 
					 | 
				
			||||||
                  </packing>
 | 
					 | 
				
			||||||
                </child>
 | 
					 | 
				
			||||||
                <child>
 | 
					                <child>
 | 
				
			||||||
                  <object class="GtkLabel" id="hash">
 | 
					                  <object class="GtkLabel" id="hash">
 | 
				
			||||||
                    <property name="visible">True</property>
 | 
					                    <property name="visible">True</property>
 | 
				
			||||||
@@ -213,7 +233,7 @@
 | 
				
			|||||||
      </object>
 | 
					      </object>
 | 
				
			||||||
    </child>
 | 
					    </child>
 | 
				
			||||||
    <action-widgets>
 | 
					    <action-widgets>
 | 
				
			||||||
      <action-widget response="-6">cancel_button</action-widget>
 | 
					      <action-widget response="-7">cancel_button</action-widget>
 | 
				
			||||||
    </action-widgets>
 | 
					    </action-widgets>
 | 
				
			||||||
  </object>
 | 
					  </object>
 | 
				
			||||||
</interface>
 | 
					</interface>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,7 +145,6 @@ class Controller_Data:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        selected_files       = state.icon_grid.get_selected_items()
 | 
					        selected_files       = state.icon_grid.get_selected_items()
 | 
				
			||||||
        # if self.selected_files:
 | 
					 | 
				
			||||||
        if selected_files:
 | 
					        if selected_files:
 | 
				
			||||||
            state.selected_files = self.format_to_uris(state.store, state.wid, state.tid, selected_files, True)
 | 
					            state.selected_files = self.format_to_uris(state.store, state.wid, state.tid, selected_files, True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,7 +147,7 @@ class WindowMixin(TabMixin):
 | 
				
			|||||||
        ctx.remove_class("notebook-unselected-focus")
 | 
					        ctx.remove_class("notebook-unselected-focus")
 | 
				
			||||||
        ctx.add_class("notebook-selected-focus")
 | 
					        ctx.add_class("notebook-selected-focus")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.window.set_title(f"SolarFM ~ {dir}")
 | 
					        self.window.set_title(f"{app_name} ~ {dir}")
 | 
				
			||||||
        self.set_bottom_labels(tab)
 | 
					        self.set_bottom_labels(tab)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_path_text(self, wid, tid):
 | 
					    def set_path_text(self, wid, tid):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ class Icon(DesktopIconMixin, VideoIconMixin):
 | 
				
			|||||||
            if file.lower().endswith(self.fvideos):              # Video icon
 | 
					            if file.lower().endswith(self.fvideos):              # Video icon
 | 
				
			||||||
                thumbnl = self.create_thumbnail(dir, file)
 | 
					                thumbnl = self.create_thumbnail(dir, file)
 | 
				
			||||||
            elif file.lower().endswith(self.fimages):            # Image Icon
 | 
					            elif file.lower().endswith(self.fimages):            # Image Icon
 | 
				
			||||||
                thumbnl = self.create_scaled_image(full_path, self.video_icon_wh)
 | 
					                thumbnl = self.create_scaled_image(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.parse_desktop_files(full_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,13 +38,13 @@ class Icon(DesktopIconMixin, VideoIconMixin):
 | 
				
			|||||||
        except Exception as e:
 | 
					        except Exception as e:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_thumbnail(self, dir, file):
 | 
					    def create_thumbnail(self, dir, file, scrub_percent = "65%"):
 | 
				
			||||||
        full_path = f"{dir}/{file}"
 | 
					        full_path = f"{dir}/{file}"
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            file_hash    = hashlib.sha256(str.encode(full_path)).hexdigest()
 | 
					            file_hash    = hashlib.sha256(str.encode(full_path)).hexdigest()
 | 
				
			||||||
            hash_img_pth = f"{self.ABS_THUMBS_PTH}/{file_hash}.jpg"
 | 
					            hash_img_pth = f"{self.ABS_THUMBS_PTH}/{file_hash}.jpg"
 | 
				
			||||||
            if isfile(hash_img_pth) == False:
 | 
					            if isfile(hash_img_pth) == False:
 | 
				
			||||||
                self.generate_video_thumbnail(full_path, hash_img_pth)
 | 
					                self.generate_video_thumbnail(full_path, hash_img_pth, scrub_percent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            thumbnl = self.create_scaled_image(hash_img_pth, self.video_icon_wh)
 | 
					            thumbnl = self.create_scaled_image(hash_img_pth, self.video_icon_wh)
 | 
				
			||||||
            if thumbnl == None: # If no icon whatsoever, return internal default
 | 
					            if thumbnl == None: # If no icon whatsoever, return internal default
 | 
				
			||||||
@@ -57,7 +57,10 @@ class Icon(DesktopIconMixin, VideoIconMixin):
 | 
				
			|||||||
            return GdkPixbuf.Pixbuf.new_from_file(f"{self.DEFAULT_ICONS}/video.png")
 | 
					            return GdkPixbuf.Pixbuf.new_from_file(f"{self.DEFAULT_ICONS}/video.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_scaled_image(self, path, wxh):
 | 
					    def create_scaled_image(self, path, wxh = None):
 | 
				
			||||||
 | 
					        if not wxh:
 | 
				
			||||||
 | 
					            wxh = self.video_icon_wh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            if path.lower().endswith(".gif"):
 | 
					            if path.lower().endswith(".gif"):
 | 
				
			||||||
                return  GdkPixbuf.PixbufAnimation.new_from_file(path) \
 | 
					                return  GdkPixbuf.PixbufAnimation.new_from_file(path) \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,9 +7,9 @@ import subprocess
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VideoIconMixin:
 | 
					class VideoIconMixin:
 | 
				
			||||||
    def generate_video_thumbnail(self, full_path, hash_img_pth):
 | 
					    def generate_video_thumbnail(self, full_path, hash_img_pth, scrub_percent = "65%"):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            proc = subprocess.Popen([self.FFMPG_THUMBNLR, "-t", "65%", "-s", "300", "-c", "jpg", "-i", full_path, "-o", hash_img_pth])
 | 
					            proc = subprocess.Popen([self.FFMPG_THUMBNLR, "-t", scrub_percent, "-s", "300", "-c", "jpg", "-i", full_path, "-o", hash_img_pth])
 | 
				
			||||||
            proc.wait()
 | 
					            proc.wait()
 | 
				
			||||||
        except Exception as e:
 | 
					        except Exception as e:
 | 
				
			||||||
            self.logger.debug(repr(e))
 | 
					            self.logger.debug(repr(e))
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user