def get_config(self): '''gets various settings for the script as set by the skinner or user''' # skinner (or user) enables the random fanart images by setting the randomfanartdelay skin string try: self.backgrounds_delay = int( xbmc.getInfoLabel("Skin.String(SkinHelper.RandomFanartDelay)")) except Exception: pass self.walls_delay = int(self.addon.getSetting("wallimages_delay")) self.wallimages.max_wallimages = int( self.addon.getSetting("max_wallimages")) self.pvr_bg_recordingsonly = self.addon.getSetting( "pvr_bg_recordingsonly") == "true" self.enable_walls = xbmc.getCondVisibility( "Skin.HasSetting(SkinHelper.EnableWallBackgrounds)") if self.addon.getSetting("enable_custom_images_path") == "true": self.custom_picturespath = self.addon.getSetting( "custom_images_path") else: self.custom_picturespath = "" try: # skinner can enable manual wall images generation so check for these settings # store in memory so wo do not have to query the skin settings too often if self.walls_delay: for key in self.all_backgrounds_keys.keys(): limitrange = xbmc.getInfoLabel( "Skin.String(%s.EnableWallImages)" % key) if limitrange: self.wallimages.manual_walls[key] = int(limitrange) except Exception as exc: log_exception(__name__, exc)
def set_day_night_theme(self, dayornight, themename, themefile): ''' Sets a new daynight theme''' currenttimevalue = xbmc.getInfoLabel( "Skin.String(SkinHelper.ColorTheme.%s.time)" % dayornight) if not currenttimevalue: currenttimevalue = "20:00" if dayornight == "night" else "07:00" timevalue = xbmcgui.Dialog().input( self.addon.getLocalizedString(32017), currenttimevalue).decode("utf-8") try: # check if the time is valid check_date = datetime(*(time.strptime(timevalue, "%H:%M")[0:6])) del check_date base_setting = "SkinHelper.ColorTheme.%s" % dayornight xbmc.executebuiltin("Skin.SetString(%s.theme,%s)" % (base_setting, try_encode(themename))) xbmc.executebuiltin("Skin.SetString(%s.time,%s)" % (base_setting, timevalue)) label = "%s (%s %s)" % (try_encode(themename), self.addon.getLocalizedString(32019), timevalue) xbmc.executebuiltin("Skin.SetString(%s.label,%s)" % (base_setting, label)) xbmc.executebuiltin("Skin.SetString(%s.file,%s)" % (base_setting, try_encode(themefile))) except Exception as exc: log_exception(__name__, exc) xbmcgui.Dialog().ok(xbmc.getLocalizedString(329), self.addon.getLocalizedString(32018))
def check_daynighttheme(self): '''check if a specific day or night theme should be applied''' if xbmc.getCondVisibility( "Skin.HasSetting(SkinHelper.EnableDayNightThemes) + " "Skin.String(SkinHelper.ColorTheme.Day.time) + " "Skin.String(SkinHelper.ColorTheme.Night.time)"): try: daytime = xbmc.getInfoLabel( "Skin.String(SkinHelper.ColorTheme.Day.time)") daytime = datetime( *(time.strptime(daytime, "%H:%M")[0:6])).time() nighttime = xbmc.getInfoLabel( "Skin.String(SkinHelper.ColorTheme.Night.time)") nighttime = datetime( *(time.strptime(nighttime, "%H:%M")[0:6])).time() timestamp = datetime.now().time() if daytime <= timestamp <= nighttime: dayornight = "Day" else: dayornight = "Night" current_theme = xbmc.getInfoLabel( "Skin.String(SkinHelper.LastColorTheme)") newtheme = xbmc.getInfoLabel( "Skin.String(SkinHelper.ColorTheme.%s.theme)" % dayornight) if current_theme != newtheme: themefile = xbmc.getInfoLabel( "Skin.String(SkinHelper.ColorTheme.%s.file)" % dayornight) self.load_colortheme(themefile) except Exception as exc: log_exception(__name__, exc)
def get_folderandprefix(self): '''get the current folder and prefix''' cur_folder = "" cont_prefix = "" try: widget_container = try_decode( self.win.getProperty("SkinHelper.WidgetContainer")) if getCondVisibility( "Window.IsActive(movieinformation)|Window.IsActive(DialogPVRInfo.xml)|Window.IsActive(DialogMusicInfo.xml)|Window.IsActive(script-script.extendedinfo-DialogVideoInfo.xml)" ): cont_prefix = "" cur_folder = try_decode( xbmc.getInfoLabel( "$INFO[Window.Property(xmlfile)]$INFO[Container.FolderPath]" "$INFO[Container.NumItems]$INFO[Container.Content]")) elif widget_container: cont_prefix = "Container(%s)." % widget_container cur_folder = try_decode( xbmc.getInfoLabel( "widget-%s-$INFO[Container(%s).NumItems]-$INFO[Container(%s).ListItemAbsolute(1).Label]" % (widget_container, widget_container, widget_container))) else: cont_prefix = "" cur_folder = try_decode( xbmc.getInfoLabel( "$INFO[Window.Property(xmlfile)]$INFO[Container.FolderPath]$INFO[Container.NumItems]$INFO[Container.Content]" )) except Exception as exc: log_exception(__name__, exc) cur_folder = "" cont_prefix = "" return (cur_folder, cont_prefix)
def onNotification(self, sender, method, data): '''builtin function for the xbmc.Monitor class''' try: log_msg("Kodi_Monitor: sender %s - method: %s - data: %s" % (sender, method, data)) data = json.loads(try_decode(data)) mediatype = "" dbid = 0 transaction = False if data and isinstance(data, dict): if data.get("item"): mediatype = data["item"].get("type", "") dbid = data["item"].get("id", 0) elif data.get("type"): mediatype = data["type"] dbid = data.get("id", 0) if data.get("transaction"): transaction = True if method == "System.OnQuit": self.win.setProperty("SkinHelperShutdownRequested", "shutdown") if method == "VideoLibrary.OnUpdate": self.process_db_update(mediatype, dbid, transaction) if method == "AudioLibrary.OnUpdate": self.process_db_update(mediatype, dbid, transaction) if method == "Player.OnStop": self.monitoring_stream = False self.infopanelshown = False self.win.clearProperty("Skinhelper.PlayerPlaying") self.win.clearProperty("TrailerPlaying") self.reset_win_props() if method == "Player.OnPlay": if not self.monitoring_stream and not getCondVisibility( "Player.DisplayAfterSeek"): self.reset_win_props() if self.wait_for_player(): if getCondVisibility("Player.HasAudio"): if getCondVisibility("Player.IsInternetStream"): self.monitor_radiostream() else: self.set_music_properties() if getCondVisibility("Pvr.IsPlayingRadio"): if getCondVisibility("!Player.IsInternetStream"): self.monitor_radiostream() else: self.set_music_properties() elif getCondVisibility( "VideoPlayer.Content(livetv) | String.StartsWith(Player.FileNameAndPath,pvr://)" ): self.monitor_livetv() else: self.set_video_properties(mediatype, dbid) self.show_info_panel() except Exception as exc: log_exception(__name__, exc)
def get_repo_addoninfo(addonid, simplecache=None): '''tries to grab info about the addon from kodi repo addons listing''' if simplecache: cache = simplecache cachestr = "skinhelper.addoninfo.%s" % addonid info = simplecache.get(cachestr) if not info: info = {"addonid": addonid, "name": "", "thumbnail": "", "author": ""} mirrorurl = "http://addons.kodi.tv/show/%s/" % addonid try: if sys.version_info.major == 3: req = urllib.request.Request(mirrorurl) req.add_header( 'User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3' ) response = urllib.request.urlopen(req) else: req = urllib2.Request(mirrorurl) req.add_header( 'User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3' ) response = urllib2.urlopen(req) body = response.read() response.close() body = body.replace('\r', '').replace('\n', '').replace('\t', '') for addondetail in re.compile( '<div id="addonDetail">(.*?)</div>').findall(body): for h2_item in re.compile('<h2>(.*?)</h2>').findall( addondetail): info["name"] = h2_item break for thumbnail in re.compile('src="(.*?)"').findall( addondetail): icon = "http://addons.kodi.tv/%s" % thumbnail info["thumbnail"] = icon break authors = [] for addonmetadata in re.compile( '<div id="addonMetaData">(.*?)</div>').findall(body): for author in re.compile('<a href="(.*?)">(.*?)</a>' ).findall(addonmetadata): authors.append(author[1]) info["author"] = ",".join(authors) break except Exception as exc: if "HTTP Error 404" not in exc: # ignore not found exceptions log_exception(__name__, exc) if simplecache: cache.set(cachestr, info) return info
def do_background_work(self): '''stuff that's processed in the background''' try: if self.exit: return log_msg("Started Background worker...") self.set_generic_props() self.listitem_details = {} if self.exit: return self.cache.check_cleanup() log_msg("Ended Background worker...") except Exception as exc: log_exception(__name__, exc)
def main(self): '''main action, load correct function''' action = self.params.get("action", "") if self.win.getProperty("SkinHelperShutdownRequested"): # do not proceed if kodi wants to exit log_msg("%s --> Not forfilling request: Kodi is exiting" % __name__, xbmc.LOGWARNING) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) else: try: if hasattr(self.__class__, action): # launch module for action provided by this plugin getattr(self, action)() else: # legacy (widget) path called !!! self.load_widget() except Exception as exc: log_exception(__name__, exc)
def __init__(self): self.cache = SimpleCache() self.mutils = MetadataUtils() self.win = xbmcgui.Window(10000) try: if sys.version_info.major == 3: self.params = dict(urllib.parse.parse_qsl(sys.argv[2].replace('?', '').lower())) else: self.params = dict(urlparse.parse_qsl(sys.argv[2].replace('?', '').lower().decode("utf-8"))) log_msg("plugin called with parameters: %s" % self.params) self.main() except Exception as exc: log_exception(__name__, exc) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) # cleanup when done processing self.close()
def __init__(self): '''Initialization and main code run''' try: self.params = self.get_params() log_msg("called with parameters: %s" % self.params) action = self.params.get("action", "") if not action: # launch main backuprestore dialog BackupRestore().backuprestore() else: # launch module for action provided by this script if hasattr(self, action): getattr(self, action)() else: log_msg("No such action: %s" % action, xbmc.LOGWARNING) except Exception as exc: log_exception(__name__, exc)
def __init__(self): self.win = xbmcgui.Window(10000) self.addon = xbmcaddon.Addon(ADDON_ID) self.params = self.get_params() log_msg('MainModule called with parameters: %s' % self.params) action = self.params.get('action', '') try: getattr(self, action)() except AttributeError: log_exception(__name__, "No such action: %s" % action) except Exception as exc: log_exception(__name__, exc) finally: xbmc.executebuiltin('dialog.Close(busydialog)') self.close()
def __init__(self): '''Initialization and main code run''' self.win = xbmcgui.Window(10000) self.addon = xbmcaddon.Addon(ADDON_ID) self.mutils = MetadataUtils() self.cache = self.mutils.cache self.params = self.get_params() log_msg("MainModule called with parameters: %s" % self.params) action = self.params.get("action", "") # launch module for action provided by this script try: getattr(self, action)() except AttributeError: log_exception(__name__, "No such action: %s" % action) except Exception as exc: log_exception(__name__, exc) # do cleanup self.close()
def check_skin_version(self): '''check if skin changed''' try: skin = xbmc.getSkinDir() skin_addon = xbmcaddon.Addon(id=skin) skin_label = try_decode(skin_addon.getAddonInfo('name')) skin_version = try_decode(skin_addon.getAddonInfo('version')) this_skin = "%s-%s" % (skin_label, skin_version) del skin_addon if self.last_skin != this_skin: # auto correct skin settings if needed self.last_skin = this_skin self.win.setProperty("SkinHelper.skinTitle", "%s - %s: %s" % (skin_label, xbmc.getLocalizedString(19114), skin_version)) self.win.setProperty("SkinHelper.skin_version", "%s: %s" % (xbmc.getLocalizedString(19114), skin_version)) self.win.setProperty("SkinHelper.Version", self.addonversion.replace(".", "")) SkinSettings().correct_skin_settings() except Exception as exc: log_exception(__name__, exc)
def handle_image(self, image): '''serve image''' if image: # send single image try: ext = image.split(".")[-1] cherrypy.response.headers['Content-Type'] = 'image/%s' % ext modified = xbmcvfs.Stat(image).st_mtime() cherrypy.response.headers['Last-Modified'] = "%s" % modified image = xbmcvfs.File(image) cherrypy.response.headers['Content-Length'] = str(image.size()) if cherrypy.request.method.upper() == 'GET': img_data = image.readBytes() image.close() return str(img_data) else: image.close() except Exception as exc: log_exception(__name__, exc) else: raise cherrypy.HTTPError(404, "No image found matching the criteria")
def show_widget_listing(self): '''display the listing for the provided action and mediatype''' media_type = self.options["mediatype"] action = self.options["action"] # set widget content type if media_type in ["favourites", "pvr", "media"]: xbmcplugin.setContent(ADDON_HANDLE, "files") else: xbmcplugin.setContent(ADDON_HANDLE, media_type) # try to get from cache first... all_items = [] # alter cache_str depending on whether "tag" is available if self.options["action"] == "similar": # if action is similar, use imdbid cache_id = self.options.get("imdbid", "") # if similar was called without imdbid, skip cache if not cache_id: self.options["skipcache"] = "true" elif self.options["action"] == "playlist" and self.options[ "mediatype"] == "media": # if action is mixed playlist, use playlist labels cache_id = self.options.get("movie_label") + self.options.get( "tv_label") + self.options.get("sort") elif self.options["action"] == "forgenre" and "genre" in self.options: cache_id = self.options.get("genre") else: # use tag otherwise cache_id = self.options.get("tag") # set cache_str cache_str = "SkinHelper.Widgets.%s.%s.%s.%s.%s" % \ (media_type, action, self.options["limit"], self.options.get("path"), cache_id) if not self.win.getProperty("widgetreload2"): # at startup we simply accept whatever is in the cache cache_checksum = None else: # we use a checksum based on the reloadparam to make sure we have the most recent data cache_checksum = self.options.get("reload", "") # only check cache if not "skipcache" if not self.options.get("skipcache") == "true": cache = self.metadatautils.cache.get(cache_str, checksum=cache_checksum) if cache: log_msg( "MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- got items from cache - CHECKSUM: %s" % (media_type, action, self.options.get("path"), self.options.get("tag"), cache_checksum)) all_items = cache # Call the correct method to get the content from json when no cache if not all_items: log_msg( "MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- no cache, quering kodi api to get items - CHECKSUM: %s" % (media_type, action, self.options.get("path"), self.options.get("tag"), cache_checksum)) # dynamically import and load the correct module, class and function try: media_module = __import__(media_type) media_class = getattr(media_module, media_type.capitalize())( self.addon, self.metadatautils, self.options) all_items = getattr(media_class, action)() del media_class except AttributeError: log_exception(__name__, "Incorrect widget action or type called") except Exception as exc: log_exception(__name__, exc) # randomize output if requested by skinner or user if self.options.get("randomize", "") == "true": all_items = sorted(all_items, key=lambda k: random.random()) # prepare listitems and store in cache all_items = self.metadatautils.process_method_on_list( self.metadatautils.kodidb.prepare_listitem, all_items) self.metadatautils.cache.set(cache_str, all_items, checksum=cache_checksum) # fill that listing... xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_UNSORTED) all_items = self.metadatautils.process_method_on_list( self.metadatautils.kodidb.create_listitem, all_items) xbmcplugin.addDirectoryItems(ADDON_HANDLE, all_items, len(all_items)) # end directory listing xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)
def create_colortheme(self): '''create a colortheme from current skin color settings''' try: current_skinfont = None json_response = kodi_json("Settings.GetSettingValue", {"setting": "lookandfeel.font"}) if json_response: current_skinfont = json_response current_skincolors = None json_response = kodi_json("Settings.GetSettingValue", {"setting": "lookandfeel.skincolors"}) if json_response: current_skincolors = json_response # user has to enter name for the theme themename = xbmcgui.Dialog().input( self.addon.getLocalizedString(32023), type=xbmcgui.INPUT_ALPHANUM).decode("utf-8") if not themename: return xbmc.executebuiltin("ActivateWindow(busydialog)") xbmc.executebuiltin( "Skin.SetString(SkinHelper.LastColorTheme,%s)" % try_encode(themename)) # add screenshot custom_thumbnail = xbmcgui.Dialog().browse( 2, self.addon.getLocalizedString(32024), 'files') if custom_thumbnail: xbmcvfs.copy(custom_thumbnail, self.userthemes_path + themename + ".jpg") # read the guisettings file to get all skin settings from resources.lib.backuprestore import BackupRestore skinsettingslist = BackupRestore().get_skinsettings([ "color", "opacity", "texture", "panel", "colour", "background", "image" ]) newlist = [] if skinsettingslist: newlist.append(("THEMENAME", themename)) newlist.append( ("DESCRIPTION", self.addon.getLocalizedString(32025))) newlist.append( ("SKINTHEME", xbmc.getInfoLabel("Skin.CurrentTheme"))) newlist.append(("SKINFONT", current_skinfont)) newlist.append(("SKINCOLORS", current_skincolors)) # look for any images in the skin settings and translate them so they can # be included in the theme backup for skinsetting in skinsettingslist: setting_type = skinsetting[0] setting_name = skinsetting[1] setting_value = skinsetting[2] if setting_type == "string" and setting_value: if (setting_value and (setting_value.endswith(".png") or setting_value.endswith(".gif") or setting_value.endswith(".jpg")) and "resource://" not in setting_value): image = get_clean_image(setting_value) extension = image.split(".")[-1] newimage = "%s_%s.%s" % ( themename, normalize_string(setting_name), extension) newimage_path = self.userthemes_path + newimage if xbmcvfs.exists(image): xbmcvfs.copy(image, newimage_path) skinsetting = (setting_type, setting_name, newimage_path) newlist.append(skinsetting) # save guisettings text_file_path = self.userthemes_path + themename + ".theme" text_file = xbmcvfs.File(text_file_path, "w") text_file.write(repr(newlist)) text_file.close() xbmc.executebuiltin("Dialog.Close(busydialog)") xbmcgui.Dialog().ok(self.addon.getLocalizedString(32026), self.addon.getLocalizedString(32027)) except Exception as exc: xbmc.executebuiltin("Dialog.Close(busydialog)") log_exception(__name__, exc) xbmcgui.Dialog().ok(self.addon.getLocalizedString(32028), self.addon.getLocalizedString(32030), str(exc))
def set_listitem_details(self, cur_listitem, content_type, prefix): '''set the window properties based on the current listitem''' try: if cur_listitem in self.listitem_details: # data already in memory all_props = self.listitem_details[cur_listitem] else: # skip if another lookup for the same listitem is already in progress... if self.lookup_busy.get(cur_listitem) or self.exit: return self.lookup_busy[cur_listitem] = True # clear all window props, do this delayed to prevent flickering of the screen thread.start_new_thread(self.delayed_flush, (cur_listitem, )) # wait if we already have more than 5 items in the queue while len(self.lookup_busy) > 5: xbmc.sleep(100) if self.exit or cur_listitem != self.last_listitem: self.lookup_busy.pop(cur_listitem, None) return # prefer listitem's contenttype over container's contenttype dbtype = xbmc.getInfoLabel("%sListItem.DBTYPE" % prefix) if not dbtype: dbtype = xbmc.getInfoLabel("%sListItem.Property(DBTYPE)" % prefix) if dbtype: content_type = dbtype + "s" # collect details from listitem details = self.get_listitem_details(content_type, prefix) if self.exit: return # music content if content_type in ["albums", "artists", "songs" ] and self.enable_musicart: details = self.metadatautils.extend_dict( details, self.metadatautils.get_music_artwork( details["artist"], details["album"], details["title"], details["discnumber"])) # moviesets elif details["path"].startswith( "videodb://movies/sets/") and details["dbid"]: details = self.metadatautils.extend_dict( details, self.metadatautils.get_moviesetdetails( details["title"], details["dbid"]), ["year"]) content_type = "sets" # video content elif content_type in [ "movies", "setmovies", "tvshows", "seasons", "episodes", "musicvideos" ]: # get imdb and tvdbid details[ "imdbnumber"], tvdbid = self.metadatautils.get_imdbtvdb_id( details["title"], content_type, details["year"], details["imdbnumber"], details["tvshowtitle"]) if self.exit: return # generic video properties (studio, streamdetails, omdb, top250) details = merge_dict( details, self.get_directors_writers(details["director"], details["writer"])) if self.enable_extrafanart: log_msg("skin.helper.service: extrafanart", xbmc.LOGINFO) if not details["filenameandpath"]: details["filenameandpath"] = details["path"] if "videodb://" not in details["filenameandpath"]: efa = self.metadatautils.get_extrafanart( details["filenameandpath"]) if efa: details["art"] = merge_dict( details["art"], efa["art"]) if self.enable_extraposter: if not details["filenameandpath"]: details["filenameandpath"] = details["path"] if "videodb://" not in details["filenameandpath"]: efa = self.metadatautils.get_extraposter( details["filenameandpath"]) if efa: details["art"] = merge_dict( details["art"], efa["art"]) if self.exit: return details = merge_dict( details, self.metadatautils.get_duration(details["duration"])) details = merge_dict(details, self.get_genres(details["genre"])) details = merge_dict( details, self.metadatautils.get_studio_logo(details["studio"])) details = merge_dict( details, self.metadatautils.get_omdb_info( details["imdbnumber"])) details = merge_dict( details, self.get_streamdetails(details["dbid"], details["path"], content_type)) # Disable when get_top250 gets crazy details = merge_dict( details, self.metadatautils.get_top250_rating( details["imdbnumber"])) if self.exit: return # tvshows-only properties (tvdb) #if content_type in ["tvshows", "seasons", "episodes"]: # details = merge_dict( # details, self.metadatautils.get_tvdb_details( # details["imdbnumber"], tvdbid)) # movies-only properties (tmdb, animated art) if content_type in ["movies", "setmovies", "tvshows"]: details = merge_dict( details, self.metadatautils.get_tmdb_details( details["imdbnumber"])) if details["imdbnumber"] and self.enable_animatedart: details = self.metadatautils.extend_dict( details, self.metadatautils.get_animated_artwork( details["imdbnumber"])) if self.exit: return # extended art if self.enable_extendedart: tmdbid = details.get("tmdb_id", "") details = self.metadatautils.extend_dict( details, self.metadatautils.get_extended_artwork( details["imdbnumber"], tvdbid, tmdbid, content_type), [ "posters", "clearlogos", "banners", "discarts", "cleararts", "characterarts" ]) # monitor listitem props when PVR is active elif content_type in [ "tvchannels", "tvrecordings", "channels", "recordings", "timers", "tvtimers" ]: details = self.get_pvr_artwork(details, prefix) # process all properties all_props = prepare_win_props(details) if "sets" not in content_type: self.listitem_details[cur_listitem] = all_props self.lookup_busy.pop(cur_listitem, None) if cur_listitem == self.last_listitem: self.set_win_props(all_props) except Exception as exc: log_exception(__name__, exc) self.lookup_busy.pop(cur_listitem, None)