def build_config(**kwargs): """ kwargs is filtered for settings that enable updates to Trakt :param kwargs: kwargs to be filtered for settings that enable updates to Trakt :return: dict of parsed config kwargs where k is Trakt account id, v is a parent location """ config = {} root_dirs = [] if sickbeard.ROOT_DIRS: root_pieces = sickbeard.ROOT_DIRS.split('|') root_dirs = root_pieces[1:] for item in [ re.findall(r'update-trakt-(\d+)-(.*)', k) for k, v in iteritems(kwargs) if k.startswith('update-trakt-') ]: for account_id, location in item: account_id = try_int(account_id, None) if None is account_id: continue for cur_dir in root_dirs: account_id = try_int(account_id, None) if account_id and decode_str( base64.urlsafe_b64encode( decode_bytes(cur_dir))) == location: if isinstance(config.get(account_id), list): config[account_id] += [cur_dir] else: config[account_id] = [cur_dir] return config
def _discover_server(self): cs = socket(AF_INET, SOCK_DGRAM) mb_listen_port = 7359 cs.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) cs.settimeout(10) result, sock_issue = '', None for server in ('EmbyServer', 'MediaBrowserServer', 'JellyfinServer'): bufr = 'who is %s?' % server try: assert len(bufr) == cs.sendto(decode_bytes(bufr), ('255.255.255.255', mb_listen_port)), \ 'Not all data sent through the socket' message, host = cs.recvfrom(1024) if message: message = decode_str(message) self._log('%s found at %s: udp query response (%s)' % (server, host[0], message)) result = ('{"Address":' not in message and message.split('|')[1] or json.loads(message).get('Address', '')) if result: break except AssertionError: sock_issue = True except (BaseException, Exception): pass if not sock_issue: try: cs.shutdown(SHUT_RDWR) except (BaseException, Exception): pass return result
def single_request(self, host, handler, request_body, verbose=0): # Add SCGI headers to the request. headers = [('CONTENT_LENGTH', str(len(request_body))), ('SCGI', '1')] header = '\x00'.join(['%s\x00%s' % (key, value) for key, value in headers]) + '\x00' header = '%d:%s' % (len(header), header) request_body = '%s,%s' % (header, request_body) sock = None try: if host: parsed = urlparse('//' + host) host, port = parsed.hostname, parsed.port addrinfo = socket.getaddrinfo(host, int(port), socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(*addrinfo[0][:3]) sock.connect(addrinfo[0][4]) else: sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(handler) # noinspection PyAttributeOutsideInit self.verbose = verbose sock.send(decode_bytes(request_body)) return self.parse_response(sock.makefile()) finally: if sock: sock.close()
def makeProviderList(): providers = [ x.provider for x in [getProviderModule(y) for y in __all__] if x ] import browser_ua import zlib headers = [1449593765, 1597250020, 1524942228] for p in providers: if abs(zlib.crc32(decode_bytes(p.name))) + 40000400 in headers: p.headers.update({'User-Agent': browser_ua.get_ua()}) return providers
def _notify(self, title, body, user_key=None, api_key=None, priority=None, device=None, sound=None, **kwargs): """ Sends a pushover notification to the address provided title: The title of the message msg: The message to send (unicode) user_key: The pushover user id to send the message to (or to subscribe with) returns: True if the message succeeded, False otherwise """ user_key = self._choose(user_key, sickbeard.PUSHOVER_USERKEY) api_key = self._choose(api_key, sickbeard.PUSHOVER_APIKEY) priority = self._choose(priority, sickbeard.PUSHOVER_PRIORITY) device = self._choose(device, sickbeard.PUSHOVER_DEVICE) sound = self._choose(sound, sickbeard.PUSHOVER_SOUND) # build up the URL and parameters params = dict(title=title, message=decode_str(body.strip()), user=user_key, timestamp=int(time.time())) if api_key: params.update(token=api_key) if priority: params.update(priority=priority) if not device: params.update(device=device) if not sound: params.update(sound=sound) # send the request to pushover result = None try: req = urllib.request.Request(API_URL) # PY2 http_response_obj has no `with` context manager http_response_obj = urllib.request.urlopen( req, decode_bytes(urlencode(params))) http_response_obj.close() except urllib.error.HTTPError as e: # HTTP status 404 if the provided email address isn't a Pushover user. if 404 == e.code: result = 'Username is wrong/not a Pushover email. Pushover will send an email to it' self._log_warning(result) # For HTTP status code 401's, it is because you are passing in either an invalid token, # or the user has not added your service. elif 401 == e.code: # HTTP status 401 if the user doesn't have the service added subscribe_note = self._notify(title, body, user_key) if subscribe_note: self._log_debug('Subscription sent') # return True else: result = 'Subscription could not be sent' self._log_error(result) else: # If you receive an HTTP status code of 400, it is because you failed to send the proper parameters if 400 == e.code: result = 'Wrong data sent to Pushover' # If you receive a HTTP status code of 429, # it is because the message limit has been reached (free limit is 7,500) elif 429 == e.code: result = 'API message limit reached - try a different API key' # If you receive a HTTP status code of 500, service is unavailable elif 500 == e.code: result = 'Unable to connect to API, service unavailable' self._log_error(result) return self._choose( (True, 'Failed to send notification: %s' % result)[bool(result)], not bool(result))
def _notify(self, title, body, access_token=None, sound=None, **kwargs): """ Sends a boxcar2 notification to the address provided title: The title of the message body: The message to send access_token: To send to this device sound: Sound profile to use returns: True if the message succeeded, False otherwise """ access_token = self._choose(access_token, sickbeard.BOXCAR2_ACCESSTOKEN) sound = self._choose(sound, sickbeard.BOXCAR2_SOUND) # build up the URL and parameters # more info goes here - # https://boxcar.uservoice.com/knowledgebase/articles/306788-how-to-send-your-boxcar-account-a-notification body = decode_str(body.strip()) data = urlencode({ 'user_credentials': access_token, 'notification[title]': '%s - %s' % (title, body), 'notification[long_message]': body, 'notification[sound]': sound, 'notification[source_name]': 'SickGear', 'notification[icon_url]': self._sg_logo_url }) # send the request to boxcar2 result = None try: req = urllib.request.Request( 'https://new.boxcar.io/api/notifications') # PY2 http_response_obj has no `with` context manager http_response_obj = urllib.request.urlopen(req, decode_bytes(data)) http_response_obj.close() except urllib.error.HTTPError as e: if not hasattr(e, 'code'): self._log_error(u'Notification failed: %s' % ex(e)) else: result = 'Notification failed. Error code: %s' % e.code self._log_error(result) if 503 == e.code: result = 'Server too busy to handle the request at this time' self._log_warning(result) else: if 404 == e.code: result = 'Access token is wrong/not associated to a device' self._log_error(result) elif 401 == e.code: result = 'Access token not recognized' self._log_error(result) elif 400 == e.code: result = 'Wrong data sent to Boxcar' self._log_error(result) except urllib.error.URLError as e: self._log_error(u'Notification failed: %s' % ex(e)) return self._choose( (True, 'Failed to send notification: %s' % result)[bool(result)], not bool(result))