def ex(e): # type: (BaseException) -> AnyStr """Returns a unicode string from the exception text if it exists""" if not PY2: return str(e) e_message = u'' if not e or not e.args: return e_message for arg in e.args: if None is not arg: if isinstance(arg, string_types): fixed_arg = fixStupidEncodings(arg, True) else: try: fixed_arg = u'error ' + fixStupidEncodings(str(arg), True) except (BaseException, Exception): fixed_arg = None if fixed_arg: if not e_message: e_message = fixed_arg else: e_message = e_message + ' : ' + fixed_arg return e_message
def _send_to_xbmc(self, command, host=None, username=None, password=None): """Handles communication to XBMC servers via HTTP API Args: command: Dictionary of field/data pairs, encoded via urllib and passed to the XBMC API via HTTP host: XBMC webserver host:port username: XBMC webserver username password: XBMC webserver password Returns: Returns response.result for successful commands or False if there was an error """ if not host: self._log_debug(u'No host passed, aborting update') return False username = self._choose(username, sickbeard.XBMC_USERNAME) password = self._choose(password, sickbeard.XBMC_PASSWORD) for key in command: if not PY2 or type(command[key]) == text_type: command[key] = command[key].encode('utf-8') enc_command = urlencode(command) self._log_debug(u'Encoded API command: ' + enc_command) url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command) try: req = urllib.request.Request(url) # if we have a password, use authentication if password: req.add_header( 'Authorization', 'Basic %s' % b64encodestring('%s:%s' % (username, password))) self._log_debug(u'Contacting (with auth header) via url: ' + fixStupidEncodings(url)) else: self._log_debug(u'Contacting via url: ' + fixStupidEncodings(url)) http_response_obj = urllib.request.urlopen( req) # PY2 http_response_obj has no `with` context manager result = decode_str(http_response_obj.read(), sickbeard.SYS_ENCODING) http_response_obj.close() self._log_debug(u'HTTP response: ' + result.replace('\n', '')) return result except (urllib.error.URLError, IOError) as e: self._log_warning(u'Couldn\'t contact HTTP at %s %s' % (fixStupidEncodings(url), ex(e))) return False
def _send_to_plex(self, command, host, username=None, password=None): """Handles communication to Plex hosts via HTTP API Args: command: Dictionary of field/data pairs, encoded via urllib and passed to the legacy xbmcCmds HTTP API host: Plex host:port username: Plex API username password: Plex API password Returns: Returns True for successful commands or False if there was an error """ if not host: self._log_error(u'No host specified, check your settings') return False for key in command: if not PY2 or type(command[key]) == text_type: command[key] = command[key].encode('utf-8') enc_command = urlencode(command) self._log_debug(u'Encoded API command: ' + enc_command) url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command) try: req = urllib.request.Request(url) if password: req.add_header( 'Authorization', 'Basic %s' % b64encodestring('%s:%s' % (username, password))) self._log_debug(u'Contacting (with auth header) via url: ' + url) else: self._log_debug(u'Contacting via url: ' + url) http_response_obj = urllib.request.urlopen( req) # PY2 http_response_obj has no `with` context manager result = decode_str(http_response_obj.read(), sickbeard.SYS_ENCODING) http_response_obj.close() self._log_debug(u'HTTP response: ' + result.replace('\n', '')) return True except (urllib.error.URLError, IOError) as e: self._log_warning(u'Couldn\'t contact Plex at ' + fixStupidEncodings(url) + ' ' + ex(e)) return False
def _recursiveSearch(self, entry, depth=0): """ Searches files in the entry This will output a list of tuples (filename, languages) """ if depth > self.max_depth and self.max_depth != 0: # we do not want to search the whole file system except if max_depth = 0 return [] if ek.ek(os.path.isfile, entry): # a file? scan it if depth != 0: # only check for valid format if recursing, trust the user mimetypes.add_type("video/x-matroska", ".mkv") mimetype = mimetypes.guess_type(entry)[0] if mimetype not in SUPPORTED_FORMATS: return [] basepath = ek.fixStupidEncodings(ek.ek(os.path.splitext, entry)[0]) # check for .xx.srt if needed if self.multi and self.languages: if self.force: return [(self.languages, [ek.ek(os.path.normpath, entry)])] needed_languages = self.languages[:] for l in self.languages: if ek.ek(os.path.exists, basepath + '.%s.srt' % l): logger.info(u"Skipping language %s for file %s as it already exists. Use the --force option to force the download" % (l, entry)) needed_languages.remove(l) if needed_languages: return [(needed_languages, [ek.ek(os.path.normpath, entry)])] return [] # single subtitle download: .srt if self.force or not ek.ek(os.path.exists, basepath + '.srt'): return [(self.languages, [ek.ek(os.path.normpath, entry)])] if ek.ek(os.path.isdir, entry): # a dir? recurse #TODO if hidden folder, don't keep going (how to handle windows/mac/linux ?) files = [] for e in ek.ek(os.listdir, entry): files.extend(self._recursiveSearch(ek.ek(os.path.join, entry, e), depth + 1)) files.sort() grouped_files = [] for languages, group in groupby(files, lambda t: t[0]): filenames = [] for t in group: filenames.extend(t[1]) grouped_files.append((languages, filenames)) return grouped_files return [] # anything else, nothing.
def listSubtitles(self, entries): """ Searches subtitles within the active plugins and returns all found matching subtitles. entries can be: - filepaths - folderpaths (N.B. internal recursive search function will be used) - filenames """ search_results = [] if isinstance(entries, basestring): entries = [ek.fixStupidEncodings(entries)] elif not isinstance(entries, list): raise TypeError('Entries should be a list or a string') for e in entries: search_results.extend(self._recursiveSearch(e)) taskCount = 0 for (l, f) in search_results: taskCount += self.searchSubtitlesThreaded(f, l) subtitles = [] for i in range(taskCount): subtitles.extend(self.resultQueue.get(timeout=10)) return subtitles
def _send_to_xbmc_json(self, command, host=None, username=None, password=None): # type: (...) -> Union[bool, Dict] """Handles communication to XBMC servers via JSONRPC Args: command: Dictionary of field/data pairs, encoded via urllib and passed to the XBMC JSON-RPC via HTTP host: XBMC webserver host:port username: XBMC webserver username password: XBMC webserver password Returns: Returns response.result for successful commands or False if there was an error """ if not host: self._log_debug(u'No host passed, aborting update') return False username = self._choose(username, sickbeard.XBMC_USERNAME) password = self._choose(password, sickbeard.XBMC_PASSWORD) command = command.encode('utf-8') self._log_debug(u'JSON command: ' + command) url = 'http://%s/jsonrpc' % host try: req = urllib.request.Request(url, command) req.add_header('Content-type', 'application/json') # if we have a password, use authentication if password: req.add_header( 'Authorization', 'Basic %s' % b64encodestring('%s:%s' % (username, password))) self._log_debug(u'Contacting (with auth header) via url: ' + fixStupidEncodings(url)) else: self._log_debug(u'Contacting via url: ' + fixStupidEncodings(url)) try: http_response_obj = urllib.request.urlopen( req) # PY2 http_response_obj has no `with` context manager except urllib.error.URLError as e: self._log_warning( u'Error while trying to retrieve API version for "%s": %s' % (host, ex(e))) return False # parse the json result try: result = json.load(http_response_obj) http_response_obj.close() self._log_debug(u'JSON response: ' + str(result)) return result # need to return response for parsing except ValueError: self._log_warning(u'Unable to decode JSON: ' + http_response_obj) return False except IOError as e: self._log_warning(u'Couldn\'t contact JSON API at ' + fixStupidEncodings(url) + ' ' + ex(e)) return False