import os import sys import socket import urllib2 import urlparse import xbmc import xbmcgui import xbmcplugin from quasar.logger import log from quasar.config import QUASARD_HOST from quasar.addon import ADDON, ADDON_ID, ADDON_PATH from quasar.util import notify, getLocalizedString, getLocalizedLabel, system_information try: import simplejson as json except ImportError: import json HANDLE = int(sys.argv[1]) class InfoLabels(dict): def __init__(self, *args, **kwargs): self.update(*args, **kwargs) def __getitem__(self, key): return dict.get(self, key.lower(), "") def __setitem__(self, key, val): dict.__setitem__(self, key.lower(), val) def update(self, *args, **kwargs): for k, v in dict(*args, **kwargs).iteritems(): self[k] = v class closing(object): def __init__(self, thing): self.thing = thing def __enter__(self): return self.thing def __exit__(self, *exc_info): self.thing.close() class NoRedirectHandler(urllib2.HTTPRedirectHandler): def http_error_302(self, req, fp, code, msg, headers): import urllib infourl = urllib.addinfourl(fp, headers, headers["Location"]) infourl.status = code infourl.code = code return infourl http_error_300 = http_error_302 http_error_301 = http_error_302 http_error_303 = http_error_302 http_error_307 = http_error_302 def getInfoLabels(): id_list = [int(s) for s in sys.argv[0].split("/") if s.isdigit()] tmdb_id = id_list[0] if id_list else None if not tmdb_id: parsed_url = urlparse.urlparse(sys.argv[0] + sys.argv[2]) query = urlparse.parse_qs(parsed_url.query) log.debug("Parsed URL: %s, Query: %s", repr(parsed_url), repr(query)) if 'tmdb' in query and 'show' not in query: tmdb_id = query['tmdb'][0] url = "%s/movie/%s/infolabels" % (QUASARD_HOST, tmdb_id) elif 'show' in query: tmdb_id = query['show'][0] if 'season' in query and 'episode' in query: url = "%s/show/%s/season/%s/episode/%s/infolabels" % (QUASARD_HOST, tmdb_id, query['season'][0], query['episode'][0]) else: url = "%s/show/%s/infolabels" % (QUASARD_HOST, tmdb_id) else: url = "%s/infolabels" % (QUASARD_HOST) elif 'movie' in sys.argv[0]: url = "%s/movie/%s/infolabels" % (QUASARD_HOST, tmdb_id) elif ('episode' in sys.argv[0] or 'show' in sys.argv[0]) and len(id_list) > 2: url = "%s/show/%s/season/%s/episode/%s/infolabels" % (QUASARD_HOST, tmdb_id, id_list[1], id_list[2]) elif 'show' in sys.argv[0] and len(id_list) == 2: url = "%s/show/%s/season/%s/episode/%s/infolabels" % (QUASARD_HOST, tmdb_id, id_list[1], 1) else: url = "%s/infolabels" % (QUASARD_HOST) log.debug("Resolving TMDB item by calling %s for %s" % (url, repr(sys.argv))) try: with closing(urllib2.urlopen(url)) as response: resolved = json.loads(response.read()) if not resolved: return {} if 'info' in resolved and resolved['info']: resolved.update(resolved['info']) if 'art' in resolved and resolved['art']: resolved['artbanner'] = '' for k, v in resolved['art'].items(): resolved['art' + k] = v if 'info' in resolved: del resolved['info'] if 'art' in resolved: del resolved['art'] if 'stream_info' in resolved: del resolved['stream_info'] if 'dbtype' not in resolved: resolved['dbtype'] = 'video' if 'mediatype' not in resolved or resolved['mediatype'] == '': resolved['Mediatype'] = resolved['dbtype'] return resolved except: log.debug("Could not resolve TMDB item: %s" % tmdb_id) return {} def _json(url): with closing(urllib2.urlopen(url)) as response: if response.code >= 300 and response.code <= 307: # Pause currently playing Quasar file to avoid doubling requests if xbmc.Player().isPlaying() and ADDON_ID in xbmc.Player().getPlayingFile(): xbmc.Player().pause() _infoLabels = InfoLabels(getInfoLabels()) item = xbmcgui.ListItem( path=response.geturl(), label=_infoLabels["label"], label2=_infoLabels["label2"], thumbnailImage=_infoLabels["thumbnail"]) item.setArt({ "poster": _infoLabels["artposter"], "banner": _infoLabels["artbanner"], "fanart": _infoLabels["artfanart"] }) item.setInfo(type='Video', infoLabels=_infoLabels) xbmcplugin.setResolvedUrl(HANDLE, True, item) return payload = response.read() try: if payload: return json.loads(payload) except: raise Exception(payload) def run(url_suffix=""): if not os.path.exists(os.path.join(ADDON_PATH, ".firstrun")): notify(getLocalizedString(30101)) system_information() return donatePath = os.path.join(ADDON_PATH, ".donate") if not os.path.exists(donatePath): with open(donatePath, "w"): os.utime(donatePath, None) dialog = xbmcgui.Dialog() dialog.ok("Quasar", getLocalizedString(30141)) socket.setdefaulttimeout(int(ADDON.getSetting("buffer_timeout"))) urllib2.install_opener(urllib2.build_opener(NoRedirectHandler())) # Pause currently playing Quasar file to avoid doubling requests if xbmc.Player().isPlaying() and ADDON_ID in xbmc.Player().getPlayingFile(): xbmc.Player().pause() url = sys.argv[0].replace("plugin://%s" % ADDON_ID, QUASARD_HOST + url_suffix) + sys.argv[2] log.debug("Requesting %s from %s" % (url, repr(sys.argv))) try: data = _json(url) except urllib2.URLError as e: if 'Connection refused' in e.reason: notify(getLocalizedString(30116), time=7000) else: import traceback map(log.error, traceback.format_exc().split("\n")) notify(e.reason, time=7000) return except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) try: msg = unicode(e) except: try: msg = str(e) except: msg = repr(e) notify(getLocalizedLabel(msg), time=7000) return if not data: return if data["content_type"]: content_type = data["content_type"] if data["content_type"].startswith("menus"): content_type = data["content_type"].split("_")[1] xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_UNSORTED) if content_type != "tvshows": xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.setContent(HANDLE, content_type) listitems = range(len(data["items"])) for i, item in enumerate(data["items"]): # Translate labels if item["label"][0:8] == "LOCALIZE": item["label"] = unicode(getLocalizedLabel(item["label"]), 'utf-8') if item["label2"][0:8] == "LOCALIZE": item["label2"] = getLocalizedLabel(item["label2"]) listItem = xbmcgui.ListItem(label=item["label"], label2=item["label2"], iconImage=item["icon"], thumbnailImage=item["thumbnail"]) if item.get("info"): listItem.setInfo("video", item["info"]) if item.get("stream_info"): for type_, values in item["stream_info"].items(): listItem.addStreamInfo(type_, values) if item.get("art"): listItem.setArt(item["art"]) elif ADDON.getSetting('default_fanart') == 'true' and item["label"] != unicode(getLocalizedString(30218), 'utf-8'): fanart = os.path.join(ADDON_PATH, "fanart.jpg") listItem.setArt({'fanart': fanart}) if item.get("context_menu"): # Translate context menus for m, menu in enumerate(item["context_menu"]): if menu[0][0:8] == "LOCALIZE": menu[0] = getLocalizedLabel(menu[0]) listItem.addContextMenuItems(item["context_menu"]) listItem.setProperty("isPlayable", item["is_playable"] and "true" or "false") if item.get("properties"): for k, v in item["properties"].items(): listItem.setProperty(k, v) listitems[i] = (item["path"], listItem, not item["is_playable"]) xbmcplugin.addDirectoryItems(HANDLE, listitems, totalItems=len(listitems)) # Set ViewMode if data["content_type"]: viewMode = ADDON.getSetting("viewmode_%s" % data["content_type"]) if viewMode: try: xbmc.executebuiltin('Container.SetViewMode(%s)' % viewMode) except Exception as e: log.warning("Unable to SetViewMode(%s): %s" % (viewMode, repr(e))) xbmcplugin.endOfDirectory(HANDLE, succeeded=True, updateListing=False, cacheToDisc=True)