def onInit(self): '''triggered when the dialog is drawn''' if self.listitem: self.clearList() kodidb = KodiDb() if isinstance(self.listitem, dict): self.listitem = kodidb.prepare_listitem(self.listitem) self.listitem = kodidb.create_listitem(self.listitem, False) del kodidb self.addItem(self.listitem) # disable some controls if existing disable_controls = [9, 7, 101, 6] for item in disable_controls: try: self.getControl(item).setVisible(False) except Exception: pass # enable some controls if existing disable_controls = [351, 352] for item in disable_controls: try: self.getControl(item).setVisible(True) self.getControl(item).setEnabled(True) except Exception: pass
def __init__(self): self.cache = SimpleCache() self.kodidb = KodiDb() self.win = xbmcgui.Window(10000) self.addon = xbmcaddon.Addon(ADDON_ID) self.kodimonitor = xbmc.Monitor() self.smartshortcuts = SmartShortCuts(self) self.wallimages = WallImages(self)
def __init__(self): self.cache = SimpleCache() self.kodi_db = KodiDb() self.win = xbmcgui.Window(10000) try: 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 favourites_nodes(self): '''build smart shortcuts for favourites''' if xbmc.getCondVisibility("Skin.HasSetting(SmartShortcuts.favorites)"): # build node listing nodes = [] favs = KodiDb().favourites() for count, fav in enumerate(favs): if fav["type"] == "window": content = fav["windowparameter"] # check if this is a valid path with content if ("script://" not in content.lower() and "mode=9" not in content.lower() and "search" not in content.lower() and "play" not in content.lower()): item_path = "ActivateWindow(%s,%s,return)" % (fav["window"], content) if "&" in content and "?" in content and "=" in content and not content.endswith("/"): content += "&widget=true" media_type = detect_plugin_content(content) if media_type: key = "favorite.%s" % count self.bgupdater.set_winprop("%s.label" % key, fav["label"]) self.bgupdater.set_winprop("%s.title" % key, fav["label"]) self.bgupdater.set_winprop("%s.action" % key, item_path) self.bgupdater.set_winprop("%s.path" % key, item_path) self.bgupdater.set_winprop("%s.content" % key, content) self.bgupdater.set_winprop("%s.type" % key, media_type) if key not in self.toplevel_nodes: self.toplevel_nodes.append(key) nodes.append(("%s.image" % key, content, fav["label"])) self.all_nodes["favourites"] = nodes
def open_item(self): '''open selected item''' control_id = self.getFocusId() listitem = self.getControl(control_id).getSelectedItem() if "videodb:" in listitem.getfilename(): # tvshow: open path xbmc.executebuiltin('ReplaceWindow(Videos,"%s")' % self.listitem.getfilename()) self.close_dialog() elif "actor" in listitem.getProperty("DBTYPE"): # cast dialog xbmc.executebuiltin("ActivateWindow(busydialog)") from dialogselect import DialogSelect results = [] kodidb = KodiDb() name = listitem.getLabel().decode("utf-8") items = kodidb.castmedia(name) items = process_method_on_list(kodidb.prepare_listitem, items) for item in items: if item["file"].startswith("videodb://"): item["file"] = "ActivateWindow(Videos,%s,return)" % item[ "file"] else: item["file"] = 'PlayMedia("%s")' % item["file"] results.append(kodidb.create_listitem(item, False)) # finished lookup - display listing with results xbmc.executebuiltin("dialog.Close(busydialog)") dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=name, richlayout=True) dialog.doModal() result = dialog.result del dialog if result: xbmc.executebuiltin(result.getfilename()) self.close_dialog() else: # video file: start playback xbmc.executebuiltin('PlayMedia("%s")' % listitem.getfilename()) self.close_dialog()
def __init__(self): '''Initialization and main code run''' self.win = xbmcgui.Window(10000) self.addon = xbmcaddon.Addon(ADDON_ID) self.kodidb = KodiDb() self.cache = SimpleCache() 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) finally: xbmc.executebuiltin("dialog.Close(busydialog)") # do cleanup self.close()
def __init__(self): self.cache = SimpleCache() self.kodi_db = KodiDb() self.win = xbmcgui.Window(10000) try: 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 open_item(self): '''open selected item''' control_id = self.getFocusId() listitem = self.getControl(control_id).getSelectedItem() if "videodb:" in listitem.getfilename(): # tvshow: open path xbmc.executebuiltin('ReplaceWindow(Videos,"%s")' % self.listitem.getfilename()) self.close_dialog() elif "actor" in listitem.getProperty("DBTYPE"): # cast dialog xbmc.executebuiltin("ActivateWindow(busydialog)") from dialogselect import DialogSelect results = [] kodidb = KodiDb() name = listitem.getLabel().decode("utf-8") items = kodidb.castmedia(name) items = process_method_on_list(kodidb.prepare_listitem, items) for item in items: if item["file"].startswith("videodb://"): item["file"] = "ActivateWindow(Videos,%s,return)" % item["file"] else: item["file"] = 'PlayMedia("%s")' % item["file"] results.append(kodidb.create_listitem(item, False)) # finished lookup - display listing with results xbmc.executebuiltin("dialog.Close(busydialog)") dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=name, richlayout=True) dialog.doModal() result = dialog.result del dialog if result: xbmc.executebuiltin(result.getfilename()) self.close_dialog() else: # video file: start playback xbmc.executebuiltin('PlayMedia("%s")' % listitem.getfilename()) self.close_dialog()
def playlists_nodes(self): '''build smart shortcuts listing for playlists''' nodes = [] if xbmc.getCondVisibility("Skin.HasSetting(SmartShortcuts.playlists)"): # build node listing count = 0 import xml.etree.ElementTree as xmltree paths = [('special://videoplaylists/', 'Videos'), ('special://musicplaylists/', 'Music')] for playlistpath in paths: if xbmcvfs.exists(playlistpath[0]): media_array = KodiDb().files(playlistpath[0]) for item in media_array: try: label = "" if item["file"].endswith(".xsp") and "Emby" not in item["file"]: playlist = item["file"] contents = xbmcvfs.File(playlist, 'r') contents_data = contents.read() contents.close() xmldata = xmltree.fromstring(contents_data) media_type = "unknown" label = item["label"] for line in xmldata.getiterator(): if line.tag == "smartplaylist": media_type = line.attrib['type'] if line.tag == "name": label = line.text key = "playlist.%s" % count item_path = "ActivateWindow(%s,%s,return)" % (playlistpath[1], playlist) self.bgupdater.set_winprop("%s.label" % key, label) self.bgupdater.set_winprop("%s.title" % key, label) self.bgupdater.set_winprop("%s.action" % key, item_path) self.bgupdater.set_winprop("%s.path" % key, item_path) self.bgupdater.set_winprop("%s.content" % key, playlist) self.bgupdater.set_winprop("%s.type" % key, media_type) nodes.append(("%s.image" % key, playlist, label)) if key not in self.toplevel_nodes: self.toplevel_nodes.append(key) count += 1 except Exception: log_msg("Error while processing smart shortcuts for playlist %s --> " "This file seems to be corrupted, please remove it from your system " "to prevent any further errors." % item["file"], xbmc.LOGWARNING) self.all_nodes["playlists"] = nodes
class MainModule: '''mainmodule provides the script methods for the skinhelper addon''' def __init__(self): '''Initialization and main code run''' self.win = xbmcgui.Window(10000) self.addon = xbmcaddon.Addon(ADDON_ID) self.kodidb = KodiDb() self.cache = SimpleCache() 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) finally: xbmc.executebuiltin("dialog.Close(busydialog)") # do cleanup self.close() def close(self): '''Cleanup Kodi Cpython instances on exit''' self.cache.close() del self.win del self.addon del self.kodidb log_msg("MainModule exited") @classmethod def get_params(self): '''extract the params from the called script path''' params = {} for arg in sys.argv[1:]: paramname = arg.split('=')[0] paramvalue = arg.replace(paramname + "=", "") paramname = paramname.lower() if paramname == "action": paramvalue = paramvalue.lower() params[paramname] = paramvalue return params def deprecated_method(self, newaddon): ''' used when one of the deprecated methods is called print warning in log and call the external script with the same parameters ''' action = self.params.get("action") log_msg("Deprecated method: %s. Please call %s directly" % (action, newaddon), xbmc.LOGWARNING) paramstring = "" for key, value in self.params.iteritems(): paramstring += ",%s=%s" % (key, value) if xbmc.getCondVisibility("System.HasAddon(%s)" % newaddon): xbmc.executebuiltin("RunAddon(%s%s)" % (newaddon, paramstring)) else: # trigger install of the addon if KODI_VERSION > 16: xbmc.executebuiltin("InstallAddon(%s)" % newaddon) else: xbmc.executebuiltin("RunPlugin(plugin://%s)" % newaddon) @staticmethod def musicsearch(): '''helper to go directly to music search dialog''' xbmc.executebuiltin("ActivateWindow(Music)") xbmc.executebuiltin("SendClick(8)") def setview(self): '''sets the selected viewmode for the container''' xbmc.executebuiltin("ActivateWindow(busydialog)") content_type = get_current_content_type() if not content_type: content_type = "files" current_view = xbmc.getInfoLabel("Container.Viewmode").decode("utf-8") view_id, view_label = self.selectview(content_type, current_view) current_forced_view = xbmc.getInfoLabel("Skin.String(SkinHelper.ForcedViews.%s)" % content_type) if view_id is not None: # also store forced view if (content_type and current_forced_view and current_forced_view != "None" and xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.ForcedViews.Enabled)")): xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s,%s)" % (content_type, view_id)) xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s.label,%s)" % (content_type, view_label)) self.win.setProperty("SkinHelper.ForcedView", view_id) if not xbmc.getCondVisibility("Control.HasFocus(%s)" % current_forced_view): xbmc.sleep(100) xbmc.executebuiltin("Container.SetViewMode(%s)" % view_id) xbmc.executebuiltin("SetFocus(%s)" % view_id) else: self.win.clearProperty("SkinHelper.ForcedView") # set view xbmc.executebuiltin("Container.SetViewMode(%s)" % view_id) def selectview(self, content_type="other", current_view=None, display_none=False): '''reads skinfile with all views to present a dialog to choose from''' cur_view_select_id = None label = "" all_views = [] if display_none: listitem = xbmcgui.ListItem(label="None") listitem.setProperty("id", "None") all_views.append(listitem) # read the special skin views file views_file = xbmc.translatePath('special://skin/extras/views.xml').decode("utf-8") if xbmcvfs.exists(views_file): doc = parse(views_file) listing = doc.documentElement.getElementsByTagName('view') itemcount = 0 for view in listing: label = xbmc.getLocalizedString(int(view.attributes['languageid'].nodeValue)) viewid = view.attributes['value'].nodeValue mediatypes = view.attributes['type'].nodeValue.lower().split(",") if label.lower() == current_view.lower() or viewid == current_view: cur_view_select_id = itemcount if display_none: cur_view_select_id += 1 if (("all" in mediatypes or content_type.lower() in mediatypes) and (not "!" + content_type.lower() in mediatypes) and not xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.view.Disabled.%s)" % viewid)): image = "special://skin/extras/viewthumbs/%s.jpg" % viewid listitem = xbmcgui.ListItem(label=label, iconImage=image) listitem.setProperty("viewid", viewid) listitem.setProperty("icon", image) all_views.append(listitem) itemcount += 1 dialog = DialogSelect("DialogSelect.xml", "", listing=all_views, windowtitle=self.addon.getLocalizedString(32012), richlayout=True) dialog.autofocus_id = cur_view_select_id dialog.doModal() result = dialog.result del dialog if result: viewid = result.getProperty("viewid") label = result.getLabel().decode("utf-8") return (viewid, label) else: return (None, None) # pylint: disable-msg=too-many-local-variables def enableviews(self): '''show select dialog to enable/disable views''' all_views = [] views_file = xbmc.translatePath('special://skin/extras/views.xml').decode("utf-8") richlayout = self.params.get("richlayout", "") == "true" if xbmcvfs.exists(views_file): doc = parse(views_file) listing = doc.documentElement.getElementsByTagName('view') for view in listing: view_id = view.attributes['value'].nodeValue label = xbmc.getLocalizedString(int(view.attributes['languageid'].nodeValue)) desc = label + " (" + str(view_id) + ")" image = "special://skin/extras/viewthumbs/%s.jpg" % view_id listitem = xbmcgui.ListItem(label=label, label2=desc, iconImage=image) listitem.setProperty("viewid", view_id) if not xbmc.getCondVisibility("Skin.HasSetting(SkinHelper.view.Disabled.%s)" % view_id): listitem.select(selected=True) excludefromdisable = False try: excludefromdisable = view.attributes['excludefromdisable'].nodeValue == "true" except Exception: pass if not excludefromdisable: all_views.append(listitem) dialog = DialogSelect( "DialogSelect.xml", "", listing=all_views, windowtitle=self.addon.getLocalizedString(32013), multiselect=True, richlayout=richlayout) dialog.doModal() result = dialog.result del dialog if result: for item in result: view_id = item.getProperty("viewid") if item.isSelected(): # view is enabled xbmc.executebuiltin("Skin.Reset(SkinHelper.view.Disabled.%s)" % view_id) else: # view is disabled xbmc.executebuiltin("Skin.SetBool(SkinHelper.view.Disabled.%s)" % view_id) # pylint: enable-msg=too-many-local-variables def setforcedview(self): '''helper that sets a forced view for a specific content type''' content_type = self.params.get("contenttype") if content_type: current_view = xbmc.getInfoLabel("Skin.String(SkinHelper.ForcedViews.%s)" % content_type) if not current_view: current_view = "0" view_id, view_label = self.selectview(content_type, current_view, True) if view_id or view_label: xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s,%s)" % (content_type, view_id)) xbmc.executebuiltin("Skin.SetString(SkinHelper.ForcedViews.%s.label,%s)" % (content_type, view_label)) @staticmethod def get_youtube_listing(searchquery): '''get items from youtube plugin by query''' lib_path = u"plugin://plugin.video.youtube/kodion/search/query/?q=%s" % searchquery return KodiDb().files(lib_path) def searchyoutube(self): '''helper to search youtube for the given title''' xbmc.executebuiltin("ActivateWindow(busydialog)") title = self.params.get("title", "") window_header = self.params.get("header", "") results = [] for media in self.get_youtube_listing(title): if not media["filetype"] == "directory": label = media["label"] label2 = media["plot"] image = "" if media.get('art'): if media['art'].get('thumb'): image = (media['art']['thumb']) listitem = xbmcgui.ListItem(label=label, label2=label2, iconImage=image) listitem.setProperty("path", media["file"]) results.append(listitem) # finished lookup - display listing with results xbmc.executebuiltin("dialog.Close(busydialog)") dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=window_header, multiselect=False, richlayout=True) dialog.doModal() result = dialog.result del dialog if result: if xbmc.getCondVisibility( "Window.IsActive(script-skin_helper_service-CustomInfo.xml) | " "Window.IsActive(movieinformation)"): xbmc.executebuiltin("Dialog.Close(movieinformation)") xbmc.executebuiltin("Dialog.Close(script-skin_helper_service-CustomInfo.xml)") xbmc.sleep(1000) xbmc.executebuiltin('PlayMedia("%s")' % result.getProperty("path")) del result def getcastmedia(self): '''helper to show a dialog with all media for a specific actor''' xbmc.executebuiltin("ActivateWindow(busydialog)") name = self.params.get("name", "") window_header = self.params.get("name", "") results = [] items = self.kodidb.castmedia(name) items = process_method_on_list(self.kodidb.prepare_listitem, items) for item in items: if item["file"].startswith("videodb://"): item["file"] = "ActivateWindow(Videos,%s,return)" % item["file"] else: item["file"] = 'PlayMedia("%s")' % item["file"] results.append(self.kodidb.create_listitem(item, False)) # finished lookup - display listing with results xbmc.executebuiltin("dialog.Close(busydialog)") dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=window_header, richlayout=True) dialog.doModal() result = dialog.result del dialog if result: while xbmc.getCondVisibility("System.HasModalDialog"): xbmc.executebuiltin("Action(Back)") xbmc.sleep(300) xbmc.executebuiltin(result.getfilename()) del result def setfocus(self): '''helper to set focus on a list or control''' control = self.params.get("control") fallback = self.params.get("fallback") position = self.params.get("position", "0") relativeposition = self.params.get("relativeposition") if relativeposition: position = int(relativeposition) - 1 count = 0 if control: while not xbmc.getCondVisibility("Control.HasFocus(%s)" % control): if xbmc.getCondVisibility("Window.IsActive(busydialog)"): xbmc.sleep(150) continue elif count == 20 or (xbmc.getCondVisibility( "!Control.IsVisible(%s) | " "!IntegerGreaterThan(Container(%s).NumItems,0)" % (control, control))): if fallback: xbmc.executebuiltin("Control.SetFocus(%s)" % fallback) break else: xbmc.executebuiltin("Control.SetFocus(%s,%s)" % (control, position)) xbmc.sleep(50) count += 1 def setwidgetcontainer(self): '''helper that reports the current selected widget container/control''' controls = self.params.get("controls", "").split("-") if controls: xbmc.sleep(50) for i in range(10): for control in controls: if xbmc.getCondVisibility("Control.IsVisible(%s) + IntegerGreaterThan(Container(%s).NumItems,0)" % (control, control)): self.win.setProperty("SkinHelper.WidgetContainer", control) return xbmc.sleep(50) self.win.clearProperty("SkinHelper.WidgetContainer") def saveskinimage(self): '''let the user select an image and save it to addon_data for easy backup''' skinstring = self.params.get("skinstring", "") allow_multi = self.params.get("multi", "") == "true" header = self.params.get("header", "") value = SkinSettings().save_skin_image(skinstring, allow_multi, header) if value: xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring.encode("utf-8"), value.encode("utf-8"))) @staticmethod def checkskinsettings(): '''performs check of all default skin settings and labels''' SkinSettings().correct_skin_settings() def setskinsetting(self): '''allows the user to set a skin setting with a select dialog''' setting = self.params.get("setting", "") org_id = self.params.get("id", "") if "$" in org_id: org_id = xbmc.getInfoLabel(org_id).decode("utf-8") header = self.params.get("header", "") SkinSettings().set_skin_setting(setting=setting, window_header=header, original_id=org_id) def setskinconstant(self): '''allows the user to set a skin constant with a select dialog''' setting = self.params.get("setting", "") value = self.params.get("value", "") header = self.params.get("header", "") SkinSettings().set_skin_constant(setting, header, value) def setskinconstants(self): '''allows the skinner to set multiple skin constants''' settings = self.params.get("settings", "").split("|") values = self.params.get("values", "").split("|") SkinSettings().set_skin_constants(settings, values) def setskinshortcutsproperty(self): '''allows the user to make a setting for skinshortcuts using the special skinsettings dialogs''' setting = self.params.get("setting", "") prop = self.params.get("property", "") header = self.params.get("header", "") SkinSettings().set_skinshortcuts_property(setting, header, prop) def togglekodisetting(self): '''toggle kodi setting''' settingname = self.params.get("setting", "") cur_value = xbmc.getCondVisibility("system.getbool(%s)" % settingname) if cur_value: new_value = "false" else: new_value = "true" xbmc.executeJSONRPC( '{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"%s","value":%s}}' % (settingname, new_value)) def setkodisetting(self): '''set kodi setting''' settingname = self.params.get("setting", "") value = self.params.get("value", "") is_int = False try: valueint = int(value) is_int = True del valueint except Exception: pass if value.lower() == "true": value = 'true' elif value.lower() == "false": value = 'false' elif is_int: value = '"%s"' % value xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue",\ "params":{"setting":"%s","value":%s}}' % (settingname, value)) def playtrailer(self): '''auto play windowed trailer inside video listing''' if not xbmc.getCondVisibility("Player.HasMedia | Container.Scrolling | Container.OnNext | " "Container.OnPrevious | !IsEmpty(Window(Home).Property(traileractionbusy))"): self.win.setProperty("traileractionbusy", "traileractionbusy") widget_container = self.params.get("widgetcontainer", "") trailer_mode = self.params.get("mode", "").replace("auto_", "") allow_youtube = self.params.get("youtube", "") == "true" if not trailer_mode: trailer_mode = "windowed" if widget_container: widget_container_prefix = "Container(%s)." % widget_container else: widget_container_prefix = "" li_title = xbmc.getInfoLabel("%sListItem.Title" % widget_container_prefix).decode('utf-8') li_trailer = xbmc.getInfoLabel("%sListItem.Trailer" % widget_container_prefix).decode('utf-8') if not li_trailer and allow_youtube: youtube_result = self.get_youtube_listing("%s Trailer" % li_title) if youtube_result: li_trailer = youtube_result[0].get("file") # always wait a bit to prevent trailer start playing when we're scrolling the list xbmc.Monitor().waitForAbort(3) if li_trailer and (li_title == xbmc.getInfoLabel("%sListItem.Title" % widget_container_prefix).decode('utf-8')): if trailer_mode == "fullscreen" and li_trailer: xbmc.executebuiltin('PlayMedia("%s")' % li_trailer) else: xbmc.executebuiltin('PlayMedia("%s",1)' % li_trailer) self.win.setProperty("TrailerPlaying", trailer_mode) self.win.clearProperty("traileractionbusy") def colorpicker(self): '''legacy''' self.deprecated_method("script.skin.helper.colorpicker") def backup(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def restore(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def reset(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def colorthemes(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def createcolortheme(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def restorecolortheme(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def conditionalbackgrounds(self): '''legacy''' self.deprecated_method("script.skin.helper.backgrounds") def splashscreen(self): '''helper to show a user defined splashscreen in the skin''' import time splashfile = self.params.get("file", "") duration = int(self.params.get("duration", 5)) if (splashfile.lower().endswith("jpg") or splashfile.lower().endswith("gif") or splashfile.lower().endswith("png") or splashfile.lower().endswith("tiff")): # this is an image file self.win.setProperty("SkinHelper.SplashScreen", splashfile) # for images we just wait for X seconds to close the splash again start_time = time.time() while (time.time() - start_time) <= duration: xbmc.sleep(500) else: # for video or audio we have to wait for the player to finish... xbmc.Player().play(splashfile, windowed=True) xbmc.sleep(500) while xbmc.getCondVisibility("Player.HasMedia"): xbmc.sleep(150) # replace startup window with home startupwindow = xbmc.getInfoLabel("System.StartupWindow") xbmc.executebuiltin("ReplaceWindow(%s)" % startupwindow) autostart_playlist = xbmc.getInfoLabel("$ESCINFO[Skin.String(autostart_playlist)]") if autostart_playlist: xbmc.executebuiltin("PlayMedia(%s)" % autostart_playlist) def videosearch(self): '''show the special search dialog''' xbmc.executebuiltin("ActivateWindow(busydialog)") from resources.lib.searchdialog import SearchDialog search_dialog = SearchDialog("script-skin_helper_service-CustomSearch.xml", self.addon.getAddonInfo('path').decode("utf-8"), "Default", "1080i") search_dialog.doModal() del search_dialog def showinfo(self): '''shows our special videoinfo dialog''' dbid = self.params.get("dbid", "") dbtype = self.params.get("dbtype", "") from infodialog import show_infodialog show_infodialog(dbid, dbtype) def deletedir(self): '''helper to delete a directory, input can be normal filesystem path or vfs''' del_path = self.params.get("path") if del_path: ret = xbmcgui.Dialog().yesno(heading=xbmc.getLocalizedString(122), line1=u"%s[CR]%s" % (xbmc.getLocalizedString(125), del_path)) if ret: success = recursive_delete_dir(del_path) if success: xbmcgui.Dialog().ok(heading=xbmc.getLocalizedString(19179), line1=self.addon.getLocalizedString(32014)) else: xbmcgui.Dialog().ok(heading=xbmc.getLocalizedString(16205), line1=xbmc.getLocalizedString(32015)) def overlaytexture(self): '''legacy: helper to let the user choose a background overlay from a skin defined folder''' skinstring = self.params.get("skinstring", "BackgroundOverlayTexture") self.params["skinstring"] = skinstring self.params["resourceaddon"] = "resource.images.backgroundoverlays" self.params["customfolder"] = "special://skin/extras/bgoverlays/" self.params["allowmulti"] = "false" self.params["header"] = self.addon.getLocalizedString(32002) self.selectimage() def busytexture(self): '''legacy: helper which lets the user select a busy spinner from predefined spinners in the skin''' skinstring = self.params.get("skinstring", "SkinHelper.SpinnerTexture") self.params["skinstring"] = skinstring self.params["resourceaddon"] = "resource.images.busyspinners" self.params["customfolder"] = "special://skin/extras/busy_spinners/" self.params["allowmulti"] = "true" self.params["header"] = self.addon.getLocalizedString(32006) self.selectimage() def selectimage(self): '''helper which lets the user select an image or imagepath from resourceaddons or custom path''' skinsettings = SkinSettings() skinstring = self.params.get("skinstring", "") skinshortcutsprop = self.params.get("skinshortcutsproperty", "") current_value = self.params.get("currentvalue", "") resource_addon = self.params.get("resourceaddon", "") allow_multi = self.params.get("allowmulti", "false") == "true" windowheader = self.params.get("header", "") skinhelper_backgrounds = self.params.get("skinhelperbackgrounds", "false") == "true" label, value = skinsettings.select_image( skinstring, allow_multi=allow_multi, windowheader=windowheader, resource_addon=resource_addon, skinhelper_backgrounds=skinhelper_backgrounds, current_value=current_value) if label: if skinshortcutsprop: # write value to skinshortcuts prop from skinshortcuts import set_skinshortcuts_property set_skinshortcuts_property(skinshortcutsprop, value, label) else: # write the values to skin strings if value.startswith("$INFO"): # we got an dynamic image from window property skinsettings.set_skin_variable(skinstring, value) value = "$VAR[%s]" % skinstring skinstring = skinstring.encode("utf-8") label = label.encode("utf-8") xbmc.executebuiltin("Skin.SetString(%s.label,%s)" % (skinstring, label)) xbmc.executebuiltin("Skin.SetString(%s.name,%s)" % (skinstring, label)) xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring, value)) xbmc.executebuiltin("Skin.SetString(%s.path,%s)" % (skinstring, value)) del skinsettings def dialogok(self): '''helper to show an OK dialog with a message''' headertxt = self.params.get("header") bodytxt = self.params.get("message") if bodytxt.startswith(" "): bodytxt = bodytxt[1:] if headertxt.startswith(" "): headertxt = headertxt[1:] dialog = xbmcgui.Dialog() dialog.ok(heading=headertxt, line1=bodytxt) del dialog def dialogyesno(self): '''helper to show a YES/NO dialog with a message''' headertxt = self.params.get("header") bodytxt = self.params.get("message") yesactions = self.params.get("yesaction", "").split("|") noactions = self.params.get("noaction", "").split("|") if bodytxt.startswith(" "): bodytxt = bodytxt[1:] if headertxt.startswith(" "): headertxt = headertxt[1:] if xbmcgui.Dialog().yesno(heading=headertxt, line1=bodytxt): for action in yesactions: xbmc.executebuiltin(action.encode("utf-8")) else: for action in noactions: xbmc.executebuiltin(action.encode("utf-8")) def textviewer(self): '''helper to show a textviewer dialog with a message''' headertxt = self.params.get("header", "") bodytxt = self.params.get("message", "") if bodytxt.startswith(" "): bodytxt = bodytxt[1:] if headertxt.startswith(" "): headertxt = headertxt[1:] xbmcgui.Dialog().textviewer(headertxt, bodytxt) def fileexists(self): '''helper to let the skinner check if a file exists and write the outcome to a window prop or skinstring''' filename = self.params.get("file") skinstring = self.params.get("skinstring") windowprop = self.params.get("winprop") if xbmcvfs.exists(filename): if windowprop: self.win.setProperty(windowprop, "exists") if skinstring: xbmc.executebuiltin("Skin.SetString(%s,exists)" % skinstring) else: if windowprop: self.win.clearProperty(windowprop) if skinstring: xbmc.executebuiltin("Skin.Reset(%s)" % skinstring) def stripstring(self): '''helper to allow the skinner to strip a string and write results to a skin string''' splitchar = self.params.get("splitchar") if splitchar.upper() == "[SPACE]": splitchar = " " skinstring = self.params.get("string") if not skinstring: skinstring = self.params.get("skinstring") output = self.params.get("output") index = self.params.get("index", 0) skinstring = skinstring.split(splitchar)[int(index)] self.win.setProperty(output, skinstring) def getfilename(self, filename=""): '''helper to display a sanitized filename in the vidoeinfo dialog''' output = self.params.get("output") if not filename: filename = xbmc.getInfoLabel("ListItem.FileNameAndPath") if not filename: filename = xbmc.getInfoLabel("ListItem.FileName") if "filename=" in filename: url_params = dict(urlparse.parse_qsl(filename)) filename = url_params.get("filename") self.win.setProperty(output, filename) def getplayerfilename(self): '''helper to parse the filename from a plugin (e.g. emby) filename''' filename = xbmc.getInfoLabel("Player.FileNameAndPath") if not filename: filename = xbmc.getInfoLabel("Player.FileName") self.getfilename(filename) def getpercentage(self): '''helper to calculate the percentage of 2 numbers and write results to a skinstring''' total = int(params.get("total")) count = int(params.get("count")) roundsteps = self.params.get("roundsteps") skinstring = self.params.get("skinstring") percentage = int(round((1.0 * count / total) * 100)) if roundsteps: roundsteps = int(roundsteps) percentage = percentage + (roundsteps - percentage) % roundsteps xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring, percentage)) def setresourceaddon(self): '''helper to let the user choose a resource addon and set that as skin string''' from resourceaddons import setresourceaddon addontype = self.params.get("addontype", "") skinstring = self.params.get("skinstring", "") setresourceaddon(addontype, skinstring) def checkresourceaddons(self): '''allow the skinner to perform a basic check if some required resource addons are available''' from resourceaddons import checkresourceaddons addonslist = self.params.get("addonslist", []) if addonslist: addonslist = addonslist.split("|") checkresourceaddons(addonslist)
class PluginContent: '''Hidden plugin entry point providing some helper features''' params = {} win = None def __init__(self): self.cache = SimpleCache() self.kodi_db = KodiDb() self.win = xbmcgui.Window(10000) try: 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 close(self): '''Cleanup Kodi Cpython instances''' self.cache.close() del self.win 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 load_widget(self): '''legacy entrypoint called (widgets are moved to seperate addon), start redirect...''' action = self.params.get("action", "") newaddon = "script.skin.helper.widgets" log_msg( "Deprecated method: %s. Please reassign your widgets to get rid of this message. -" "This automatic redirect will be removed in the future" % (action), xbmc.LOGWARNING) paramstring = "" for key, value in self.params.iteritems(): paramstring += ",%s=%s" % (key, value) if getCondVisibility("System.HasAddon(%s)" % newaddon): # TEMP !!! for backwards compatability reasons only - to be removed in the near future!! import imp addon = xbmcaddon.Addon(newaddon) addon_path = addon.getAddonInfo('path').decode("utf-8") imp.load_source('plugin', os.path.join(addon_path, "plugin.py")) from plugin import main main.Main() del addon else: # trigger install of the addon if KODI_VERSION > 16: xbmc.executebuiltin("InstallAddon(%s)" % newaddon) else: xbmc.executebuiltin("RunPlugin(plugin://%s)" % newaddon) def playchannel(self): '''play channel from widget helper''' params = {"item": {"channelid": int(self.params["channelid"])}} self.kodi_db.set_json("Player.Open", params) def playrecording(self): '''retrieve the recording and play to get resume working''' recording = self.kodi_db.recording(self.params["recordingid"]) params = {"item": {"recordingid": recording["recordingid"]}} self.kodi_db.set_json("Player.Open", params) # manually seek because passing resume to the player json cmd doesn't seem to work if recording["resume"].get("position"): for i in range(50): if getCondVisibility("Player.HasVideo"): break xbmc.sleep(50) xbmc.Player().seekTime(recording["resume"].get("position")) def launch(self): '''launch any builtin action using a plugin listitem''' if "runscript" in self.params["path"]: self.params["path"] = self.params["path"].replace("?", ",") xbmc.executebuiltin(self.params["path"]) def playalbum(self): '''helper to play an entire album''' xbmc.executeJSONRPC( '{ "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "albumid": %d } }, "id": 1 }' % int(self.params["albumid"])) def smartshortcuts(self): '''called from skinshortcuts to retrieve listing of all smart shortcuts''' import skinshortcuts skinshortcuts.get_smartshortcuts(self.params.get("path", "")) @staticmethod def backgrounds(): '''called from skinshortcuts to retrieve listing of all backgrounds''' import skinshortcuts skinshortcuts.get_backgrounds() def widgets(self): '''called from skinshortcuts to retrieve listing of all widgetss''' import skinshortcuts skinshortcuts.get_widgets(self.params.get("path", ""), self.params.get("sublevel", "")) def resourceimages(self): '''retrieve listing of specific resource addon images''' from resourceaddons import get_resourceimages addontype = self.params.get("addontype", "") for item in get_resourceimages(addontype, True): listitem = xbmcgui.ListItem(item[0], label2=item[2], path=item[1], iconImage=item[3]) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item[1], listitem=listitem, isFolder=False) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def extrafanart(self): '''helper to display extrafanart in multiimage control in the skin''' fanarts = eval(self.params["fanarts"]) # process extrafanarts for count, item in enumerate(fanarts): listitem = xbmcgui.ListItem("fanart%s" % count, path=item) listitem.setProperty('mimetype', 'image/jpeg') xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item, listitem=listitem) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def genrebackground(self): '''helper to display images for a specific genre in multiimage control in the skin''' genre = self.params.get("genre").split(".")[0] arttype = self.params.get("arttype", "fanart") randomize = self.params.get("random", "false") == "true" mediatype = self.params.get("mediatype", "movies") if genre and genre != "..": filters = [{"operator": "is", "field": "genre", "value": genre}] if randomize: sort = {"method": "random", "order": "descending"} else: sort = {"method": "sorttitle", "order": "ascending"} items = getattr(self.kodi_db, mediatype)(sort=sort, filters=filters, limits=(0, 50)) for item in items: image = get_clean_image(item["art"].get(arttype, "")) if image: image = get_clean_image(item["art"][arttype]) listitem = xbmcgui.ListItem(image, path=image) listitem.setProperty('mimetype', 'image/jpeg') xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=image, listitem=listitem) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def getcastmedia(self): '''helper to display get all media for a specific actor''' name = self.params.get("name") if name: all_items = self.kodi_db.castmedia(name) all_items = process_method_on_list(self.kodi_db.prepare_listitem, all_items) all_items = process_method_on_list(self.kodi_db.create_listitem, all_items) xbmcplugin.addDirectoryItems(int(sys.argv[1]), all_items, len(all_items)) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def getcast(self): '''helper to get all cast for a given media item''' db_id = None all_cast = [] all_cast_names = list() cache_str = "" download_thumbs = self.params.get("downloadthumbs", "") == "true" extended_cast_action = self.params.get("castaction", "") == "extendedinfo" tmdb = Tmdb() movie = self.params.get("movie") tvshow = self.params.get("tvshow") episode = self.params.get("episode") movieset = self.params.get("movieset") try: # try to parse db_id if movieset: cache_str = "movieset.castcache-%s-%s" % ( self.params["movieset"], download_thumbs) db_id = int(movieset) elif tvshow: cache_str = "tvshow.castcache-%s-%s" % (self.params["tvshow"], download_thumbs) db_id = int(tvshow) elif movie: cache_str = "movie.castcache-%s-%s" % (self.params["movie"], download_thumbs) db_id = int(movie) elif episode: cache_str = "episode.castcache-%s-%s" % ( self.params["episode"], download_thumbs) db_id = int(episode) except Exception: pass cachedata = self.cache.get(cache_str) if cachedata: # get data from cache all_cast = cachedata else: # retrieve data from json api... if movie and db_id: all_cast = self.kodi_db.movie(db_id)["cast"] elif movie and not db_id: filters = [{ "operator": "is", "field": "title", "value": movie }] result = self.kodi_db.movies(filters=filters) all_cast = result[0]["cast"] if result else [] elif tvshow and db_id: all_cast = self.kodi_db.tvshow(db_id)["cast"] elif tvshow and not db_id: filters = [{ "operator": "is", "field": "title", "value": tvshow }] result = self.kodi_db.tvshows(filters=filters) all_cast = result[0]["cast"] if result else [] elif episode and db_id: all_cast = self.kodi_db.episode(db_id)["cast"] elif episode and not db_id: filters = [{ "operator": "is", "field": "title", "value": episode }] result = self.kodi_db.episodes(filters=filters) all_cast = result[0]["cast"] if result else [] elif movieset: if not db_id: for item in self.kodi_db.moviesets(): if item["title"].lower() == movieset.lower(): db_id = item["setid"] if db_id: json_result = self.kodi_db.movieset( db_id, include_set_movies_fields=["cast"]) if "movies" in json_result: for movie in json_result['movies']: all_cast += movie['cast'] # optional: download missing actor thumbs if all_cast and download_thumbs: for cast in all_cast: if cast.get("thumbnail"): cast["thumbnail"] = get_clean_image( cast.get("thumbnail")) if not cast.get("thumbnail"): artwork = tmdb.get_actor(cast["name"]) cast["thumbnail"] = artwork.get("thumb", "") # lookup tmdb if item is requested that is not in local db if not all_cast: tmdbdetails = {} if movie and not db_id: tmdbdetails = tmdb.search_movie(movie) elif tvshow and not db_id: tmdbdetails = tmdb.search_tvshow(tvshow) if tmdbdetails.get("cast"): all_cast = tmdbdetails["cast"] # save to cache self.cache.set(cache_str, all_cast) # process listing with the results... for cast in all_cast: if cast.get("name") not in all_cast_names: liz = xbmcgui.ListItem(label=cast.get("name"), label2=cast.get("role"), iconImage=cast.get("thumbnail")) if extended_cast_action: url = "RunScript(script.extendedinfo,info=extendedactorinfo,name=%s)" % cast.get( "name") url = "plugin://script.skin.helper.service/?action=launch&path=%s" % url is_folder = False else: url = "RunScript(script.skin.helper.service,action=getcastmedia,name=%s)" % cast.get( "name") url = "plugin://script.skin.helper.service/?action=launch&path=%s" % urlencode( url) is_folder = False all_cast_names.append(cast.get("name")) liz.setThumbnailImage(cast.get("thumbnail")) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=liz, isFolder=is_folder) xbmcplugin.endOfDirectory(int(sys.argv[1])) @staticmethod def alphabet(): '''display an alphabet scrollbar in listings''' all_letters = [] if xbmc.getInfoLabel("Container.NumItems"): for i in range(int(xbmc.getInfoLabel("Container.NumItems"))): all_letters.append( xbmc.getInfoLabel("Listitem(%s).SortLetter" % i).upper()) start_number = "" for number in ["2", "3", "4", "5", "6", "7", "8", "9"]: if number in all_letters: start_number = number break for letter in [ start_number, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ]: if letter == start_number: label = "#" else: label = letter listitem = xbmcgui.ListItem(label=label) if letter not in all_letters: lipath = "noop" listitem.setProperty("NotAvailable", "true") else: lipath = "plugin://script.skin.helper.service/?action=alphabetletter&letter=%s" % letter xbmcplugin.addDirectoryItem(int(sys.argv[1]), lipath, listitem, isFolder=False) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def alphabetletter(self): '''used with the alphabet scrollbar to jump to a letter''' if KODI_VERSION > 16: xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=False, listitem=xbmcgui.ListItem()) letter = self.params.get("letter", "").upper() jumpcmd = "" if letter in ["A", "B", "C", "2"]: jumpcmd = "2" elif letter in ["D", "E", "F", "3"]: jumpcmd = "3" elif letter in ["G", "H", "I", "4"]: jumpcmd = "4" elif letter in ["J", "K", "L", "5"]: jumpcmd = "5" elif letter in ["M", "N", "O", "6"]: jumpcmd = "6" elif letter in ["P", "Q", "R", "S", "7"]: jumpcmd = "7" elif letter in ["T", "U", "V", "8"]: jumpcmd = "8" elif letter in ["W", "X", "Y", "Z", "9"]: jumpcmd = "9" if jumpcmd: xbmc.executebuiltin("SetFocus(50)") for i in range(40): xbmc.executeJSONRPC( '{ "jsonrpc": "2.0", "method": "Input.ExecuteAction",\ "params": { "action": "jumpsms%s" }, "id": 1 }' % (jumpcmd)) xbmc.sleep(50) if xbmc.getInfoLabel("ListItem.Sortletter").upper() == letter: break
def get_youtube_listing(searchquery): '''get items from youtube plugin by query''' lib_path = u"plugin://plugin.video.youtube/kodion/search/query/?q=%s" % searchquery return KodiDb().files(lib_path)
class PluginContent: '''Hidden plugin entry point providing some helper features''' params = {} win = None def __init__(self): self.cache = SimpleCache() self.kodi_db = KodiDb() self.win = xbmcgui.Window(10000) try: 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 close(self): '''Cleanup Kodi Cpython instances''' self.cache.close() del self.win 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 load_widget(self): '''legacy entrypoint called (widgets are moved to seperate addon), start redirect...''' action = self.params.get("action", "") newaddon = "script.skin.helper.widgets" log_msg("Deprecated method: %s. Please reassign your widgets to get rid of this message. -" "This automatic redirect will be removed in the future" % (action), xbmc.LOGWARNING) paramstring = "" for key, value in self.params.iteritems(): paramstring += ",%s=%s" % (key, value) if xbmc.getCondVisibility("System.HasAddon(%s)" % newaddon): # TEMP !!! for backwards compatability reasons only - to be removed in the near future!! import imp addon = xbmcaddon.Addon(newaddon) addon_path = addon.getAddonInfo('path').decode("utf-8") imp.load_source('plugin', os.path.join(addon_path, "plugin.py")) from plugin import main main.Main() del addon else: # trigger install of the addon if KODI_VERSION > 16: xbmc.executebuiltin("InstallAddon(%s)" % newaddon) else: xbmc.executebuiltin("RunPlugin(plugin://%s)" % newaddon) def playchannel(self): '''play channel from widget helper''' params = {"item": {"channelid": int(self.params["channelid"])}} self.kodi_db.set_json("Player.Open", params) def playrecording(self): '''retrieve the recording and play to get resume working''' recording = self.kodi_db.recording(self.params["recordingid"]) params = {"item": {"recordingid": recording["recordingid"]}} self.kodi_db.set_json("Player.Open", params) # manually seek because passing resume to the player json cmd doesn't seem to work if recording["resume"].get("position"): for i in range(50): if xbmc.getCondVisibility("Player.HasVideo"): break xbmc.sleep(50) xbmc.Player().seekTime(recording["resume"].get("position")) def launch(self): '''launch any builtin action using a plugin listitem''' if "runscript" in self.params["path"]: self.params["path"] = self.params["path"].replace("?", ",") xbmc.executebuiltin(self.params["path"]) def playalbum(self): '''helper to play an entire album''' xbmc.executeJSONRPC( '{ "jsonrpc": "2.0", "method": "Player.Open", "params": { "item": { "albumid": %d } }, "id": 1 }' % int(self.params["albumid"])) def smartshortcuts(self): '''called from skinshortcuts to retrieve listing of all smart shortcuts''' import skinshortcuts skinshortcuts.get_smartshortcuts(self.params.get("path", "")) @staticmethod def backgrounds(): '''called from skinshortcuts to retrieve listing of all backgrounds''' import skinshortcuts skinshortcuts.get_backgrounds() def widgets(self): '''called from skinshortcuts to retrieve listing of all widgetss''' import skinshortcuts skinshortcuts.get_widgets(self.params.get("path", ""), self.params.get("sublevel", "")) def resourceimages(self): '''retrieve listing of specific resource addon images''' from resourceaddons import get_resourceimages addontype = self.params.get("addontype", "") for item in get_resourceimages(addontype, True): listitem = xbmcgui.ListItem(item[0], label2=item[2], path=item[1], iconImage=item[3]) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item[1], listitem=listitem, isFolder=False) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def extrafanart(self): '''helper to display extrafanart in multiimage control in the skin''' fanarts = eval(self.params["fanarts"]) # process extrafanarts for item in fanarts: listitem = xbmcgui.ListItem(item, path=item) listitem.setProperty('mimetype', 'image/jpeg') xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item, listitem=listitem) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def genrebackground(self): '''helper to display images for a specific genre in multiimage control in the skin''' genre = self.params.get("genre").split(".")[0] arttype = self.params.get("arttype", "fanart") randomize = self.params.get("random", "false") == "true" mediatype = self.params.get("mediatype", "movies") if genre and genre != "..": filters = [{"operator": "is", "field": "genre", "value": genre}] if randomize: sort = {"method": "random", "order": "descending"} else: sort = {"method": "sorttitle", "order": "ascending"} items = getattr(self.kodi_db, mediatype)( sort=sort, filters=filters, limits=(0, 50)) for item in items: image = get_clean_image(item["art"].get(arttype, "")) if image: image = get_clean_image(item["art"][arttype]) listitem = xbmcgui.ListItem(image, path=image) listitem.setProperty('mimetype', 'image/jpeg') xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=image, listitem=listitem) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def getcastmedia(self): '''helper to display get all media for a specific actor''' name = self.params.get("name") if name: all_items = self.kodi_db.castmedia(name) all_items = process_method_on_list(self.kodi_db.prepare_listitem, all_items) all_items = process_method_on_list(self.kodi_db.create_listitem, all_items) xbmcplugin.addDirectoryItems(int(sys.argv[1]), all_items, len(all_items)) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def getcast(self): '''helper to get all cast for a given media item''' db_id = None all_cast = [] all_cast_names = list() cache_str = "" download_thumbs = self.params.get("downloadthumbs", "") == "true" extended_cast_action = self.params.get("castaction", "") == "extendedinfo" tmdb = Tmdb() movie = self.params.get("movie") tvshow = self.params.get("tvshow") episode = self.params.get("episode") movieset = self.params.get("movieset") try: # try to parse db_id if movieset: cache_str = "movieset.castcache-%s-%s" % (self.params["movieset"], download_thumbs) db_id = int(movieset) elif tvshow: cache_str = "tvshow.castcache-%s-%s" % (self.params["tvshow"], download_thumbs) db_id = int(tvshow) elif movie: cache_str = "movie.castcache-%s-%s" % (self.params["movie"], download_thumbs) db_id = int(movie) elif episode: cache_str = "episode.castcache-%s-%s" % (self.params["episode"], download_thumbs) db_id = int(episode) except Exception: pass cachedata = self.cache.get(cache_str) if cachedata: # get data from cache all_cast = cachedata else: # retrieve data from json api... if movie and db_id: all_cast = self.kodi_db.movie(db_id)["cast"] elif movie and not db_id: filters = [{"operator": "is", "field": "title", "value": movie}] result = self.kodi_db.movies(filters=filters) all_cast = result[0]["cast"] if result else [] elif tvshow and db_id: all_cast = self.kodi_db.tvshow(db_id)["cast"] elif tvshow and not db_id: filters = [{"operator": "is", "field": "title", "value": tvshow}] result = self.kodi_db.tvshows(filters=filters) all_cast = result[0]["cast"] if result else [] elif episode and db_id: all_cast = self.kodi_db.episode(db_id)["cast"] elif episode and not db_id: filters = [{"operator": "is", "field": "title", "value": episode}] result = self.kodi_db.episodes(filters=filters) all_cast = result[0]["cast"] if result else [] elif movieset: if not db_id: for item in self.kodi_db.moviesets(): if item["title"].lower() == movieset.lower(): db_id = item["setid"] if db_id: json_result = self.kodi_db.movieset(db_id, include_set_movies_fields=["cast"]) if "movies" in json_result: for movie in json_result['movies']: all_cast += movie['cast'] # optional: download missing actor thumbs if all_cast and download_thumbs: for cast in all_cast: if cast.get("thumbnail"): cast["thumbnail"] = get_clean_image(cast.get("thumbnail")) if not cast.get("thumbnail"): artwork = tmdb.get_actor(cast["name"]) cast["thumbnail"] = artwork.get("thumb", "") # lookup tmdb if item is requested that is not in local db if not all_cast: tmdbdetails = {} if movie and not db_id: tmdbdetails = tmdb.search_movie(movie) elif tvshow and not db_id: tmdbdetails = tmdb.search_tvshow(tvshow) if tmdbdetails.get("cast"): all_cast = tmdbdetails["cast"] # save to cache self.cache.set(cache_str, all_cast) # process listing with the results... for cast in all_cast: if cast.get("name") not in all_cast_names: liz = xbmcgui.ListItem(label=cast.get("name"), label2=cast.get("role"), iconImage=cast.get("thumbnail")) if extended_cast_action: url = "RunScript(script.extendedinfo,info=extendedactorinfo,name=%s)" % cast.get("name") url = "plugin://script.skin.helper.service/?action=launch&path=%s" % url is_folder = False else: url = "RunScript(script.skin.helper.service,action=getcastmedia,name=%s)" % cast.get("name") url = "plugin://script.skin.helper.service/?action=launch&path=%s" % urlencode(url) is_folder = False all_cast_names.append(cast.get("name")) liz.setThumbnailImage(cast.get("thumbnail")) xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=liz, isFolder=is_folder) xbmcplugin.endOfDirectory(int(sys.argv[1])) @staticmethod def alphabet(): '''display an alphabet scrollbar in listings''' all_letters = [] if xbmc.getInfoLabel("Container.NumItems"): for i in range(int(xbmc.getInfoLabel("Container.NumItems"))): all_letters.append(xbmc.getInfoLabel("Listitem(%s).SortLetter" % i).upper()) start_number = "" for number in ["2", "3", "4", "5", "6", "7", "8", "9"]: if number in all_letters: start_number = number break for letter in [start_number, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]: if letter == start_number: label = "#" else: label = letter listitem = xbmcgui.ListItem(label=label) if letter not in all_letters: lipath = "noop" listitem.setProperty("NotAvailable", "true") else: lipath = "plugin://script.skin.helper.service/?action=alphabetletter&letter=%s" % letter xbmcplugin.addDirectoryItem(int(sys.argv[1]), lipath, listitem, isFolder=False) xbmcplugin.endOfDirectory(handle=int(sys.argv[1])) def alphabetletter(self): '''used with the alphabet scrollbar to jump to a letter''' if KODI_VERSION > 16: xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=False, listitem=xbmcgui.ListItem()) letter = self.params.get("letter", "").upper() jumpcmd = "" if letter in ["A", "B", "C", "2"]: jumpcmd = "2" elif letter in ["D", "E", "F", "3"]: jumpcmd = "3" elif letter in ["G", "H", "I", "4"]: jumpcmd = "4" elif letter in ["J", "K", "L", "5"]: jumpcmd = "5" elif letter in ["M", "N", "O", "6"]: jumpcmd = "6" elif letter in ["P", "Q", "R", "S", "7"]: jumpcmd = "7" elif letter in ["T", "U", "V", "8"]: jumpcmd = "8" elif letter in ["W", "X", "Y", "Z", "9"]: jumpcmd = "9" if jumpcmd: xbmc.executebuiltin("SetFocus(50)") for i in range(40): xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "method": "Input.ExecuteAction",\ "params": { "action": "jumpsms%s" }, "id": 1 }' % (jumpcmd)) xbmc.sleep(50) if xbmc.getInfoLabel("ListItem.Sortletter").upper() == letter: break
class MainModule: '''mainmodule provides the script methods for the skinhelper addon''' def __init__(self): '''Initialization and main code run''' self.win = xbmcgui.Window(10000) self.addon = xbmcaddon.Addon(ADDON_ID) self.kodidb = KodiDb() self.cache = SimpleCache() 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) finally: xbmc.executebuiltin("dialog.Close(busydialog)") # do cleanup self.close() def close(self): '''Cleanup Kodi Cpython instances on exit''' self.cache.close() del self.win del self.addon del self.kodidb log_msg("MainModule exited") @classmethod def get_params(self): '''extract the params from the called script path''' params = {} for arg in sys.argv[1:]: paramname = arg.split('=')[0] paramvalue = arg.replace(paramname + "=", "") paramname = paramname.lower() if paramname == "action": paramvalue = paramvalue.lower() params[paramname] = paramvalue return params def deprecated_method(self, newaddon): ''' used when one of the deprecated methods is called print warning in log and call the external script with the same parameters ''' action = self.params.get("action") log_msg( "Deprecated method: %s. Please call %s directly" % (action, newaddon), xbmc.LOGWARNING) paramstring = "" for key, value in self.params.iteritems(): paramstring += ",%s=%s" % (key, value) if xbmc.getCondVisibility("System.HasAddon(%s)" % newaddon): xbmc.executebuiltin("RunAddon(%s%s)" % (newaddon, paramstring)) else: # trigger install of the addon if KODI_VERSION > 16: xbmc.executebuiltin("InstallAddon(%s)" % newaddon) else: xbmc.executebuiltin("RunPlugin(plugin://%s)" % newaddon) @staticmethod def musicsearch(): '''helper to go directly to music search dialog''' xbmc.executebuiltin("ActivateWindow(Music)") xbmc.executebuiltin("SendClick(8)") def setview(self): '''sets the selected viewmode for the container''' xbmc.executebuiltin("ActivateWindow(busydialog)") content_type = get_current_content_type() if not content_type: content_type = "files" current_view = xbmc.getInfoLabel("Container.Viewmode").decode("utf-8") view_id, view_label = self.selectview(content_type, current_view) current_forced_view = xbmc.getInfoLabel( "Skin.String(SkinHelper.ForcedViews.%s)" % content_type) if view_id is not None: # also store forced view if (content_type and current_forced_view and current_forced_view != "None" and xbmc.getCondVisibility( "Skin.HasSetting(SkinHelper.ForcedViews.Enabled)")): xbmc.executebuiltin( "Skin.SetString(SkinHelper.ForcedViews.%s,%s)" % (content_type, view_id)) xbmc.executebuiltin( "Skin.SetString(SkinHelper.ForcedViews.%s.label,%s)" % (content_type, view_label)) self.win.setProperty("SkinHelper.ForcedView", view_id) if not xbmc.getCondVisibility( "Control.HasFocus(%s)" % current_forced_view): xbmc.sleep(100) xbmc.executebuiltin("Container.SetViewMode(%s)" % view_id) xbmc.executebuiltin("SetFocus(%s)" % view_id) else: self.win.clearProperty("SkinHelper.ForcedView") # set view xbmc.executebuiltin("Container.SetViewMode(%s)" % view_id) def selectview(self, content_type="other", current_view=None, display_none=False): '''reads skinfile with all views to present a dialog to choose from''' cur_view_select_id = None label = "" all_views = [] if display_none: listitem = xbmcgui.ListItem(label="None") listitem.setProperty("id", "None") all_views.append(listitem) # read the special skin views file views_file = xbmc.translatePath( 'special://skin/extras/views.xml').decode("utf-8") if xbmcvfs.exists(views_file): doc = parse(views_file) listing = doc.documentElement.getElementsByTagName('view') itemcount = 0 for view in listing: label = xbmc.getLocalizedString( int(view.attributes['languageid'].nodeValue)) viewid = view.attributes['value'].nodeValue mediatypes = view.attributes['type'].nodeValue.lower().split( ",") if label.lower() == current_view.lower( ) or viewid == current_view: cur_view_select_id = itemcount if display_none: cur_view_select_id += 1 if (("all" in mediatypes or content_type.lower() in mediatypes) and (not "!" + content_type.lower() in mediatypes) and not xbmc.getCondVisibility( "Skin.HasSetting(SkinHelper.view.Disabled.%s)" % viewid)): image = "special://skin/extras/viewthumbs/%s.jpg" % viewid listitem = xbmcgui.ListItem(label=label, iconImage=image) listitem.setProperty("viewid", viewid) listitem.setProperty("icon", image) all_views.append(listitem) itemcount += 1 dialog = DialogSelect("DialogSelect.xml", "", listing=all_views, windowtitle=self.addon.getLocalizedString(32012), richlayout=True) dialog.autofocus_id = cur_view_select_id dialog.doModal() result = dialog.result del dialog if result: viewid = result.getProperty("viewid") label = result.getLabel().decode("utf-8") return (viewid, label) else: return (None, None) # pylint: disable-msg=too-many-local-variables def enableviews(self): '''show select dialog to enable/disable views''' all_views = [] views_file = xbmc.translatePath( 'special://skin/extras/views.xml').decode("utf-8") richlayout = self.params.get("richlayout", "") == "true" if xbmcvfs.exists(views_file): doc = parse(views_file) listing = doc.documentElement.getElementsByTagName('view') for view in listing: view_id = view.attributes['value'].nodeValue label = xbmc.getLocalizedString( int(view.attributes['languageid'].nodeValue)) desc = label + " (" + str(view_id) + ")" image = "special://skin/extras/viewthumbs/%s.jpg" % view_id listitem = xbmcgui.ListItem(label=label, label2=desc, iconImage=image) listitem.setProperty("viewid", view_id) if not xbmc.getCondVisibility( "Skin.HasSetting(SkinHelper.view.Disabled.%s)" % view_id): listitem.select(selected=True) excludefromdisable = False try: excludefromdisable = view.attributes[ 'excludefromdisable'].nodeValue == "true" except Exception: pass if not excludefromdisable: all_views.append(listitem) dialog = DialogSelect("DialogSelect.xml", "", listing=all_views, windowtitle=self.addon.getLocalizedString(32013), multiselect=True, richlayout=richlayout) dialog.doModal() result = dialog.result del dialog if result: for item in result: view_id = item.getProperty("viewid") if item.isSelected(): # view is enabled xbmc.executebuiltin( "Skin.Reset(SkinHelper.view.Disabled.%s)" % view_id) else: # view is disabled xbmc.executebuiltin( "Skin.SetBool(SkinHelper.view.Disabled.%s)" % view_id) # pylint: enable-msg=too-many-local-variables def setforcedview(self): '''helper that sets a forced view for a specific content type''' content_type = self.params.get("contenttype") if content_type: current_view = xbmc.getInfoLabel( "Skin.String(SkinHelper.ForcedViews.%s)" % content_type) if not current_view: current_view = "0" view_id, view_label = self.selectview(content_type, current_view, True) if view_id or view_label: xbmc.executebuiltin( "Skin.SetString(SkinHelper.ForcedViews.%s,%s)" % (content_type, view_id)) xbmc.executebuiltin( "Skin.SetString(SkinHelper.ForcedViews.%s.label,%s)" % (content_type, view_label)) @staticmethod def get_youtube_listing(searchquery): '''get items from youtube plugin by query''' lib_path = u"plugin://plugin.video.youtube/kodion/search/query/?q=%s" % searchquery return KodiDb().files(lib_path) def searchyoutube(self): '''helper to search youtube for the given title''' xbmc.executebuiltin("ActivateWindow(busydialog)") title = self.params.get("title", "") window_header = self.params.get("header", "") results = [] for media in self.get_youtube_listing(title): if not media["filetype"] == "directory": label = media["label"] label2 = media["plot"] image = "" if media.get('art'): if media['art'].get('thumb'): image = (media['art']['thumb']) listitem = xbmcgui.ListItem(label=label, label2=label2, iconImage=image) listitem.setProperty("path", media["file"]) results.append(listitem) # finished lookup - display listing with results xbmc.executebuiltin("dialog.Close(busydialog)") dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=window_header, multiselect=False, richlayout=True) dialog.doModal() result = dialog.result del dialog if result: if xbmc.getCondVisibility( "Window.IsActive(script-skin_helper_service-CustomInfo.xml) | " "Window.IsActive(movieinformation)"): xbmc.executebuiltin("Dialog.Close(movieinformation)") xbmc.executebuiltin( "Dialog.Close(script-skin_helper_service-CustomInfo.xml)") xbmc.sleep(1000) xbmc.executebuiltin('PlayMedia("%s")' % result.getProperty("path")) del result def getcastmedia(self): '''helper to show a dialog with all media for a specific actor''' xbmc.executebuiltin("ActivateWindow(busydialog)") name = self.params.get("name", "") window_header = self.params.get("name", "") results = [] items = self.kodidb.castmedia(name) items = process_method_on_list(self.kodidb.prepare_listitem, items) for item in items: if item["file"].startswith("videodb://"): item[ "file"] = "ActivateWindow(Videos,%s,return)" % item["file"] else: item["file"] = 'PlayMedia("%s")' % item["file"] results.append(self.kodidb.create_listitem(item, False)) # finished lookup - display listing with results xbmc.executebuiltin("dialog.Close(busydialog)") dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=window_header, richlayout=True) dialog.doModal() result = dialog.result del dialog if result: while xbmc.getCondVisibility("System.HasModalDialog"): xbmc.executebuiltin("Action(Back)") xbmc.sleep(300) xbmc.executebuiltin(result.getfilename()) del result def setfocus(self): '''helper to set focus on a list or control''' control = self.params.get("control") fallback = self.params.get("fallback") position = self.params.get("position", "0") relativeposition = self.params.get("relativeposition") if relativeposition: position = int(relativeposition) - 1 count = 0 if control: while not xbmc.getCondVisibility("Control.HasFocus(%s)" % control): if xbmc.getCondVisibility("Window.IsActive(busydialog)"): xbmc.sleep(150) continue elif count == 20 or (xbmc.getCondVisibility( "!Control.IsVisible(%s) | " "!IntegerGreaterThan(Container(%s).NumItems,0)" % (control, control))): if fallback: xbmc.executebuiltin("Control.SetFocus(%s)" % fallback) break else: xbmc.executebuiltin("Control.SetFocus(%s,%s)" % (control, position)) xbmc.sleep(50) count += 1 def setwidgetcontainer(self): '''helper that reports the current selected widget container/control''' controls = self.params.get("controls", "").split("-") if controls: xbmc.sleep(50) for i in range(10): for control in controls: if xbmc.getCondVisibility( "Control.IsVisible(%s) + IntegerGreaterThan(Container(%s).NumItems,0)" % (control, control)): self.win.setProperty("SkinHelper.WidgetContainer", control) return xbmc.sleep(50) self.win.clearProperty("SkinHelper.WidgetContainer") def saveskinimage(self): '''let the user select an image and save it to addon_data for easy backup''' skinstring = self.params.get("skinstring", "") allow_multi = self.params.get("multi", "") == "true" header = self.params.get("header", "") value = SkinSettings().save_skin_image(skinstring, allow_multi, header) if value: xbmc.executebuiltin( "Skin.SetString(%s,%s)" % (skinstring.encode("utf-8"), value.encode("utf-8"))) @staticmethod def checkskinsettings(): '''performs check of all default skin settings and labels''' SkinSettings().correct_skin_settings() def setskinsetting(self): '''allows the user to set a skin setting with a select dialog''' setting = self.params.get("setting", "") org_id = self.params.get("id", "") if "$" in org_id: org_id = xbmc.getInfoLabel(org_id).decode("utf-8") header = self.params.get("header", "") SkinSettings().set_skin_setting(setting=setting, window_header=header, original_id=org_id) def setskinconstant(self): '''allows the user to set a skin constant with a select dialog''' setting = self.params.get("setting", "") value = self.params.get("value", "") header = self.params.get("header", "") SkinSettings().set_skin_constant(setting, header, value) def setskinconstants(self): '''allows the skinner to set multiple skin constants''' settings = self.params.get("settings", "").split("|") values = self.params.get("values", "").split("|") SkinSettings().set_skin_constants(settings, values) def setskinshortcutsproperty(self): '''allows the user to make a setting for skinshortcuts using the special skinsettings dialogs''' setting = self.params.get("setting", "") prop = self.params.get("property", "") header = self.params.get("header", "") SkinSettings().set_skinshortcuts_property(setting, header, prop) def togglekodisetting(self): '''toggle kodi setting''' settingname = self.params.get("setting", "") cur_value = xbmc.getCondVisibility("system.getbool(%s)" % settingname) if cur_value: new_value = "false" else: new_value = "true" xbmc.executeJSONRPC( '{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"%s","value":%s}}' % (settingname, new_value)) def setkodisetting(self): '''set kodi setting''' settingname = self.params.get("setting", "") value = self.params.get("value", "") is_int = False try: valueint = int(value) is_int = True del valueint except Exception: pass if value.lower() == "true": value = 'true' elif value.lower() == "false": value = 'false' elif is_int: value = '"%s"' % value xbmc.executeJSONRPC( '{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue",\ "params":{"setting":"%s","value":%s}}' % (settingname, value)) def playtrailer(self): '''auto play windowed trailer inside video listing''' if not xbmc.getCondVisibility( "Player.HasMedia | Container.Scrolling | Container.OnNext | " "Container.OnPrevious | !IsEmpty(Window(Home).Property(traileractionbusy))" ): self.win.setProperty("traileractionbusy", "traileractionbusy") widget_container = self.params.get("widgetcontainer", "") trailer_mode = self.params.get("mode", "").replace("auto_", "") allow_youtube = self.params.get("youtube", "") == "true" if not trailer_mode: trailer_mode = "windowed" if widget_container: widget_container_prefix = "Container(%s)." % widget_container else: widget_container_prefix = "" li_title = xbmc.getInfoLabel( "%sListItem.Title" % widget_container_prefix).decode('utf-8') li_trailer = xbmc.getInfoLabel( "%sListItem.Trailer" % widget_container_prefix).decode('utf-8') if not li_trailer and allow_youtube: youtube_result = self.get_youtube_listing("%s Trailer" % li_title) if youtube_result: li_trailer = youtube_result[0].get("file") # always wait a bit to prevent trailer start playing when we're scrolling the list xbmc.Monitor().waitForAbort(3) if li_trailer and (li_title == xbmc.getInfoLabel( "%sListItem.Title" % widget_container_prefix).decode('utf-8')): if trailer_mode == "fullscreen" and li_trailer: xbmc.executebuiltin('PlayMedia("%s")' % li_trailer) else: xbmc.executebuiltin('PlayMedia("%s",1)' % li_trailer) self.win.setProperty("TrailerPlaying", trailer_mode) self.win.clearProperty("traileractionbusy") def colorpicker(self): '''legacy''' self.deprecated_method("script.skin.helper.colorpicker") def backup(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def restore(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def reset(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def colorthemes(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def createcolortheme(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def restorecolortheme(self): '''legacy''' self.deprecated_method("script.skin.helper.skinbackup") def conditionalbackgrounds(self): '''legacy''' self.deprecated_method("script.skin.helper.backgrounds") def splashscreen(self): '''helper to show a user defined splashscreen in the skin''' import time splashfile = self.params.get("file", "") duration = int(self.params.get("duration", 5)) if (splashfile.lower().endswith("jpg") or splashfile.lower().endswith("gif") or splashfile.lower().endswith("png") or splashfile.lower().endswith("tiff")): # this is an image file self.win.setProperty("SkinHelper.SplashScreen", splashfile) # for images we just wait for X seconds to close the splash again start_time = time.time() while (time.time() - start_time) <= duration: xbmc.sleep(500) else: # for video or audio we have to wait for the player to finish... xbmc.Player().play(splashfile, windowed=True) xbmc.sleep(500) while xbmc.getCondVisibility("Player.HasMedia"): xbmc.sleep(150) # replace startup window with home startupwindow = xbmc.getInfoLabel("System.StartupWindow") xbmc.executebuiltin("ReplaceWindow(%s)" % startupwindow) autostart_playlist = xbmc.getInfoLabel( "$ESCINFO[Skin.String(autostart_playlist)]") if autostart_playlist: xbmc.executebuiltin("PlayMedia(%s)" % autostart_playlist) def videosearch(self): '''show the special search dialog''' xbmc.executebuiltin("ActivateWindow(busydialog)") from resources.lib.searchdialog import SearchDialog search_dialog = SearchDialog( "script-skin_helper_service-CustomSearch.xml", self.addon.getAddonInfo('path').decode("utf-8"), "Default", "1080i") search_dialog.doModal() del search_dialog def showinfo(self): '''shows our special videoinfo dialog''' dbid = self.params.get("dbid", "") dbtype = self.params.get("dbtype", "") from infodialog import show_infodialog show_infodialog(dbid, dbtype) def deletedir(self): '''helper to delete a directory, input can be normal filesystem path or vfs''' del_path = self.params.get("path") if del_path: ret = xbmcgui.Dialog().yesno( heading=xbmc.getLocalizedString(122), line1=u"%s[CR]%s" % (xbmc.getLocalizedString(125), del_path)) if ret: success = recursive_delete_dir(del_path) if success: xbmcgui.Dialog().ok( heading=xbmc.getLocalizedString(19179), line1=self.addon.getLocalizedString(32014)) else: xbmcgui.Dialog().ok(heading=xbmc.getLocalizedString(16205), line1=xbmc.getLocalizedString(32015)) def overlaytexture(self): '''legacy: helper to let the user choose a background overlay from a skin defined folder''' skinstring = self.params.get("skinstring", "BackgroundOverlayTexture") self.params["skinstring"] = skinstring self.params["resourceaddon"] = "resource.images.backgroundoverlays" self.params["customfolder"] = "special://skin/extras/bgoverlays/" self.params["allowmulti"] = "false" self.params["header"] = self.addon.getLocalizedString(32002) self.selectimage() def busytexture(self): '''legacy: helper which lets the user select a busy spinner from predefined spinners in the skin''' skinstring = self.params.get("skinstring", "SkinHelper.SpinnerTexture") self.params["skinstring"] = skinstring self.params["resourceaddon"] = "resource.images.busyspinners" self.params["customfolder"] = "special://skin/extras/busy_spinners/" self.params["allowmulti"] = "true" self.params["header"] = self.addon.getLocalizedString(32006) self.selectimage() def selectimage(self): '''helper which lets the user select an image or imagepath from resourceaddons or custom path''' skinsettings = SkinSettings() skinstring = self.params.get("skinstring", "") skinshortcutsprop = self.params.get("skinshortcutsproperty", "") current_value = self.params.get("currentvalue", "") resource_addon = self.params.get("resourceaddon", "") allow_multi = self.params.get("allowmulti", "false") == "true" windowheader = self.params.get("header", "") skinhelper_backgrounds = self.params.get("skinhelperbackgrounds", "false") == "true" label, value = skinsettings.select_image( skinstring, allow_multi=allow_multi, windowheader=windowheader, resource_addon=resource_addon, skinhelper_backgrounds=skinhelper_backgrounds, current_value=current_value) if label: if skinshortcutsprop: # write value to skinshortcuts prop from skinshortcuts import set_skinshortcuts_property set_skinshortcuts_property(skinshortcutsprop, value, label) else: # write the values to skin strings if value.startswith("$INFO"): # we got an dynamic image from window property skinsettings.set_skin_variable(skinstring, value) value = "$VAR[%s]" % skinstring skinstring = skinstring.encode("utf-8") label = label.encode("utf-8") xbmc.executebuiltin("Skin.SetString(%s.label,%s)" % (skinstring, label)) xbmc.executebuiltin("Skin.SetString(%s.name,%s)" % (skinstring, label)) xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring, value)) xbmc.executebuiltin("Skin.SetString(%s.path,%s)" % (skinstring, value)) del skinsettings def dialogok(self): '''helper to show an OK dialog with a message''' headertxt = self.params.get("header") bodytxt = self.params.get("message") if bodytxt.startswith(" "): bodytxt = bodytxt[1:] if headertxt.startswith(" "): headertxt = headertxt[1:] dialog = xbmcgui.Dialog() dialog.ok(heading=headertxt, line1=bodytxt) del dialog def dialogyesno(self): '''helper to show a YES/NO dialog with a message''' headertxt = self.params.get("header") bodytxt = self.params.get("message") yesactions = self.params.get("yesaction", "").split("|") noactions = self.params.get("noaction", "").split("|") if bodytxt.startswith(" "): bodytxt = bodytxt[1:] if headertxt.startswith(" "): headertxt = headertxt[1:] if xbmcgui.Dialog().yesno(heading=headertxt, line1=bodytxt): for action in yesactions: xbmc.executebuiltin(action.encode("utf-8")) else: for action in noactions: xbmc.executebuiltin(action.encode("utf-8")) def textviewer(self): '''helper to show a textviewer dialog with a message''' headertxt = self.params.get("header", "") bodytxt = self.params.get("message", "") if bodytxt.startswith(" "): bodytxt = bodytxt[1:] if headertxt.startswith(" "): headertxt = headertxt[1:] xbmcgui.Dialog().textviewer(headertxt, bodytxt) def fileexists(self): '''helper to let the skinner check if a file exists and write the outcome to a window prop or skinstring''' filename = self.params.get("file") skinstring = self.params.get("skinstring") windowprop = self.params.get("winprop") if xbmcvfs.exists(filename): if windowprop: self.win.setProperty(windowprop, "exists") if skinstring: xbmc.executebuiltin("Skin.SetString(%s,exists)" % skinstring) else: if windowprop: self.win.clearProperty(windowprop) if skinstring: xbmc.executebuiltin("Skin.Reset(%s)" % skinstring) def stripstring(self): '''helper to allow the skinner to strip a string and write results to a skin string''' splitchar = self.params.get("splitchar") if splitchar.upper() == "[SPACE]": splitchar = " " skinstring = self.params.get("string") if not skinstring: skinstring = self.params.get("skinstring") output = self.params.get("output") index = self.params.get("index", 0) skinstring = skinstring.split(splitchar)[int(index)] self.win.setProperty(output, skinstring) def getfilename(self, filename=""): '''helper to display a sanitized filename in the vidoeinfo dialog''' output = self.params.get("output") if not filename: filename = xbmc.getInfoLabel("ListItem.FileNameAndPath") if not filename: filename = xbmc.getInfoLabel("ListItem.FileName") if "filename=" in filename: url_params = dict(urlparse.parse_qsl(filename)) filename = url_params.get("filename") self.win.setProperty(output, filename) def getplayerfilename(self): '''helper to parse the filename from a plugin (e.g. emby) filename''' filename = xbmc.getInfoLabel("Player.FileNameAndPath") if not filename: filename = xbmc.getInfoLabel("Player.FileName") self.getfilename(filename) def getpercentage(self): '''helper to calculate the percentage of 2 numbers and write results to a skinstring''' total = int(params.get("total")) count = int(params.get("count")) roundsteps = self.params.get("roundsteps") skinstring = self.params.get("skinstring") percentage = int(round((1.0 * count / total) * 100)) if roundsteps: roundsteps = int(roundsteps) percentage = percentage + (roundsteps - percentage) % roundsteps xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring, percentage)) def setresourceaddon(self): '''helper to let the user choose a resource addon and set that as skin string''' from resourceaddons import setresourceaddon addontype = self.params.get("addontype", "") skinstring = self.params.get("skinstring", "") setresourceaddon(addontype, skinstring) def checkresourceaddons(self): '''allow the skinner to perform a basic check if some required resource addons are available''' from resourceaddons import checkresourceaddons addonslist = self.params.get("addonslist", []) if addonslist: addonslist = addonslist.split("|") checkresourceaddons(addonslist)
class SearchBackgroundThread(threading.Thread): '''Background thread to complement our search dialog, fills the listing while UI keeps responsive''' active = True dialog = None search_string = "" def __init__(self, *args): xbmc.log("SearchBackgroundThread Init") threading.Thread.__init__(self, *args) self.kodidb = KodiDb() self.actors = [] thread.start_new_thread(self.set_actors, ()) def set_search(self, searchstr): '''set search query''' self.search_string = searchstr def stop_running(self): '''stop thread end exit''' self.active = False def set_dialog(self, dialog): '''set the active dialog to perform actions''' self.dialog = dialog def set_actors(self): '''fill list with all actors''' self.actors = self.kodidb.actors() def run(self): '''Main run loop for the background thread''' last_searchstring = "" monitor = xbmc.Monitor() while not monitor.abortRequested() and self.active: if self.search_string != last_searchstring: last_searchstring = self.search_string self.do_search(self.search_string) monitor.waitForAbort(1) del monitor def do_search(self, search_term): '''scrape results for search query''' movies_list = self.dialog.getControl(3110) series_list = self.dialog.getControl(3111) cast_list = self.dialog.getControl(3112) # clear current values movies_list.reset() series_list.reset() cast_list.reset() if len(search_term) == 0: return filters = [{"operator": "contains", "field": "title", "value": search_term}] # Process movies items = self.kodidb.movies(filters=filters) items = process_method_on_list(self.kodidb.prepare_listitem, items) result = [] for item in items: result.append(self.kodidb.create_listitem(item, False)) movies_list.addItems(result) # Process tvshows items = self.kodidb.tvshows(filters=filters) items = process_method_on_list(self.kodidb.prepare_listitem, items) result = [] for item in items: item["file"] = 'videodb://tvshows/titles/%s' % item['tvshowid'] item["isFolder"] = True result.append(self.kodidb.create_listitem(item, False)) series_list.addItems(result) # Process cast result = [] for item in self.actors: if search_term.lower() in item["label"].lower(): item = self.kodidb.prepare_listitem(item) item["file"] = "RunScript(script.skin.helper.service,action=getcastmedia,name=%s)" % item["label"] result.append(self.kodidb.create_listitem(item, False)) cast_list.addItems(result)
def __init__(self, *args): xbmc.log("SearchBackgroundThread Init") threading.Thread.__init__(self, *args) self.kodidb = KodiDb() self.actors = [] thread.start_new_thread(self.set_actors, ())
class BackgroundsUpdater(): '''Background service providing rotating backgrounds to Kodi skins''' exit = False all_backgrounds = {} all_backgrounds2 = {} all_backgrounds_labels = [] backgrounds_delay = 0 walls_delay = 30 enable_walls = False all_backgrounds_keys = {} prefetch_images = 30 # number of images to cache in memory for each library path pvr_bg_recordingsonly = False custom_picturespath = "" winprops = {} def __init__(self): self.cache = SimpleCache() self.kodidb = KodiDb() self.win = xbmcgui.Window(10000) self.addon = xbmcaddon.Addon(ADDON_ID) self.kodimonitor = xbmc.Monitor() self.smartshortcuts = SmartShortCuts(self) self.wallimages = WallImages(self) def stop(self): '''stop running our background service ''' log_msg("BackgroundsUpdater - stop called", xbmc.LOGNOTICE) self.smartshortcuts.exit = True self.wallimages.exit = True self.exit = True xbmc.sleep(100) # allow threads to process the stop request del self.smartshortcuts del self.wallimages del self.win del self.kodimonitor del self.addon def run(self): '''called to start our background service ''' log_msg("BackgroundsUpdater - started", xbmc.LOGNOTICE) self.winpropcache() self.get_config() backgrounds_task_interval = 0 walls_task_interval = 0 delayed_task_interval = 112 while not self.kodimonitor.abortRequested(): # Process backgrounds only if we're not watching fullscreen video if xbmc.getCondVisibility( "![Window.IsActive(fullscreenvideo) | Window.IsActive(script.pseudotv.TVOverlay.xml) | " "Window.IsActive(script.pseudotv.live.TVOverlay.xml)] | " "Window.IsActive(script.pseudotv.live.EPG.xml)"): # background stuff like reading the skin settings and generating smart shortcuts if delayed_task_interval >= 120: delayed_task_interval = 0 self.get_config() self.report_allbackgrounds() self.smartshortcuts.build_smartshortcuts() self.winpropcache(True) # force refresh smart shortcuts on request if self.win.getProperty("refreshsmartshortcuts"): self.win.clearProperty("refreshsmartshortcuts") self.smartshortcuts.build_smartshortcuts() # Update home backgrounds every interval (if enabled by skinner) if self.backgrounds_delay and backgrounds_task_interval >= self.backgrounds_delay: backgrounds_task_interval = 0 self.update_backgrounds() # Update wall images every interval (if enabled by skinner) if self.enable_walls and self.walls_delay and ( walls_task_interval >= self.walls_delay): walls_task_interval = 0 thread.start_new_thread( self.wallimages.update_wallbackgrounds, ()) self.wallimages.update_manualwalls() self.kodimonitor.waitForAbort(1) backgrounds_task_interval += 1 walls_task_interval += 1 delayed_task_interval += 1 # abort requested self.stop() def get_config(self): '''gets various settings for the script as set by the skinner or user''' # set all backgrounds in global cache for quick startup self.winpropcache(True) # 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.iterkeys(): 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 report_allbackgrounds(self): '''sets a list of all known backgrounds as winprop to be retrieved from skinshortcuts''' if self.all_backgrounds_labels: self.set_winprop("SkinHelper.AllBackgrounds", repr(self.all_backgrounds_labels)) def set_winprop(self, key, value): '''sets a window property and writes it to our global list''' self.winprops[key] = value if isinstance(value, unicode): value = value.encode("utf-8") self.win.setProperty(key, value) def winpropcache(self, setcache=False): '''sets/gets the current window props in a global cache to load them immediately at startup''' if setcache: self.cache.set("skinhelper.backgrounds", self.winprops) else: cache = self.cache.get("skinhelper.backgrounds") if cache: for key, value in cache.iteritems(): if value: if isinstance(value, unicode): value = value.encode("utf-8") self.win.setProperty(key.encode("utf-8"), value) def get_images_from_vfspath(self, lib_path): '''get all images from the given vfs path''' result = [] # safety check: check if no library windows are active to prevent any addons setting the view if (xbmc.getCondVisibility("Window.IsMedia") and "plugin" in lib_path) or self.exit: return result lib_path = get_content_path(lib_path) if "plugin.video.emby" in lib_path and "browsecontent" in lib_path and "filter" not in lib_path: lib_path = lib_path + "&filter=random" items = self.kodidb.get_json( "Files.GetDirectory", returntype="", optparam=("directory", lib_path), fields=["title", "art", "thumbnail", "fanart"], sort={ "method": "random", "order": "descending" }, limits=(0, self.prefetch_images)) for media in items: image = {} if media['label'].lower() == "next page": continue if media.get('art'): if media['art'].get('fanart'): image["fanart"] = get_clean_image(media['art']['fanart']) elif media['art'].get('tvshow.fanart'): image["fanart"] = get_clean_image( media['art']['tvshow.fanart']) elif media['art'].get('artist.fanart'): image["fanart"] = get_clean_image( media['art']['artist.fanart']) if media['art'].get('thumb'): image["thumbnail"] = get_clean_image(media['art']['thumb']) if not image.get('fanart') and media.get("fanart"): image["fanart"] = get_clean_image(media['fanart']) if not image.get("thumbnail") and media.get("thumbnail"): image["thumbnail"] = get_clean_image(media["thumbnail"]) # only append items which have a fanart image if image.get("fanart"): # also append other art to the dict image["title"] = media.get('title', '') if not image.get("title"): image["title"] = media.get('label', '') image["landscape"] = get_clean_image( media.get('art', {}).get('landscape', '')) image["poster"] = get_clean_image( media.get('art', {}).get('poster', '')) image["clearlogo"] = get_clean_image( media.get('art', {}).get('clearlogo', '')) result.append(image) random.shuffle(result) return result def get_pictures(self): '''get images we can use as pictures background''' images = [] # load the pictures from the custom path or from all picture sources if self.custom_picturespath: # load images from custom path files = xbmcvfs.listdir(self.custom_picturespath)[1] random.shuffle(files) # pick max 20 images from path for file in files[:20]: if file.lower().endswith(".jpg") or file.lower().endswith( ".png"): image = os.path.join(self.custom_picturespath, file.decode("utf-8")) images.append({ "fanart": image, "title": file.decode("utf-8") }) else: # load pictures from all picture sources media_array = self.kodidb.get_json('Files.GetSources', optparam=("media", "pictures")) randomdirs = [] for source in media_array: if 'file' in source: if "plugin://" not in source["file"]: dirs = xbmcvfs.listdir(source["file"])[0] random.shuffle(dirs) # randomize output if dirs: # pick 10 subdirectories for randomdir in dirs[:10]: randomdir = os.path.join( source["file"], randomdir.decode("utf-8")) randomdirs.append(randomdir) # append root to dirs so we can also list images in the root randomdirs.append(source["file"]) # pick 5 images from each dir for item in randomdirs: files2 = xbmcvfs.listdir(item)[1] random.shuffle(files2) for count, filename in enumerate(files2): if (filename.endswith(".jpg") or filename.endswith(".png") ) and count < 6: filename = filename.decode("utf-8") image = os.path.join(item, filename) images.append({ "fanart": image, "title": filename }) return images def set_background(self, win_prop, lib_path, fallback_image="", label=None): '''set the window property for the background image''' image = None if win_prop in self.all_backgrounds2: # pick one random image from the small list using normal random function if len(self.all_backgrounds2[win_prop]) > 0: image = random.choice(self.all_backgrounds2[win_prop]) elif win_prop in self.all_backgrounds and len( self.all_backgrounds[win_prop]) > 0: # list is already in memory and still contains images, grab the next item in line image = self.all_backgrounds[win_prop][0] # delete image from list when we've used it so we have truly randomized images del self.all_backgrounds[win_prop][0] else: # no images in memory - load them from vfs if isinstance(lib_path, list): images = self.get_global_backgrounds(lib_path) elif lib_path == "pictures": images = self.get_pictures() elif lib_path == "pvr": images = self.get_pvr_backgrounds() else: images = self.get_images_from_vfspath(lib_path) # store images in memory if len(images) < self.prefetch_images: # this path did not return enough images so we store it in a different list # which will not be flushed self.all_backgrounds2[win_prop] = images if images: image = random.choice(images) else: # normal approach: store the current set of images in a list # images are taken from that list one-by-one untill it's empty # once empty a fresh pair of images will be retrieved for the path # this way we have fully randomized images while there's no need # to store a big pile of data in memory image = images[0] del images[0] self.all_backgrounds[win_prop] = images # also store the key + label in a list for skinshortcuts - only if the path actually has images if image: if not any(win_prop in item for item in self.all_backgrounds_labels): if label and isinstance(label, int): label = xbmc.getInfoLabel("$ADDON[%s %s]" % (ADDON_ID, label)) elif not label: label = win_prop self.all_backgrounds_labels.append((win_prop, label)) # set the image if image: for key, value in image.iteritems(): # image is actually a dict if key == "fanart": self.set_winprop(win_prop, value) else: # set additional image properties self.set_winprop("%s.%s" % (win_prop, key), value) else: # no image - use fallback_image self.set_winprop(win_prop, fallback_image) def get_global_backgrounds(self, keys): '''get random backgrounds from multiple other collections''' images = [] for key in keys: if key in self.all_backgrounds and self.all_backgrounds[key]: images += self.all_backgrounds[key] random.shuffle(images) return images def get_pvr_backgrounds(self): '''get the images for pvr items by using the skinhelper widgets as source''' images = [] widgetreload = self.win.getProperty("widgetreload2") rec_images = self.get_images_from_vfspath( "plugin://script.skin.helper.widgets/?mediatype=pvr" "&action=recordings&limit=50&reload=%s" % widgetreload) if rec_images: # result can be None images = rec_images if not self.pvr_bg_recordingsonly: tv_images = self.get_images_from_vfspath( "plugin://script.skin.helper.widgets/?mediatype=pvr" "&action=channels&limit=25&reload=%s" % widgetreload) if tv_images: # result can be None images += tv_images return images def update_backgrounds(self): '''update all our provided backgrounds''' # conditional background self.win.setProperty("SkinHelper.ConditionalBackground", get_cond_background()) # movies backgrounds if xbmc.getCondVisibility("Library.HasContent(movies)"): # random/all movies self.set_background("SkinHelper.AllMoviesBackground", "videodb://movies/titles/", label=32010) # in progress movies self.set_background( "SkinHelper.InProgressMoviesBackground", "videodb://movies/titles/?xsp=%s" % urlencode( '{"limit":50,"order":{"direction":"ascending","method":"random"},' '"rules":{"and":[{"field":"inprogress","operator":"true","value":[]}]},"type":"movies"}' ), label=32012) # recent movies self.set_background("SkinHelper.RecentMoviesBackground", "videodb://recentlyaddedmovies/", label=32011) # unwatched movies self.set_background( "SkinHelper.UnwatchedMoviesBackground", "videodb://movies/titles/?xsp=%s" % urlencode( '{"limit":50,"order":{"direction":"ascending","method":"random"},' '"rules":{"and":[{"field":"playcount","operator":"is","value":0}]},"type":"movies"}' ), label=32013) # tvshows backgrounds if xbmc.getCondVisibility("Library.HasContent(tvshows)"): # random/all tvshows self.set_background("SkinHelper.AllTvShowsBackground", "videodb://tvshows/titles/", label=32014) # in progress tv shows self.set_background( "SkinHelper.InProgressShowsBackground", "videodb://tvshows/titles/?xsp=%s" % urlencode( '{"limit":50,"order":{"direction":"ascending","method":"random"},' '"rules":{"and":[{"field":"inprogress","operator":"true","value":[]}]},"type":"tvshows"}' ), label=32016) # recent episodes self.set_background("SkinHelper.RecentEpisodesBackground", "videodb://recentlyaddedepisodes/", label=32015) # all musicvideos if xbmc.getCondVisibility("Library.HasContent(musicvideos)"): self.set_background("SkinHelper.AllMusicVideosBackground", "videodb://musicvideos/titles", label=32018) # all music if xbmc.getCondVisibility("Library.HasContent(music)"): # music artists self.set_background("SkinHelper.AllMusicBackground", "musicdb://artists/", label=32019) # recent albums self.set_background("SkinHelper.RecentMusicBackground", "musicdb://recentlyaddedalbums/", label=32023) # random songs self.set_background("SkinHelper.AllMusicSongsBackground", "musicdb://songs/", label=32022) # tmdb backgrounds (extendedinfo) if xbmc.getCondVisibility("System.HasAddon(script.extendedinfo)"): self.set_background( "SkinHelper.TopRatedMovies", "plugin://script.extendedinfo/?info=topratedmovies", label=32020) self.set_background( "SkinHelper.TopRatedShows", "plugin://script.extendedinfo/?info=topratedtvshows", label=32021) # pictures background self.set_background("SkinHelper.PicturesBackground", "pictures", label=32017) # pvr background if xbmc.getCondVisibility("PVR.HasTvChannels"): self.set_background("SkinHelper.PvrBackground", "pvr", label=32024) # smartshortcuts backgrounds for node in self.smartshortcuts.get_smartshortcuts_nodes(): self.set_background(node[0], node[1], label=node[2]) # global backgrounds self.set_background("SkinHelper.GlobalFanartBackground", [ "SkinHelper.AllMoviesBackground", "SkinHelper.AllTvShowsBackground", "SkinHelper.AllMusicVideosBackground", "SkinHelper.AllMusicBackground" ], label=32009) self.set_background("SkinHelper.AllVideosBackground", [ "SkinHelper.AllMoviesBackground", "SkinHelper.AllTvShowsBackground", "SkinHelper.AllMusicVideosBackground" ], label=32025) self.set_background("SkinHelper.AllVideosBackground2", [ "SkinHelper.AllMoviesBackground", "SkinHelper.AllTvShowsBackground" ], label=32026) self.set_background("SkinHelper.RecentVideosBackground", [ "SkinHelper.RecentMoviesBackground", "SkinHelper.RecentEpisodesBackground" ], label=32027) self.set_background("SkinHelper.InProgressVideosBackground", [ "SkinHelper.InProgressMoviesBackground", "SkinHelper.InProgressShowsBackground" ], label=32028)