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