Compare commits
	
		
			3 Commits
		
	
	
		
			74d53690e2
			...
			bebe0c7cba
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bebe0c7cba | |||
| 43fe513bb1 | |||
| 3d0a714106 | 
| @@ -1,11 +1,11 @@ | |||||||
| { | { | ||||||
|     "manifest": { |     "manifest": { | ||||||
|         "name": "Favorites Plugin", |         "name": "Favorites", | ||||||
|         "author": "ITDominator", |         "author": "ITDominator", | ||||||
|         "version": "0.0.1", |         "version": "0.0.1", | ||||||
|         "support": "", |         "support": "", | ||||||
|         "requests": { |         "requests": { | ||||||
|             "ui_target": "plugin_control_list", |             "ui_target": "main_menu_bttn_box_bar", | ||||||
|             "pass_fm_events": "true", |             "pass_fm_events": "true", | ||||||
|             "pass_ui_objects": ["path_entry"], |             "pass_ui_objects": ["path_entry"], | ||||||
|             "bind_keys": [] |             "bind_keys": [] | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ def daemon_threaded(fn): | |||||||
|  |  | ||||||
| class Plugin: | class Plugin: | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.name               = "Favorites Plugin"  # NOTE: Need to remove after establishing private bidirectional 1-1 message bus |         self.name               = "Favorites"  # 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.path               = os.path.dirname(os.path.realpath(__file__)) |         self.path               = os.path.dirname(os.path.realpath(__file__)) | ||||||
|         self._GLADE_FILE        = f"{self.path}/favorites.glade" |         self._GLADE_FILE        = f"{self.path}/favorites.glade" | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								plugins/movie_tv_info/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								plugins/movie_tv_info/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | """ | ||||||
|  |     Pligin Module | ||||||
|  | """ | ||||||
							
								
								
									
										3
									
								
								plugins/movie_tv_info/__main__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								plugins/movie_tv_info/__main__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | """ | ||||||
|  |     Pligin Package | ||||||
|  | """ | ||||||
							
								
								
									
										12
									
								
								plugins/movie_tv_info/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								plugins/movie_tv_info/manifest.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | { | ||||||
|  |     "manifest": { | ||||||
|  |         "name": "Movie/TV Info", | ||||||
|  |         "author": "ITDominator", | ||||||
|  |         "version": "0.0.1", | ||||||
|  |         "support": "", | ||||||
|  |         "requests": { | ||||||
|  |             "ui_target": "context_menu", | ||||||
|  |             "pass_fm_events": "true" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										220
									
								
								plugins/movie_tv_info/movie_tv_info.glade
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								plugins/movie_tv_info/movie_tv_info.glade
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!-- Generated with glade 3.38.2 --> | ||||||
|  | <interface> | ||||||
|  |   <requires lib="gtk+" version="3.16"/> | ||||||
|  |   <object class="GtkImage" id="image1"> | ||||||
|  |     <property name="visible">True</property> | ||||||
|  |     <property name="can-focus">False</property> | ||||||
|  |     <property name="stock">gtk-media-play</property> | ||||||
|  |   </object> | ||||||
|  |   <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="GtkTextBuffer" id="textbuffer"/> | ||||||
|  |   <object class="GtkDialog" id="info_dialog"> | ||||||
|  |     <property name="can-focus">False</property> | ||||||
|  |     <property name="border-width">6</property> | ||||||
|  |     <property name="title" translatable="yes">Movie / TV Info</property> | ||||||
|  |     <property name="modal">True</property> | ||||||
|  |     <property name="window-position">center-on-parent</property> | ||||||
|  |     <property name="default-width">420</property> | ||||||
|  |     <property name="destroy-with-parent">True</property> | ||||||
|  |     <property name="type-hint">dialog</property> | ||||||
|  |     <property name="skip-taskbar-hint">True</property> | ||||||
|  |     <property name="skip-pager-hint">True</property> | ||||||
|  |     <property name="gravity">center</property> | ||||||
|  |     <child internal-child="vbox"> | ||||||
|  |       <object class="GtkBox" id="dialog_vbox"> | ||||||
|  |         <property name="visible">True</property> | ||||||
|  |         <property name="can-focus">False</property> | ||||||
|  |         <property name="spacing">12</property> | ||||||
|  |         <child internal-child="action_area"> | ||||||
|  |           <object class="GtkButtonBox" id="dialog_action_area"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="layout-style">end</property> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkButton" id="cancel_button"> | ||||||
|  |                 <property name="label">gtk-close</property> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="can-default">True</property> | ||||||
|  |                 <property name="receives-default">False</property> | ||||||
|  |                 <property name="use-stock">True</property> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">True</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">0</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="expand">False</property> | ||||||
|  |             <property name="fill">False</property> | ||||||
|  |             <property name="pack-type">end</property> | ||||||
|  |             <property name="position">0</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |         <child> | ||||||
|  |           <object class="GtkBox"> | ||||||
|  |             <property name="visible">True</property> | ||||||
|  |             <property name="can-focus">False</property> | ||||||
|  |             <property name="orientation">vertical</property> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkImage" id="thumbnail_preview_img"> | ||||||
|  |                 <property name="height-request">320</property> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">False</property> | ||||||
|  |                 <property name="margin-start">5</property> | ||||||
|  |                 <property name="margin-end">5</property> | ||||||
|  |                 <property name="margin-top">5</property> | ||||||
|  |                 <property name="stock">gtk-missing-image</property> | ||||||
|  |                 <property name="icon_size">6</property> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">True</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">0</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkBox"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">False</property> | ||||||
|  |                 <property name="orientation">vertical</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkTextView" id="overview_textview"> | ||||||
|  |                     <property name="height-request">120</property> | ||||||
|  |                     <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="margin-top">10</property> | ||||||
|  |                     <property name="margin-bottom">10</property> | ||||||
|  |                     <property name="wrap-mode">word</property> | ||||||
|  |                     <property name="cursor-visible">False</property> | ||||||
|  |                     <property name="buffer">textbuffer</property> | ||||||
|  |                     <property name="overwrite">True</property> | ||||||
|  |                     <property name="monospace">True</property> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="expand">True</property> | ||||||
|  |                     <property name="fill">True</property> | ||||||
|  |                     <property name="position">0</property> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">1</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkTable" id="general_table"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">False</property> | ||||||
|  |                 <property name="border-width">4</property> | ||||||
|  |                 <property name="n-rows">3</property> | ||||||
|  |                 <property name="n-columns">2</property> | ||||||
|  |                 <property name="column-spacing">12</property> | ||||||
|  |                 <property name="row-spacing">6</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkLinkButton" id="trailer_link"> | ||||||
|  |                     <property name="label" translatable="yes">Trailer</property> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">True</property> | ||||||
|  |                     <property name="receives-default">True</property> | ||||||
|  |                     <property name="image">image1</property> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="right-attach">2</property> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkLabel"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="label" translatable="yes"><b>File _Name:</b></property> | ||||||
|  |                     <property name="use-markup">True</property> | ||||||
|  |                     <property name="use-underline">True</property> | ||||||
|  |                     <property name="xalign">0</property> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="top-attach">1</property> | ||||||
|  |                     <property name="bottom-attach">2</property> | ||||||
|  |                     <property name="x-options">GTK_FILL</property> | ||||||
|  |                     <property name="y-options"/> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkLabel"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="label" translatable="yes"><b>_Location:</b></property> | ||||||
|  |                     <property name="use-markup">True</property> | ||||||
|  |                     <property name="use-underline">True</property> | ||||||
|  |                     <property name="xalign">0</property> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="top-attach">2</property> | ||||||
|  |                     <property name="bottom-attach">3</property> | ||||||
|  |                     <property name="x-options">GTK_FILL</property> | ||||||
|  |                     <property name="y-options"/> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkEntry" id="file_name"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">True</property> | ||||||
|  |                     <property name="editable">False</property> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="left-attach">1</property> | ||||||
|  |                     <property name="right-attach">2</property> | ||||||
|  |                     <property name="top-attach">1</property> | ||||||
|  |                     <property name="bottom-attach">2</property> | ||||||
|  |                     <property name="y-options"/> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkEntry" id="file_location"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">True</property> | ||||||
|  |                     <property name="editable">False</property> | ||||||
|  |                   </object> | ||||||
|  |                   <packing> | ||||||
|  |                     <property name="left-attach">1</property> | ||||||
|  |                     <property name="right-attach">2</property> | ||||||
|  |                     <property name="top-attach">2</property> | ||||||
|  |                     <property name="bottom-attach">3</property> | ||||||
|  |                     <property name="x-options">GTK_FILL</property> | ||||||
|  |                     <property name="y-options"/> | ||||||
|  |                   </packing> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">2</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |           </object> | ||||||
|  |           <packing> | ||||||
|  |             <property name="expand">True</property> | ||||||
|  |             <property name="fill">True</property> | ||||||
|  |             <property name="position">1</property> | ||||||
|  |           </packing> | ||||||
|  |         </child> | ||||||
|  |       </object> | ||||||
|  |     </child> | ||||||
|  |     <action-widgets> | ||||||
|  |       <action-widget response="-7">cancel_button</action-widget> | ||||||
|  |     </action-widgets> | ||||||
|  |   </object> | ||||||
|  | </interface> | ||||||
							
								
								
									
										216
									
								
								plugins/movie_tv_info/plugin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								plugins/movie_tv_info/plugin.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  | # Python imports | ||||||
|  | import os, threading, subprocess, time, inspect, requests, shutil | ||||||
|  |  | ||||||
|  | # Lib imports | ||||||
|  | import gi | ||||||
|  | gi.require_version('Gtk', '3.0') | ||||||
|  | gi.require_version('GdkPixbuf', '2.0') | ||||||
|  | from gi.repository import Gtk, GLib, GdkPixbuf | ||||||
|  |  | ||||||
|  | # Application imports | ||||||
|  | from tmdbscraper import scraper | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # 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 Plugin: | ||||||
|  |     def __init__(self): | ||||||
|  |         self.path                   = os.path.dirname(os.path.realpath(__file__)) | ||||||
|  |         self.name                   = "Movie/TV Info"   # 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}/movie_tv_info.glade" | ||||||
|  |  | ||||||
|  |         self._builder               = None | ||||||
|  |         self._dialog                = None | ||||||
|  |         self._thumbnail_preview_img = None | ||||||
|  |         self._tmdb                  = scraper.get_tmdb_scraper() | ||||||
|  |         self._state                 = None | ||||||
|  |         self._overview              = None | ||||||
|  |         self._file_name             = None | ||||||
|  |         self._file_location         = None | ||||||
|  |         self._trailer_link          = 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("info_dialog") | ||||||
|  |         self._overview              = self._builder.get_object("textbuffer") | ||||||
|  |         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") | ||||||
|  |         self._trailer_link          = self._builder.get_object("trailer_link") | ||||||
|  |  | ||||||
|  |         button = Gtk.Button(label=self.name) | ||||||
|  |         button.connect("button-release-event", self._show_info_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_info_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: | ||||||
|  |             self._state = state | ||||||
|  |             self._set_ui_data() | ||||||
|  |             response   = self._thumbnailer_dialog.run() | ||||||
|  |             if response in [Gtk.ResponseType.CLOSE, Gtk.ResponseType.DELETE_EVENT]: | ||||||
|  |                 self._thumbnailer_dialog.hide() | ||||||
|  |  | ||||||
|  |     def _set_ui_data(self): | ||||||
|  |         title, path, trailer, video_data = self.get_video_data() | ||||||
|  |         keys = video_data.keys() if video_data else None | ||||||
|  |  | ||||||
|  |         overview_text  = video_data["overview"] if video_data else f"...NO {self.name.upper()} DATA..." | ||||||
|  |  | ||||||
|  |         self.set_text_data(title, path, overview_text) | ||||||
|  |         self.set_thumbnail(video_data) if video_data else ... | ||||||
|  |         self.set_trailer_link(trailer) | ||||||
|  |  | ||||||
|  |         print(video_data["videos"]) if not keys in ("", None) and "videos" in keys else ... | ||||||
|  |  | ||||||
|  |     def get_video_data(self): | ||||||
|  |         uri            = self._state.selected_files[0] | ||||||
|  |         path           = self._state.tab.get_current_directory() | ||||||
|  |         parts          = uri.split("/") | ||||||
|  |         _title         = parts[ len(parts) - 1 ] | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             title          = _title.split("(")[0].strip() | ||||||
|  |             startIndex     = _title.index('(') + 1 | ||||||
|  |             endIndex       = _title.index(')') | ||||||
|  |             date           = title[startIndex:endIndex] | ||||||
|  |         except Exception as e: | ||||||
|  |             print(repr(e)) | ||||||
|  |             title          = _title | ||||||
|  |             date           = None | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |  | ||||||
|  |             video_data    = self._tmdb.search(title, date)[0] | ||||||
|  |             video_id      = video_data["id"] | ||||||
|  |             try: | ||||||
|  |                 results = self._tmdb.tmdbapi.get_movie(str(video_id), append_to_response="videos")["videos"]["results"] | ||||||
|  |                 for result in results: | ||||||
|  |                     if "YouTube" in result["site"]: | ||||||
|  |                         trailer = result["key"] | ||||||
|  |  | ||||||
|  |                 if not trailer: | ||||||
|  |                     raise Exception("No key found. Defering to none...") | ||||||
|  |             except Exception as e: | ||||||
|  |                 print("No trailer found...") | ||||||
|  |                 trailer = None | ||||||
|  |  | ||||||
|  |         except Exception as e: | ||||||
|  |             print(repr(e)) | ||||||
|  |             video_data    = None | ||||||
|  |  | ||||||
|  |         return title, path, trailer, video_data | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def set_text_data(self, title, path, overview_text): | ||||||
|  |         self._file_name.set_text(title) | ||||||
|  |         self._file_location.set_text(path) | ||||||
|  |         self._overview.set_text(overview_text) | ||||||
|  |  | ||||||
|  |     @threaded | ||||||
|  |     def set_thumbnail(self, video_data): | ||||||
|  |         background_url = video_data["backdrop_path"] | ||||||
|  |         # background_url = video_data["poster_path"] | ||||||
|  |         background_pth = "/tmp/sfm_mvtv_info.jpg" | ||||||
|  |  | ||||||
|  |         try: | ||||||
|  |             os.remove(background_pth) | ||||||
|  |         except Exception as e: | ||||||
|  |             ... | ||||||
|  |  | ||||||
|  |         r = requests.get(background_url, stream = True) | ||||||
|  |  | ||||||
|  |         if r.status_code == 200: | ||||||
|  |             r.raw.decode_content = True | ||||||
|  |             with open(background_pth,'wb') as f: | ||||||
|  |                 shutil.copyfileobj(r.raw, f) | ||||||
|  |  | ||||||
|  |             print('Cover Background Image sucessfully retreived...') | ||||||
|  |             preview_pixbuf = GdkPixbuf.Pixbuf.new_from_file(background_pth) | ||||||
|  |             self._thumbnail_preview_img.set_from_pixbuf(preview_pixbuf) | ||||||
|  |         else: | ||||||
|  |             print('Cover Background Image Couldn\'t be retreived...') | ||||||
|  |  | ||||||
|  |     def set_trailer_link(self, trailer): | ||||||
|  |         if trailer: | ||||||
|  |             self._trailer_link.set_uri(f"https://www.youtube.com/watch?v={trailer}") | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     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)) | ||||||
							
								
								
									
										22
									
								
								plugins/movie_tv_info/tmdbscraper/scraper.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								plugins/movie_tv_info/tmdbscraper/scraper.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | import json | ||||||
|  | import sys | ||||||
|  |  | ||||||
|  | from .lib.tmdbscraper.tmdb import TMDBMovieScraper | ||||||
|  | from .lib.tmdbscraper.fanarttv import get_details as get_fanarttv_artwork | ||||||
|  | from .lib.tmdbscraper.imdbratings import get_details as get_imdb_details | ||||||
|  | from .lib.tmdbscraper.traktratings import get_trakt_ratinginfo | ||||||
|  | from .scraper_datahelper import combine_scraped_details_info_and_ratings, \ | ||||||
|  |     combine_scraped_details_available_artwork, find_uniqueids_in_text, get_params | ||||||
|  | from .scraper_config import configure_scraped_details, PathSpecificSettings, \ | ||||||
|  |     configure_tmdb_artwork, is_fanarttv_configured | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_tmdb_scraper(): | ||||||
|  |     language       = 'en-US' | ||||||
|  |     certcountry    = 'us' | ||||||
|  |     ADDON_SETTINGS = None | ||||||
|  |     return TMDBMovieScraper(ADDON_SETTINGS, language, certcountry) | ||||||
							
								
								
									
										111
									
								
								plugins/movie_tv_info/tmdbscraper/scraper_config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								plugins/movie_tv_info/tmdbscraper/scraper_config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | |||||||
|  | def configure_scraped_details(details, settings): | ||||||
|  |     details = _configure_rating_prefix(details, settings) | ||||||
|  |     details = _configure_keeporiginaltitle(details, settings) | ||||||
|  |     details = _configure_trailer(details, settings) | ||||||
|  |     details = _configure_multiple_studios(details, settings) | ||||||
|  |     details = _configure_default_rating(details, settings) | ||||||
|  |     details = _configure_tags(details, settings) | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | def configure_tmdb_artwork(details, settings): | ||||||
|  |     if 'available_art' not in details: | ||||||
|  |         return details | ||||||
|  |  | ||||||
|  |     art = details['available_art'] | ||||||
|  |     fanart_enabled = settings.getSettingBool('fanart') | ||||||
|  |     if not fanart_enabled: | ||||||
|  |         if 'fanart' in art: | ||||||
|  |             del art['fanart'] | ||||||
|  |         if 'set.fanart' in art: | ||||||
|  |             del art['set.fanart'] | ||||||
|  |     if not settings.getSettingBool('landscape'): | ||||||
|  |         if 'landscape' in art: | ||||||
|  |             if fanart_enabled: | ||||||
|  |                 art['fanart'] = art.get('fanart', []) + art['landscape'] | ||||||
|  |             del art['landscape'] | ||||||
|  |         if 'set.landscape' in art: | ||||||
|  |             if fanart_enabled: | ||||||
|  |                 art['set.fanart'] = art.get('set.fanart', []) + art['set.landscape'] | ||||||
|  |             del art['set.landscape'] | ||||||
|  |  | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | def is_fanarttv_configured(settings): | ||||||
|  |     return settings.getSettingBool('enable_fanarttv_artwork') | ||||||
|  |  | ||||||
|  | def _configure_rating_prefix(details, settings): | ||||||
|  |     if details['info'].get('mpaa'): | ||||||
|  |         details['info']['mpaa'] = settings.getSettingString('certprefix') + details['info']['mpaa'] | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | def _configure_keeporiginaltitle(details, settings): | ||||||
|  |     if settings.getSettingBool('keeporiginaltitle'): | ||||||
|  |         details['info']['title'] = details['info']['originaltitle'] | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | def _configure_trailer(details, settings): | ||||||
|  |     if details['info'].get('trailer') and not settings.getSettingBool('trailer'): | ||||||
|  |         del details['info']['trailer'] | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | def _configure_multiple_studios(details, settings): | ||||||
|  |     if not settings.getSettingBool('multiple_studios'): | ||||||
|  |         details['info']['studio'] = details['info']['studio'][:1] | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | def _configure_default_rating(details, settings): | ||||||
|  |     imdb_default = bool(details['ratings'].get('imdb')) and settings.getSettingString('RatingS') == 'IMDb' | ||||||
|  |     trakt_default = bool(details['ratings'].get('trakt')) and settings.getSettingString('RatingS') == 'Trakt' | ||||||
|  |     default_rating = 'themoviedb' | ||||||
|  |     if imdb_default: | ||||||
|  |         default_rating = 'imdb' | ||||||
|  |     elif trakt_default: | ||||||
|  |         default_rating = 'trakt' | ||||||
|  |     if default_rating not in details['ratings']: | ||||||
|  |         default_rating = list(details['ratings'].keys())[0] if details['ratings'] else None | ||||||
|  |     for rating_type in details['ratings'].keys(): | ||||||
|  |         details['ratings'][rating_type]['default'] = rating_type == default_rating | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | def _configure_tags(details, settings): | ||||||
|  |     if not settings.getSettingBool('add_tags'): | ||||||
|  |         del details['info']['tag'] | ||||||
|  |     return details | ||||||
|  |  | ||||||
|  | # pylint: disable=invalid-name | ||||||
|  | try: | ||||||
|  |     basestring | ||||||
|  | except NameError: # py2 / py3 | ||||||
|  |     basestring = str | ||||||
|  |  | ||||||
|  | #pylint: disable=redefined-builtin | ||||||
|  | class PathSpecificSettings(object): | ||||||
|  |     # read-only shim for typed `xbmcaddon.Addon().getSetting*` methods | ||||||
|  |     def __init__(self, settings_dict, log_fn): | ||||||
|  |         self.data = settings_dict | ||||||
|  |         self.log = log_fn | ||||||
|  |  | ||||||
|  |     def getSettingBool(self, id): | ||||||
|  |         return self._inner_get_setting(id, bool, False) | ||||||
|  |  | ||||||
|  |     def getSettingInt(self, id): | ||||||
|  |         return self._inner_get_setting(id, int, 0) | ||||||
|  |  | ||||||
|  |     def getSettingNumber(self, id): | ||||||
|  |         return self._inner_get_setting(id, float, 0.0) | ||||||
|  |  | ||||||
|  |     def getSettingString(self, id): | ||||||
|  |         return self._inner_get_setting(id, basestring, '') | ||||||
|  |  | ||||||
|  |     def _inner_get_setting(self, setting_id, setting_type, default): | ||||||
|  |         value = self.data.get(setting_id) | ||||||
|  |         if isinstance(value, setting_type): | ||||||
|  |             return value | ||||||
|  |         self._log_bad_value(value, setting_id) | ||||||
|  |         return default | ||||||
|  |  | ||||||
|  |     def _log_bad_value(self, value, setting_id): | ||||||
|  |         if value is None: | ||||||
|  |             self.log("requested setting ({0}) was not found.".format(setting_id)) | ||||||
|  |         else: | ||||||
|  |             self.log('failed to load value "{0}" for setting {1}'.format(value, setting_id)) | ||||||
							
								
								
									
										54
									
								
								plugins/movie_tv_info/tmdbscraper/scraper_datahelper.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								plugins/movie_tv_info/tmdbscraper/scraper_datahelper.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | import re | ||||||
|  | try: | ||||||
|  |     from urlparse import parse_qsl | ||||||
|  | except ImportError: # py2 / py3 | ||||||
|  |     from urllib.parse import parse_qsl | ||||||
|  |  | ||||||
|  | # get addon params from the plugin path querystring | ||||||
|  | def get_params(argv): | ||||||
|  |     result = {'handle': int(argv[0])} | ||||||
|  |     if len(argv) < 2 or not argv[1]: | ||||||
|  |         return result | ||||||
|  |  | ||||||
|  |     result.update(parse_qsl(argv[1].lstrip('?'))) | ||||||
|  |     return result | ||||||
|  |  | ||||||
|  | def combine_scraped_details_info_and_ratings(original_details, additional_details): | ||||||
|  |     def update_or_set(details, key, value): | ||||||
|  |         if key in details: | ||||||
|  |             details[key].update(value) | ||||||
|  |         else: | ||||||
|  |             details[key] = value | ||||||
|  |  | ||||||
|  |     if additional_details: | ||||||
|  |         if additional_details.get('info'): | ||||||
|  |             update_or_set(original_details, 'info', additional_details['info']) | ||||||
|  |         if additional_details.get('ratings'): | ||||||
|  |             update_or_set(original_details, 'ratings', additional_details['ratings']) | ||||||
|  |     return original_details | ||||||
|  |  | ||||||
|  | def combine_scraped_details_available_artwork(original_details, additional_details): | ||||||
|  |     if additional_details and additional_details.get('available_art'): | ||||||
|  |         available_art = additional_details['available_art'] | ||||||
|  |         if not original_details.get('available_art'): | ||||||
|  |             original_details['available_art'] = available_art | ||||||
|  |         else: | ||||||
|  |             for arttype, artlist in available_art.items(): | ||||||
|  |                 original_details['available_art'][arttype] = \ | ||||||
|  |                     artlist + original_details['available_art'].get(arttype, []) | ||||||
|  |  | ||||||
|  |     return original_details | ||||||
|  |  | ||||||
|  | def find_uniqueids_in_text(input_text): | ||||||
|  |     result = {} | ||||||
|  |     res = re.search(r'(themoviedb.org/movie/)([0-9]+)', input_text) | ||||||
|  |     if (res): | ||||||
|  |         result['tmdb'] = res.group(2) | ||||||
|  |     res = re.search(r'imdb....?/title/tt([0-9]+)', input_text) | ||||||
|  |     if (res): | ||||||
|  |         result['imdb'] = 'tt' + res.group(1) | ||||||
|  |     else: | ||||||
|  |         res = re.search(r'imdb....?/Title\?t{0,2}([0-9]+)', input_text) | ||||||
|  |         if (res): | ||||||
|  |             result['imdb'] = 'tt' + res.group(1) | ||||||
|  |     return result | ||||||
							
								
								
									
										175
									
								
								plugins/movie_tv_info/tmdbscraper/scraper_xbmc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								plugins/movie_tv_info/tmdbscraper/scraper_xbmc.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,175 @@ | |||||||
|  | import json | ||||||
|  | import sys | ||||||
|  | import xbmc | ||||||
|  | import xbmcaddon | ||||||
|  | import xbmcgui | ||||||
|  | import xbmcplugin | ||||||
|  |  | ||||||
|  | from lib.tmdbscraper.tmdb import TMDBMovieScraper | ||||||
|  | from lib.tmdbscraper.fanarttv import get_details as get_fanarttv_artwork | ||||||
|  | from lib.tmdbscraper.imdbratings import get_details as get_imdb_details | ||||||
|  | from lib.tmdbscraper.traktratings import get_trakt_ratinginfo | ||||||
|  | from scraper_datahelper import combine_scraped_details_info_and_ratings, \ | ||||||
|  |     combine_scraped_details_available_artwork, find_uniqueids_in_text, get_params | ||||||
|  | from scraper_config import configure_scraped_details, PathSpecificSettings, \ | ||||||
|  |     configure_tmdb_artwork, is_fanarttv_configured | ||||||
|  |  | ||||||
|  | ADDON_SETTINGS = xbmcaddon.Addon() | ||||||
|  | ID = ADDON_SETTINGS.getAddonInfo('id') | ||||||
|  |  | ||||||
|  | def log(msg, level=xbmc.LOGDEBUG): | ||||||
|  |     xbmc.log(msg='[{addon}]: {msg}'.format(addon=ID, msg=msg), level=level) | ||||||
|  |  | ||||||
|  | def get_tmdb_scraper(settings): | ||||||
|  |     language = settings.getSettingString('language') | ||||||
|  |     certcountry = settings.getSettingString('tmdbcertcountry') | ||||||
|  |     return TMDBMovieScraper(ADDON_SETTINGS, language, certcountry) | ||||||
|  |  | ||||||
|  | def search_for_movie(title, year, handle, settings): | ||||||
|  |     log("Find movie with title '{title}' from year '{year}'".format(title=title, year=year), xbmc.LOGINFO) | ||||||
|  |     title = _strip_trailing_article(title) | ||||||
|  |     search_results = get_tmdb_scraper(settings).search(title, year) | ||||||
|  |     if not search_results: | ||||||
|  |         return | ||||||
|  |     if 'error' in search_results: | ||||||
|  |         header = "The Movie Database Python error searching with web service TMDB" | ||||||
|  |         xbmcgui.Dialog().notification(header, search_results['error'], xbmcgui.NOTIFICATION_WARNING) | ||||||
|  |         log(header + ': ' + search_results['error'], xbmc.LOGWARNING) | ||||||
|  |         return | ||||||
|  |  | ||||||
|  |     for movie in search_results: | ||||||
|  |         listitem = _searchresult_to_listitem(movie) | ||||||
|  |         uniqueids = {'tmdb': str(movie['id'])} | ||||||
|  |         xbmcplugin.addDirectoryItem(handle=handle, url=build_lookup_string(uniqueids), | ||||||
|  |             listitem=listitem, isFolder=True) | ||||||
|  |  | ||||||
|  | _articles = [prefix + article for prefix in (', ', ' ') for article in ("the", "a", "an")] | ||||||
|  | def _strip_trailing_article(title): | ||||||
|  |     title = title.lower() | ||||||
|  |     for article in _articles: | ||||||
|  |         if title.endswith(article): | ||||||
|  |             return title[:-len(article)] | ||||||
|  |     return title | ||||||
|  |  | ||||||
|  | def _searchresult_to_listitem(movie): | ||||||
|  |     movie_info = {'title': movie['title']} | ||||||
|  |     movie_label = movie['title'] | ||||||
|  |  | ||||||
|  |     movie_year = movie['release_date'].split('-')[0] if movie.get('release_date') else None | ||||||
|  |     if movie_year: | ||||||
|  |         movie_label += ' ({})'.format(movie_year) | ||||||
|  |         movie_info['year'] = movie_year | ||||||
|  |  | ||||||
|  |     listitem = xbmcgui.ListItem(movie_label, offscreen=True) | ||||||
|  |  | ||||||
|  |     listitem.setInfo('video', movie_info) | ||||||
|  |     if movie['poster_path']: | ||||||
|  |         listitem.setArt({'thumb': movie['poster_path']}) | ||||||
|  |  | ||||||
|  |     return listitem | ||||||
|  |  | ||||||
|  | # Low limit because a big list of artwork can cause trouble in some cases | ||||||
|  | # (a column can be too large for the MySQL integration), | ||||||
|  | # and how useful is a big list anyway? Not exactly rhetorical, this is an experiment. | ||||||
|  | IMAGE_LIMIT = 10 | ||||||
|  |  | ||||||
|  | def add_artworks(listitem, artworks): | ||||||
|  |     for arttype, artlist in artworks.items(): | ||||||
|  |         if arttype == 'fanart': | ||||||
|  |             continue | ||||||
|  |         for image in artlist[:IMAGE_LIMIT]: | ||||||
|  |             listitem.addAvailableArtwork(image['url'], arttype) | ||||||
|  |  | ||||||
|  |     fanart_to_set = [{'image': image['url'], 'preview': image['preview']} | ||||||
|  |         for image in artworks['fanart'][:IMAGE_LIMIT]] | ||||||
|  |     listitem.setAvailableFanart(fanart_to_set) | ||||||
|  |  | ||||||
|  | def get_details(input_uniqueids, handle, settings): | ||||||
|  |     if not input_uniqueids: | ||||||
|  |         return False | ||||||
|  |     details = get_tmdb_scraper(settings).get_details(input_uniqueids) | ||||||
|  |     if not details: | ||||||
|  |         return False | ||||||
|  |     if 'error' in details: | ||||||
|  |         header = "The Movie Database Python error with web service TMDB" | ||||||
|  |         xbmcgui.Dialog().notification(header, details['error'], xbmcgui.NOTIFICATION_WARNING) | ||||||
|  |         log(header + ': ' + details['error'], xbmc.LOGWARNING) | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     details = configure_tmdb_artwork(details, settings) | ||||||
|  |  | ||||||
|  |     if settings.getSettingString('RatingS') == 'IMDb' or settings.getSettingBool('imdbanyway'): | ||||||
|  |         imdbinfo = get_imdb_details(details['uniqueids']) | ||||||
|  |         if 'error' in imdbinfo: | ||||||
|  |             header = "The Movie Database Python error with website IMDB" | ||||||
|  |             log(header + ': ' + imdbinfo['error'], xbmc.LOGWARNING) | ||||||
|  |         else: | ||||||
|  |             details = combine_scraped_details_info_and_ratings(details, imdbinfo) | ||||||
|  |  | ||||||
|  |     if settings.getSettingString('RatingS') == 'Trakt' or settings.getSettingBool('traktanyway'): | ||||||
|  |         traktinfo = get_trakt_ratinginfo(details['uniqueids']) | ||||||
|  |         details = combine_scraped_details_info_and_ratings(details, traktinfo) | ||||||
|  |  | ||||||
|  |     if is_fanarttv_configured(settings): | ||||||
|  |         fanarttv_info = get_fanarttv_artwork(details['uniqueids'], | ||||||
|  |             settings.getSettingString('fanarttv_clientkey'), | ||||||
|  |             settings.getSettingString('fanarttv_language'), | ||||||
|  |             details['_info']['set_tmdbid']) | ||||||
|  |         details = combine_scraped_details_available_artwork(details, fanarttv_info) | ||||||
|  |  | ||||||
|  |     details = configure_scraped_details(details, settings) | ||||||
|  |  | ||||||
|  |     listitem = xbmcgui.ListItem(details['info']['title'], offscreen=True) | ||||||
|  |     listitem.setInfo('video', details['info']) | ||||||
|  |     listitem.setCast(details['cast']) | ||||||
|  |     listitem.setUniqueIDs(details['uniqueids'], 'tmdb') | ||||||
|  |     add_artworks(listitem, details['available_art']) | ||||||
|  |  | ||||||
|  |     for rating_type, value in details['ratings'].items(): | ||||||
|  |         if 'votes' in value: | ||||||
|  |             listitem.setRating(rating_type, value['rating'], value['votes'], value['default']) | ||||||
|  |         else: | ||||||
|  |             listitem.setRating(rating_type, value['rating'], defaultt=value['default']) | ||||||
|  |  | ||||||
|  |     xbmcplugin.setResolvedUrl(handle=handle, succeeded=True, listitem=listitem) | ||||||
|  |     return True | ||||||
|  |  | ||||||
|  | def find_uniqueids_in_nfo(nfo, handle): | ||||||
|  |     uniqueids = find_uniqueids_in_text(nfo) | ||||||
|  |     if uniqueids: | ||||||
|  |         listitem = xbmcgui.ListItem(offscreen=True) | ||||||
|  |         xbmcplugin.addDirectoryItem( | ||||||
|  |             handle=handle, url=build_lookup_string(uniqueids), listitem=listitem, isFolder=True) | ||||||
|  |  | ||||||
|  | def build_lookup_string(uniqueids): | ||||||
|  |     return json.dumps(uniqueids) | ||||||
|  |  | ||||||
|  | def parse_lookup_string(uniqueids): | ||||||
|  |     try: | ||||||
|  |         return json.loads(uniqueids) | ||||||
|  |     except ValueError: | ||||||
|  |         log("Can't parse this lookup string, is it from another add-on?\n" + uniqueids, xbmc.LOGWARNING) | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  | def run(): | ||||||
|  |     params = get_params(sys.argv[1:]) | ||||||
|  |     enddir = True | ||||||
|  |     if 'action' in params: | ||||||
|  |         settings = ADDON_SETTINGS if not params.get('pathSettings') else \ | ||||||
|  |             PathSpecificSettings(json.loads(params['pathSettings']), lambda msg: log(msg, xbmc.LOGWARNING)) | ||||||
|  |         action = params["action"] | ||||||
|  |         if action == 'find' and 'title' in params: | ||||||
|  |             search_for_movie(params["title"], params.get("year"), params['handle'], settings) | ||||||
|  |         elif action == 'getdetails' and 'url' in params: | ||||||
|  |             enddir = not get_details(parse_lookup_string(params["url"]), params['handle'], settings) | ||||||
|  |         elif action == 'NfoUrl' and 'nfo' in params: | ||||||
|  |             find_uniqueids_in_nfo(params["nfo"], params['handle']) | ||||||
|  |         else: | ||||||
|  |             log("unhandled action: " + action, xbmc.LOGWARNING) | ||||||
|  |     else: | ||||||
|  |         log("No action in 'params' to act on", xbmc.LOGWARNING) | ||||||
|  |     if enddir: | ||||||
|  |         xbmcplugin.endOfDirectory(params['handle']) | ||||||
|  |  | ||||||
|  | if __name__ == '__main__': | ||||||
|  |     run() | ||||||
| @@ -10,6 +10,12 @@ from utils.settings import Settings | |||||||
| from core.controller import Controller | from core.controller import Controller | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class App_Launch_Exception(Exception): | ||||||
|  |     ... | ||||||
|  |  | ||||||
|  | class Controller_Start_Exceptio(Exception): | ||||||
|  |     ... | ||||||
|  |  | ||||||
|  |  | ||||||
| class Application(IPCServer): | class Application(IPCServer): | ||||||
|     """ Create Settings and Controller classes. Bind signal to Builder. Inherit from Builtins to bind global methods and classes. """ |     """ Create Settings and Controller classes. Bind signal to Builder. Inherit from Builtins to bind global methods and classes. """ | ||||||
| @@ -32,7 +38,7 @@ class Application(IPCServer): | |||||||
|                     message = f"FILE|{args.new_tab}" |                     message = f"FILE|{args.new_tab}" | ||||||
|                     self.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") |                 raise App_Launch_Exception("IPC Server Exists: Will send path(s) to it and close...\nNote: If no fm exists, remove /tmp/solarfm-ipc.sock") | ||||||
|  |  | ||||||
|  |  | ||||||
|         settings = Settings() |         settings = Settings() | ||||||
| @@ -40,7 +46,7 @@ class Application(IPCServer): | |||||||
|  |  | ||||||
|         controller = Controller(args, unknownargs, settings) |         controller = Controller(args, unknownargs, settings) | ||||||
|         if not controller: |         if not controller: | ||||||
|             raise Exception("Controller exited and doesn't exist...") |             raise Controller_Start_Exceptio("Controller exited and doesn't exist...") | ||||||
|  |  | ||||||
|         # Gets the methods from the classes and sets to handler. |         # Gets the methods from the classes and sets to handler. | ||||||
|         # Then, builder connects to any signals it needs. |         # Then, builder connects to any signals it needs. | ||||||
|   | |||||||
| @@ -50,7 +50,8 @@ class ManifestProcessor: | |||||||
|  |  | ||||||
|         if "ui_target" in keys: |         if "ui_target" in keys: | ||||||
|             if requests["ui_target"] in  [ |             if requests["ui_target"] in  [ | ||||||
|                                             "none", "other", "main_Window", "main_menu_bar", "path_menu_bar", "plugin_control_list", |                                             "none", "other", "main_Window", "main_menu_bar", | ||||||
|  |                                             "main_menu_bttn_box_bar", "path_menu_bar", "plugin_control_list", | ||||||
|                                             "context_menu", "window_1", "window_2", "window_3", "window_4" |                                             "context_menu", "window_1", "window_2", "window_3", "window_4" | ||||||
|                                         ]: |                                         ]: | ||||||
|                 if requests["ui_target"] == "other": |                 if requests["ui_target"] == "other": | ||||||
|   | |||||||
| @@ -65,7 +65,9 @@ class Plugins: | |||||||
|  |  | ||||||
|     def load_plugin_module(self, path, folder, target): |     def load_plugin_module(self, path, folder, target): | ||||||
|         os.chdir(path) |         os.chdir(path) | ||||||
|         sys.path.insert(0, path) |         sys.path.insert(0, path)  # NOTE: I think I'm not using this correctly... | ||||||
|  |         # The folder and target aren't working to create parent package references, so using as stopgap. | ||||||
|  |         # The above is probably polutling import logic and will cause unforseen import issues. | ||||||
|         spec   = importlib.util.spec_from_file_location(folder, target) |         spec   = importlib.util.spec_from_file_location(folder, target) | ||||||
|         module = importlib.util.module_from_spec(spec) |         module = importlib.util.module_from_spec(spec) | ||||||
|         spec.loader.exec_module(module) |         spec.loader.exec_module(module) | ||||||
|   | |||||||
| @@ -1008,7 +1008,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|               </packing> |               </packing> | ||||||
|             </child> |             </child> | ||||||
|             <child> |             <child> | ||||||
|               <object class="GtkButtonBox"> |               <object class="GtkButtonBox" id="main_menu_bttn_box_bar"> | ||||||
|                 <property name="visible">True</property> |                 <property name="visible">True</property> | ||||||
|                 <property name="can-focus">False</property> |                 <property name="can-focus">False</property> | ||||||
|                 <property name="spacing">5</property> |                 <property name="spacing">5</property> | ||||||
| @@ -2364,12 +2364,20 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|           </packing> |           </packing> | ||||||
|         </child> |         </child> | ||||||
|         <child> |         <child> | ||||||
|           <object class="GtkBox"> |           <object class="GtkBox" id="context_menu"> | ||||||
|             <property name="visible">True</property> |             <property name="visible">True</property> | ||||||
|             <property name="can-focus">False</property> |             <property name="can-focus">False</property> | ||||||
|             <property name="orientation">vertical</property> |             <property name="orientation">vertical</property> | ||||||
|             <child> |             <child> | ||||||
|               <object class="GtkBox" id="context_menu"> |               <object class="GtkExpander"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="margin-top">5</property> | ||||||
|  |                 <property name="margin-bottom">5</property> | ||||||
|  |                 <property name="expanded">True</property> | ||||||
|  |                 <property name="label-fill">True</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkBox"> | ||||||
|                     <property name="visible">True</property> |                     <property name="visible">True</property> | ||||||
|                     <property name="can-focus">False</property> |                     <property name="can-focus">False</property> | ||||||
|                     <property name="orientation">vertical</property> |                     <property name="orientation">vertical</property> | ||||||
| @@ -2439,6 +2447,37 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                         <property name="position">3</property> |                         <property name="position">3</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |                 <child type="label"> | ||||||
|  |                   <object class="GtkLabel"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="hexpand">False</property> | ||||||
|  |                     <property name="label" translatable="yes">Open</property> | ||||||
|  |                     <property name="justify">center</property> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">4</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkExpander"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="margin-top">5</property> | ||||||
|  |                 <property name="margin-bottom">5</property> | ||||||
|  |                 <property name="expanded">True</property> | ||||||
|  |                 <property name="label-fill">True</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkBox"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="orientation">vertical</property> | ||||||
|                     <child> |                     <child> | ||||||
|                       <object class="GtkButton"> |                       <object class="GtkButton"> | ||||||
|                         <property name="label">gtk-new</property> |                         <property name="label">gtk-new</property> | ||||||
| @@ -2447,14 +2486,13 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                         <property name="can-focus">True</property> |                         <property name="can-focus">True</property> | ||||||
|                         <property name="receives-default">True</property> |                         <property name="receives-default">True</property> | ||||||
|                         <property name="tooltip-text" translatable="yes">New File/Folder...</property> |                         <property name="tooltip-text" translatable="yes">New File/Folder...</property> | ||||||
|                     <property name="margin-top">20</property> |  | ||||||
|                         <property name="use-stock">True</property> |                         <property name="use-stock">True</property> | ||||||
|                         <signal name="button-release-event" handler="do_action_from_menu_controls" swapped="no"/> |                         <signal name="button-release-event" handler="do_action_from_menu_controls" swapped="no"/> | ||||||
|                       </object> |                       </object> | ||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">4</property> |                         <property name="position">0</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2472,7 +2510,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">5</property> |                         <property name="position">1</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2490,7 +2528,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">6</property> |                         <property name="position">2</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2508,7 +2546,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">7</property> |                         <property name="position">3</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2526,7 +2564,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">8</property> |                         <property name="position">4</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2544,9 +2582,40 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">9</property> |                         <property name="position">5</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |                 <child type="label"> | ||||||
|  |                   <object class="GtkLabel"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="hexpand">False</property> | ||||||
|  |                     <property name="label" translatable="yes">File Actions</property> | ||||||
|  |                     <property name="justify">center</property> | ||||||
|  |                     <property name="ellipsize">end</property> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|  |               <packing> | ||||||
|  |                 <property name="expand">False</property> | ||||||
|  |                 <property name="fill">True</property> | ||||||
|  |                 <property name="position">5</property> | ||||||
|  |               </packing> | ||||||
|  |             </child> | ||||||
|  |             <child> | ||||||
|  |               <object class="GtkExpander"> | ||||||
|  |                 <property name="visible">True</property> | ||||||
|  |                 <property name="can-focus">True</property> | ||||||
|  |                 <property name="margin-top">5</property> | ||||||
|  |                 <property name="margin-bottom">10</property> | ||||||
|  |                 <property name="label-fill">True</property> | ||||||
|  |                 <child> | ||||||
|  |                   <object class="GtkBox"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="orientation">vertical</property> | ||||||
|                     <child> |                     <child> | ||||||
|                       <object class="GtkButton" id="restore_from_trash"> |                       <object class="GtkButton" id="restore_from_trash"> | ||||||
|                         <property name="label" translatable="yes">Restore From Trash</property> |                         <property name="label" translatable="yes">Restore From Trash</property> | ||||||
| @@ -2555,13 +2624,12 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                         <property name="can-focus">True</property> |                         <property name="can-focus">True</property> | ||||||
|                         <property name="receives-default">True</property> |                         <property name="receives-default">True</property> | ||||||
|                         <property name="tooltip-text" translatable="yes">Restore From Trash...</property> |                         <property name="tooltip-text" translatable="yes">Restore From Trash...</property> | ||||||
|                     <property name="margin-top">20</property> |  | ||||||
|                         <signal name="button-release-event" handler="do_action_from_menu_controls" swapped="no"/> |                         <signal name="button-release-event" handler="do_action_from_menu_controls" swapped="no"/> | ||||||
|                       </object> |                       </object> | ||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">10</property> |                         <property name="position">0</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2577,7 +2645,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">11</property> |                         <property name="position">1</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2596,7 +2664,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">12</property> |                         <property name="position">2</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2614,7 +2682,7 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">13</property> |                         <property name="position">3</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                     <child> |                     <child> | ||||||
| @@ -2633,14 +2701,25 @@ SolarFM is developed on Atom, git, and using Python 3+ with Gtk GObject introspe | |||||||
|                       <packing> |                       <packing> | ||||||
|                         <property name="expand">False</property> |                         <property name="expand">False</property> | ||||||
|                         <property name="fill">True</property> |                         <property name="fill">True</property> | ||||||
|                     <property name="position">14</property> |                         <property name="position">4</property> | ||||||
|                       </packing> |                       </packing> | ||||||
|                     </child> |                     </child> | ||||||
|                   </object> |                   </object> | ||||||
|  |                 </child> | ||||||
|  |                 <child type="label"> | ||||||
|  |                   <object class="GtkLabel"> | ||||||
|  |                     <property name="visible">True</property> | ||||||
|  |                     <property name="can-focus">False</property> | ||||||
|  |                     <property name="hexpand">False</property> | ||||||
|  |                     <property name="label" translatable="yes">Trash</property> | ||||||
|  |                     <property name="justify">center</property> | ||||||
|  |                   </object> | ||||||
|  |                 </child> | ||||||
|  |               </object> | ||||||
|               <packing> |               <packing> | ||||||
|                 <property name="expand">False</property> |                 <property name="expand">False</property> | ||||||
|                 <property name="fill">True</property> |                 <property name="fill">True</property> | ||||||
|                 <property name="position">2</property> |                 <property name="position">6</property> | ||||||
|               </packing> |               </packing> | ||||||
|             </child> |             </child> | ||||||
|           </object> |           </object> | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ | |||||||
|                                     "<Control>r"], |                                     "<Control>r"], | ||||||
|         "delete_files"           : ["Delete", |         "delete_files"           : ["Delete", | ||||||
|                                     "<Shift><Control>d"], |                                     "<Shift><Control>d"], | ||||||
|         "tggl_top_main_menubar"  : "<Alt>", |         "tggl_top_main_menubar"  : "<Alt>h", | ||||||
|         "trash_files"            : "<Shift><Control>t", |         "trash_files"            : "<Shift><Control>t", | ||||||
|         "tear_down"              : "<Control>q", |         "tear_down"              : "<Control>q", | ||||||
|         "go_up"                  : "<Control>Up", |         "go_up"                  : "<Control>Up", | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user