#!/usr/bin/python # -*- coding: utf-8 -*- ''' script.skin.helper.service Helper service and scripts for Kodi skins resourceaddons.py several helpers to get data/images from kodi image resource addons ''' import xbmc import xbmcvfs import xbmcgui import xbmcaddon from utils import KODI_VERSION, ADDON_ID, log_exception, kodi_json, getCondVisibility from dialogselect import DialogSelect import urllib2 import re from simplecache import SimpleCache def setresourceaddon(addontype, skinstring="", header=""): '''helper to let the user choose a resource addon and set that as skin string''' xbmc.executebuiltin("ActivateWindow(busydialog)") cur_value = xbmc.getInfoLabel("Skin.String(%s.name)" % skinstring).decode("utf-8") listing = [] addon = xbmcaddon.Addon(ADDON_ID) if not header: header = addon.getLocalizedString(32010) # none option listitem = xbmcgui.ListItem(label=addon.getLocalizedString(32001), iconImage="DefaultAddonNone.png") listitem.setProperty("addonid", "none") listing.append(listitem) # custom path listitem = xbmcgui.ListItem(label=addon.getLocalizedString(32009), iconImage="DefaultFolder.png") listitem.setProperty("addonid", "custom") listing.append(listitem) # available resource addons for item in get_resourceaddons(addontype): label2 = "%s: %s" % (xbmc.getLocalizedString(21863), item["author"]) listitem = xbmcgui.ListItem(label=item["name"], label2=label2, iconImage=item["thumbnail"]) listitem.setPath(item["path"]) listitem.setProperty("addonid", item["addonid"]) listing.append(listitem) # special skinhelper paths if addontype == "resource.images.moviegenrefanart": label = addon.getLocalizedString(32019) listitem = xbmcgui.ListItem( label=label, label2="Skin Helper Service", iconImage="special://home/addons/script.skin.helper.service/icon.png") listitem.setPath("plugin://script.skin.helper.service/?action=moviegenrebackground&genre=") listitem.setProperty("addonid", "skinhelper.forgenre") listing.append(listitem) # show select dialog with choices dialog = DialogSelect("DialogSelect.xml", "", listing=listing, windowtitle=header, richlayout=True, getmorebutton=addontype, autofocuslabel=cur_value) dialog.doModal() result = dialog.result del dialog # process selection... if isinstance(result, bool) and result: # refresh listing requested by getmore button del addon return setresourceaddon(addontype, skinstring) elif result: addon_id = result.getProperty("addonid") addon_name = result.getLabel().decode("utf-8") if addon_id == "none" and skinstring: # None xbmc.executebuiltin('Skin.Reset(%s)' % skinstring) xbmc.executebuiltin('Skin.Reset(%s.ext)' % skinstring) xbmc.executebuiltin('Skin.SetString(%s.name,%s)' % (skinstring, addon_name)) xbmc.executebuiltin('Skin.SetString(%s.label,%s)' % (skinstring, addon_name)) xbmc.executebuiltin('Skin.Reset(%s.path)' % skinstring) xbmc.executebuiltin('Skin.Reset(%s.multi)' % skinstring) else: if addon_id == "custom": # custom path dialog = xbmcgui.Dialog() custom_path = dialog.browse(0, addon.getLocalizedString(32005), 'files') del dialog result.setPath(custom_path) addonpath = result.getfilename().decode("utf-8") if addonpath: is_multi, extension = get_multi_extension(addonpath) xbmc.executebuiltin('Skin.SetString(%s,%s)' % (skinstring, addonpath)) xbmc.executebuiltin('Skin.SetString(%s.path,%s)' % (skinstring, addonpath)) xbmc.executebuiltin('Skin.SetString(%s.name,%s)' % (skinstring, addon_name)) xbmc.executebuiltin('Skin.SetString(%s.label,%s)' % (skinstring, addon_name)) xbmc.executebuiltin('Skin.SetString(%s.ext,%s)' % (skinstring, extension)) if is_multi: xbmc.executebuiltin('Skin.SetBool(%s.multi)' % skinstring) else: xbmc.executebuiltin('Skin.Reset(%s.multi)' % skinstring) del addon def downloadresourceaddons(addontype): '''show dialog with all available resource addons on the repo so the user can install one''' xbmc.executebuiltin("ActivateWindow(busydialog)") listitems = [] addon = xbmcaddon.Addon(ADDON_ID) for item in get_repo_resourceaddons(addontype): if not getCondVisibility("System.HasAddon(%s)" % item["addonid"]): label2 = "%s: %s" % (xbmc.getLocalizedString(21863), item["author"]) listitem = xbmcgui.ListItem(label=item["name"], label2=label2, iconImage=item["thumbnail"]) listitem.setPath(item["path"]) listitem.setProperty("addonid", item["addonid"]) listitems.append(listitem) # if no addons available show OK dialog.. if not listitems: dialog = xbmcgui.Dialog() dialog.ok(addon.getLocalizedString(32021), addon.getLocalizedString(32022)) del dialog else: # show select dialog with choices dialog = DialogSelect("DialogSelect.xml", "", listing=listitems, windowtitle=addon.getLocalizedString(32021), richlayout=True) dialog.doModal() result = dialog.result del dialog del addon # process selection... if result: addon_id = result.getProperty("addonid") # trigger install... monitor = xbmc.Monitor() if KODI_VERSION > 16: xbmc.executebuiltin("InstallAddon(%s)" % addon_id) else: xbmc.executebuiltin("RunPlugin(plugin://%s)" % addon_id) count = 0 # wait (max 2 minutes) untill install is completed install_succes = False while not monitor.waitForAbort(1) and not install_succes and count < 120: install_succes = getCondVisibility("System.HasAddon(%s)" % addon_id) del monitor if install_succes: return True return False def checkresourceaddons(addonslist): '''allow the skinner to perform a basic check if some required resource addons are available''' addon = xbmcaddon.Addon(ADDON_ID) for item in addonslist: setting = item.split(";")[0] addontype = item.split(";")[1] addontypelabel = item.split(";")[2] skinsetting = xbmc.getInfoLabel("Skin.String(%s.path)" % setting).decode("utf-8") if not skinsetting or (skinsetting and getCondVisibility("!System.HasAddon(%s)" % skinsetting.replace("resource://", "").replace("/", ""))): # skin setting is empty or filled with non existing addon... if not checkresourceaddon(setting, addontype): ret = xbmcgui.Dialog().yesno( heading=addon.getLocalizedString(32007) % addontypelabel, line1=addon.getLocalizedString(32008) % addontypelabel) xbmc.executebuiltin("Skin.Reset(%s.path)" % setting) if ret: downloadresourceaddons(addontype) checkresourceaddon(setting, addontype) del addon def checkresourceaddon(skinstring="", addontype=""): ''' check for existing resource addons of specified type and set first one found''' if not addontype: addontype = params.get("addontype") if not skinstring: skinstring = params.get("skinstring") if addontype and skinstring: for item in get_resourceaddons(addontype): xbmc.executebuiltin("Skin.SetString(%s,%s)" % (skinstring, item['path'])) xbmc.executebuiltin("Skin.SetString(%s.path,%s)" % (skinstring, item['path'])) xbmc.executebuiltin("Skin.SetString(%s.name,%s)" % (skinstring, item['name'])) xbmc.executebuiltin("Skin.SetString(%s.label,%s)" % (skinstring, item['name'])) is_multi, extension = get_multi_extension(item["path"]) if is_multi: xbmc.executebuiltin("Skin.SetBool(%s.multi)" % (skinstring)) xbmc.executebuiltin("Skin.SetString(%s.ext,%s)" % (skinstring, extension)) return True return False def get_resourceaddons(filterstr=""): '''helper to retrieve all installed resource addons''' result = [] params = {"type": "kodi.resource.images", "properties": ["name", "thumbnail", "path", "author"]} for item in kodi_json("Addons.GetAddons", params, "addons"): if not filterstr or item['addonid'].lower().startswith(filterstr.lower()): item["path"] = "resource://%s/" % item["addonid"] result.append(item) return result def get_multi_extension(filepath): '''check if resource addon or custom path has subfolders (multiimage)''' is_multi = False extension = "" dirs, files = xbmcvfs.listdir(filepath) if len(dirs) > 0: is_multi = True if not is_multi: for item in files: extension = "." + item.split(".")[-1] break return (is_multi, extension) def get_repo_resourceaddons(filterstr=""): '''helper to retrieve all available resource addons on the kodi repo''' result = [] simplecache = SimpleCache() for item in xbmcvfs.listdir("addons://all/kodi.resource.images/")[1]: if not filterstr or item.lower().startswith(filterstr.lower()): addoninfo = get_repo_addoninfo(item, simplecache) if not addoninfo.get("name"): addoninfo = {"addonid": item, "name": item, "author": ""} addoninfo["thumbnail"] = "http://mirrors.kodi.tv/addons/krypton/%s/icon.png" % item addoninfo["path"] = "resource://%s/" % item result.append(addoninfo) simplecache.close() return result 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: req = urllib2.Request(mirrorurl) req.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3') response = urllib2.urlopen(req) body = response.read() response.close() body = body.replace('\r', '').replace('\n', '').replace('\t', '') for addondetail in re.compile('<div id="addonDetail">(.*?)</div>').findall(body): for h2_item in re.compile('<h2>(.*?)</h2>').findall(addondetail): info["name"] = h2_item break for thumbnail in re.compile('src="(.*?)"').findall(addondetail): icon = "http://addons.kodi.tv/%s" % thumbnail info["thumbnail"] = icon break authors = [] for addonmetadata in re.compile('<div id="addonMetaData">(.*?)</div>').findall(body): for author in re.compile('<a href="(.*?)">(.*?)</a>').findall(addonmetadata): authors.append(author[1]) info["author"] = ",".join(authors) break except Exception as exc: if "HTTP Error 404" not in exc: # ignore not found exceptions log_exception(__name__, exc) if simplecache: cache.set(cachestr, info) return info def get_resourceimages(addontype, recursive=False): '''retrieve listing of specific resource addon images''' images = [] for addon in get_resourceaddons(addontype): addonpath = addon["path"] if xbmcvfs.exists("special://home/addons/%s/resources/" % addon["addonid"]): addonpath = "special://home/addons/%s/resources/" % addon["addonid"] images += walk_directory(addonpath, recursive, addon["name"]) return images def walk_directory(browsedir, recursive=False, label2=""): '''list all images in a directory''' images = [] if xbmcvfs.exists(browsedir): dirs = xbmcvfs.listdir(browsedir)[0] subdirs = [browsedir] for directory in dirs: directory = directory.decode("utf-8") cur_dir = "%s%s/" % (browsedir, directory) if recursive: subdirs.append(cur_dir) else: label = directory images.append((label, cur_dir, label2, "DefaultFolder.png")) for subdir in subdirs: for imagefile in xbmcvfs.listdir(subdir)[1]: imagefile = imagefile.decode("utf-8") label = imagefile imagepath = subdir + imagefile images.append((label, imagepath, label2, imagepath)) return images