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

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

        self.walls_delay = int(self.addon.getSetting("wallimages_delay"))
        self.wallimages.max_wallimages = int(
            self.addon.getSetting("max_wallimages"))
        self.pvr_bg_recordingsonly = self.addon.getSetting(
            "pvr_bg_recordingsonly") == "true"
        self.enable_walls = xbmc.getCondVisibility(
            "Skin.HasSetting(SkinHelper.EnableWallBackgrounds)")
        if self.addon.getSetting("enable_custom_images_path") == "true":
            self.custom_picturespath = self.addon.getSetting(
                "custom_images_path")
        else:
            self.custom_picturespath = ""
        try:
            # skinner can enable manual wall images generation so check for these settings
            # store in memory so wo do not have to query the skin settings too often
            if self.walls_delay:
                for key in self.all_backgrounds_keys.keys():
                    limitrange = xbmc.getInfoLabel(
                        "Skin.String(%s.EnableWallImages)" % key)
                    if limitrange:
                        self.wallimages.manual_walls[key] = int(limitrange)
        except Exception as exc:
            log_exception(__name__, exc)
 def set_day_night_theme(self, dayornight, themename, themefile):
     ''' Sets a new daynight theme'''
     currenttimevalue = xbmc.getInfoLabel(
         "Skin.String(SkinHelper.ColorTheme.%s.time)" % dayornight)
     if not currenttimevalue:
         currenttimevalue = "20:00" if dayornight == "night" else "07:00"
     timevalue = xbmcgui.Dialog().input(
         self.addon.getLocalizedString(32017),
         currenttimevalue).decode("utf-8")
     try:
         # check if the time is valid
         check_date = datetime(*(time.strptime(timevalue, "%H:%M")[0:6]))
         del check_date
         base_setting = "SkinHelper.ColorTheme.%s" % dayornight
         xbmc.executebuiltin("Skin.SetString(%s.theme,%s)" %
                             (base_setting, try_encode(themename)))
         xbmc.executebuiltin("Skin.SetString(%s.time,%s)" %
                             (base_setting, timevalue))
         label = "%s  (%s %s)" % (try_encode(themename),
                                  self.addon.getLocalizedString(32019),
                                  timevalue)
         xbmc.executebuiltin("Skin.SetString(%s.label,%s)" %
                             (base_setting, label))
         xbmc.executebuiltin("Skin.SetString(%s.file,%s)" %
                             (base_setting, try_encode(themefile)))
     except Exception as exc:
         log_exception(__name__, exc)
         xbmcgui.Dialog().ok(xbmc.getLocalizedString(329),
                             self.addon.getLocalizedString(32018))
 def check_daynighttheme(self):
     '''check if a specific day or night theme should be applied'''
     if xbmc.getCondVisibility(
             "Skin.HasSetting(SkinHelper.EnableDayNightThemes) + "
             "Skin.String(SkinHelper.ColorTheme.Day.time) + "
             "Skin.String(SkinHelper.ColorTheme.Night.time)"):
         try:
             daytime = xbmc.getInfoLabel(
                 "Skin.String(SkinHelper.ColorTheme.Day.time)")
             daytime = datetime(
                 *(time.strptime(daytime, "%H:%M")[0:6])).time()
             nighttime = xbmc.getInfoLabel(
                 "Skin.String(SkinHelper.ColorTheme.Night.time)")
             nighttime = datetime(
                 *(time.strptime(nighttime, "%H:%M")[0:6])).time()
             timestamp = datetime.now().time()
             if daytime <= timestamp <= nighttime:
                 dayornight = "Day"
             else:
                 dayornight = "Night"
             current_theme = xbmc.getInfoLabel(
                 "Skin.String(SkinHelper.LastColorTheme)")
             newtheme = xbmc.getInfoLabel(
                 "Skin.String(SkinHelper.ColorTheme.%s.theme)" % dayornight)
             if current_theme != newtheme:
                 themefile = xbmc.getInfoLabel(
                     "Skin.String(SkinHelper.ColorTheme.%s.file)" %
                     dayornight)
                 self.load_colortheme(themefile)
         except Exception as exc:
             log_exception(__name__, exc)
示例#4
0
 def get_folderandprefix(self):
     '''get the current folder and prefix'''
     cur_folder = ""
     cont_prefix = ""
     try:
         widget_container = try_decode(
             self.win.getProperty("SkinHelper.WidgetContainer"))
         if getCondVisibility(
                 "Window.IsActive(movieinformation)|Window.IsActive(DialogPVRInfo.xml)|Window.IsActive(DialogMusicInfo.xml)|Window.IsActive(script-script.extendedinfo-DialogVideoInfo.xml)"
         ):
             cont_prefix = ""
             cur_folder = try_decode(
                 xbmc.getInfoLabel(
                     "$INFO[Window.Property(xmlfile)]$INFO[Container.FolderPath]"
                     "$INFO[Container.NumItems]$INFO[Container.Content]"))
         elif widget_container:
             cont_prefix = "Container(%s)." % widget_container
             cur_folder = try_decode(
                 xbmc.getInfoLabel(
                     "widget-%s-$INFO[Container(%s).NumItems]-$INFO[Container(%s).ListItemAbsolute(1).Label]"
                     % (widget_container, widget_container,
                        widget_container)))
         else:
             cont_prefix = ""
             cur_folder = try_decode(
                 xbmc.getInfoLabel(
                     "$INFO[Window.Property(xmlfile)]$INFO[Container.FolderPath]$INFO[Container.NumItems]$INFO[Container.Content]"
                 ))
     except Exception as exc:
         log_exception(__name__, exc)
         cur_folder = ""
         cont_prefix = ""
     return (cur_folder, cont_prefix)
示例#5
0
    def onNotification(self, sender, method, data):
        '''builtin function for the xbmc.Monitor class'''
        try:
            log_msg("Kodi_Monitor: sender %s - method: %s  - data: %s" %
                    (sender, method, data))
            data = json.loads(try_decode(data))
            mediatype = ""
            dbid = 0
            transaction = False
            if data and isinstance(data, dict):
                if data.get("item"):
                    mediatype = data["item"].get("type", "")
                    dbid = data["item"].get("id", 0)
                elif data.get("type"):
                    mediatype = data["type"]
                    dbid = data.get("id", 0)
                if data.get("transaction"):
                    transaction = True

            if method == "System.OnQuit":
                self.win.setProperty("SkinHelperShutdownRequested", "shutdown")

            if method == "VideoLibrary.OnUpdate":
                self.process_db_update(mediatype, dbid, transaction)

            if method == "AudioLibrary.OnUpdate":
                self.process_db_update(mediatype, dbid, transaction)

            if method == "Player.OnStop":
                self.monitoring_stream = False
                self.infopanelshown = False
                self.win.clearProperty("Skinhelper.PlayerPlaying")
                self.win.clearProperty("TrailerPlaying")
                self.reset_win_props()

            if method == "Player.OnPlay":
                if not self.monitoring_stream and not getCondVisibility(
                        "Player.DisplayAfterSeek"):
                    self.reset_win_props()
                if self.wait_for_player():
                    if getCondVisibility("Player.HasAudio"):
                        if getCondVisibility("Player.IsInternetStream"):
                            self.monitor_radiostream()
                        else:
                            self.set_music_properties()
                    if getCondVisibility("Pvr.IsPlayingRadio"):
                        if getCondVisibility("!Player.IsInternetStream"):
                            self.monitor_radiostream()
                        else:
                            self.set_music_properties()
                    elif getCondVisibility(
                            "VideoPlayer.Content(livetv) | String.StartsWith(Player.FileNameAndPath,pvr://)"
                    ):
                        self.monitor_livetv()
                    else:
                        self.set_video_properties(mediatype, dbid)
                        self.show_info_panel()
        except Exception as exc:
            log_exception(__name__, exc)
def get_repo_addoninfo(addonid, simplecache=None):
    '''tries to grab info about the addon from kodi repo addons listing'''
    if simplecache:
        cache = simplecache
        cachestr = "skinhelper.addoninfo.%s" % addonid
        info = simplecache.get(cachestr)
    if not info:
        info = {"addonid": addonid, "name": "", "thumbnail": "", "author": ""}
        mirrorurl = "http://addons.kodi.tv/show/%s/" % addonid
        try:
            if sys.version_info.major == 3:
                req = urllib.request.Request(mirrorurl)
                req.add_header(
                    'User-Agent',
                    'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3'
                )
                response = urllib.request.urlopen(req)
            else:
                req = urllib2.Request(mirrorurl)
                req.add_header(
                    'User-Agent',
                    'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3'
                )
                response = urllib2.urlopen(req)
            body = response.read()
            response.close()
            body = body.replace('\r', '').replace('\n', '').replace('\t', '')
            for addondetail in re.compile(
                    '<div id="addonDetail">(.*?)</div>').findall(body):
                for h2_item in re.compile('<h2>(.*?)</h2>').findall(
                        addondetail):
                    info["name"] = h2_item
                    break
                for thumbnail in re.compile('src="(.*?)"').findall(
                        addondetail):
                    icon = "http://addons.kodi.tv/%s" % thumbnail
                    info["thumbnail"] = icon
                    break
                authors = []
                for addonmetadata in re.compile(
                        '<div id="addonMetaData">(.*?)</div>').findall(body):
                    for author in re.compile('<a href="(.*?)">(.*?)</a>'
                                             ).findall(addonmetadata):
                        authors.append(author[1])
                info["author"] = ",".join(authors)
                break
        except Exception as exc:
            if "HTTP Error 404" not in exc:  # ignore not found exceptions
                log_exception(__name__, exc)
        if simplecache:
            cache.set(cachestr, info)
    return info
示例#7
0
 def do_background_work(self):
     '''stuff that's processed in the background'''
     try:
         if self.exit:
             return
         log_msg("Started Background worker...")
         self.set_generic_props()
         self.listitem_details = {}
         if self.exit:
             return
         self.cache.check_cleanup()
         log_msg("Ended Background worker...")
     except Exception as exc:
         log_exception(__name__, exc)
示例#8
0
 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)
示例#9
0
    def __init__(self):
        self.cache = SimpleCache()
        self.mutils = MetadataUtils()
        self.win = xbmcgui.Window(10000)
        try:
            if sys.version_info.major == 3:
                self.params = dict(urllib.parse.parse_qsl(sys.argv[2].replace('?', '').lower()))
            else:
                self.params = dict(urlparse.parse_qsl(sys.argv[2].replace('?', '').lower().decode("utf-8")))
            log_msg("plugin called with parameters: %s" % self.params)
            self.main()
        except Exception as exc:
            log_exception(__name__, exc)
            xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

        # cleanup when done processing
        self.close()
 def __init__(self):
     '''Initialization and main code run'''
     try:
         self.params = self.get_params()
         log_msg("called with parameters: %s" % self.params)
         action = self.params.get("action", "")
         if not action:
             # launch main backuprestore dialog
             BackupRestore().backuprestore()
         else:
             # launch module for action provided by this script
             if hasattr(self, action):
                 getattr(self, action)()
             else:
                 log_msg("No such action: %s" % action, xbmc.LOGWARNING)
     except Exception as exc:
         log_exception(__name__, exc)
示例#11
0
    def __init__(self):
        self.win = xbmcgui.Window(10000)
        self.addon = xbmcaddon.Addon(ADDON_ID)

        self.params = self.get_params()
        log_msg('MainModule called with parameters: %s' % self.params)
        action = self.params.get('action', '')

        try:
            getattr(self, action)()
        except AttributeError:
            log_exception(__name__, "No such action: %s" % action)
        except Exception as exc:
            log_exception(__name__, exc)
        finally:
            xbmc.executebuiltin('dialog.Close(busydialog)')

        self.close()
示例#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()
示例#13
0
 def check_skin_version(self):
     '''check if skin changed'''
     try:
         skin = xbmc.getSkinDir()
         skin_addon = xbmcaddon.Addon(id=skin)
         skin_label = try_decode(skin_addon.getAddonInfo('name'))
         skin_version = try_decode(skin_addon.getAddonInfo('version'))
         this_skin = "%s-%s" % (skin_label, skin_version)
         del skin_addon
         if self.last_skin != this_skin:
             # auto correct skin settings if needed
             self.last_skin = this_skin
             self.win.setProperty("SkinHelper.skinTitle", "%s - %s: %s"
                                  % (skin_label, xbmc.getLocalizedString(19114), skin_version))
             self.win.setProperty("SkinHelper.skin_version", "%s: %s"
                                  % (xbmc.getLocalizedString(19114), skin_version))
             self.win.setProperty("SkinHelper.Version", self.addonversion.replace(".", ""))
             SkinSettings().correct_skin_settings()
     except Exception as exc:
         log_exception(__name__, exc)
 def handle_image(self, image):
     '''serve image'''
     if image:
         # send single image
         try:
             ext = image.split(".")[-1]
             cherrypy.response.headers['Content-Type'] = 'image/%s' % ext
             modified = xbmcvfs.Stat(image).st_mtime()
             cherrypy.response.headers['Last-Modified'] = "%s" % modified
             image = xbmcvfs.File(image)
             cherrypy.response.headers['Content-Length'] = str(image.size())
             if cherrypy.request.method.upper() == 'GET':
                 img_data = image.readBytes()
                 image.close()
                 return str(img_data)
             else:
                 image.close()
         except Exception as exc:
             log_exception(__name__, exc)
     else:
         raise cherrypy.HTTPError(404,
                                  "No image found matching the criteria")
示例#15
0
    def show_widget_listing(self):
        '''display the listing for the provided action and mediatype'''
        media_type = self.options["mediatype"]
        action = self.options["action"]
        # set widget content type
        if media_type in ["favourites", "pvr", "media"]:
            xbmcplugin.setContent(ADDON_HANDLE, "files")
        else:
            xbmcplugin.setContent(ADDON_HANDLE, media_type)

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

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

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

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

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

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

        # end directory listing
        xbmcplugin.endOfDirectory(handle=ADDON_HANDLE)
    def create_colortheme(self):
        '''create a colortheme from current skin color settings'''
        try:
            current_skinfont = None
            json_response = kodi_json("Settings.GetSettingValue",
                                      {"setting": "lookandfeel.font"})
            if json_response:
                current_skinfont = json_response
            current_skincolors = None
            json_response = kodi_json("Settings.GetSettingValue",
                                      {"setting": "lookandfeel.skincolors"})
            if json_response:
                current_skincolors = json_response

            # user has to enter name for the theme
            themename = xbmcgui.Dialog().input(
                self.addon.getLocalizedString(32023),
                type=xbmcgui.INPUT_ALPHANUM).decode("utf-8")
            if not themename:
                return

            xbmc.executebuiltin("ActivateWindow(busydialog)")
            xbmc.executebuiltin(
                "Skin.SetString(SkinHelper.LastColorTheme,%s)" %
                try_encode(themename))

            # add screenshot
            custom_thumbnail = xbmcgui.Dialog().browse(
                2, self.addon.getLocalizedString(32024), 'files')

            if custom_thumbnail:
                xbmcvfs.copy(custom_thumbnail,
                             self.userthemes_path + themename + ".jpg")

            # read the guisettings file to get all skin settings
            from resources.lib.backuprestore import BackupRestore
            skinsettingslist = BackupRestore().get_skinsettings([
                "color", "opacity", "texture", "panel", "colour", "background",
                "image"
            ])
            newlist = []
            if skinsettingslist:
                newlist.append(("THEMENAME", themename))
                newlist.append(
                    ("DESCRIPTION", self.addon.getLocalizedString(32025)))
                newlist.append(
                    ("SKINTHEME", xbmc.getInfoLabel("Skin.CurrentTheme")))
                newlist.append(("SKINFONT", current_skinfont))
                newlist.append(("SKINCOLORS", current_skincolors))

                # look for any images in the skin settings and translate them so they can
                # be included in the theme backup
                for skinsetting in skinsettingslist:
                    setting_type = skinsetting[0]
                    setting_name = skinsetting[1]
                    setting_value = skinsetting[2]
                    if setting_type == "string" and setting_value:
                        if (setting_value
                                and (setting_value.endswith(".png")
                                     or setting_value.endswith(".gif")
                                     or setting_value.endswith(".jpg"))
                                and "resource://" not in setting_value):
                            image = get_clean_image(setting_value)
                            extension = image.split(".")[-1]
                            newimage = "%s_%s.%s" % (
                                themename, normalize_string(setting_name),
                                extension)
                            newimage_path = self.userthemes_path + newimage
                            if xbmcvfs.exists(image):
                                xbmcvfs.copy(image, newimage_path)
                                skinsetting = (setting_type, setting_name,
                                               newimage_path)
                    newlist.append(skinsetting)

                # save guisettings
                text_file_path = self.userthemes_path + themename + ".theme"
                text_file = xbmcvfs.File(text_file_path, "w")
                text_file.write(repr(newlist))
                text_file.close()
                xbmc.executebuiltin("Dialog.Close(busydialog)")
                xbmcgui.Dialog().ok(self.addon.getLocalizedString(32026),
                                    self.addon.getLocalizedString(32027))
        except Exception as exc:
            xbmc.executebuiltin("Dialog.Close(busydialog)")
            log_exception(__name__, exc)
            xbmcgui.Dialog().ok(self.addon.getLocalizedString(32028),
                                self.addon.getLocalizedString(32030), str(exc))
示例#17
0
    def set_listitem_details(self, cur_listitem, content_type, prefix):
        '''set the window properties based on the current listitem'''
        try:
            if cur_listitem in self.listitem_details:
                # data already in memory
                all_props = self.listitem_details[cur_listitem]
            else:
                # skip if another lookup for the same listitem is already in progress...
                if self.lookup_busy.get(cur_listitem) or self.exit:
                    return
                self.lookup_busy[cur_listitem] = True

                # clear all window props, do this delayed to prevent flickering of the screen
                thread.start_new_thread(self.delayed_flush, (cur_listitem, ))

                # wait if we already have more than 5 items in the queue
                while len(self.lookup_busy) > 5:
                    xbmc.sleep(100)
                    if self.exit or cur_listitem != self.last_listitem:
                        self.lookup_busy.pop(cur_listitem, None)
                        return

                # prefer listitem's contenttype over container's contenttype
                dbtype = xbmc.getInfoLabel("%sListItem.DBTYPE" % prefix)
                if not dbtype:
                    dbtype = xbmc.getInfoLabel("%sListItem.Property(DBTYPE)" %
                                               prefix)
                if dbtype:
                    content_type = dbtype + "s"

                # collect details from listitem
                details = self.get_listitem_details(content_type, prefix)

                if self.exit:
                    return

                # music content
                if content_type in ["albums", "artists", "songs"
                                    ] and self.enable_musicart:
                    details = self.metadatautils.extend_dict(
                        details,
                        self.metadatautils.get_music_artwork(
                            details["artist"], details["album"],
                            details["title"], details["discnumber"]))
                # moviesets
                elif details["path"].startswith(
                        "videodb://movies/sets/") and details["dbid"]:
                    details = self.metadatautils.extend_dict(
                        details,
                        self.metadatautils.get_moviesetdetails(
                            details["title"], details["dbid"]), ["year"])
                    content_type = "sets"
                # video content
                elif content_type in [
                        "movies", "setmovies", "tvshows", "seasons",
                        "episodes", "musicvideos"
                ]:

                    # get imdb and tvdbid
                    details[
                        "imdbnumber"], tvdbid = self.metadatautils.get_imdbtvdb_id(
                            details["title"], content_type, details["year"],
                            details["imdbnumber"], details["tvshowtitle"])

                    if self.exit:
                        return

                    # generic video properties (studio, streamdetails, omdb, top250)
                    details = merge_dict(
                        details,
                        self.get_directors_writers(details["director"],
                                                   details["writer"]))
                    if self.enable_extrafanart:
                        log_msg("skin.helper.service: extrafanart",
                                xbmc.LOGINFO)
                        if not details["filenameandpath"]:
                            details["filenameandpath"] = details["path"]
                        if "videodb://" not in details["filenameandpath"]:
                            efa = self.metadatautils.get_extrafanart(
                                details["filenameandpath"])
                            if efa:
                                details["art"] = merge_dict(
                                    details["art"], efa["art"])
                    if self.enable_extraposter:
                        if not details["filenameandpath"]:
                            details["filenameandpath"] = details["path"]
                        if "videodb://" not in details["filenameandpath"]:
                            efa = self.metadatautils.get_extraposter(
                                details["filenameandpath"])
                            if efa:
                                details["art"] = merge_dict(
                                    details["art"], efa["art"])
                    if self.exit:
                        return

                    details = merge_dict(
                        details,
                        self.metadatautils.get_duration(details["duration"]))
                    details = merge_dict(details,
                                         self.get_genres(details["genre"]))
                    details = merge_dict(
                        details,
                        self.metadatautils.get_studio_logo(details["studio"]))
                    details = merge_dict(
                        details,
                        self.metadatautils.get_omdb_info(
                            details["imdbnumber"]))
                    details = merge_dict(
                        details,
                        self.get_streamdetails(details["dbid"],
                                               details["path"], content_type))
                    # Disable when get_top250 gets crazy
                    details = merge_dict(
                        details,
                        self.metadatautils.get_top250_rating(
                            details["imdbnumber"]))

                    if self.exit:
                        return

                    # tvshows-only properties (tvdb)
                    #if content_type in ["tvshows", "seasons", "episodes"]:
                    #    details = merge_dict(
                    #        details, self.metadatautils.get_tvdb_details(
                    #            details["imdbnumber"], tvdbid))

                    # movies-only properties (tmdb, animated art)
                    if content_type in ["movies", "setmovies", "tvshows"]:
                        details = merge_dict(
                            details,
                            self.metadatautils.get_tmdb_details(
                                details["imdbnumber"]))
                        if details["imdbnumber"] and self.enable_animatedart:
                            details = self.metadatautils.extend_dict(
                                details,
                                self.metadatautils.get_animated_artwork(
                                    details["imdbnumber"]))

                    if self.exit:
                        return

                    # extended art
                    if self.enable_extendedart:
                        tmdbid = details.get("tmdb_id", "")
                        details = self.metadatautils.extend_dict(
                            details,
                            self.metadatautils.get_extended_artwork(
                                details["imdbnumber"], tvdbid, tmdbid,
                                content_type), [
                                    "posters", "clearlogos", "banners",
                                    "discarts", "cleararts", "characterarts"
                                ])
                # monitor listitem props when PVR is active
                elif content_type in [
                        "tvchannels", "tvrecordings", "channels", "recordings",
                        "timers", "tvtimers"
                ]:
                    details = self.get_pvr_artwork(details, prefix)

                # process all properties
                all_props = prepare_win_props(details)
                if "sets" not in content_type:
                    self.listitem_details[cur_listitem] = all_props

                self.lookup_busy.pop(cur_listitem, None)

            if cur_listitem == self.last_listitem:
                self.set_win_props(all_props)
        except Exception as exc:
            log_exception(__name__, exc)
            self.lookup_busy.pop(cur_listitem, None)