def __init__(self, kodidb=None): """Initialize - optionaly provide KodiDb object""" if not kodidb: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb
class Imdb(object): """Info from IMDB (currently only top250)""" def __init__(self, simplecache=None, kodidb=None): """Initialize - optionaly provide simplecache object""" if not simplecache: from simplecache import SimpleCache self.cache = SimpleCache() else: self.cache = simplecache if not kodidb: if sys.version_info.major == 3: from .kodidb import KodiDb else: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb @use_cache(2) def get_top250_rating(self, imdb_id): """get the top250 rating for the given imdbid""" return {"IMDB.Top250": self.get_top250_db().get(imdb_id, 0)} @use_cache(7) def get_top250_db(self): """ get the top250 listing for both movies and tvshows as dict with imdbid as key uses 7 day cache to prevent overloading the server """ results = {} for listing in [("top", "chttp_tt_"), ("toptv", "chttvtp_tt_")]: html = requests.get("http://www.imdb.com/chart/%s" % listing[0], headers={'User-agent': 'Mozilla/5.0'}, timeout=20) soup = BeautifulSoup.BeautifulSoup(html.text, features="html.parser") for table in soup.findAll('table'): if table.get("class") == "chart full-width": for td_def in table.findAll('td'): if td_def.get("class") == "titleColumn": a_link = td_def.find("a") if a_link: url = a_link["href"] imdb_id = url.split("/")[2] imdb_rank = url.split(listing[1])[1] results[imdb_id] = try_parse_int(imdb_rank) self.write_kodidb(results) return results def write_kodidb(self, results): """store the top250 position in kodi database to access it with ListItem.Top250""" for imdb_id in results: kodi_movie = self.kodidb.movie_by_imdbid(imdb_id) if kodi_movie: params = { "movieid": kodi_movie["movieid"], "top250": results[imdb_id] } self.kodidb.set_json('VideoLibrary.SetMovieDetails', params)
def __init__(self, kodidb=None): """Initialize - optionaly provide KodiDb object""" if not kodidb: if sys.version_info.major == 3: from .kodidb import KodiDb else: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb
def __init__(self, simplecache=None, kodidb=None): '''Initialize - optionaly provide simplecache object''' if not simplecache: from simplecache import SimpleCache self.cache = SimpleCache() else: self.cache = simplecache if not kodidb: from kodidb import KodiDb self.kodidb = KodiDb(self.cache) else: self.kodidb = kodidb
def __init__(self, simplecache=None, kodidb=None): """Initialize - optionaly provide SimpleCache and KodiDb object""" if not kodidb: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb if not simplecache: from simplecache import SimpleCache self.cache = SimpleCache() else: self.cache = simplecache
def __init__(self, simplecache=None, kodidb=None): """Initialize - optionaly provide simplecache object""" if not simplecache: from simplecache import SimpleCache self.cache = SimpleCache() else: self.cache = simplecache if not kodidb: if sys.version_info.major == 3: from .kodidb import KodiDb else: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb
class Albums(object): def __init__(self, addon, options): self.addon = addon self.options = options self.kodidb = KodiDb() def search(self): '''search for albums that match a given string''' if 'artistid' in self.options: all_items = self.kodidb.albums(self.options['artistid']) else: all_items = self.kodidb.albums() return process_method_on_list(self.process_album, all_items) def process_album(self, item): '''transform the json received from kodi into something we can use''' item['file'] = 'musicdb://albums/%s' % item['albumid'] item['isFolder'] = True return item
class Songs(object): def __init__(self, addon, options): self.addon = addon self.options = options self.kodidb = KodiDb() def search(self): '''search for songs that match a given string''' if 'artistid' in self.options: all_items = self.kodidb.songs(self.options['artistid']) else: all_items = self.kodidb.songs() return process_method_on_list(self.process_song, all_items) def process_song(self, item): '''transform the json received from kodi into something we can use''' # Not the real file -- abusing this to get at the song id item['file'] = 'musicdb://songs/%s' % item['songid'] return item
class Movies(object): def __init__(self, addon, options): self.addon = addon self.options = options self.kodidb = KodiDb() def search(self): '''search for movies that match a given string''' all_items = self.kodidb.movies() return process_method_on_list(self.process_movie, all_items) def process_movie(self, item): '''transform the json received from kodi into something we can use''' return item
def __init__(self, simplecache=None, kodidb=None): '''Initialize - optionaly provide SimpleCache and KodiDb object''' if not kodidb: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb if not simplecache: from simplecache import SimpleCache self.cache = SimpleCache() else: self.cache = simplecache
class Addons(object): def __init__(self, addon, options): self.addon = addon self.options = options self.kodidb = KodiDb() def search(self): '''search for addons that match a given string''' all_items = self.kodidb.addons() return process_method_on_list(self.process_addon, all_items) def process_addon(self, item): '''transform the json received from kodi into something we can use''' item['label'] = item['name'] # abusing this to get at the addon id.. item['file'] = item['addonid'] return item
class ChannelLogos(object): """get channellogo""" def __init__(self, kodidb=None): """Initialize - optionaly provide KodiDb object""" if not kodidb: if sys.version_info.major == 3: from .kodidb import KodiDb else: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb def get_channellogo(self, channelname): """get channellogo for the supplied channelname""" result = {} for searchmethod in [self.search_kodi]: if result: break result = searchmethod(channelname) return result def search_kodi(self, searchphrase): """search kodi json api for channel logo""" result = "" if xbmc.getCondVisibility("PVR.HasTVChannels"): results = self.kodidb.get_json('PVR.GetChannels', fields=["thumbnail"], returntype="tvchannels", optparam=("channelgroupid", "alltv")) for item in results: if item["label"] == searchphrase: channelicon = get_clean_image(item['thumbnail']) if channelicon and xbmcvfs.exists(channelicon): result = channelicon break return result
def detect_plugin_content(plugin_path): '''based on the properties of a vfspath we try to detect the content type''' content_type = "" if not plugin_path: return "" # detect content based on the path if "listing" in plugin_path: content_type = "folder" elif "movie" in plugin_path.lower(): content_type = "movies" elif "album" in plugin_path.lower(): content_type = "albums" elif "show" in plugin_path.lower(): content_type = "tvshows" elif "episode" in plugin_path.lower(): content_type = "episodes" elif "song" in plugin_path.lower(): content_type = "songs" elif "musicvideo" in plugin_path.lower(): content_type = "musicvideos" elif "pvr" in plugin_path.lower(): content_type = "pvr" elif "type=dynamic" in plugin_path.lower(): content_type = "movies" elif "videos" in plugin_path.lower(): content_type = "movies" elif "type=both" in plugin_path.lower(): content_type = "movies" elif "media" in plugin_path.lower(): content_type = "movies" elif "favourites" in plugin_path.lower(): content_type = "movies" elif ("box" in plugin_path.lower() or "dvd" in plugin_path.lower() or "rentals" in plugin_path.lower() or "incinemas" in plugin_path.lower() or "comingsoon" in plugin_path.lower() or "upcoming" in plugin_path.lower() or "opening" in plugin_path.lower() or "intheaters" in plugin_path.lower()): content_type = "movies" # if we didn't get the content based on the path, we need to probe the addon... if not content_type and not xbmc.getCondVisibility( "Window.IsMedia"): # safety check from kodidb import KodiDb media_array = KodiDb().files(plugin_path, limits=(0, 1)) for item in media_array: if item.get("filetype", "") == "directory": content_type = "folder" break elif item.get("type") and item["type"] != "unknown": content_type = item["type"] + "s" break elif "showtitle" not in item and "artist" not in item: # these properties are only returned in the json response if we're looking at actual file content... # if it's missing it means this is a main directory listing and no need to # scan the underlying listitems. content_type = "files" break if "showtitle" not in item and "artist" in item: # AUDIO ITEMS if item["type"] == "artist": content_type = "artists" break elif (isinstance(item["artist"], list) and len(item["artist"]) > 0 and item["artist"][0] == item["title"]): content_type = "artists" break elif item["type"] == "album" or item["album"] == item["title"]: content_type = "albums" break elif ((item["type"] == "song" and "play_album" not in item["file"]) or (item["artist"] and item["album"])): content_type = "songs" break else: # VIDEO ITEMS if item["showtitle"] and not item.get("artist"): # this is a tvshow, episode or season... if item["type"] == "season" or (item["season"] > -1 and item["episode"] == -1): content_type = "seasons" break elif item["type"] == "episode" or item[ "season"] > -1 and item["episode"] > -1: content_type = "episodes" break else: content_type = "tvshows" break elif item.get("artist"): # this is a musicvideo! content_type = "musicvideos" break elif (item["type"] == "movie" or item.get("imdbnumber") or item.get("mpaa") or item.get("trailer") or item.get("studio")): content_type = "movies" break log_msg("detect_plugin_path_content for: %s - result: %s" % (plugin_path, content_type)) return content_type
class AnimatedArt(object): '''get animated artwork''' ignore_cache = False def __init__(self, simplecache=None, kodidb=None): '''Initialize - optionaly provide SimpleCache and KodiDb object''' if not kodidb: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb if not simplecache: from simplecache import SimpleCache self.cache = SimpleCache() else: self.cache = simplecache @use_cache(14) def get_animated_artwork(self, imdb_id, manual_select=False, ignore_cache=False): '''returns all available animated art for the given imdbid/tmdbid''' # prefer local result kodi_movie = self.kodidb.movie_by_imdbid(imdb_id) if not manual_select and kodi_movie and kodi_movie["art"].get("animatedposter"): result = { "animatedposter": kodi_movie["art"].get("animatedposter"), "animatedfanart": kodi_movie["art"].get("animatedfanart") } else: result = { "animatedposter": self.poster(imdb_id, manual_select), "animatedfanart": self.fanart(imdb_id, manual_select), "imdb_id": imdb_id } self.write_kodidb(result) log_msg("get_animated_artwork for imdbid: %s - result: %s" % (imdb_id, result)) return result def poster(self, imdb_id, manual_select=False): '''return preferred animated poster, optionally show selectdialog for manual selection''' img = self.select_art(self.posters(imdb_id), manual_select, "poster") return self.process_image(img, "poster", imdb_id) def fanart(self, imdb_id, manual_select=False): '''return preferred animated fanart, optionally show selectdialog for manual selection''' img = self.select_art(self.fanarts(imdb_id), manual_select, "fanart") return self.process_image(img, "fanart", imdb_id) def posters(self, imdb_id): '''return all animated posters for the given imdb_id (imdbid can also be tmdbid)''' return self.get_art(imdb_id, "posters") def fanarts(self, imdb_id): '''return animated fanarts for the given imdb_id (imdbid can also be tmdbid)''' return self.get_art(imdb_id, "fanarts") def get_art(self, imdb_id, art_type): '''get the artwork''' art_db = self.get_animatedart_db() if art_db.get(imdb_id): return art_db[imdb_id][art_type] return [] def get_animatedart_db(self): '''get the full animated art database as dict with imdbid and tmdbid as key uses 7 day cache to prevent overloading the server''' # get all animated posters from the online json file cache = self.cache.get("animatedartdb") if cache: return cache art_db = {} data = get_json('http://www.consiliumb.com/animatedgifs/movies.json', None) base_url = data.get("baseURL", "") if data and data.get('movies'): for item in data['movies']: for db_id in ["imdbid", "tmdbid"]: key = item[db_id] art_db[key] = {"posters": [], "fanarts": []} for entry in item['entries']: entry_new = { "contributedby": entry["contributedBy"], "dateadded": entry["dateAdded"], "language": entry["language"], "source": entry["source"], "image": "%s/%s" % (base_url, entry["image"].replace(".gif", "_original.gif")), "thumb": "%s/%s" % (base_url, entry["image"])} if entry['type'] == 'poster': art_db[key]["posters"].append(entry_new) elif entry['type'] == 'background': art_db[key]["fanarts"].append(entry_new) self.cache.set("animatedartdb", art_db, expiration=timedelta(days=7)) return art_db @staticmethod def select_art(items, manual_select=False, art_type=""): '''select the preferred image from the list''' image = None if manual_select: # show selectdialog to manually select the item results_list = [] # add none and browse entries listitem = xbmcgui.ListItem(label=xbmc.getLocalizedString(231), iconImage="DefaultAddonNone.png") results_list.append(listitem) listitem = xbmcgui.ListItem(label=xbmc.getLocalizedString(1030), iconImage="DefaultFolder.png") results_list.append(listitem) for item in items: labels = [item["contributedby"], item["dateadded"], item["language"], item["source"]] label = " / ".join(labels) listitem = xbmcgui.ListItem(label=label, iconImage=item["thumb"]) results_list.append(listitem) if manual_select and results_list: dialog = DialogSelect("DialogSelect.xml", "", listing=results_list, window_title=art_type) dialog.doModal() selected_item = dialog.result del dialog if selected_item == 0: image = "" if selected_item == 1: # browse for image dialog = xbmcgui.Dialog() image = dialog.browse(2, xbmc.getLocalizedString(1030), 'files', mask='.gif').decode("utf-8") del dialog elif selected_item > 1: # user has selected an image from online results image = items[selected_item - 2]["image"] elif items: # just grab the first item as best match image = items[0]["image"] return image @staticmethod def process_image(image_url, art_type, imdb_id): '''animated gifs need to be stored locally, otherwise they won't work''' # make sure that our local path for the gif images exists addon = xbmcaddon.Addon(ADDON_ID) gifs_path = "%sanimatedgifs/" % addon.getAddonInfo('profile') del addon if not xbmcvfs.exists(gifs_path): xbmcvfs.mkdirs(gifs_path) # only process existing images if not image_url or not xbmcvfs.exists(image_url): return None # copy the image to our local path and return the new path as value local_filename = "%s%s_%s.gif" % (gifs_path, imdb_id, art_type) if xbmcvfs.exists(local_filename): xbmcvfs.delete(local_filename) # we don't use xbmcvfs.copy because we want to wait for the action to complete img = xbmcvfs.File(image_url) img_data = img.readBytes() img.close() img = xbmcvfs.File(local_filename, 'w') img.write(img_data) img.close() return local_filename def write_kodidb(self, artwork): '''store the animated artwork in kodi database to access it with ListItem.Art(animatedartX)''' kodi_movie = self.kodidb.movie_by_imdbid(artwork["imdb_id"]) if kodi_movie: params = { "movieid": kodi_movie["movieid"], "art": {"animatedfanart": artwork["animatedfanart"], "animatedposter": artwork["animatedposter"]} } self.kodidb.set_json('VideoLibrary.SetMovieDetails', params)
def __init__(self, addon, options): self.addon = addon self.options = options self.kodidb = KodiDb()
class ChannelLogos(object): """get channellogo""" def __init__(self, kodidb=None): """Initialize - optionaly provide KodiDb object""" if not kodidb: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb def get_channellogo(self, channelname): """get channellogo for the supplied channelname""" result = {} for searchmethod in [self.search_kodi, self.search_logosdb]: if result: break result = searchmethod(channelname) return result def search_logosdb(self, searchphrase): """search logo on thelogosdb""" result = "" for searchphrase in [ searchphrase, searchphrase.lower().replace(" hd", "") ]: if result: break for item in self.get_data_from_logosdb(searchphrase): img = item['strLogoWide'] if img: if ".jpg" in img or ".png" in img: result = img break return result def search_kodi(self, searchphrase): """search kodi json api for channel logo""" result = "" if xbmc.getCondVisibility("PVR.HasTVChannels"): results = self.kodidb.get_json('PVR.GetChannels', fields=["thumbnail"], returntype="tvchannels", optparam=("channelgroupid", "alltv")) for item in results: if item["label"] == searchphrase: channelicon = get_clean_image(item['thumbnail']) if channelicon and xbmcvfs.exists(channelicon): result = channelicon break return result @staticmethod def get_data_from_logosdb(searchphrase): """helper method to get data from thelogodb json API""" params = {"s": searchphrase} data = get_json( 'http://www.thelogodb.com/api/json/v1/3241/tvchannel.php', params) if data and data.get('channels'): return data["channels"] else: return []
class AnimatedArt(object): '''get animated artwork''' ignore_cache = False def __init__(self, simplecache=None, kodidb=None): '''Initialize - optionaly provide SimpleCache and KodiDb object''' if not kodidb: from kodidb import KodiDb self.kodidb = KodiDb() else: self.kodidb = kodidb if not simplecache: from simplecache import SimpleCache self.cache = SimpleCache() else: self.cache = simplecache @use_cache(14) def get_animated_artwork(self, imdb_id, manual_select=False, ignore_cache=False): '''returns all available animated art for the given imdbid/tmdbid''' # no cache so grab the results result = { "animatedposter": self.poster(imdb_id, manual_select), "animatedfanart": self.fanart(imdb_id, manual_select), "imdb_id": imdb_id } self.write_kodidb(result) log_msg("get_animated_artwork for imdbid: %s - result: %s" % (imdb_id, result)) return result def poster(self, imdb_id, manual_select=False): '''return preferred animated poster, optionally show selectdialog for manual selection''' img = self.select_art(self.posters(imdb_id), manual_select, "poster") return self.process_image(img, "poster", imdb_id) def fanart(self, imdb_id, manual_select=False): '''return preferred animated fanart, optionally show selectdialog for manual selection''' img = self.select_art(self.fanarts(imdb_id), manual_select, "fanart") return self.process_image(img, "fanart", imdb_id) def posters(self, imdb_id): '''return all animated posters for the given imdb_id (imdbid can also be tmdbid)''' return self.get_art(imdb_id, "posters") def fanarts(self, imdb_id): '''return animated fanarts for the given imdb_id (imdbid can also be tmdbid)''' return self.get_art(imdb_id, "fanarts") def get_art(self, imdb_id, art_type): '''get the artwork''' art_db = self.get_animatedart_db() if art_db.get(imdb_id): return art_db[imdb_id][art_type] return [] def get_animatedart_db(self): '''get the full animated art database as dict with imdbid and tmdbid as key uses 7 day cache to prevent overloading the server''' # get all animated posters from the online json file cache = self.cache.get("animatedartdb") if cache: return cache art_db = {} data = get_json('http://www.consiliumb.com/animatedgifs/movies.json', None) base_url = data.get("baseURL", "") if data and data.get('movies'): for item in data['movies']: for db_id in ["imdbid", "tmdbid"]: key = item[db_id] art_db[key] = {"posters": [], "fanarts": []} for entry in item['entries']: entry_new = { "contributedby": entry["contributedBy"], "dateadded": entry["dateAdded"], "language": entry["language"], "source": entry["source"], "image": "%s/%s" % (base_url, entry["image"].replace( ".gif", "_original.gif")), "thumb": "%s/%s" % (base_url, entry["image"]) } if entry['type'] == 'poster': art_db[key]["posters"].append(entry_new) elif entry['type'] == 'background': art_db[key]["fanarts"].append(entry_new) self.cache.set("animatedartdb", art_db, expiration=timedelta(days=7)) return art_db @staticmethod def select_art(items, manual_select=False, art_type=""): '''select the preferred image from the list''' image = None if manual_select: # show selectdialog to manually select the item results_list = [] # add none and browse entries listitem = xbmcgui.ListItem(label=xbmc.getLocalizedString(231), iconImage="DefaultAddonNone.png") results_list.append(listitem) listitem = xbmcgui.ListItem(label=xbmc.getLocalizedString(1030), iconImage="DefaultFolder.png") results_list.append(listitem) for item in items: labels = [ item["contributedby"], item["dateadded"], item["language"], item["source"] ] label = " / ".join(labels) listitem = xbmcgui.ListItem(label=label, iconImage=item["thumb"]) results_list.append(listitem) if manual_select and results_list: dialog = DialogSelect("DialogSelect.xml", "", listing=results_list, window_title=art_type) dialog.doModal() selected_item = dialog.result del dialog if selected_item == 1: # browse for image dialog = xbmcgui.Dialog() image = dialog.browse(2, xbmc.getLocalizedString(1030), 'files', mask='.gif').decode("utf-8") del dialog elif selected_item > 1: # user has selected an image from online results image = items[selected_item - 2]["image"] elif items: # just grab the first item as best match image = items[0]["image"] return image @staticmethod def process_image(image_url, art_type, imdb_id): '''animated gifs need to be stored locally, otherwise they won't work''' # make sure that our local path for the gif images exists addon = xbmcaddon.Addon(ADDON_ID) gifs_path = "%s/animatedgifs/" % addon.getAddonInfo('profile') del addon if not xbmcvfs.exists(gifs_path): xbmcvfs.mkdirs(gifs_path) # only process existing images if not image_url or not xbmcvfs.exists(image_url): return None # copy the image to our local path and return the new path as value local_filename = "%s%s_%s.gif" % (gifs_path, imdb_id, art_type) if xbmcvfs.exists(local_filename): xbmcvfs.delete(local_filename) # we don't use xbmcvfs.copy because we want to wait for the action to complete img = xbmcvfs.File(image_url) img_data = img.readBytes() img.close() img = xbmcvfs.File(local_filename, 'w') img.write(img_data) img.close() return local_filename def write_kodidb(self, artwork): '''store the animated artwork in kodi database to access it with ListItem.Art(animatedartX)''' kodi_movie = self.kodidb.movie_by_imdbid(artwork["imdb_id"]) if kodi_movie: params = { "movieid": kodi_movie["movieid"], "art": { "animatedfanart": artwork["animatedfanart"], "animatedposter": artwork["animatedposter"] } } self.kodidb.set_json('VideoLibrary.SetMovieDetails', params)