def __init__(self):
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.metadatautils = MetadataUtils()
        self.addonname = self.addon.getAddonInfo('name').decode("utf-8")
        self.addonversion = self.addon.getAddonInfo('version').decode("utf-8")
        self.kodimonitor = KodiMonitor(metadatautils=self.metadatautils, win=self.win)
        self.listitem_monitor = ListItemMonitor(
            metadatautils=self.metadatautils, win=self.win, monitor=self.kodimonitor)
        self.webservice = WebService(self.metadatautils)
        self.win.clearProperty("SkinHelperShutdownRequested")

        # start the extra threads
        self.listitem_monitor.start()
        self.webservice.start()
        
        log_msg('%s version %s started' % (self.addonname, self.addonversion), xbmc.LOGNOTICE)

        # run as service, check skin every 10 seconds and keep the other threads alive
        while not self.kodimonitor.abortRequested():

            # check skin version info
            self.check_skin_version()

            # sleep for 10 seconds
            self.kodimonitor.waitForAbort(10)

        # Abort was requested while waiting. We should exit
        self.close()
def favourites_widgets():
    """widgets from favourites"""
    favourites = kodi_json(
        'Favourites.GetFavourites', {
            "type": None,
            "properties": ["path", "thumbnail", "window", "windowparameter"]
        })
    widgets = []
    if favourites:
        for fav in favourites:
            if "windowparameter" in fav:
                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()):
                    label = fav["title"]
                    log_msg("skinshortcuts widgets processing favourite: %s" %
                            label)
                    mutils = MetadataUtils()
                    mediatype = mutils.detect_plugin_content(content)
                    del mutils
                    if mediatype and mediatype != "empty":
                        widgets.append([label, content, mediatype])
    return widgets
Ejemplo n.º 3
0
def getMeta(label, type='tvshows', yrs=''):
    metadatautils = MetadataUtils()
    metadatautils.tmdb.api_key = '9c47d05a3f5f3a00104f6586412306af'
    return metadatautils.get_tmdb_details(title=label,
                                          year=yrs,
                                          media_type=type,
                                          manual_select=False)
def playlists_widgets():
    '''skin provided playlists'''
    widgets = []
    import xml.etree.ElementTree as xmltree
    for playlist_path in ["special://skin/playlists/",
                          "special://skin/extras/widgetplaylists/", "special://skin/extras/playlists/"]:
        if xbmcvfs.exists(playlist_path):
            log_msg("skinshortcuts widgets processing: %s" % playlist_path)
            media_array = kodi_json('Files.GetDirectory', {"directory": playlist_path, "media": "files"})
            for item in media_array:
                if item["file"].endswith(".xsp"):
                    playlist = item["file"]
                    contents = xbmcvfs.File(item["file"], 'r')
                    contents_data = contents.read().decode('utf-8')
                    contents.close()
                    xmldata = xmltree.fromstring(contents_data.encode('utf-8'))
                    media_type = ""
                    label = item["label"]
                    for line in xmldata.getiterator():
                        if line.tag == "smartplaylist":
                            media_type = line.attrib['type']
                        if line.tag == "name":
                            label = line.text
                    try:
                        languageid = int(label)
                        label = xbmc.getLocalizedString(languageid)
                    except Exception:
                        pass
                    if not media_type:
                        mutils = MetadataUtils()
                        media_type = mutils.detect_plugin_content(playlist)
                        del mutils
                    widgets.append([label, playlist, media_type])
    return widgets
def plugin_widgetlisting(pluginpath, sublevel=""):
    """get all nodes in a plugin listing"""
    widgets = []
    if sublevel:
        media_array = kodi_json('Files.GetDirectory', {
            "directory": pluginpath,
            "media": "files"
        })
    else:
        if not getCondVisibility("System.HasAddon(%s)" % pluginpath):
            return []
        media_array = kodi_json('Files.GetDirectory', {
            "directory": "plugin://%s" % pluginpath,
            "media": "files"
        })
    for item in media_array:
        log_msg("skinshortcuts widgets processing: %s" % (item["file"]))
        content = item["file"]
        label = item["label"]
        # extendedinfo has some login-required widgets, skip those
        if ("script.extendedinfo" in pluginpath and not EXTINFO_CREDS
                and ("info=starred" in content or "info=rated" in content
                     or "info=account" in content)):
            continue
        if item.get("filetype", "") == "file":
            continue
        mutils = MetadataUtils()
        media_type = mutils.detect_plugin_content(item["file"])
        del mutils
        if media_type == "empty":
            continue
        if media_type == "folder":
            content = "plugin://script.skin.helper.service?action=widgets&path=%s&sublevel=%s" % (
                urlencode(item["file"]), label)
        # add reload param for widgets
        if "reload=" not in content:
            if "movies" in content:
                reloadstr = "&reload=$INFO[Window(Home).Property(widgetreload-movies)]"
            elif "episodes" in content:
                reloadstr = "&reload=$INFO[Window(Home).Property(widgetreload-episodes)]"
            elif "tvshows" in content:
                reloadstr = "&reload=$INFO[Window(Home).Property(widgetreload-tvshows)]"
            elif "musicvideos" in content:
                reloadstr = "&reload=$INFO[Window(Home).Property(widgetreload-musicvideos)]"
            elif "albums" in content or "songs" in content or "artists" in content:
                reloadstr = "&reload=$INFO[Window(Home).Property(widgetreload-music)]"
            else:
                reloadstr = "&reload=$INFO[Window(Home).Property(widgetreload)]"\
                    "$INFO[Window(Home).Property(widgetreload2)]"
            content = content + reloadstr
        content = content.replace("&limit=100", "&limit=25")
        widgets.append([label, content, media_type])
        if pluginpath == "script.extendedinfo" and not sublevel:
            # some additional entrypoints for extendedinfo...
            widgets += extendedinfo_youtube_widgets()
    return widgets
 def __init__(self, *args, **kwargs):
     self.cache = SimpleCache()
     self.mutils = MetadataUtils()
     self.win = xbmcgui.Window(10000)
     self.addon = xbmcaddon.Addon(ADDON_ID)
     self.smartshortcuts = SmartShortCuts(self)
     self.wallimages = WallImages(self)
     self.kodimonitor = kwargs.get("kodimonitor")
     self.event = threading.Event()
     threading.Thread.__init__(self, *args)
Ejemplo n.º 7
0
def show_infodialog(dbid="", media_type=""):
    '''shows the special info dialog for this media'''
    cont_prefix = get_cont_prefix()
    metadatautils = MetadataUtils()
    item_details = {}

    # if dbid is provided we prefer that info else we try to locate the dbid and dbtype
    if not (dbid and media_type):
        dbid, media_type = get_cur_listitem(cont_prefix)

    if media_type.endswith("s"):
        media_type = media_type[:-1]

    # get basic details from kodi db if we have a valid dbid and dbtype
    if dbid and media_type:
        if hasattr(metadatautils.kodidb.__class__, media_type):
            item_details = getattr(metadatautils.kodidb, media_type)(dbid)

    # only proceed if we have a media_type
    if media_type:
        title = try_decode(xbmc.getInfoLabel("%sListItem.Title" % cont_prefix))
        # music content
        if media_type in ["album", "artist", "song"]:
            artist = try_decode(xbmc.getInfoLabel("%sListItem.AlbumArtist" % cont_prefix))
            if not artist:
                artist = try_decode(xbmc.getInfoLabel("%sListItem.Artist" % cont_prefix))
            album = try_decode(xbmc.getInfoLabel("%sListItem.Album" % cont_prefix))
            disc = try_decode(xbmc.getInfoLabel("%sListItem.DiscNumber" % cont_prefix))
            if artist:
                item_details = metadatautils.extend_dict(item_details, metadatautils.get_music_artwork(artist, album, title, disc))
        # movieset
        elif media_type == "movieset" and dbid:
            item_details = metadatautils.extend_dict(item_details, metadatautils.get_moviesetdetails(dbid))
        # pvr item
        elif media_type in ["tvchannel", "tvrecording", "channel", "recording"]:
            channel = try_decode(xbmc.getInfoLabel("%sListItem.ChannelName" % cont_prefix))
            genre = xbmc.getInfoLabel("%sListItem.Genre" % cont_prefix)
            item_details["type"] = media_type
            item_details = metadatautils.extend_dict(item_details, metadatautils.get_pvr_artwork(title, channel, genre))

    metadatautils.close()
    # proceed with infodialog if we have details
    if item_details:
        widget_container = xbmc.getInfoLabel("Window(Home).Property(SkinHelper.WidgetContainer)")
        win = DialogVideoInfo("DialogVideoInfo.xml", "", listitem=item_details)
        xbmc.executebuiltin("SetProperty(SkinHelper.WidgetContainer,50,Home)")
        win.doModal()
        xbmc.executebuiltin("SetProperty(SkinHelper.WidgetContainer,%s,Home)" % widget_container)
        del win
Ejemplo n.º 8
0
    def __init__(self):
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.metadatautils = MetadataUtils()
        self.addonname = self.addon.getAddonInfo('name').decode("utf-8")
        self.addonversion = self.addon.getAddonInfo('version').decode("utf-8")
        self.kodimonitor = KodiMonitor(metadatautils=self.metadatautils, win=self.win)
        listitem_monitor = ListItemMonitor(
            metadatautils=self.metadatautils, win=self.win, monitor=self.kodimonitor)
        webservice = WebService(metadatautils=self.metadatautils)

        # start the extra threads
        listitem_monitor.start()
        webservice.start()
        self.win.clearProperty("SkinHelperShutdownRequested")
        log_msg('%s version %s started' % (self.addonname, self.addonversion), xbmc.LOGNOTICE)

        # run as service, check skin every 10 seconds and keep the other threads alive
        while not self.kodimonitor.abortRequested():

            # check skin version info
            self.check_skin_version()

            # sleep for 10 seconds
            self.kodimonitor.waitForAbort(10)

        # Abort was requested while waiting. We should exit
        self.win.setProperty("SkinHelperShutdownRequested", "shutdown")
        log_msg('Shutdown requested !', xbmc.LOGNOTICE)
        # stop the extra threads
        listitem_monitor.stop()
        webservice.stop()

        # cleanup objects
        self.close()
Ejemplo n.º 9
0
    def onInit(self):
        '''triggered when the dialog is drawn'''
        if self.listitem:
            self.clearList()
            mutils = MetadataUtils()
            if isinstance(self.listitem, dict):
                self.listitem = mutils.kodidb.prepare_listitem(self.listitem)
                self.listitem = mutils.kodidb.create_listitem(self.listitem, False)
            del mutils
            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
Ejemplo n.º 10
0
 def get_youtube_listing(searchquery):
     '''get items from youtube plugin by query'''
     lib_path = "plugin://plugin.video.youtube/kodion/search/query/?q=%s" % searchquery
     metadatautils = MetadataUtils()
     files = metadatautils.kodidb.files(lib_path)
     del metadatautils
     return files
    def __init__(self):
        self.cache = SimpleCache()
        self.mutils = MetadataUtils()
        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()
Ejemplo n.º 12
0
    def __init__(self):
        '''Initialization and main code run'''
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.mutils = MetadataUtils()
        self.cache = self.mutils.cache

        self.params = self.get_params()
        log_msg("MainModule called with parameters: %s" % self.params)
        action = self.params.get("action", "")
        # launch module for action provided by this script
        try:
            getattr(self, action)()
        except AttributeError:
            log_exception(__name__, "No such action: %s" % action)
        except Exception as exc:
            log_exception(__name__, exc)

        # do cleanup
        self.close()
Ejemplo n.º 13
0
    def __init__(self):
        """ Initialization """

        self.metadatautils = MetadataUtils()
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.win = xbmcgui.Window(10000)
        self.options = self.get_options()

        # skip if shutdown requested
        if self.win.getProperty("SkinHelperShutdownRequested"):
            log_msg("Not forfilling request: Kodi is exiting!", xbmc.LOGWARNING)
            xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)

        elif "mediatype" not in self.options or "action" not in self.options:
            # we need both mediatype and action, so show the main listing
            self.mainlisting()
        else:
            # we have a mediatype and action so display the widget listing
            self.show_widget_listing()

        self.close()
Ejemplo n.º 14
0
    def __init__(self):
        ''' Initialization '''

        self.metadatautils = MetadataUtils()
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.win = xbmcgui.Window(10000)
        self.options = self.get_options()

        # skip if shutdown requested
        if self.win.getProperty("SkinHelperShutdownRequested"):
            log_msg("Not forfilling request: Kodi is exiting!", xbmc.LOGWARNING)
            xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)

        elif not "mediatype" in self.options or not "action" in self.options:
            # we need both mediatype and action, so show the main listing
            self.mainlisting()
        else:
            # we have a mediatype and action so display the widget listing
            self.show_widget_listing()

        self.close()
Ejemplo n.º 15
0
def show_infodialog(dbid="", media_type=""):
    '''shows the special info dialog for this media'''
    cont_prefix = get_cont_prefix()
    metadatautils = MetadataUtils()
    item_details = {}

    # if dbid is provided we prefer that info else we try to locate the dbid and dbtype
    if not (dbid and media_type):
        dbid, media_type = get_cur_listitem(cont_prefix)

    if media_type.endswith("s"):
        media_type = media_type[:-1]

    # get basic details from kodi db if we have a valid dbid and dbtype
    if dbid and media_type:
        if hasattr(metadatautils.kodidb.__class__, media_type):
            item_details = getattr(metadatautils.kodidb, media_type)(dbid)

    # only proceed if we have a media_type
    if media_type:
        title = xbmc.getInfoLabel("%sListItem.Title" % cont_prefix).decode('utf-8')
        # music content
        if media_type in ["album", "artist", "song"]:
            artist = xbmc.getInfoLabel("%sListItem.AlbumArtist" % cont_prefix).decode('utf-8')
            if not artist:
                artist = xbmc.getInfoLabel("%sListItem.Artist" % cont_prefix).decode('utf-8')
            album = xbmc.getInfoLabel("%sListItem.Album" % cont_prefix).decode('utf-8')
            disc = xbmc.getInfoLabel("%sListItem.DiscNumber" % cont_prefix).decode('utf-8')
            if artist:
                item_details = extend_dict(item_details, metadatautils.get_music_artwork(artist, album, title, disc))
        # movieset
        elif media_type == "movieset" and dbid:
            item_details = extend_dict(item_details, metadatautils.get_moviesetdetails(dbid))
        # pvr item
        elif media_type in ["tvchannel", "tvrecording", "channel", "recording"]:
            channel = xbmc.getInfoLabel("%sListItem.ChannelName" % cont_prefix).decode('utf-8')
            genre = xbmc.getInfoLabel("%sListItem.Genre" % cont_prefix)
            item_details["type"] = media_type
            item_details = extend_dict(item_details, metadatautils.get_pvr_artwork(title, channel, genre))

    metadatautils.close()
    # proceed with infodialog if we have details
    if item_details:
        win = DialogVideoInfo("DialogVideoInfo.xml", "", listitem=item_details)
        win.doModal()
        del win
Ejemplo n.º 16
0
class Main(object):
    """Main entry path for our widget listing. Process the arguments and load correct class and module"""

    def __init__(self):
        """ Initialization """

        self.metadatautils = MetadataUtils()
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.win = xbmcgui.Window(10000)
        self.options = self.get_options()

        # skip if shutdown requested
        if self.win.getProperty("SkinHelperShutdownRequested"):
            log_msg("Not forfilling request: Kodi is exiting!", xbmc.LOGWARNING)
            xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)

        elif "mediatype" not in self.options or "action" not in self.options:
            # we need both mediatype and action, so show the main listing
            self.mainlisting()
        else:
            # we have a mediatype and action so display the widget listing
            self.show_widget_listing()

        self.close()

    def close(self):
        """Cleanup Kodi Cpython instances"""
        self.metadatautils.close()
        del self.addon
        del self.win
        log_msg("MainModule exited")

    def get_options(self):
        """get the options provided to the plugin path"""

        options = dict(urlparse.parse_qsl(sys.argv[2].replace('?', '').lower().decode("utf-8")))

        # set the widget settings as options
        options["hide_watched"] = self.addon.getSetting("hide_watched") == "true"
        if self.addon.getSetting("hide_watched_recent") == "true" and "recent" in options.get("action", ""):
            options["hide_watched"] = True
        options["num_recent_similar"] = int(self.addon.getSetting("num_recent_similar"))
        options["exp_recommended"] = self.addon.getSetting("exp_recommended") == "true"
        options["mylist"] = self.addon.getSetting("mylist") == "true"
        options["extended_info"] = self.addon.getSetting("extended_info") == "true"
        options["hide_watched_similar"] = self.addon.getSetting("hide_watched_similar") == "true"
        options["next_inprogress_only"] = self.addon.getSetting("nextup_inprogressonly") == "true"
        options["episodes_enable_specials"] = self.addon.getSetting("episodes_enable_specials") == "true"
        options["group_episodes"] = self.addon.getSetting("episodes_grouping") == "true"
        if "limit" in options:
            options["limit"] = int(options["limit"])
        else:
            options["limit"] = int(self.addon.getSetting("default_limit"))

        if "mediatype" not in options and "action" in options:
            # get the mediatype and action from the path (for backwards compatability with old style paths)
            for item in [
                ("movies", "movies"),
                ("shows", "tvshows"),
                ("episode", "episodes"),
                ("musicvideos", "musicvideos"),
                ("pvr", "pvr"),
                ("albums", "albums"),
                ("songs", "songs"),
                ("artists", "artists"),
                ("media", "media"),
                ("favourites", "favourites"),
                ("favorites", "favourites")]:
                if item[0] in options["action"]:
                    options["mediatype"] = item[1]
                    options["action"] = options["action"].replace(item[1], "").replace(item[0], "")
                    break

        # prefer reload param for the mediatype
        if "mediatype" in options:
            alt_reload = self.win.getProperty("widgetreload-%s" % options["mediatype"])
            if options["mediatype"] == "favourites" or "favourite" in options["action"]:
                options["skipcache"] = "true"
            elif alt_reload:
                options["reload"] = alt_reload
            if not options.get("action") and options["mediatype"] == "favourites":
                options["action"] = "favourites"
            elif not options.get("action"):
                options["action"] = "listing"
            if "listing" in options["action"]:
                options["skipcache"] = "true"
            if options["action"] == "browsegenres" and options["mediatype"] == "randommovies":
                options["mediatype"] = "movies"
                options["random"] = True
            elif options["action"] == "browsegenres" and options["mediatype"] == "randomtvshows":
                options["mediatype"] = "tvshows"
                options["random"] = True

        return options

    def show_widget_listing(self):
        """display the listing for the provided action and mediatype"""
        media_type = self.options["mediatype"]
        action = self.options["action"]
        # set widget content type
        if media_type in ["favourites", "pvr", "media"]:
            xbmcplugin.setContent(ADDON_HANDLE, "files")
        else:
            xbmcplugin.setContent(ADDON_HANDLE, media_type)

        # try to get from cache first...
        all_items = []
        # alter cache_str depending on whether "tag" is available
        if self.options["action"] == "similar":
            # if action is similar, use imdbid
            cache_id = self.options.get("imdbid", "")
            # if similar was called without imdbid, skip cache
            if not self.options.get("imdbid", ""):
                self.options["skipcache"] = "true"
        elif self.options["action"] == "playlist" and self.options["mediatype"] == "media":
            # if action is mixed playlist, use playlist labels
            cache_id = self.options.get("movie_label") + self.options.get("tv_label") + self.options.get("sort")
        elif self.options["action"] == "forgenre" and "genre" in self.options:
            cache_id = self.options.get("genre")
        else:
            # use tag otherwise
            cache_id = self.options.get("tag")
        cache_str = "SkinHelper.Widgets.%s.%s.%s.%s.%s" % (media_type,
                                                           action, self.options["limit"], self.options.get("path"),
                                                           cache_id)
        if not self.win.getProperty("widgetreload2"):
            # at startup we simply accept whatever is in the cache
            cache_checksum = None
        else:
            # we use a checksum based on the reloadparam to make sure we have the most recent data
            cache_checksum = self.options.get("reload", "")
        # only check cache if not "skipcache"
        if not self.options.get("skipcache") == "true":
            cache = self.metadatautils.cache.get(cache_str, checksum=cache_checksum)
            if cache:
                log_msg("MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- got items from cache - CHECKSUM: %s"
                        % (media_type, action, self.options.get("path"), self.options.get("tag"), cache_checksum))
                all_items = cache

        # Call the correct method to get the content from json when no cache
        if not all_items:
            log_msg(
                "MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- no cache, quering kodi api to get items - CHECKSUM: %s"
                % (media_type, action, self.options.get("path"), self.options.get("tag"), cache_checksum))

            # dynamically import and load the correct module, class and function
            try:
                media_module = __import__(media_type)
                media_class = getattr(
                    media_module,
                    media_type.capitalize())(self.addon, self.metadatautils, self.options)
                all_items = getattr(media_class, action)()
                del media_class
            except AttributeError:
                log_exception(__name__, "Incorrect widget action or type called")
            except Exception as exc:
                log_exception(__name__, exc)

            # randomize output if requested by skinner or user
            if self.options.get("randomize", "") == "true":
                all_items = sorted(all_items, key=lambda k: random.random())

            # prepare listitems and store in cache
            all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.prepare_listitem, all_items)
            self.metadatautils.cache.set(cache_str, all_items, checksum=cache_checksum)

        # fill that listing...
        xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_UNSORTED)
        all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.create_listitem, all_items)
        xbmcplugin.addDirectoryItems(ADDON_HANDLE, all_items, len(all_items))

        # end directory listing
        xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)

    def mainlisting(self):
        """main listing"""
        all_items = []
        xbmcplugin.setContent(ADDON_HANDLE, "files")

        # movie node
        if xbmc.getCondVisibility("Library.HasContent(movies)"):
            all_items.append((xbmc.getLocalizedString(342), "movieslisting", "DefaultMovies.png"))

        # tvshows and episodes nodes
        if xbmc.getCondVisibility("Library.HasContent(tvshows)"):
            all_items.append((xbmc.getLocalizedString(20343), "tvshowslisting", "DefaultTvShows.png"))
            all_items.append((xbmc.getLocalizedString(20360), "episodeslisting", "DefaultTvShows.png"))

        # pvr node
        if xbmc.getCondVisibility("Pvr.HasTVChannels"):
            all_items.append((self.addon.getLocalizedString(32054), "pvrlisting", "DefaultAddonPVRClient.png"))

        # music nodes
        if xbmc.getCondVisibility("Library.HasContent(music)"):
            all_items.append((xbmc.getLocalizedString(132), "albumslisting", "DefaultAlbumCover.png"))
            all_items.append((xbmc.getLocalizedString(134), "songslisting", "DefaultMusicSongs.png"))
            all_items.append((xbmc.getLocalizedString(133), "artistslisting", "DefaultArtist.png"))

        # musicvideo node
        if xbmc.getCondVisibility("Library.HasContent(musicvideos)"):
            all_items.append((xbmc.getLocalizedString(20389), "musicvideoslisting", "DefaultAddonAlbumInfo.png"))

        # media node
        if xbmc.getCondVisibility(
                "Library.HasContent(movies) | Library.HasContent(tvshows) | Library.HasContent(music)"):
            all_items.append((self.addon.getLocalizedString(32057), "medialisting", "DefaultAddonAlbumInfo.png"))

        # favourites node
        all_items.append((xbmc.getLocalizedString(10134), "favouriteslisting", "DefaultAddonAlbumInfo.png"))

        # process the listitems and display listing
        all_items = self.metadatautils.process_method_on_list(create_main_entry, all_items)
        all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.prepare_listitem, all_items)
        all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.create_listitem, all_items)
        xbmcplugin.addDirectoryItems(ADDON_HANDLE, all_items, len(all_items))
        xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)
Ejemplo n.º 17
0
    script.skin.helper.service
    Contextmenu for Music art
'''

import xbmc
import xbmcgui
from metadatautils import MetadataUtils
import time

# pylint: disable-msg=invalid-constant-name

# Kodi contextmenu item to configure music artwork
if __name__ == '__main__':

    win = xbmcgui.Window(10000)
    metadatautils = MetadataUtils()
    win.setProperty("SkinHelper.Artwork.ManualLookup", "busy")
    track = xbmc.getInfoLabel("ListItem.Title").decode('utf-8')
    album = xbmc.getInfoLabel("ListItem.Album").decode('utf-8')
    artist = xbmc.getInfoLabel("ListItem.Artist").decode('utf-8')
    disc = xbmc.getInfoLabel("ListItem.DiscNumber").decode('utf-8')
    metadatautils.music_artwork_options(artist, album, track, disc)
    metadatautils.close()
    # refresh music widgets
    timestr = time.strftime("%Y%m%d%H%M%S", time.gmtime())
    win.setProperty("widgetreload-music", timestr)
    win.setProperty("widgetreloadmusic", timestr)
    win.setProperty("widgetreload-albums", timestr)
    win.setProperty("widgetreload-songs", timestr)
    win.clearProperty("SkinHelper.Artwork.ManualLookup")
    del win
Ejemplo n.º 18
0
    if imdb_id and not imdb_id.startswith("tt"):
        imdb_id = ""
    if not imdb_id:
        year = xbmc.getInfoLabel("ListItem.Year").decode('utf-8')
        title = xbmc.getInfoLabel("ListItem.Title").decode('utf-8').split(",")[0].split("(")[0]
        if content_type in ["episodes", "seasons"]:
            title = xbmc.getInfoLabel("ListItem.TvShowTitle").decode('utf-8')
        if title:
            log_msg("Animated Art: lookup imdbid by title and year: (%s - %s)" % (title, year), xbmc.LOGNOTICE)
            imdb_id = metadatautils.get_omdb_info("", title, year, content_type).get("imdbnumber", "")
        if not imdb_id:
            return title
    return imdb_id

# Kodi contextmenu item to configure the artwork
if __name__ == '__main__':
    xbmc.executebuiltin("ActivateWindow(busydialog)")
    log_msg("Contextmenu for Animated Art opened", xbmc.LOGNOTICE)
    ARTUTILS = MetadataUtils()
    WIN = xbmcgui.Window(10000)
    imdb_id = get_imdb_id(WIN, ARTUTILS)
    WIN.setProperty("SkinHelper.Artwork.ManualLookup", "busy")
    log_msg("Animated Art: Query animated art by IMDBID: %s" % imdb_id, xbmc.LOGNOTICE)
    artwork = ARTUTILS.get_animated_artwork(imdb_id, ignore_cache=True, manual_select=True)
    log_msg("Animated Art result: %s" % artwork, xbmc.LOGNOTICE)
    xbmc.executebuiltin("Dialog.Close(busydialog)")
    xbmc.executebuiltin("Container.Refresh")
    WIN.clearProperty("SkinHelper.Artwork.ManualLookup")
    del WIN
    ARTUTILS.close()
Ejemplo n.º 19
0
'''
    script.skin.helper.service
    Contextmenu for Pvr art
'''

import xbmc
import xbmcgui
from metadatautils import MetadataUtils

# pylint: disable-msg=invalid-constant-name

# Kodi contextmenu item to configure pvr artwork
if __name__ == '__main__':

    ##### PVR Artwork ########
    win = xbmcgui.Window(10000)
    win.setProperty("SkinHelper.Artwork.ManualLookup", "busy")
    xbmc.executebuiltin("ActivateWindow(busydialog)")
    title = xbmc.getInfoLabel("ListItem.Title").decode('utf-8')
    if not title:
        title = xbmc.getInfoLabel("ListItem.Label").decode('utf-8')
    channel = xbmc.getInfoLabel("ListItem.ChannelName").decode('utf-8')
    genre = xbmc.getInfoLabel("ListItem.Genre").decode('utf-8')
    metadatautils = MetadataUtils()
    metadatautils.pvr_artwork_options(title, channel, genre)
    xbmc.executebuiltin("Dialog.Close(busydialog)")
    win.clearProperty("SkinHelper.Artwork.ManualLookup")
    metadatautils.close()
    del win
class BackgroundsUpdater(threading.Thread):
    '''Background service providing rotating backgrounds to Kodi skins'''
    exit = False
    event = None
    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, *args, **kwargs):
        self.cache = SimpleCache()
        self.mutils = MetadataUtils()
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.smartshortcuts = SmartShortCuts(self)
        self.wallimages = WallImages(self)
        self.kodimonitor = kwargs.get("kodimonitor")
        self.event = threading.Event()
        threading.Thread.__init__(self, *args)

    def stop(self):
        '''stop running our background service '''
        self.smartshortcuts.exit = True
        self.wallimages.exit = True
        self.exit = True
        self.event.set()
        self.event.clear()
        self.join(0.5)
        del self.smartshortcuts
        del self.wallimages
        del self.win
        del self.addon

    def run(self):
        '''called to start our background service '''
        log_msg("BackgroundsUpdater - started", xbmc.LOGINFO)
        self.winpropcache()
        self.get_config()
        backgrounds_task_interval = 0
        walls_task_interval = 0
        delayed_task_interval = 112

        while not self.exit:

            # 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.report_allbackgrounds()
                    self.winpropcache(True)

                if self.exit:
                    break

                # 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()

                if self.exit:
                    break

                # 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

    def get_config(self):
        '''gets various settings for the script as set by the skinner or user'''

        # skinner (or user) enables the random fanart images by setting the randomfanartdelay skin string
        try:
            self.backgrounds_delay = int(
                xbmc.getInfoLabel("Skin.String(SkinHelper.RandomFanartDelay)"))
        except Exception:
            pass

        self.walls_delay = int(self.addon.getSetting("wallimages_delay"))
        self.wallimages.max_wallimages = int(
            self.addon.getSetting("max_wallimages"))
        self.pvr_bg_recordingsonly = self.addon.getSetting(
            "pvr_bg_recordingsonly") == "true"
        self.enable_walls = xbmc.getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnableWallBackgrounds)")
        if self.addon.getSetting("enable_custom_images_path") == "true":
            self.custom_picturespath = self.addon.getSetting(
                "custom_images_path")
        else:
            self.custom_picturespath = ""
        try:
            # skinner can enable manual wall images generation so check for these settings
            # store in memory so wo do not have to query the skin settings too often
            if self.walls_delay:
                for key in self.all_backgrounds_keys.keys():
                    limitrange = xbmc.getInfoLabel(
                        "Skin.String(%s.EnableWallImages)" % key)
                    if limitrange:
                        self.wallimages.manual_walls[key] = int(limitrange)
        except Exception as exc:
            log_exception(__name__, exc)

    def 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'''
        if self.exit:
            return
        self.winprops[key] = value
        if isinstance(value, str):
            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'''
        cachestr = "skinhelper.backgrounds.%s" % xbmc.getInfoLabel(
            "System.ProfileName")
        if setcache:
            self.cache.set(cachestr, self.winprops)
        else:
            cache = self.cache.get(cachestr)
            if cache:
                for key, value in cache.items():
                    if value:
                        self.win.setProperty(key, 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-next-gen" in lib_path and "browsecontent" in lib_path and "filter" not in lib_path:
            lib_path = lib_path + "&filter=random"

        items = self.mutils.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 * 2))
        for media in items:
            image = {}
            if media['label'].lower() == "next page":
                continue
            if media.get('art'):
                if media['art'].get('fanart'):
                    image["fanart"] = self.mutils.get_clean_image(
                        media['art']['fanart'])
                elif media['art'].get('tvshow.fanart'):
                    image["fanart"] = self.mutils.get_clean_image(
                        media['art']['tvshow.fanart'])
                elif media['art'].get('artist.fanart'):
                    image["fanart"] = self.mutils.get_clean_image(
                        media['art']['artist.fanart'])
                if media['art'].get('thumb'):
                    image["thumbnail"] = self.mutils.get_clean_image(
                        media['art']['thumb'])
            if not image.get('fanart') and media.get("fanart"):
                image["fanart"] = self.mutils.get_clean_image(media['fanart'])
            if not image.get("thumbnail") and media.get("thumbnail"):
                image["thumbnail"] = self.mutils.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"] = self.mutils.get_clean_image(
                    media.get('art', {}).get('landscape', ''))
                image["poster"] = self.mutils.get_clean_image(
                    media.get('art', {}).get('poster', ''))
                image["clearlogo"] = self.mutils.get_clean_image(
                    media.get('art', {}).get('clearlogo', ''))
                result.append(image)
            if len(result) == self.prefetch_images:
                break
        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.mutils.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'''
        if self.exit:
            return
        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 with minimized possibility of duplicates
            del self.all_backgrounds[win_prop][0]
        else:
            # no images in memory - load them from vfs
            if 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:
                self.save_background_label(win_prop, label)
        # set the image
        self.set_image(win_prop, image, fallback_image)

    def set_global_background(self,
                              win_prop,
                              keys,
                              fallback_image="",
                              label=None):
        '''get random background from random other collection'''
        image = None
        # pick random category-key
        random.shuffle(keys)
        for key in keys:
            if key in self.all_backgrounds2 and self.all_backgrounds2[key]:
                # pick random image from this category
                image = random.choice(self.all_backgrounds2[key])
            elif key in self.all_backgrounds and self.all_backgrounds[key]:
                # pick random image from this category
                image = random.choice(self.all_backgrounds[key])
            if image or self.exit:
                break
        # also store the win_prop + label in a list for skinshortcuts - only if the path actually has images
        if image:
            self.save_background_label(win_prop, label)
        # set the image
        self.set_image(win_prop, image, fallback_image)
        return image

    def set_image(self, win_prop, image, fallback_image):
        ''' actually set the image window property'''
        if image:
            for key, value in image.items():  # 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)
        elif fallback_image:
            # no image - use fallback_image
            self.set_winprop(win_prop, fallback_image)

    def save_background_label(self, win_prop, label):
        ''' store background label in list, used for exachnge with other scripts'''
        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))

    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_global_background("SkinHelper.GlobalFanartBackground", [
            "SkinHelper.AllMoviesBackground",
            "SkinHelper.AllTvShowsBackground",
            "SkinHelper.AllMusicVideosBackground",
            "SkinHelper.AllMusicBackground"
        ],
                                   label=32009)
        self.set_global_background("SkinHelper.AllVideosBackground", [
            "SkinHelper.AllMoviesBackground",
            "SkinHelper.AllTvShowsBackground",
            "SkinHelper.AllMusicVideosBackground"
        ],
                                   label=32025)
        self.set_global_background("SkinHelper.AllVideosBackground2", [
            "SkinHelper.AllMoviesBackground", "SkinHelper.AllTvShowsBackground"
        ],
                                   label=32026)
        self.set_global_background("SkinHelper.RecentVideosBackground", [
            "SkinHelper.RecentMoviesBackground",
            "SkinHelper.RecentEpisodesBackground"
        ],
                                   label=32027)
        self.set_global_background("SkinHelper.InProgressVideosBackground", [
            "SkinHelper.InProgressMoviesBackground",
            "SkinHelper.InProgressShowsBackground"
        ],
                                   label=32028)
 def __init__(self, *args):
     xbmc.log("SearchBackgroundThread Init")
     threading.Thread.__init__(self, *args)
     self.mutils = MetadataUtils()
     self.actors = []
     thread.start_new_thread(self.set_actors, ())
Ejemplo n.º 22
0
 def __init__(self, *args, **kwargs):
     self.metadatautils = MetadataUtils()
     xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
Ejemplo n.º 23
0
'''

import os, sys
import xbmc
import xbmcgui
from metadatautils import MetadataUtils
from resources.lib.utils import try_decode
import time

# pylint: disable-msg=invalid-constant-name

# Kodi contextmenu item to configure music artwork
if __name__ == '__main__':

    win = xbmcgui.Window(10000)
    metadatautils = MetadataUtils()
    win.setProperty("SkinHelper.Artwork.ManualLookup", "busy")
    track = try_decode(xbmc.getInfoLabel("ListItem.Title"))
    album = try_decode(xbmc.getInfoLabel("ListItem.Album"))
    artist = try_decode(xbmc.getInfoLabel("ListItem.Artist"))
    disc = try_decode(xbmc.getInfoLabel("ListItem.DiscNumber"))
    metadatautils.music_artwork_options(artist, album, track, disc)
    metadatautils.close()
    # refresh music widgets
    timestr = time.strftime("%Y%m%d%H%M%S", time.gmtime())
    win.setProperty("widgetreload-music", timestr)
    win.setProperty("widgetreloadmusic", timestr)
    win.setProperty("widgetreload-albums", timestr)
    win.setProperty("widgetreload-songs", timestr)
    win.clearProperty("SkinHelper.Artwork.ManualLookup")
    del win
Ejemplo n.º 24
0
class RoonOSD(xbmcgui.WindowXMLDialog):
    ''' Special OSD to control Roon zone'''
    update_thread = None
    roon = None
    is_playing = True
    shuffle_state = False
    repeat_state = "off"

    def __init__(self, *args, **kwargs):
        self.metadatautils = MetadataUtils()
        xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)

    def onInit(self):
        '''triggers on initialization of the dialog'''
        if not self.roon:
            host = addon_setting("proxy_host")
            port = addon_setting("proxy_port")
            zone_id = addon_setting("zone_id")
            self.roon = RoonServer(host, port, zone_id)
        self.update_thread = RoonOSDUpdateThread()
        self.update_thread.set_dialog(self)
        self.update_thread.start()

    def onAction(self, action):
        '''triggers on kodi navigation events'''
        action_id = action.getId()
        #log_msg("onAction: %s" % action_id)
        if action_id in (9, 10, 92, 216, 247, 257, 275, 61467, 61448):
            self.close_dialog()
        elif action_id in (12, 68, 79, 229):
            self.toggle_playback()
        elif action_id in (184, 14, 97, 3):
            self.roon.next_track()
        elif action_id in (185, 15, 98, 4):
            self.roon.previous_track()
        elif action_id in (13, ):
            self.roon.stop_playback()
        elif action_id in (88, ):
            self.roon.volume_up()
        elif action_id in (89, ):
            self.roon.volume_down()

    def close_dialog(self):
        '''stop background thread and close the dialog'''
        self.update_thread.stop_running()
        self.metadatautils.close()
        self.close()

    def onClick(self, control_id):
        '''Kodi builtin: triggers if window is clicked'''
        if control_id == 3201:
            self.roon.previous_track()
        elif control_id == 3203:
            self.toggle_playback()
        elif control_id == 3204:
            self.roon.next_track()
        elif control_id == 3206 and self.shuffle_state:
            self.roon.shuffle(False)
        elif control_id == 3206 and not self.shuffle_state:
            self.roon.shuffle(True)
        elif control_id == 3208:
            self.roon.toggle_repeat()
        elif control_id == 3209:
            self.roon.stop_playback()
        elif control_id == 3210:
            self.select_zone()
        elif control_id == 3212:
            self.roon.volume_down()
        elif control_id == 3214:
            self.roon.volume_up()

    def toggle_playback(self):
        '''toggle play/pause'''
        if self.is_playing:
            self.is_playing = False
            self.getControl(3202).setEnabled(False)
            self.roon.pause_playback()
        else:
            self.is_playing = True
            self.getControl(3202).setEnabled(True)
            self.roon.start_playback()

    def select_zone(self):
        ''' select active zone '''
        xbmc.executebuiltin("ActivateWindow(busydialog")
        all_zones = self.roon.send_request("zones")
        if all_zones:
            all_zones = all_zones["zones"].values()
            all_zone_names = [item["display_name"] for item in all_zones]
        else:
            all_zone_names = []
            addon_setting("proxy_host", "")
        dialog = xbmcgui.Dialog()
        ret = dialog.select("Select zone", all_zone_names)
        if ret != -1:
            selected_zone = all_zones[ret]
            self.roon.zone_id = selected_zone["zone_id"]
            addon_setting("zone_id", selected_zone["zone_id"])
            addon_setting("zone_name", selected_zone["display_name"])
        del dialog
        xbmc.executebuiltin("Dialog.Close(busydialog)")
        xbmc.executebuiltin("Container.Refresh")
class SearchDialog(xbmcgui.WindowXMLDialog):
    ''' Special window to search the Kodi video database'''
    search_thread = None
    search_string = ""

    def __init__(self, *args, **kwargs):
        self.mutils = MetadataUtils()
        xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)

    def onInit(self):
        '''triggers on initialization of the dialog'''
        self.search_thread = SearchBackgroundThread()
        self.search_thread.set_dialog(self)
        self.search_thread.start()

    def onAction(self, action):
        '''triggers on kodi navigation events'''
        if self.getFocusId() in [3110, 3111, 3112]:
            # one of the media lists is focused
            if action.getId() in (11, ):
                # info key on media item
                self.show_info()
            if action.getId() in (9, 10, 92, 216, 247, 257, 275, 61467, 61448, ):
                # close dialog
                self.close_dialog()
        else:
            # search keyboard is focused
            if action.getId() in (9, 10, 92, 216, 247, 257, 275, 61467, 61448, ):
                # backspace
                self.remove_char()
            else:
                self.action_textbox(action)

    def close_dialog(self):
        '''stop background thread and close the dialog'''
        self.search_thread.stop_running()
        self.mutils.close()
        self.close()

    def remove_char(self):
        '''remove character from query string'''
        if len(self.search_string) == 0 or self.search_string == " ":
            self.close_dialog()
        else:
            if len(self.search_string) == 1:
                search_term = " "
            else:
                search_term = self.search_string[:-1]
            self.setFocusId(3056)
            self.getControl(3010).setLabel(search_term)
            self.search_string = search_term
            self.search_thread.set_search(search_term)

    def action_textbox(self, act):
        '''special handler to allow direct typing to search'''
        action_number_0 = 58
        action_number_9 = 67
        action = act.getId()
        button = act.getButtonCode()

        # Upper-case values
        if button >= 0x2f041 and button <= 0x2f05b:
            self.add_character(chr(button - 0x2F000))

        # Lower-case values
        if button >= 0xf041 and button <= 0xf05b:
            self.add_character(chr(button - 0xEFE0))

        # Numbers
        if action >= action_number_0 and action <= action_number_9:
            self.add_character(chr(action - action_number_0 + 48))

        # Backspace
        if button == 0xF008:
            if len(self.search_string) >= 1:
                self.remove_char()

        # Delete
        if button == 0xF02E:
            self.clear_search()

        # Space
        if button == 0xF020:
            self.add_character(" ")

        if getCondVisibility("Window.IsVisible(10111)"):
            # close shutdown window if visible
            xbmc.executebuiltin("Dialog.close(10111)")

    def focus_char(self, char):
        '''focus specified character'''
        alphanum = ['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', '0', '1', '2', '3',
                    '4', '5', '6', '7', '8', '9', '', ' '].index(str(char).upper())
        self.setFocusId(3020 + alphanum)

    def onClick(self, control_id):
        '''Kodi builtin: triggers if window is clicked'''
        if control_id == 3020:
            self.add_character("A")
        elif control_id == 3021:
            self.add_character("B")
        elif control_id == 3022:
            self.add_character("C")
        elif control_id == 3023:
            self.add_character("D")
        elif control_id == 3024:
            self.add_character("E")
        elif control_id == 3025:
            self.add_character("F")
        elif control_id == 3026:
            self.add_character("G")
        elif control_id == 3027:
            self.add_character("H")
        elif control_id == 3028:
            self.add_character("I")
        elif control_id == 3029:
            self.add_character("J")
        elif control_id == 3030:
            self.add_character("K")
        elif control_id == 3031:
            self.add_character("L")
        elif control_id == 3032:
            self.add_character("M")
        elif control_id == 3033:
            self.add_character("N")
        elif control_id == 3034:
            self.add_character("O")
        elif control_id == 3035:
            self.add_character("P")
        elif control_id == 3036:
            self.add_character("Q")
        elif control_id == 3037:
            self.add_character("R")
        elif control_id == 3038:
            self.add_character("S")
        elif control_id == 3039:
            self.add_character("T")
        elif control_id == 3040:
            self.add_character("U")
        elif control_id == 3041:
            self.add_character("V")
        elif control_id == 3042:
            self.add_character("W")
        elif control_id == 3043:
            self.add_character("X")
        elif control_id == 3044:
            self.add_character("Y")
        elif control_id == 3045:
            self.add_character("Z")
        elif control_id == 3046:
            self.add_character("0")
        elif control_id == 3047:
            self.add_character("1")
        elif control_id == 3048:
            self.add_character("2")
        elif control_id == 3049:
            self.add_character("3")
        elif control_id == 3050:
            self.add_character("4")
        elif control_id == 3051:
            self.add_character("5")
        elif control_id == 3052:
            self.add_character("6")
        elif control_id == 3053:
            self.add_character("7")
        elif control_id == 3054:
            self.add_character("8")
        elif control_id == 3055:
            self.add_character("9")
        elif control_id == 3056:
            self.remove_char()
        elif control_id == 3057:
            self.add_character(" ")
        elif control_id == 3058:
            self.clear_search()
        elif control_id == 3010:
            search_term = xbmcgui.Dialog().input(xbmc.getLocalizedString(16017), type=xbmcgui.INPUT_ALPHANUM)
            self.getControl(3010).setLabel(search_term)
            self.search_string = search_term
            self.search_thread.set_search(search_term)
        elif control_id in [3110, 3111, 3112]:
            self.open_item()

    def clear_search(self):
        '''clears the search textbox'''
        self.setFocusId(3058)
        self.getControl(3010).setLabel(" ")
        self.search_string = ""
        self.search_thread.set_search("")

    def add_character(self, char):
        '''add character to our search textbox'''
        self.focus_char(char)
        search_term = self.search_string + char
        self.getControl(3010).setLabel(search_term)
        self.search_string = search_term
        self.search_thread.set_search(search_term)

    def show_info(self):
        '''show info dialog for selected item'''
        control_id = self.getFocusId()
        listitem = self.getControl(control_id).getSelectedItem()
        if "actor" in listitem.getProperty("DBTYPE"):
            xbmc.executebuiltin("RunScript(script.extendedinfo,info=extendedactorinfo,name=%s)" % listitem.getLabel())
        else:
            from .infodialog import DialogVideoInfo
            win = DialogVideoInfo("DialogVideoInfo.xml", "", listitem=listitem)
            win.doModal()
            result = win.result
            del win
            if result:
                self.close_dialog()

    def open_item(self):
        '''open selected item'''
        control_id = self.getFocusId()
        listitem = self.getControl(control_id).getSelectedItem()
        if "videodb:" in listitem.getLabel():
            # tvshow: open path
            xbmc.executebuiltin('ReplaceWindow(Videos,"%s")' % self.listitem.getLabel())
            self.close_dialog()
        elif "actor" in listitem.getProperty("DBTYPE"):
            # cast dialog
            if sys.version_info.major == 3:
                from .dialogselect import DialogSelect
            else:
                from dialogselect import DialogSelect
            results = []
            name = try_decode(listitem.getLabel())
            items = self.mutils.kodidb.castmedia(name)
            items = self.mutils.process_method_on_list(self.mutils.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.mutils.kodidb.create_listitem(item, False))
            # finished lookup - display listing with results
            dialog = DialogSelect("DialogSelect.xml", "", listing=results, windowtitle=name, richlayout=True)
            dialog.doModal()
            result = dialog.result
            del dialog
            if result:
                xbmc.executebuiltin(result.getLabel())
                self.close_dialog()
        else:
            # video file: start playback
            xbmc.executebuiltin('PlayMedia("%s")' % listitem.getLabel())
            self.close_dialog()
Ejemplo n.º 26
0
class MainService:
    '''our main background service running the various threads'''
    last_skin = ""

    def __init__(self):
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.metadatautils = MetadataUtils()
        self.addonname = self.addon.getAddonInfo('name').decode("utf-8")
        self.addonversion = self.addon.getAddonInfo('version').decode("utf-8")
        self.kodimonitor = KodiMonitor(metadatautils=self.metadatautils,
                                       win=self.win)
        listitem_monitor = ListItemMonitor(metadatautils=self.metadatautils,
                                           win=self.win,
                                           monitor=self.kodimonitor)
        webservice = WebService(metadatautils=self.metadatautils)

        # start the extra threads
        listitem_monitor.start()
        webservice.start()
        self.win.clearProperty("SkinHelperShutdownRequested")
        log_msg('%s version %s started' % (self.addonname, self.addonversion),
                xbmc.LOGNOTICE)

        # run as service, check skin every 10 seconds and keep the other threads alive
        while not self.kodimonitor.abortRequested():

            # check skin version info
            self.check_skin_version()

            # sleep for 10 seconds
            self.kodimonitor.waitForAbort(10)

        # Abort was requested while waiting. We should exit
        self.win.setProperty("SkinHelperShutdownRequested", "shutdown")
        log_msg('Shutdown requested !', xbmc.LOGNOTICE)
        # stop the extra threads
        listitem_monitor.stop()
        webservice.stop()

        # cleanup objects
        self.close()

    def close(self):
        '''Cleanup Kodi Cpython instances'''
        self.metadatautils.close()
        del self.win
        del self.kodimonitor
        del self.metadatautils
        log_msg('%s version %s stopped' % (self.addonname, self.addonversion),
                xbmc.LOGNOTICE)

    def check_skin_version(self):
        '''check if skin changed'''
        try:
            skin = xbmc.getSkinDir()
            skin_addon = xbmcaddon.Addon(id=skin)
            skin_label = skin_addon.getAddonInfo('name').decode("utf-8")
            skin_version = skin_addon.getAddonInfo('version').decode("utf-8")
            del skin_addon
            if self.last_skin != skin_label + skin_version:
                # auto correct skin settings
                self.last_skin = skin_label + skin_version
                self.win.setProperty(
                    "SkinHelper.skinTitle", "%s - %s: %s" %
                    (skin_label, xbmc.getLocalizedString(19114), skin_version))
                self.win.setProperty(
                    "SkinHelper.skin_version",
                    "%s: %s" % (xbmc.getLocalizedString(19114), skin_version))
                self.win.setProperty("SkinHelper.Version",
                                     self.addonversion.replace(".", ""))
                SkinSettings().correct_skin_settings()
        except Exception as exc:
            log_exception(__name__, exc)
Ejemplo n.º 27
0
 def __init__(self, *args, **kwargs):
     self.metadatautils = MetadataUtils()
     xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
Ejemplo n.º 28
0
class SpotifyOSD(xbmcgui.WindowXMLDialog):
    ''' Special OSD to control Spotify Connect player'''
    update_thread = None
    sp = None
    is_playing = True
    shuffle_state = False
    repeat_state = "off"

    def __init__(self, *args, **kwargs):
        self.metadatautils = MetadataUtils()
        xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)

    def onInit(self):
        '''triggers on initialization of the dialog'''
        self.update_thread = SpotifyOSDUpdateThread()
        self.update_thread.set_dialog(self)
        self.update_thread.start()

    def onAction(self, action):
        '''triggers on kodi navigation events'''
        action_id = action.getId()
        if action_id in (9, 10, 92, 216, 247, 257, 275, 61467, 61448, ):
            self.close_dialog()
        elif action_id in (12, 68, 79, 229):
            self.toggle_playback()
        elif action_id in (184, 14, 97):
            self.sp.next_track()
        elif action_id in (185, 15, 98):
            self.sp.previous_track()

    def close_dialog(self):
        '''stop background thread and close the dialog'''
        self.update_thread.stop_running()
        try:
            self.sp.pause_playback()
        except:
            pass
        self.metadatautils.close()
        self.close()

    def onClick(self, control_id):
        '''Kodi builtin: triggers if window is clicked'''
        if control_id == 3201:
            self.sp.previous_track()
        elif control_id == 3203:
            self.toggle_playback()
        elif control_id == 3204:
            self.sp.next_track()
        elif control_id == 3206 and self.shuffle_state:
            self.sp.shuffle(False)
        elif control_id == 3206 and not self.shuffle_state:
            self.sp.shuffle(True)
        elif control_id == 3208 and self.repeat_state == "off":
            self.sp.repeat("track")
        elif control_id == 3208 and self.repeat_state == "track":
            self.sp.repeat("context")
        elif control_id == 3208 and self.repeat_state == "context":
            self.sp.repeat("off")

    def toggle_playback(self):
        '''toggle play/pause'''
        if self.is_playing:
            self.is_playing = False
            self.getControl(3202).setEnabled(False)
            try:
                self.sp.pause_playback()
            except Exception:
                pass
        else:
            self.is_playing = True
            self.getControl(3202).setEnabled(True)
            self.sp.start_playback()
Ejemplo n.º 29
0
class SpotifyOSD(xbmcgui.WindowXMLDialog):
    ''' Special OSD to control Spotify Connect player'''
    update_thread = None
    sp = None
    is_playing = True
    shuffle_state = False
    repeat_state = "off"

    def __init__(self, *args, **kwargs):
        self.metadatautils = MetadataUtils()
        xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)

    def onInit(self):
        '''triggers on initialization of the dialog'''
        self.update_thread = SpotifyOSDUpdateThread()
        self.update_thread.set_dialog(self)
        self.update_thread.start()

    def onAction(self, action):
        '''triggers on kodi navigation events'''
        action_id = action.getId()
        if action_id in (
                9,
                10,
                92,
                216,
                247,
                257,
                275,
                61467,
                61448,
        ):
            self.close_dialog()
        elif action_id in (12, 68, 79, 229):
            self.toggle_playback()
        elif action_id in (184, 14, 97):
            self.sp.next_track()
        elif action_id in (185, 15, 98):
            self.sp.previous_track()

    def close_dialog(self):
        '''stop background thread and close the dialog'''
        self.update_thread.stop_running()
        try:
            self.sp.pause_playback()
        except:
            pass
        self.metadatautils.close()
        self.close()

    def onClick(self, control_id):
        '''Kodi builtin: triggers if window is clicked'''
        if control_id == 3201:
            self.sp.previous_track()
        elif control_id == 3203:
            self.toggle_playback()
        elif control_id == 3204:
            self.sp.next_track()
        elif control_id == 3206 and self.shuffle_state:
            self.sp.shuffle(False)
        elif control_id == 3206 and not self.shuffle_state:
            self.sp.shuffle(True)
        elif control_id == 3208 and self.repeat_state == "off":
            self.sp.repeat("track")
        elif control_id == 3208 and self.repeat_state == "track":
            self.sp.repeat("context")
        elif control_id == 3208 and self.repeat_state == "context":
            self.sp.repeat("off")

    def toggle_playback(self):
        '''toggle play/pause'''
        if self.is_playing:
            self.is_playing = False
            self.getControl(3202).setEnabled(False)
            try:
                self.sp.pause_playback()
            except Exception:
                pass
        else:
            self.is_playing = True
            self.getControl(3202).setEnabled(True)
            self.sp.start_playback()
Ejemplo n.º 30
0
class Main(object):
    '''Main entry path for our widget listing. Process the arguments and load correct class and module'''

    def __init__(self):
        ''' Initialization '''

        self.metadatautils = MetadataUtils()
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.win = xbmcgui.Window(10000)
        self.options = self.get_options()

        # skip if shutdown requested
        if self.win.getProperty("SkinHelperShutdownRequested"):
            log_msg("Not forfilling request: Kodi is exiting!", xbmc.LOGWARNING)
            xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)

        elif not "mediatype" in self.options or not "action" in self.options:
            # we need both mediatype and action, so show the main listing
            self.mainlisting()
        else:
            # we have a mediatype and action so display the widget listing
            self.show_widget_listing()

        self.close()

    def close(self):
        '''Cleanup Kodi Cpython instances'''
        self.metadatautils.close()
        del self.addon
        del self.win
        log_msg("MainModule exited")

    def get_options(self):
        '''get the options provided to the plugin path'''

        options = dict(urlparse.parse_qsl(sys.argv[2].replace('?', '').lower().decode("utf-8")))

        # set the widget settings as options
        options["hide_watched"] = self.addon.getSetting("hide_watched") == "true"
        if self.addon.getSetting("hide_watched_recent") == "true" and "recent" in options.get("action", ""):
            options["hide_watched"] = True
        options["num_recent_similar"] = int(self.addon.getSetting("num_recent_similar"))
        options["exp_recommended"] = self.addon.getSetting("exp_recommended") == "true"
        options["hide_watched_similar"] = self.addon.getSetting("hide_watched_similar") == "true"
        options["next_inprogress_only"] = self.addon.getSetting("nextup_inprogressonly") == "true"
        options["episodes_enable_specials"] = self.addon.getSetting("episodes_enable_specials") == "true"
        options["group_episodes"] = self.addon.getSetting("episodes_grouping") == "true"
        if "limit" in options:
            options["limit"] = int(options["limit"])
        else:
            options["limit"] = int(self.addon.getSetting("default_limit"))

        if not "mediatype" in options and "action" in options:
            # get the mediatype and action from the path (for backwards compatability with old style paths)
            for item in [
                ("movies", "movies"),
                ("shows", "tvshows"),
                ("episode", "episodes"),
                ("musicvideos", "musicvideos"),
                ("pvr", "pvr"),
                ("albums", "albums"),
                ("songs", "songs"),
                ("artists", "artists"),
                ("media", "media"),
                ("favourites", "favourites"),
                    ("favorites", "favourites")]:
                if item[0] in options["action"]:
                    options["mediatype"] = item[1]
                    options["action"] = options["action"].replace(item[1], "").replace(item[0], "")
                    break

        # prefer reload param for the mediatype
        if "mediatype" in options:
            alt_reload = self.win.getProperty("widgetreload-%s" % options["mediatype"])
            if options["mediatype"] == "favourites" or "favourite" in options["action"]:
                options["skipcache"] = "true"
            elif alt_reload:
                options["reload"] = alt_reload
            if not options.get("action") and options["mediatype"] == "favourites":
                options["action"] = "favourites"
            elif not options.get("action"):
                options["action"] = "listing"
            if "listing" in options["action"]:
                options["skipcache"] = "true"
            if options["action"] == "browsegenres" and options["mediatype"] == "randommovies":
                options["mediatype"] = "movies"
                options["random"] = True
            elif options["action"] == "browsegenres" and options["mediatype"] == "randomtvshows":
                options["mediatype"] = "tvshows"
                options["random"] = True

        return options

    def show_widget_listing(self):
        '''display the listing for the provided action and mediatype'''
        media_type = self.options["mediatype"]
        action = self.options["action"]
        # set widget content type
        if media_type in ["favourites", "pvr", "media"]:
            xbmcplugin.setContent(ADDON_HANDLE, "files")
        else:
            xbmcplugin.setContent(ADDON_HANDLE, media_type)

        # try to get from cache first...
        all_items = []
        # alter cache_str depending on whether "tag" is available
        if self.options["action"] == "similar":
            # if action is similar, use imdbid
            cache_id = self.options.get("imdbid", "")
            # if similar was called without imdbid, skip cache
            if not self.options.get("imdbid", ""):
                self.options["skipcache"] = "true"
        elif self.options["action"] == "playlist" and self.options["mediatype"]=="media":
            # if action is mixed playlist, use playlist labels
            cache_id = self.options.get("movie_label")+self.options.get("tv_label")
        else:
            # use tag otherwise
            cache_id = self.options.get("tag")
        cache_str = "SkinHelper.Widgets.%s.%s.%s.%s.%s" % (media_type,
                    action, self.options["limit"], self.options.get("path"), cache_id)
        if not self.win.getProperty("widgetreload2"):
            # at startup we simply accept whatever is in the cache
            cache_checksum = None
        else:
            # we use a checksum based on the reloadparam to make sure we have the most recent data
            cache_checksum = self.options.get("reload","")
        # only check cache if not "skipcache"
        if not self.options.get("skipcache") == "true":
            cache = self.metadatautils.cache.get(cache_str, checksum=cache_checksum)
            if cache:
                log_msg("MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- got items from cache - CHECKSUM: %s"
                        % (media_type, action, self.options.get("path"), self.options.get("tag"), cache_checksum))
                all_items = cache

        # Call the correct method to get the content from json when no cache
        if not all_items:
            log_msg("MEDIATYPE: %s - ACTION: %s - PATH: %s - TAG: %s -- no cache, quering kodi api to get items - CHECKSUM: %s"
                    % (media_type, action, self.options.get("path"), self.options.get("tag"), cache_checksum))

            # dynamically import and load the correct module, class and function
            try:
                media_module = __import__(media_type)
                media_class = getattr(
                    media_module,
                    media_type.capitalize())(self.addon, self.metadatautils, self.options)
                all_items = getattr(media_class, action)()
                del media_class
            except AttributeError:
                log_exception(__name__, "Incorrect widget action or type called")
            except Exception as exc:
                log_exception(__name__, exc)

            # randomize output if requested by skinner or user
            if self.options.get("randomize", "") == "true":
                all_items = sorted(all_items, key=lambda k: random.random())

            # prepare listitems and store in cache
            all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.prepare_listitem, all_items)
            self.metadatautils.cache.set(cache_str, all_items, checksum=cache_checksum)

        # fill that listing...
        xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_UNSORTED)
        all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.create_listitem, all_items)
        xbmcplugin.addDirectoryItems(ADDON_HANDLE, all_items, len(all_items))

        # end directory listing
        xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)

    def mainlisting(self):
        '''main listing'''
        all_items = []
        xbmcplugin.setContent(ADDON_HANDLE, "files")

        # movie node
        if xbmc.getCondVisibility("Library.HasContent(movies)"):
            all_items.append((xbmc.getLocalizedString(342), "movieslisting", "DefaultMovies.png"))

        # tvshows and episodes nodes
        if xbmc.getCondVisibility("Library.HasContent(tvshows)"):
            all_items.append((xbmc.getLocalizedString(20343), "tvshowslisting", "DefaultTvShows.png"))
            all_items.append((xbmc.getLocalizedString(20360), "episodeslisting", "DefaultTvShows.png"))

        # pvr node
        if xbmc.getCondVisibility("Pvr.HasTVChannels"):
            all_items.append((self.addon.getLocalizedString(32054), "pvrlisting", "DefaultAddonPVRClient.png"))

        # music nodes
        if xbmc.getCondVisibility("Library.HasContent(music)"):
            all_items.append((xbmc.getLocalizedString(132), "albumslisting", "DefaultAlbumCover.png"))
            all_items.append((xbmc.getLocalizedString(134), "songslisting", "DefaultMusicSongs.png"))
            all_items.append((xbmc.getLocalizedString(133), "artistslisting", "DefaultArtist.png"))

        # musicvideo node
        if xbmc.getCondVisibility("Library.HasContent(musicvideos)"):
            all_items.append((xbmc.getLocalizedString(20389), "musicvideoslisting", "DefaultAddonAlbumInfo.png"))

        # media node
        if xbmc.getCondVisibility(
                "Library.HasContent(movies) | Library.HasContent(tvshows) | Library.HasContent(music)"):
            all_items.append((self.addon.getLocalizedString(32057), "medialisting", "DefaultAddonAlbumInfo.png"))

        # favourites node
        all_items.append((xbmc.getLocalizedString(10134), "favouriteslisting", "DefaultAddonAlbumInfo.png"))

        # process the listitems and display listing
        all_items = self.metadatautils.process_method_on_list(create_main_entry, all_items)
        all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.prepare_listitem, all_items)
        all_items = self.metadatautils.process_method_on_list(self.metadatautils.kodidb.create_listitem, all_items)
        xbmcplugin.addDirectoryItems(ADDON_HANDLE, all_items, len(all_items))
        xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)
class PluginContent:
    '''Hidden plugin entry point providing some helper features'''
    params = {}
    win = None

    def __init__(self):
        self.cache = SimpleCache()
        self.mutils = MetadataUtils()
        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()
        self.mutils.close()
        del self.mutils
        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.mutils.kodidb.set_json("Player.Open", params)

    def playrecording(self):
        '''retrieve the recording and play to get resume working'''
        recording = self.mutils.kodidb.recording(self.params["recordingid"])
        params = {"item": {"recordingid": recording["recordingid"]}}
        self.mutils.kodidb.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 extraposter(self):
        '''helper to display extraposter in multiimage control in the skin'''
        posters = eval(self.params["posters"])
        # process extraposters
        for count, item in enumerate(posters):
            listitem = xbmcgui.ListItem("poster%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.mutils.kodidb, mediatype)(sort=sort,
                                                           filters=filters,
                                                           limits=(0, 50))
            for item in items:
                image = self.mutils.get_clean_image(item["art"].get(
                    arttype, ""))
                if image:
                    image = self.mutils.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.mutils.kodidb.castmedia(name)
            all_items = self.mutils.process_method_on_list(
                self.mutils.kodidb.prepare_listitem, all_items)
            all_items = self.mutils.process_method_on_list(
                self.mutils.kodidb.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"
        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.mutils.kodidb.movie(db_id)["cast"]
            elif movie and not db_id:
                filters = [{
                    "operator": "is",
                    "field": "title",
                    "value": movie
                }]
                result = self.mutils.kodidb.movies(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif tvshow and db_id:
                all_cast = self.mutils.kodidb.tvshow(db_id)["cast"]
            elif tvshow and not db_id:
                filters = [{
                    "operator": "is",
                    "field": "title",
                    "value": tvshow
                }]
                result = self.mutils.kodidb.tvshows(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif episode and db_id:
                all_cast = self.mutils.kodidb.episode(db_id)["cast"]
            elif episode and not db_id:
                filters = [{
                    "operator": "is",
                    "field": "title",
                    "value": episode
                }]
                result = self.mutils.kodidb.episodes(filters=filters)
                all_cast = result[0]["cast"] if result else []
            elif movieset:
                if not db_id:
                    for item in self.mutils.kodidb.moviesets():
                        if item["title"].lower() == movieset.lower():
                            db_id = item["setid"]
                if db_id:
                    json_result = self.mutils.kodidb.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"] = self.mutils.get_clean_image(
                            cast.get("thumbnail"))
                    if not cast.get("thumbnail"):
                        artwork = self.mutils.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 = self.mutils.tmdb.search_movie(movie)
                elif tvshow and not db_id:
                    tmdbdetails = self.mutils.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 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.mutils = MetadataUtils()
        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.dialog.mutils.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.dialog.mutils.kodidb.movies(filters=filters)
        items = self.mutils.process_method_on_list(self.dialog.mutils.kodidb.prepare_listitem, items)
        result = []
        for item in items:
            result.append(self.dialog.mutils.kodidb.create_listitem(item, False))
        movies_list.addItems(result)

        # Process tvshows
        items = self.dialog.mutils.kodidb.tvshows(filters=filters)
        items = self.mutils.process_method_on_list(self.dialog.mutils.kodidb.prepare_listitem, items)
        result = []
        for item in items:
            item["file"] = 'videodb://tvshows/titles/%s' % item['tvshowid']
            item["isFolder"] = True
            result.append(self.dialog.mutils.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.dialog.mutils.kodidb.prepare_listitem(item)
                item["file"] = "RunScript(script.skin.helper.service,action=getcastmedia,name=%s)" % item["label"]
                result.append(self.dialog.mutils.kodidb.create_listitem(item, False))
        cast_list.addItems(result)
    script.skin.helper.service
    Contextmenu for Pvr art
'''

import os, sys
import xbmc
import xbmcgui
from metadatautils import MetadataUtils
from utils import try_decode

# pylint: disable-msg=invalid-constant-name

# Kodi contextmenu item to configure pvr artwork
if __name__ == '__main__':

    ##### PVR Artwork ########
    win = xbmcgui.Window(10000)
    win.setProperty("SkinHelper.Artwork.ManualLookup", "busy")
    xbmc.executebuiltin("ActivateWindow(busydialog)")
    title = try_decode(xbmc.getInfoLabel("ListItem.Title"))
    if not title:
        title = try_decode(xbmc.getInfoLabel("ListItem.Label"))
    channel = try_decode(xbmc.getInfoLabel("ListItem.ChannelName"))
    genre = try_decode(xbmc.getInfoLabel("ListItem.Genre"))
    metadatautils = MetadataUtils()
    metadatautils.pvr_artwork_options(title, channel, genre)
    xbmc.executebuiltin("Dialog.Close(busydialog)")
    win.clearProperty("SkinHelper.Artwork.ManualLookup")
    metadatautils.close()
    del win
Ejemplo n.º 34
0
            log_msg(
                "Animated Art: lookup imdbid by title and year: (%s - %s)" %
                (title, year), xbmc.LOGNOTICE)
            imdb_id = metadatautils.get_omdb_info("", title, year,
                                                  content_type).get(
                                                      "imdbnumber", "")
        if not imdb_id:
            return title
    return imdb_id


# Kodi contextmenu item to configure the artwork
if __name__ == '__main__':
    xbmc.executebuiltin("ActivateWindow(busydialog)")
    log_msg("Contextmenu for Animated Art opened", xbmc.LOGNOTICE)
    ARTUTILS = MetadataUtils()
    WIN = xbmcgui.Window(10000)
    imdb_id = get_imdb_id(WIN, ARTUTILS)
    WIN.setProperty("SkinHelper.Artwork.ManualLookup", "busy")
    log_msg("Animated Art: Query animated art by IMDBID: %s" % imdb_id,
            xbmc.LOGNOTICE)
    artwork = ARTUTILS.get_animated_artwork(imdb_id,
                                            manual_select=True,
                                            ignore_cache=True)
    log_msg("Animated Art result: %s" % artwork, xbmc.LOGNOTICE)
    xbmc.executebuiltin("Dialog.Close(busydialog)")
    xbmc.executebuiltin("Container.Refresh")
    WIN.clearProperty("SkinHelper.Artwork.ManualLookup")
    del WIN
    ARTUTILS.close()
Ejemplo n.º 35
0
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.mutils = MetadataUtils()
        self.cache = self.mutils.cache

        self.params = self.get_params()
        log_msg("MainModule called with parameters: %s" % self.params)
        action = self.params.get("action", "")
        # launch module for action provided by this script
        try:
            getattr(self, action)()
        except AttributeError:
            log_exception(__name__, "No such action: %s" % action)
        except Exception as exc:
            log_exception(__name__, exc)
        finally:
            xbmc.executebuiltin("dialog.Close(busydialog)")

        # do cleanup
        self.close()

    def close(self):
        '''Cleanup Kodi Cpython instances on exit'''
        self.mutils.close()
        del self.win
        del self.addon
        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 = ""
        if sys.version_info.major == 3:
            for key, value in self.params.items():
                paramstring += ",%s=%s" % (key, value)
        else:
            for key, value in self.params.iteritems():
                paramstring += ",%s=%s" % (key, value)
        if 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 = try_decode(xbmc.getInfoLabel("Container.Viewmode"))
        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 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 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
        if sys.version_info.major == 3:
            views_file = try_decode(
                xbmcvfs.translatePath('special://skin/extras/views.xml'))
        else:
            views_file = try_decode(
                xbmc.translatePath('special://skin/extras/views.xml'))
        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 getCondVisibility(
                            "Skin.HasSetting(SkinHelper.view.Disabled.%s)" %
                            viewid)):
                    image = "special://skin/extras/viewthumbs/%s.jpg" % viewid
                    listitem = xbmcgui.ListItem(label=label)
                    listitem.setArt({'icon': 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 = try_decode(result.getLabel())
            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 = []
        if sys.version_info.major == 3:
            views_file = try_decode(
                xbmcvfs.translatePath('special://skin/extras/views.xml'))
        else:
            views_file = try_decode(
                xbmc.translatePath('special://skin/extras/views.xml'))
        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)
                listitem.setArt({'icon': image})
                listitem.setProperty("viewid", view_id)
                if not 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 = "plugin://plugin.video.youtube/kodion/search/query/?q=%s" % searchquery
        metadatautils = MetadataUtils()
        files = metadatautils.kodidb.files(lib_path)
        del metadatautils
        return files

    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)
                listitem.setArt({'icon': 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 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.mutils.kodidb.castmedia(name)
        items = self.mutils.process_method_on_list(
            self.mutils.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.mutils.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 getCondVisibility(
                    "System.HasModalDialog | System.HasVisibleModalDialog"):
                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 getCondVisibility("Control.HasFocus(%s)" % control):
                if getCondVisibility("Window.IsActive(busydialog)"):
                    xbmc.sleep(150)
                    continue
                elif count == 20 or (getCondVisibility(
                        "!Control.IsVisible(%s) | "
                        "!Integer.IsGreater(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 getCondVisibility(
                            "Control.IsVisible(%s) + Integer.IsGreater(Container(%s).NumItems,0)"
                            % (control, control)):
                        self.win.setProperty("SkinHelper.WidgetContainer",
                                             control)
                        return
                xbmc.sleep(50)

    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 = try_decode(xbmc.getInfoLabel(org_id))
        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 = 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", '')
        numvalue = self.params.get("numvalue", '')
        if numvalue:
            value = '%s' % numvalue
        else:
            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 getCondVisibility(
                "Container.Scrolling | Container.OnNext | "
                "Container.OnPrevious | !String.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)
            li_trailer = xbmc.getInfoLabel("%sListItem.Trailer" %
                                           widget_container_prefix)
            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)):
                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 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'''
        from resources.lib.searchdialog import SearchDialog
        search_dialog = SearchDialog(
            "script-skin_helper_service-CustomSearch.xml",
            try_decode(self.addon.getAddonInfo('path')), "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(message="%s" %
                                         (xbmc.getLocalizedString(125)),
                                         heading=xbmc.getLocalizedString(122))
            if ret:
                success = recursive_delete_dir(del_path)
                if success:
                    xbmcgui.Dialog().ok(
                        heading=xbmc.getLocalizedString(19179),
                        message=self.addon.getLocalizedString(32014),
                        line2=self.addon.getLocalizedString(32014))
                else:
                    xbmcgui.Dialog().ok(
                        heading=xbmc.getLocalizedString(16205),
                        message=xbmc.getLocalizedString(32015),
                        line2=self.addon.getLocalizedString(32014))

    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 = clean_string(self.params.get("header", ""))
        bodytxt = clean_string(self.params.get("message", ""))
        dialog = xbmcgui.Dialog()
        dialog.ok(heading=headertxt, message=bodytxt)
        del dialog

    def dialogyesno(self):
        '''helper to show a YES/NO dialog with a message'''
        headertxt = clean_string(self.params.get("header", ""))
        bodytxt = clean_string(self.params.get("message", ""))
        yesactions = self.params.get("yesaction", "").split("|")
        noactions = self.params.get("noaction", "").split("|")
        if xbmcgui.Dialog().yesno(heading=headertxt, message=bodytxt):
            for action in yesactions:
                xbmc.executebuiltin(action)
        else:
            for action in noactions:
                xbmc.executebuiltin(action)

    def textviewer(self):
        '''helper to show a textviewer dialog with a message'''
        headertxt = clean_string(self.params.get("header", ""))
        bodytxt = clean_string(self.params.get("message", ""))
        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)
        if skinstring is not None:
            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(urllib.parse.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)
Ejemplo n.º 36
0
class MainService:
    '''our main background service running the various threads'''
    last_skin = ""

    def __init__(self):
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)
        self.metadatautils = MetadataUtils()
        self.addonname = self.addon.getAddonInfo('name').decode("utf-8")
        self.addonversion = self.addon.getAddonInfo('version').decode("utf-8")
        self.kodimonitor = KodiMonitor(metadatautils=self.metadatautils, win=self.win)
        listitem_monitor = ListItemMonitor(
            metadatautils=self.metadatautils, win=self.win, monitor=self.kodimonitor)
        webservice = WebService(metadatautils=self.metadatautils)

        # start the extra threads
        listitem_monitor.start()
        webservice.start()
        self.win.clearProperty("SkinHelperShutdownRequested")
        log_msg('%s version %s started' % (self.addonname, self.addonversion), xbmc.LOGNOTICE)

        # run as service, check skin every 10 seconds and keep the other threads alive
        while not self.kodimonitor.abortRequested():

            # check skin version info
            self.check_skin_version()

            # sleep for 10 seconds
            self.kodimonitor.waitForAbort(10)

        # Abort was requested while waiting. We should exit
        self.win.setProperty("SkinHelperShutdownRequested", "shutdown")
        log_msg('Shutdown requested !', xbmc.LOGNOTICE)
        # stop the extra threads
        listitem_monitor.stop()
        webservice.stop()

        # cleanup objects
        self.close()

    def close(self):
        '''Cleanup Kodi Cpython instances'''
        self.metadatautils.close()
        del self.win
        del self.kodimonitor
        del self.metadatautils
        log_msg('%s version %s stopped' % (self.addonname, self.addonversion), xbmc.LOGNOTICE)

    def check_skin_version(self):
        '''check if skin changed'''
        try:
            skin = xbmc.getSkinDir()
            skin_addon = xbmcaddon.Addon(id=skin)
            skin_label = skin_addon.getAddonInfo('name').decode("utf-8")
            skin_version = skin_addon.getAddonInfo('version').decode("utf-8")
            this_skin = "%s-%s" % (skin_label, skin_version)
            del skin_addon
            if self.last_skin != this_skin:
                # auto correct skin settings if needed
                self.last_skin = this_skin
                self.win.setProperty("SkinHelper.skinTitle", "%s - %s: %s"
                                     % (skin_label, xbmc.getLocalizedString(19114), skin_version))
                self.win.setProperty("SkinHelper.skin_version", "%s: %s"
                                     % (xbmc.getLocalizedString(19114), skin_version))
                self.win.setProperty("SkinHelper.Version", self.addonversion.replace(".", ""))
                SkinSettings().correct_skin_settings()
        except Exception as exc:
            log_exception(__name__, exc)