def _dispatch_delete(self, objectname): try: self._objects[objectname]._shutdown() except Exception: _log.error("Error when shutting down the object %s:", type(self._objects[objectname])) _log.debug(traceback.format_exc()) del self._objects[objectname]
def Wait_Window_Loaded(self): tries = 5 while self.Window_Is_Loading(): if tries == 0: log.error("Failed to wait till window has finished loading") return int(False) tries = tries - 1 time.sleep(0.3) log.debug("Finished waiting till window has finished loading") return int(True)
def read_and_dispatch(self, timeout=None, thread=True, condition=None): """ Read one message from socket (with timeout specified by the optional argument *timeout*) and dispatches that message. Parameters: **timeout** = None Timeout in seconds of the read operation. If it is None (or ommitted) then the read will wait until new data is available. **(return value)** True, in case of the operation has suceeded and **one** message has been dispatched. False, if no data or malformed data has been received. """ self.read_lock.acquire() self.reading_event.set() try: if condition: if condition() is False: return False if thread: dispatch_item = self.dispatch_item_threaded else: dispatch_item = self.dispatch_item_single data = self.read(timeout=timeout) if not data: return False try: item = json.loads(data, self) if type(item) is list: # batch call for i in item: dispatch_item(i) elif type(item) is dict: # std call if 'result' in item: self.dispatch_item_single(item) else: dispatch_item(item) else: # Unknown format :-( _log.debug("Received message with unknown format type: %s", type(item)) return False except Exception: _log.debug(traceback.format_exc()) return False return True finally: self.reading_event.clear() self.read_lock.release()
def write_line(self, data): """ Write a line *data* to socket. It appends a **newline** at the end of the *data* before sending it. The string MUST NOT contain **newline** otherwise an AssertionError will raise. Parameters: **data** String containing the data to be sent. """ assert ('\n' not in data) self.write_lock.acquire() try: try: data = data.encode('utf-8') except AttributeError: pass if self._debug_socket: _log.debug("<:%d: %s", len(data), data.decode('utf-8')[:130]) self._wbuffer += data + b'\n' sbytes = 0 while self._wbuffer: try: sbytes = self._sck.send(self._wbuffer) except IOError: _log.debug("Read socket error: IOError (timeout: %r)", self._sck.gettimeout()) _log.debug(traceback.format_exc(0)) return 0 except socket.error: _log.debug("Read socket error: socket.error (timeout: %r)", self._sck.gettimeout()) _log.debug(traceback.format_exc(0)) return 0 except: raise if sbytes == 0: break self._wbuffer = self._wbuffer[sbytes:] if self._wbuffer: _log.warning("%d bytes left in write buffer", len(self._wbuffer)) return len(self._wbuffer) finally: self.write_lock.release()
def Player_WatchTimes(self): error = "" watchedTime = "0" videoDuration = "0" try: watchedTime = str(XBMC_PLAYER.getTime()) videoDuration = str(XBMC_PLAYER.getTotalTime()) log.debug("Watched: %s, duration: %s" % (watchedTime, videoDuration)) except Exception as e: error = "Stopped playing: %s" % repr(e) watchTimes = { "watchedTime": watchedTime, "videoDuration": videoDuration, "error": error } return watchTimes
def register(search, search_movie, search_episode, search_season=None): try: payload = json.loads(base64.b64decode(sys.argv[1])) except: notify(getLocalizedString(30102), time=1000) return results = () method = { "search": search, "search_movie": search_movie, "search_season": search_season, "search_episode": search_episode, }.get(payload["method"]) or (lambda *a, **kw: []) try: results = () try: objects = method(payload["search_object"]) if objects is not None: results = tuple(objects) except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (getLocalizedString(30224), repr(e).encode('utf-8'))) try: urllib_request.urlopen("%s/provider/%s/failure" % (da_inc_HOST, ADDON_ID)) except: pass finally: try: req = urllib_request.Request(payload["callback_url"], data=json.dumps(results)) with closing(urllib_request.urlopen(req)) as response: log.debug("callback returned: %d" % response.getcode()) except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (getLocalizedString(30224), repr(e).encode('utf-8'))) try: urllib_request.urlopen("%s/provider/%s/failure" % (da_inc_HOST, ADDON_ID)) except: pass
def _readn(self): """ Internal function which reads from socket waiting for a newline """ streambuffer = self._buffer pos = streambuffer.find(b'\n') # _log.debug("read...") # retry = 0 while pos == -1: data = b'' try: data = self._sck.recv(2048) except IOError as inst: _log.debug("Read socket error: IOError%r (timeout: %r)", inst.args, self._sck.gettimeout()) if inst.errno in (errno.EAGAIN, errno.EWOULDBLOCK): if self._sck.gettimeout() == 0: # if it was too fast self._sck.settimeout(5) continue # time.sleep(0.5) # retry += 1 # if retry < 10: # _log.debug("Retry %s", retry) # continue # _log.debug(traceback.format_exc(0)) if inst.errno in self._SOCKET_COMM_ERRORS: raise EofError(len(streambuffer)) return b'' except socket.error as inst: _log.error("Read socket error: socket.error%r (timeout: %r)", inst.args, self._sck.gettimeout()) # _log.debug(traceback.format_exc(0)) return b'' except: raise if not data: raise EofError(len(streambuffer)) # _log.debug("readbuf+: %r", data) streambuffer += data pos = streambuffer.find(b'\n') self._buffer = streambuffer[pos + 1:] streambuffer = streambuffer[:pos] # _log.debug("read: %r", buffer) return streambuffer
def _format_exception(self, obj, method, args, kw, exc): etype, evalue, etb = exc funargs = ", ".join([repr(x) for x in args] + ["%s=%r" % (k, kw[k]) for k in kw]) if len(funargs) > 40: funargs = funargs[:37] + "..." _log.error("(%s) In Handler method %s.%s(%s) ", obj.__class__.__module__, obj.__class__.__name__, method, funargs) _log.debug("\n".join([ "%s::%s:%d %s" % (filename, fnname, lineno, srcline) for filename, lineno, fnname, srcline in traceback.extract_tb(etb)[1:] ])) _log.error("Unhandled error: %s: %s", etype.__name__, evalue) del etb return '%s: %s' % (etype.__name__, evalue)
def write_thread(self): abort = False while not abort: self.write_thread_semaphore.acquire() try: item = self.write_thread_queue.pop(0) except IndexError: # pop from empty list? _log.warning("write queue was empty??") continue abort = item.get("abort", False) event = item.get("event") write_data = item.get("write_data") if write_data: item["result"] = self.write_now(write_data) if event: event.set() if self._debug_socket: _log.debug("Writing thread finished.")
def _send(self, response): txtResponse = None try: txtResponse = json.dumps(response, self) except Exception as e: _log.error( "An unexpected error ocurred when trying to create the message: %r", e) response = { 'result': None, 'error': "InternalServerError: " + repr(e) } txtResponse = json.dumps(response, self) try: self.write(txtResponse) except TypeError: _log.debug("response was: %r", response) raise
def read_line(self): """ Read a line of *data* from socket. It removes the `\\n` at the end before returning the value. If the original packet contained `\\n`, the message will be decoded as two or more messages. Returns the line of *data* received from the socket. """ self.read_lock.acquire() try: data = self._readn() if len(data) and self._debug_socket: _log.debug(">:%d: %s", len(data), data.decode('utf-8')[:130]) return data.decode('utf-8') finally: self.read_lock.release()
def setresponse(self, value): """ Method used by Connection instance to tell Request that a Response is available to this request. Parameters: **value** Value (JSON decoded) received from socket. """ self.responses.put(value) for callback in self.callbacks: try: callback(self) except Exception as exc: _log.error("Error on callback: %r", exc) _log.debug(traceback.format_exc()) self.event_response.set() # helper for threads. if self.auto_close: self.close()
def start_da_inc(**kwargs): jsonrpc_failures = 0 while jsonrpc_enabled() is False: jsonrpc_failures += 1 log.warning( "Unable to connect to Kodi's JSON-RPC service, retrying...") if jsonrpc_failures > 1: time.sleep(5) if not jsonrpc_enabled(notify=True): log.error( "Unable to reach Kodi's JSON-RPC service, aborting...") return False else: break time.sleep(3) da_inc_dir, da_inc_binary = get_da_inc_binary() log.info("Binary dir: %s, item: %s " % (da_inc_dir, da_inc_binary)) if da_inc_dir is False or da_inc_binary is False: return False lockfile = os.path.join(ADDON_PATH, ".lockfile") if os.path.exists(lockfile): log.warning("Existing process found from lockfile, killing...") try: with open(lockfile) as lf: pid = int(lf.read().rstrip(" \t\r\n\0")) os.kill(pid, 9) except OSError as e: if e.errno != 3: # Ignore: OSError: [Errno 3] No such process log.error(repr(e)) except Exception as e: log.error(repr(e)) if binary_platform["os"] == "windows": try: library_lockfile = os.path.join( xbmc.translatePath( ADDON.getAddonInfo("profile")).decode('utf-8'), "library.db.lock") log.warning("Removing library.db.lock file at %s ..." % library_lockfile) os.remove(library_lockfile) except Exception as e: log.error(repr(e)) SW_HIDE = 0 STARTF_USESHOWWINDOW = 1 args = [da_inc_binary] kwargs["cwd"] = da_inc_dir if binary_platform["os"] == "windows": args[0] = getWindowsShortPath(da_inc_binary) kwargs["cwd"] = getWindowsShortPath(da_inc_dir) si = subprocess.STARTUPINFO() si.dwFlags = STARTF_USESHOWWINDOW si.wShowWindow = SW_HIDE clear_fd_inherit_flags() kwargs["startupinfo"] = si else: env = os.environ.copy() env["LD_LIBRARY_PATH"] = "%s:%s" % (da_inc_dir, env.get("LD_LIBRARY_PATH", "")) kwargs["env"] = env kwargs["close_fds"] = True wait_counter = 1 log.debug("Checking for visible") while xbmc.getCondVisibility( 'Window.IsVisible(10140)') or xbmc.getCondVisibility( 'Window.IsActive(10140)'): if wait_counter == 1: log.info( 'Add-on settings currently opened, waiting before starting...') if wait_counter > 300: break time.sleep(1) wait_counter += 1 log.info("da_inc: start args: %s, kw: %s" % (args, kwargs)) if hasSubprocess: return subprocess.Popen(args, **kwargs) return False
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 xbmc.getInfoLabel("ListItem.DBID"): # url = "%s/infolabels" % (da_inc_HOST) # elif not tmdb_id: if not tmdb_id: request_url = sys.argv[0] + sys.argv[2] parsed_url = urllib_parse.urlparse(request_url) query = urllib_parse.parse_qs(parsed_url.query) log.debug("Parsed URL: %s, Query: %s", repr(parsed_url), repr(query)) if 'tmdb' in query and 'type' in query and query['type'][0] == 'search': tmdb_id = query['tmdb'][0] url = "%s/search/infolabels/%s" % (da_inc_HOST, tmdb_id) elif '/search' in parsed_url and 'tmdb' in query: tmdb_id = query['tmdb'][0] url = "%s/search/infolabels/%s" % (da_inc_HOST, tmdb_id) elif '/search' in parsed_url and 'q' in query: tmdb_id = query['q'][0] url = "%s/search/infolabels/%s" % (da_inc_HOST, tmdb_id) elif 'tmdb' in query and 'type' in query and query['type'][ 0] == 'movie': tmdb_id = query['tmdb'][0] url = "%s/movie/%s/infolabels" % (da_inc_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" % ( da_inc_HOST, tmdb_id, query['season'][0], query['episode'][0]) else: url = "%s/show/%s/infolabels" % (da_inc_HOST, tmdb_id) else: url = "%s/infolabels" % (da_inc_HOST) elif 'movie' in sys.argv[0]: url = "%s/movie/%s/infolabels" % (da_inc_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" % ( da_inc_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" % ( da_inc_HOST, tmdb_id, id_list[1], 1) else: url = "%s/infolabels" % (da_inc_HOST) log.debug("Resolving TMDB item by calling %s for %s" % (url, repr(sys.argv))) try: with closing(urllib_request.urlopen(url)) as response: resolved = json.loads(response.read(), parse_int=str) 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 http_error_302(self, req, fp, code, msg, headers): infourl = urllib_response.addinfourl(fp, headers, headers["Location"]) infourl.status = code infourl.code = code log.debug("Redirecting to: %s", headers["Location"]) return infourl
def run(url_suffix="", retry=0): try: buffer_timeout = int(ADDON.getSetting("buffer_timeout")) if buffer_timeout < 60: buffer_timeout = 60 except: buffer_timeout = 60 buffer_timeout = buffer_timeout * 2 try: preload_timeout = int(ADDON.getSetting("preload_timeout")) if preload_timeout < 1: preload_timeout = 1 except: preload_timeout = 1 socket.setdefaulttimeout(buffer_timeout) urllib_request.install_opener( urllib_request.build_opener(NoRedirectHandler())) # Pause currently playing da_inc file to avoid doubling requests try: if xbmc.Player().isPlaying() and ADDON_ID in xbmc.Player( ).getPlayingFile(): xbmc.Player().pause() except: pass url = sys.argv[0].replace("plugin://%s" % ADDON_ID, da_inc_HOST + url_suffix) + sys.argv[2] query_add = "" if len(sys.argv) > 3: app = sys.argv[3].replace(":", "=") # Replacing resume=false with resume=true if item is launched from main window title = xbmc.getInfoLabel('ListItem.Title') label = xbmc.getInfoLabel('ListItem.Label') # if "resume" in app and not title and not label: # app = app.replace("resume=false", "resume=true") # if "resume" not in app and not title and not label: if not title and not label: if app: app = app.replace("resume=false", "") app += "&" if app and "resume" not in app: app += "resume=true" query_add = app elif "play" in url or "links" in url: query_add = "resume=true" if query_add and "resume" not in url: query_add = query_add.replace("resume=", "doresume=") if "?" in url: url += "&" + query_add else: url += "?" + query_add log.debug("Requesting %s from %s" % (url, repr(sys.argv))) try: data = _json(url) except PlayerException as e: redirect_url = e.__str__() log.debug("Launching player with %s" % (redirect_url)) xbmcplugin.endOfDirectory(HANDLE, succeeded=True) xbmc.sleep(500) xbmc.executeJSONRPC( '{"jsonrpc":"2.0","method":"Player.Open","params":{"item":{"file":"%s"}},"id":"1"}' % (redirect_url)) return except RedirectException as e: redirect_url = e.__str__() log.debug("Redirecting Kodi with %s" % (redirect_url)) xbmcplugin.endOfDirectory(HANDLE, succeeded=True) xbmc.sleep(500) if "keyboard=1" in sys.argv[0]: xbmc.executebuiltin('Container.Update(%s,replace)' % (redirect_url)) else: xbmc.executebuiltin('Container.Update(%s)' % (redirect_url)) return except urllib_error.URLError as e: # We can retry the request if connection is refused. # For example when plugin has not yet started but is requested by someone. if retry <= 2: time.sleep(preload_timeout) return run(retry=retry + 1) if isinstance(e.reason, IOError) or isinstance( e.reason, OSError) or '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 = six.ensure_text(e.__str__(), errors='ignore') except: try: msg = six.ensure_binary(e.__str__(), errors='ignore') 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) else: xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_TITLE_IGNORE_THE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(HANDLE, xbmcplugin.SORT_METHOD_GENRE) xbmcplugin.setContent(HANDLE, content_type) listitems = list(range(len(data["items"]))) for i, item in enumerate(data["items"]): # Translate labels if item["label"][0:8] == "LOCALIZE": item["label"] = getLocalizedLabel(item["label"]) if isinstance(item["label"], str): item["label"] = six.ensure_text(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"] != six.ensure_text( getLocalizedString(30218), 'utf-8'): fanart = os.path.join(ADDON_PATH, "fanart.png") 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=False)