def preprocesstorrent(resultlist): selresult = "" for result in resultlist: if selresult == "": selresult = result elif int(selresult[1]) < int(result[1]): # if size is lower than new result replace previous selected result (bigger size = better quality?) selresult = result try: request = urllib2.Request(selresult[2]) request.add_header('Accept-encoding', 'gzip') if selresult[3] == 'Kick Ass Torrent': request.add_header('Referer', 'http://kat.ph/') response = urllib2.urlopen(request) if response.info().get('Content-Encoding') == 'gzip': buf = StringIO(response.read()) f = gzip.GzipFile(fileobj=buf) torrent = f.read() else: torrent = response.read() except ExpatError: logger.error('Unable to torrent %s' % selresult[2]) return torrent, selresult
def torrentAction(method, arguments): host = headphones.TRANSMISSION_HOST username = headphones.TRANSMISSION_USERNAME password = headphones.TRANSMISSION_PASSWORD sessionid = None if not host.startswith('http'): host = 'http://' + host if host.endswith('/'): host = host[:-1] host = host + "/transmission/rpc" request = urllib2.Request(host) if username and password: base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') request.add_header("Authorization", "Basic %s" % base64string) opener = urllib2.build_opener() try: data = opener.open(request).read() except urllib2.HTTPError, e: if e.code == 409: sessionid = e.hdrs['x-transmission-session-id'] else: logger.error('Could not connect to Transmission. Error: ' + str(e))
def create_https_certificates(ssl_cert, ssl_key): """ Stolen from SickBeard (http://github.com/midgetspy/Sick-Beard): Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key' """ from headphones import logger try: from OpenSSL import crypto from lib.certgen import createKeyPair, createCertRequest, createCertificate, TYPE_RSA, serial except: logger.warn("pyOpenSSL module missing, please install to enable HTTPS") return False # Create the CA Certificate cakey = createKeyPair(TYPE_RSA, 1024) careq = createCertRequest(cakey, CN='Certificate Authority') cacert = createCertificate(careq, (careq, cakey), serial, (0, 60*60*24*365*10)) # ten years cname = 'Headphones' pkey = createKeyPair(TYPE_RSA, 1024) req = createCertRequest(pkey, CN=cname) cert = createCertificate(req, (cacert, cakey), serial, (0, 60*60*24*365*10)) # ten years # Save the key and certificate to disk try: open(ssl_key, 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) open(ssl_cert, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) except Exception, e: logger.error("Error creating SSL key and certificate: %s", e) return False
def musicScan(self, path, redirect=None): headphones.MUSIC_DIR = path headphones.config_write() try: threading.Thread(target=librarysync.libraryScan).start() except Exception, e: logger.error('Unable to complete the scan: %s' % e)
def embedLyrics(downloaded_track_list): logger.info('Adding lyrics') # TODO: If adding lyrics for flac & lossy, only fetch the lyrics once # and apply it to both files for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.error('Could not read %s. Not checking lyrics' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) continue if f.albumartist and f.title: metalyrics = lyrics.getLyrics(f.albumartist, f.title) elif f.artist and f.title: metalyrics = lyrics.getLyrics(f.artist, f.title) else: logger.info('No artist/track metadata found for track: %s. Not fetching lyrics' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) metalyrics = None if lyrics: logger.debug('Adding lyrics to: %s' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) f.lyrics = metalyrics f.save()
def set(self, value): # abbreviation. I am too lazy to write 'self._inikey', will use 'k' s = self._section # section k = self._inikey # key t = self._initype # type if self._config_callback is None: msg = 'Option [{0}][{1}] was not binded/registered with config'.format(s, k) logger.error(msg) raise ConfigError(msg) config = self._config_callback() if s not in config: # create section: logger.debug('Section [{0}] for option [{0}][{1}] doesn\'t exists in config. Create empty.'.format(s, k)) config[s] = {} if k not in config[s]: # debug about new config value: logger.debug('Option [{0}][{1}] doesn\'t exists in config. Set to default.'.format(s, k)) # convert value to storable types: if value is None: value = '' elif not isinstance(value, _primitives): logger.debug('Value of option [{0}][{1}] is not primitive [{2}], will `str` it'.format(s, k, type(value))) value = str(value) else: value = t(value) config[s][k] = value
def notify(self, message, event): if not headphones.CONFIG.JOIN_ENABLED or \ not headphones.CONFIG.JOIN_APIKEY: return icon = "https://cdn.rawgit.com/Headphones/" \ "headphones/develop/data/images/headphoneslogo.png" if not self.deviceid: self.deviceid = "group.all" l = [x.strip() for x in self.deviceid.split(',')] if len(l) > 1: self.url += '&deviceIds={deviceid}' else: self.url += '&deviceId={deviceid}' response = urllib2.urlopen(self.url.format(apikey=self.apikey, title=quote_plus(event), text=quote_plus( message.encode( "utf-8")), icon=icon, deviceid=self.deviceid)) if response: logger.info(u"Join notifications sent.") return True else: logger.error(u"Join notification failed.") return False
def encode(albumPath): # Return if xld details not found if XLD: global xldProfile (xldProfile, xldFormat, xldBitrate) = getXldProfile.getXldProfile(headphones.XLDPROFILE) if not xldFormat: logger.error('Details for xld profile \'%s\' not found, files will not be re-encoded', xldProfile) return None tempDirEncode=os.path.join(albumPath,"temp") musicFiles=[] musicFinalFiles=[] musicTempFiles=[] encoder = "" # Create temporary directory, but remove the old one first. try: if os.path.exists(tempDirEncode): shutil.rmtree(tempDirEncode) time.sleep(1) os.mkdir(tempDirEncode) except Exception, e: logger.exception("Unable to create temporary directory") return None
def notify(self, artist=None, album=None, snatched=None): title = 'Headphones' api = headphones.NMA_APIKEY nma_priority = headphones.NMA_PRIORITY logger.debug(u"NMA title: " + title) logger.debug(u"NMA API: " + api) logger.debug(u"NMA Priority: " + str(nma_priority)) if snatched: event = snatched + " snatched!" message = "Headphones has snatched: " + snatched else: event = artist + ' - ' + album + ' complete!' message = "Headphones has downloaded and postprocessed: " + artist + ' [' + album + ']' logger.debug(u"NMA event: " + event) logger.debug(u"NMA message: " + message) batch = False p = pynma.PyNMA() keys = api.split(',') p.addkey(keys) if len(keys) > 1: batch = True response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) if not response[api][u'code'] == u'200': logger.error(u'Could not send notification to NotifyMyAndroid') return False else: return True
def setTorrentPath(result): logger.debug('Deluge: Setting download path') if not any(delugeweb_auth): _get_auth() try: if headphones.CONFIG.DELUGE_DONE_DIRECTORY or headphones.CONFIG.DOWNLOAD_TORRENT_DIR: post_data = json.dumps({"method": "core.set_torrent_move_completed", "params": [result['hash'], True], "id": 7}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) if headphones.CONFIG.DELUGE_DONE_DIRECTORY: move_to = headphones.CONFIG.DELUGE_DONE_DIRECTORY else: move_to = headphones.CONFIG.DOWNLOAD_TORRENT_DIR if not os.path.exists(move_to): logger.debug('Deluge: %s directory doesn\'t exist, let\'s create it' % move_to) os.makedirs(move_to) post_data = json.dumps({"method": "core.set_torrent_move_completed_path", "params": [result['hash'], move_to], "id": 8}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) return not json.loads(response.text)['error'] return True except Exception as e: logger.error('Deluge: Setting torrent move-to directory failed: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return None
def moveFiles(albumpath, release, tracks): try: year = release['ReleaseDate'][:4] except TypeError: year = '' artist = release['ArtistName'].replace('/', '_') album = release['AlbumTitle'].replace('/', '_') releasetype = release['Type'].replace('/', '_') if release['ArtistName'].startswith('The '): sortname = release['ArtistName'][4:] else: sortname = release['ArtistName'] if sortname.isdigit(): firstchar = '0-9' else: firstchar = sortname[0] lowerfirst = firstchar.lower() values = { 'artist': artist, 'album': album, 'year': year, 'first': firstchar, 'lowerfirst': lowerfirst, 'releasetype': releasetype } folder = helpers.replace_all(headphones.FOLDER_FORMAT, values) folder = folder.replace('./', '_/').replace(':','_').replace('?','_') if folder.endswith('.'): folder = folder.replace(folder[len(folder)-1], '_') destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING) if os.path.exists(destination_path): i = 1 while True: newfolder = folder + '[%i]' % i destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, newfolder)).encode(headphones.SYS_ENCODING) if os.path.exists(destination_path): i += 1 else: folder = newfolder break logger.info('Moving files from %s to %s' % (unicode(albumpath, headphones.SYS_ENCODING, errors="replace"), unicode(destination_path, headphones.SYS_ENCODING, errors="replace"))) try: os.makedirs(destination_path) except Exception, e: logger.error('Could not create folder for %s. Not moving: %s' % (release['AlbumTitle'], e)) return albumpath
def notify(self, artist, album, albumartpath): hosts = [x.strip() for x in self.hosts.split(",")] header = "Headphones" message = "%s - %s added to your library" % (artist, album) time = "3000" # in ms for host in hosts: logger.info("Sending notification command to XMBC @ " + host) try: version = self._sendjson(host, "Application.GetProperties", {"properties": ["version"]})["version"][ "major" ] if version < 12: # Eden notification = header + "," + message + "," + time + "," + albumartpath notifycommand = {"command": "ExecBuiltIn", "parameter": "Notification(" + notification + ")"} request = self._sendhttp(host, notifycommand) else: # Frodo params = {"title": header, "message": message, "displaytime": int(time), "image": albumartpath} request = self._sendjson(host, "GUI.ShowNotification", params) if not request: raise Exception except Exception: logger.error("Error sending notification request to XBMC")
def notify(self, artist, album, albumartpath): hosts = [x.strip() for x in self.hosts.split(',')] header = "Headphones" message = "%s - %s added to your library" % (artist, album) time = "3000" # in ms for host in hosts: logger.info('Sending notification command to XMBC @ ' + host) try: version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})[ 'version']['major'] if version < 12: # Eden notification = header + "," + message + "," + time + \ "," + albumartpath notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')'} request = self._sendhttp(host, notifycommand) else: # Frodo params = {'title': header, 'message': message, 'displaytime': int(time), 'image': albumartpath} request = self._sendjson(host, 'GUI.ShowNotification', params) if not request: raise Exception except Exception: logger.error('Error sending notification request to XBMC')
def sendNZB(nzb): params = {} if headphones.SAB_USERNAME: params['ma_username'] = headphones.SAB_USERNAME if headphones.SAB_PASSWORD: params['ma_password'] = headphones.SAB_PASSWORD if headphones.SAB_APIKEY: params['apikey'] = headphones.SAB_APIKEY if headphones.SAB_CATEGORY: params['cat'] = headphones.SAB_CATEGORY # if it's a normal result we just pass SAB the URL if nzb.resultType == "nzb": # for newzbin results send the ID to sab specifically if nzb.provider.getID() == 'newzbin': id = nzb.provider.getIDFromURL(nzb.url) if not id: logger.info("Unable to send NZB to sab, can't find ID in URL "+str(nzb.url)) return False params['mode'] = 'addid' params['name'] = id else: params['mode'] = 'addurl' params['name'] = nzb.url # if we get a raw data result we want to upload it to SAB elif nzb.resultType == "nzbdata": # Sanitize the file a bit, since we can only use ascii chars with MultiPartPostHandler nzbdata = helpers.latinToAscii(nzb.extraInfo[0]) params['mode'] = 'addfile' multiPartParams = {"nzbfile": (helpers.latinToAscii(nzb.name)+".nzb", nzbdata)} if not headphones.SAB_HOST.startswith('http'): headphones.SAB_HOST = 'http://' + headphones.SAB_HOST if headphones.SAB_HOST.endswith('/'): headphones.SAB_HOST = headphones.SAB_HOST[0:len(headphones.SAB_HOST)-1] url = headphones.SAB_HOST + "/" + "api?" + urllib.urlencode(params) try: if nzb.resultType == "nzb": f = urllib.urlopen(url) elif nzb.resultType == "nzbdata": cookies = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler.MultipartPostHandler) req = urllib2.Request(url, multiPartParams, headers={'User-Agent': USER_AGENT}) f = opener.open(req) except (EOFError, IOError), e: logger.error(u"Unable to connect to SAB with URL: %s" % url) return False
def addAlbumArt(artwork, albumpath, release): logger.info('Adding album art to folder') try: year = release['ReleaseDate'][:4] except TypeError: year = '' values = { '$Artist': release['ArtistName'], '$Album': release['AlbumTitle'], '$Year': year, '$artist': release['ArtistName'].lower(), '$album': release['AlbumTitle'].lower(), '$year': year } album_art_name = helpers.replace_all(headphones.ALBUM_ART_FORMAT.strip(), values) + ".jpg" album_art_name = helpers.replace_illegal_chars(album_art_name).encode(headphones.SYS_ENCODING, 'replace') if headphones.FILE_UNDERSCORES: album_art_name = album_art_name.replace(' ', '_') if album_art_name.startswith('.'): album_art_name = album_art_name.replace(0, '_') try: file = open(os.path.join(albumpath, album_art_name), 'wb') file.write(artwork) file.close() except Exception, e: logger.error('Error saving album art: %s' % str(e)) return
def musicScan(self, path): headphones.MUSIC_DIR = path headphones.config_write() try: threading.Thread(target=importer.scanMusic, args=[path]).start() except Exception, e: logger.error('Unable to complete the scan: %s' % e)
def getFolder(hash): # Get Active Directory from settings active_dir, completed_dir = getSettingsDirectories() if not active_dir: logger.error('Could not get "Put new downloads in:" directory from uTorrent settings, please ensure it is set') return None # Get Torrent Folder Name torrent_folder, cacheid = dirTorrent(hash) # If there's no folder yet then it's probably a magnet, try until folder is populated if torrent_folder == active_dir or not torrent_folder: tries = 1 while (torrent_folder == active_dir or torrent_folder is None) and tries <= 10: tries += 1 time.sleep(6) torrent_folder, cacheid = dirTorrent(hash, cacheid) if torrent_folder == active_dir or not torrent_folder: torrent_folder, cacheid = dirTorrent(hash, cacheid, return_name=True) return torrent_folder else: if headphones.SYS_PLATFORM != "win32": torrent_folder = torrent_folder.replace("\\", "/") return os.path.basename(os.path.normpath(torrent_folder))
def request_lastfm(method, **kwargs): """ Call a Last.FM API method. Automatically sets the method and API key. Method will return the result if no error occured. By default, this method will request the JSON format, since it is more lightweight than XML. """ # Prepare request kwargs["method"] = method kwargs.setdefault("api_key", API_KEY) kwargs.setdefault("format", "json") # Send request logger.debug("Calling Last.FM method: %s", method) logger.debug("Last.FM call parameters: %s", kwargs) data = request.request_json(ENTRY_POINT, timeout=TIMEOUT, params=kwargs, rate_limit=(lock, REQUEST_LIMIT)) # Parse response and check for errors. if not data: logger.error("Error calling Last.FM method: %s", method) return if "error" in data: logger.error("Last.FM returned an error: %s", data["message"]) return return data
def sab_api_call(request_type=None, params={}, **kwargs): if not headphones.CONFIG.SAB_HOST.startswith('http'): headphones.CONFIG.SAB_HOST = 'http://' + headphones.CONFIG.SAB_HOST if headphones.CONFIG.SAB_HOST.endswith('/'): headphones.CONFIG.SAB_HOST = headphones.CONFIG.SAB_HOST[ 0:len(headphones.CONFIG.SAB_HOST) - 1] url = headphones.CONFIG.SAB_HOST + "/" + "api?" if headphones.CONFIG.SAB_USERNAME: params['ma_username'] = headphones.CONFIG.SAB_USERNAME if headphones.CONFIG.SAB_PASSWORD: params['ma_password'] = headphones.CONFIG.SAB_PASSWORD if headphones.CONFIG.SAB_APIKEY: params['apikey'] = headphones.CONFIG.SAB_APIKEY if request_type == 'send_nzb' and headphones.CONFIG.SAB_CATEGORY: params['cat'] = headphones.CONFIG.SAB_CATEGORY params['output'] = 'json' response = request.request_json(url, params=params, **kwargs) if not response: logger.error("Error connecting to SABnzbd on url: %s" % headphones.CONFIG.SAB_HOST) return False else: logger.debug("Successfully connected to SABnzbd on url: %s" % headphones.CONFIG.SAB_HOST) return response
def preprocess(resultlist): if not headphones.USENET_RETENTION: usenet_retention = 2000 else: usenet_retention = int(headphones.USENET_RETENTION) for result in resultlist: nzb = getresultNZB(result) if nzb: try: d = minidom.parseString(nzb) node = d.documentElement nzbfiles = d.getElementsByTagName("file") skipping = False for nzbfile in nzbfiles: if int(nzbfile.getAttribute("date")) < (time.time() - usenet_retention * 86400): logger.info('NZB contains a file out of your retention. Skipping.') skipping = True break if skipping: continue #TODO: Do we want rar checking in here to try to keep unknowns out? #or at least the option to do so? except ExpatError: logger.error('Unable to parse the best result NZB. Skipping.') continue return nzb, result else: logger.error("Couldn't retrieve the best nzb. Skipping.") return (False, False)
def login(self): """ Logs in user """ loginpage = 'http://login.rutracker.org/forum/login.php' post_params = { 'login_username': headphones.CONFIG.RUTRACKER_USER, 'login_password': headphones.CONFIG.RUTRACKER_PASSWORD, 'login': b'\xc2\xf5\xee\xe4' # '%C2%F5%EE%E4' } logger.info("Attempting to log in to rutracker...") try: r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) # try again if not self.has_bb_data_cookie(r): time.sleep(10) r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) if self.has_bb_data_cookie(r): self.loggedin = True logger.info("Successfully logged in to rutracker") else: logger.error( "Could not login to rutracker, credentials maybe incorrect, site is down or too many attempts. Try again later") self.loggedin = False return self.loggedin except Exception as e: logger.error("Unknown error logging in to rutracker: %s" % e) self.loggedin = False return self.loggedin
def utorrent_add_file(self, data): host = headphones.CONFIG.UTORRENT_HOST if not host.startswith('http'): host = 'http://' + host if host.endswith('/'): host = host[:-1] if host.endswith('/gui'): host = host[:-4] base_url = host url = base_url + '/gui/' self.session.auth = (headphones.CONFIG.UTORRENT_USERNAME, headphones.CONFIG.UTORRENT_PASSWORD) try: r = self.session.get(url + 'token.html') except Exception as e: logger.error('Error getting token: %s', e) return if r.status_code == 401: logger.debug('Error reaching utorrent') return regex = re.search(r'.+>([^<]+)</div></html>', r.text) if regex is None: logger.debug('Error reading token') return self.session.params = {'token': regex.group(1)} files = {'torrent_file': ("", data)} try: self.session.post(url, params={'action': 'add-file'}, files=files) except Exception as e: logger.exception('Error adding file to utorrent %s', e)
def request_json(url, **kwargs): """ Wrapper for `request_response', which will decode the response as JSON object and return the result, if no exceptions are raised. As an option, a validator callback can be given, which should return True if the result is valid. """ validator = kwargs.pop("validator", None) response = request_response(url, **kwargs) if response is not None: try: result = response.json() if validator and not validator(result): logger.error("JSON validation result failed") else: return result except ValueError: logger.error("Response returned invalid JSON data") # Debug response if headphones.VERBOSE: server_message(response)
def create_https_certificates(ssl_cert, ssl_key): """ Create a pair of self-signed HTTPS certificares and store in them in 'ssl_cert' and 'ssl_key'. Method assumes pyOpenSSL is installed. This code is stolen from SickBeard (http://github.com/midgetspy/Sick-Beard). """ from headphones import logger from OpenSSL import crypto from certgen import createKeyPair, createCertRequest, createCertificate, \ TYPE_RSA, serial # Create the CA Certificate cakey = createKeyPair(TYPE_RSA, 2048) careq = createCertRequest(cakey, CN="Certificate Authority") cacert = createCertificate(careq, (careq, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years pkey = createKeyPair(TYPE_RSA, 2048) req = createCertRequest(pkey, CN="Headphones") cert = createCertificate(req, (cacert, cakey), serial, (0, 60 * 60 * 24 * 365 * 10)) # ten years # Save the key and certificate to disk try: with open(ssl_key, "w") as fp: fp.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) with open(ssl_cert, "w") as fp: fp.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) except IOError as e: logger.error("Error creating SSL key and certificate: %s", e) return False return True
def get_torrent(self, url, savelocation=None): torrent_id = dict([part.split('=') for part in urlparse(url)[4].split('&')])['t'] self.cookiejar.set_cookie(cookielib.Cookie(version=0, name='bb_dl', value=torrent_id, port=None, port_specified=False, domain='.rutracker.org', domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)) downloadurl = 'http://dl.rutracker.org/forum/dl.php?t=' + torrent_id torrent_name = torrent_id + '.torrent' try: prev = os.umask(headphones.UMASK) page = self.opener.open(downloadurl) torrent = page.read() decoded = bdecode(torrent) metainfo = decoded['info'] tor_hash = sha1(bencode(metainfo)).hexdigest() if savelocation: download_path = os.path.join(savelocation, torrent_name) else: tempdir = mkdtemp(suffix='_rutracker_torrents') download_path = os.path.join(tempdir, torrent_name) fp = open (download_path, 'wb') fp.write (torrent) fp.close () os.umask(prev) # Add file to utorrent if headphones.TORRENT_DOWNLOADER == 2: self.utorrent_add_file(download_path) except Exception, e: logger.error('Error getting torrent: %s' % e) return False
def torrentAction(method, arguments): host = headphones.CONFIG.TRANSMISSION_HOST username = headphones.CONFIG.TRANSMISSION_USERNAME password = headphones.CONFIG.TRANSMISSION_PASSWORD if not host.startswith("http"): host = "http://" + host if host.endswith("/"): host = host[:-1] # Fix the URL. We assume that the user does not point to the RPC endpoint, # so add it if it is missing. parts = list(urlparse.urlparse(host)) if not parts[0] in ("http", "https"): parts[0] = "http" if not parts[2].endswith("/rpc"): parts[2] += "/transmission/rpc" host = urlparse.urlunparse(parts) # Retrieve session id auth = (username, password) if username and password else None response = request.request_response(host, auth=auth, whitelist_status_code=[401, 409]) if response is None: logger.error("Error gettings Transmission session ID") return # Parse response if response.status_code == 401: if auth: logger.error("Username and/or password not accepted by " "Transmission") else: logger.error("Transmission authorization required") return elif response.status_code == 409: session_id = response.headers["x-transmission-session-id"] if not session_id: logger.error("Expected a Session ID from Transmission") return # Prepare next request headers = {"x-transmission-session-id": session_id} data = {"method": method, "arguments": arguments} response = request.request_json(host, method="POST", data=json.dumps(data), headers=headers, auth=auth) print response if not response: logger.error("Error sending torrent to Transmission") return return response
def addTorrent(link, hash): uTorrentClient = utorrentclient() # Get Active Directory from settings active_dir, completed_dir = getSettingsDirectories() if not active_dir or not completed_dir: logger.error('Could not get "Put new downloads in:" or "Move completed downloads to:" directories from uTorrent settings, please ensure they are set') return None uTorrentClient.add_url(link) # Get Torrent Folder Name torrent_folder, cacheid = dirTorrent(hash) # If there's no folder yet then it's probably a magnet, try until folder is populated if torrent_folder == active_dir or not torrent_folder: tries = 1 while (torrent_folder == active_dir or torrent_folder == None) and tries <= 10: tries += 1 time.sleep(6) torrent_folder, cacheid = dirTorrent(hash, cacheid) if torrent_folder == active_dir or not torrent_folder: torrent_folder, cacheid = dirTorrent(hash, cacheid, return_name=True) labelTorrent(hash) return torrent_folder else: labelTorrent(hash) return os.path.basename(os.path.normpath(torrent_folder))
def setSeedRatio(result): logger.debug('Deluge: Setting seed ratio') if not any(delugeweb_auth): _get_auth() ratio = None if result['ratio']: ratio = result['ratio'] try: if ratio: post_data = json.dumps({"method": "core.set_torrent_stop_at_ratio", "params": [result['hash'], True], "id": 5}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) post_data = json.dumps({"method": "core.set_torrent_stop_ratio", "params": [result['hash'], float(ratio)], "id": 6}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) return not json.loads(response.text)['error'] return True except Exception as e: logger.error('Deluge: Setting seed ratio failed: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return None
def action(self, query, args=None): with db_lock: if query == None: return sqlResult = None attempt = 0 while attempt < 5: try: if args == None: #logger.debug(self.filename+": "+query) sqlResult = self.connection.execute(query) else: #logger.debug(self.filename+": "+query+" with args "+str(args)) sqlResult = self.connection.execute(query, args) self.connection.commit() break except sqlite3.OperationalError, e: if "unable to open database file" in e.message or "database is locked" in e.message: logger.warn('Database Error: %s' % e) attempt += 1 time.sleep(1) else: logger.error('Database error: %s' % e) raise except sqlite3.DatabaseError, e: logger.error('Fatal Error executing %s :: %s' % (query, e)) raise
def preprocesstorrent(resultlist): selresult = "" for result in resultlist: try: if selresult == "": selresult = result request = urllib2.Request(result[2]) request.add_header('Accept-encoding', 'gzip') response = urllib2.urlopen(request) if response.info().get('Content-Encoding') == 'gzip': buf = StringIO( response.read()) f = gzip.GzipFile(fileobj=buf) torrent = f.read() else: torrent = response.read() elif int(selresult[1]) < int(result[1]): selresult = result request = urllib2.Request(result[2]) request.add_header('Accept-encoding', 'gzip') response = urllib2.urlopen(request) if response.info().get('Content-Encoding') == 'gzip': buf = StringIO( response.read()) f = gzip.GzipFile(fileobj=buf) torrent = f.read() else: torrent = response.read() except ExpatError: logger.error('Unable to torrent file. Skipping.') continue return torrent, selresult
def launch_browser(host, port, root): if host == '0.0.0.0': host = 'localhost' if CONFIG.ENABLE_HTTPS: protocol = 'https' else: protocol = 'http' try: webbrowser.open('%s://%s:%i%s' % (protocol, host, port, root)) except Exception as e: logger.error('Could not launch browser: %s', e)
def cleanupFiles(albumpath): logger.info('Cleaning up files') for r, d, f in os.walk(albumpath): for files in f: if not any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS): logger.debug('Removing: %s' % files) try: os.remove(os.path.join(r, files)) except Exception, e: logger.error( u'Could not remove file: %s. Error: %s' % (files.decode(headphones.SYS_ENCODING, 'replace'), e))
def embedAlbumArt(artwork, downloaded_track_list): logger.info('Embedding album art') for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.error(u'Could not read %s. Not adding album art' % downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) continue logger.debug('Adding album art to: %s' % downloaded_track) f.art = artwork f.save()
def embedAlbumArt(artwork, downloaded_track_list): logger.info('Embedding album art') for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.error('Could not read %s. Not adding album art' % downloaded_track) continue logger.debug('Adding album art to: %s' % downloaded_track) f.art = artwork f.save()
def login(self): """ Logs in user """ loginpage = 'http://rutracker.org/forum/login.php' post_params = { 'login_username': headphones.CONFIG.RUTRACKER_USER, 'login_password': headphones.CONFIG.RUTRACKER_PASSWORD, 'login': b'\xc2\xf5\xee\xe4' # '%C2%F5%EE%E4' } logger.info("Attempting to log in to rutracker...") try: r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) # try again if not self.has_bb_session_cookie(r): time.sleep(10) if headphones.CONFIG.RUTRACKER_COOKIE: logger.info( "Attempting to log in using predefined cookie...") r = self.session.post( loginpage, data=post_params, timeout=self.timeout, allow_redirects=False, cookies={ 'bb_session': headphones.CONFIG.RUTRACKER_COOKIE }) else: r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) if self.has_bb_session_cookie(r): self.loggedin = True logger.info("Successfully logged in to rutracker") else: logger.error( "Could not login to rutracker, credentials maybe incorrect, site is down or too many attempts. Try again later" ) self.loggedin = False return self.loggedin except Exception as e: logger.error("Unknown error logging in to rutracker: %s" % e) self.loggedin = False return self.loggedin
def sendNZB(nzb): params = {} # if it's a normal result we just pass SAB the URL if nzb.resultType == "nzb": # for newzbin results send the ID to sab specifically if nzb.provider.getID() == 'newzbin': id = nzb.provider.getIDFromURL(nzb.url) if not id: logger.info( "Unable to send NZB to sab, can't find ID in URL " + str(nzb.url)) return False params['mode'] = 'addid' params['name'] = id else: params['mode'] = 'addurl' params['name'] = nzb.url # if we get a raw data result we want to upload it to SAB elif nzb.resultType == "nzbdata": # Sanitize the file a bit, since we can only use ascii chars with MultiPartPostHandler nzbdata = helpers.latinToAscii(nzb.extraInfo[0]) params['mode'] = 'addfile' files = {"nzbfile": (helpers.latinToAscii(nzb.name) + ".nzb", nzbdata)} headers = {'User-Agent': USER_AGENT} logger.info("Attempting to connect to SABnzbd on url: %s" % headphones.CONFIG.SAB_HOST) if nzb.resultType == "nzb": response = sab_api_call('send_nzb', params=params) elif nzb.resultType == "nzbdata": cookies = cookielib.CookieJar() response = sab_api_call('send_nzb', params=params, method="post", files=files, cookies=cookies, headers=headers) if not response: logger.info(u"No data returned from SABnzbd, NZB not sent") return False if response['status']: logger.info(u"NZB sent to SABnzbd successfully") return True else: logger.error(u"Error sending NZB to SABnzbd: %s" % response['error']) return False
def preprocesstorrent(resultlist): selresult = "" for result in resultlist: try: if selresult == "": selresult = result torrent = urllib2.urlopen(result[2], timeout=30).read() elif int(selresult[1]) < int(result[1]): selresult = result torrent = urllib2.urlopen(result[2], timeout=30).read() except ExpatError: logger.error('Unable to torrent file. Skipping.') continue return torrent, selresult
def sendNZB(nzb): addToTop = False nzbgetXMLrpc = "%(username)s:%(password)s@%(host)s/xmlrpc" if headphones.CONFIG.NZBGET_HOST is None: logger.error(u"No NZBget host found in configuration. Please configure it.") return False if headphones.CONFIG.NZBGET_HOST.startswith('https://'): nzbgetXMLrpc = 'https://' + nzbgetXMLrpc headphones.CONFIG.NZBGET_HOST.replace('https://', '', 1) else: nzbgetXMLrpc = 'http://' + nzbgetXMLrpc headphones.CONFIG.NZBGET_HOST.replace('http://', '', 1) url = nzbgetXMLrpc % {"host": headphones.CONFIG.NZBGET_HOST, "username": headphones.CONFIG.NZBGET_USERNAME, "password": headphones.CONFIG.NZBGET_PASSWORD} nzbGetRPC = xmlrpclib.ServerProxy(url) try: if nzbGetRPC.writelog("INFO", "headphones connected to drop of %s any moment now." % (nzb.name + ".nzb")): logger.debug(u"Successfully connected to NZBget") else: logger.info(u"Successfully connected to NZBget, but unable to send a message" % (nzb.name + ".nzb")) except httplib.socket.error: logger.error(u"Please check your NZBget host and port (if it is running). NZBget is not responding to this combination") return False except xmlrpclib.ProtocolError, e: if (e.errmsg == "Unauthorized"): logger.error(u"NZBget password is incorrect.") else: logger.error(u"Protocol Error: " + e.errmsg) return False
def setTorrentPath(result): logger.debug('Deluge: Setting download path') if not any(delugeweb_auth): _get_auth() try: if headphones.CONFIG.DELUGE_DONE_DIRECTORY or headphones.CONFIG.DOWNLOAD_TORRENT_DIR: post_data = json.dumps({ "method": "core.set_torrent_move_completed", "params": [result['hash'], True], "id": 7 }) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) if headphones.CONFIG.DELUGE_DONE_DIRECTORY: move_to = headphones.CONFIG.DELUGE_DONE_DIRECTORY else: move_to = headphones.CONFIG.DOWNLOAD_TORRENT_DIR # If Deluge host is remote, disable path checks for now if headphones.CONFIG.DELUGE_FOREIGN != 1: if not os.path.exists(move_to): logger.debug( 'Deluge: %s directory doesn\'t exist, let\'s create it' % move_to) os.makedirs(move_to) post_data = json.dumps({ "method": "core.set_torrent_move_completed_path", "params": [result['hash'], move_to], "id": 8 }) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) return not json.loads(response.text)['error'] return True except Exception as e: logger.error('Deluge: Setting torrent move-to directory failed: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return None
def getXldProfile(xldProfile): xldProfileNotFound = xldProfile expanded = os.path.expanduser('~/Library/Preferences/jp.tmkk.XLD.plist') if not os.path.isfile(expanded): logger.warn("Could not find xld preferences at: %s", expanded) return (xldProfileNotFound, None, None) # Get xld preferences plist try: preferences = biplist.readPlist(expanded) except (biplist.InvalidPlistException, biplist.NotBinaryPlistException), e: logger.error("Error reading xld preferences plist: %s", e) return (xldProfileNotFound, None, None)
def removeTorrent(torrentid, remove_data=False): logger.debug('Deluge: Remove torrent %s' % torrentid) if not any(delugeweb_auth): _get_auth() try: logger.debug('Deluge: Checking if torrent %s finished seeding' % str(torrentid)) post_data = json.dumps({"method": "web.get_torrent_status", "params": [ torrentid, [ "name", "ratio", "state" ] ], "id": 26}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) try: state = json.loads(response.text)['result']['state'] except KeyError as e: logger.debug('Deluge: "state" KeyError when trying to remove torrent %s' % str(torrentid)) return False not_finished = ["queued", "seeding", "downloading", "checking", "error"] result = False if state.lower() in not_finished: logger.debug('Deluge: Torrent %s is either queued or seeding, not removing yet' % str(torrentid)) return False else: logger.debug('Deluge: Removing torrent %s' % str(torrentid)) post_data = json.dumps({"method": "core.remove_torrent", "params": [ torrentid, remove_data ], "id": 25}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) result = json.loads(response.text)['result'] return result except Exception as e: logger.error('Deluge: Removing torrent failed: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return None
def getVersion(): if version.HEADPHONES_VERSION.startswith('win32build'): headphones.INSTALL_TYPE = 'win' # Don't have a way to update exe yet, but don't want to set VERSION to None return 'Windows Install', 'master' elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')): headphones.INSTALL_TYPE = 'git' output, err = runGit('rev-parse HEAD') if not output: logger.error('Couldn\'t find latest installed version.') cur_commit_hash = None cur_commit_hash = str(output) if not re.match('^[a-z0-9]+$', cur_commit_hash): logger.error('Output doesn\'t look like a hash, not using it') cur_commit_hash = None if headphones.DO_NOT_OVERRIDE_GIT_BRANCH and headphones.GIT_BRANCH: branch_name = headphones.GIT_BRANCH else: branch_name, err = runGit('rev-parse --abbrev-ref HEAD') branch_name = branch_name if not branch_name and headphones.GIT_BRANCH: logger.error( 'Could not retrieve branch name from git. Falling back to %s' % headphones.GIT_BRANCH) branch_name = headphones.GIT_BRANCH if not branch_name: logger.error( 'Could not retrieve branch name from git. Defaulting to master' ) branch_name = 'master' return cur_commit_hash, branch_name else: headphones.INSTALL_TYPE = 'source' version_file = os.path.join(headphones.PROG_DIR, 'version.txt') if not os.path.isfile(version_file): return None, 'master' with open(version_file, 'r') as f: current_version = f.read().strip(' \n\r') if current_version: return current_version, headphones.GIT_BRANCH else: return None, 'master'
def _add_torrent_file(result): logger.debug('Deluge: Adding file') if not any(delugeweb_auth): _get_auth() try: # content is torrent file contents that needs to be encoded to base64 post_data = json.dumps({ "method": "core.add_torrent_file", "params": [ result['name'] + '.torrent', b64encode(result['content'].encode('utf8')), {} ], "id": 2 }) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert) result['hash'] = json.loads(response.text)['result'] logger.debug('Deluge: Response was %s' % str(json.loads(response.text))) return json.loads(response.text)['result'] except UnicodeDecodeError: try: # content is torrent file contents that needs to be encoded to base64 # this time let's try leaving the encoding as is logger.debug( 'Deluge: There was a decoding issue, let\'s try again') post_data = json.dumps({ "method": "core.add_torrent_file", "params": [ result['name'] + '.torrent', b64encode(result['content']), {} ], "id": 22 }) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert) result['hash'] = json.loads(response.text)['result'] logger.debug('Deluge: Response was %s' % str(json.loads(response.text))) return json.loads(response.text)['result'] except Exception as e: logger.error( 'Deluge: Adding torrent file failed after decode: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return False except Exception as e: logger.error('Deluge: Adding torrent file failed: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return False
def updateFilePermissions(albumpaths): for folder in albumpaths: logger.info("Updating file permissions in " + folder.decode(headphones.SYS_ENCODING, 'replace')) for r, d, f in os.walk(folder): for files in f: full_path = os.path.join(r, files) try: os.chmod(full_path, int(headphones.FILE_PERMISSIONS, 8)) except: logger.error( "Could not change permissions for file: " + full_path.decode(headphones.SYS_ENCODING, 'replace')) continue
def get_torrent_data(self, url): """ return the .torrent data """ torrent_id = dict([part.split('=') for part in urlparse(url)[4].split('&')])['t'] downloadurl = 'http://rutracker.org/forum/dl.php?t=' + torrent_id cookie = {'bb_dl': torrent_id} try: headers = {'Referer': url} r = self.session.post(url=downloadurl, cookies=cookie, headers=headers, timeout=self.timeout) return r.content except Exception as e: logger.error('Error getting torrent: %s', e) return False
def _add_torrent_file(result): logger.debug('Deluge: Adding file') options = {} if headphones.CONFIG.DELUGE_DOWNLOAD_DIRECTORY: options['download_location'] = headphones.CONFIG.DELUGE_DOWNLOAD_DIRECTORY if headphones.CONFIG.DELUGE_DONE_DIRECTORY or headphones.CONFIG.DOWNLOAD_TORRENT_DIR: options['move_completed'] = 1 if headphones.CONFIG.DELUGE_DONE_DIRECTORY: options['move_completed_path'] = headphones.CONFIG.DELUGE_DONE_DIRECTORY else: options['move_completed_path'] = headphones.CONFIG.DOWNLOAD_TORRENT_DIR if headphones.CONFIG.DELUGE_PAUSED: options['add_paused'] = headphones.CONFIG.DELUGE_PAUSED if not any(delugeweb_auth): _get_auth() try: # content is torrent file contents that needs to be encoded to base64 post_data = json.dumps({"method": "core.add_torrent_file", "params": [result['name'] + '.torrent', b64encode(result['content'].encode('utf8')), options], "id": 2}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) result['hash'] = json.loads(response.text)['result'] logger.debug('Deluge: Response was %s' % str(json.loads(response.text))) return json.loads(response.text)['result'] except UnicodeDecodeError: try: # content is torrent file contents that needs to be encoded to base64 # this time let's try leaving the encoding as is logger.debug('Deluge: There was a decoding issue, let\'s try again') post_data = json.dumps({"method": "core.add_torrent_file", "params": [result['name'].decode('utf8') + '.torrent', b64encode(result['content']), options], "id": 22}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) result['hash'] = json.loads(response.text)['result'] logger.debug('Deluge: Response was %s' % str(json.loads(response.text))) return json.loads(response.text)['result'] except Exception as e: logger.error('Deluge: Adding torrent file failed after decode: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return False except Exception as e: logger.error('Deluge: Adding torrent file failed: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return False
def _add_torrent_url(result): logger.debug('Deluge: Adding URL') if not any(delugeweb_auth): _get_auth() try: post_data = json.dumps({"method": "web.download_torrent_from_url", "params": [result['url'], {}], "id": 32}) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth, verify=deluge_verify_cert, headers=headers) result['location'] = json.loads(response.text)['result'] logger.debug('Deluge: Response was %s' % str(json.loads(response.text))) return json.loads(response.text)['result'] except Exception as e: logger.error('Deluge: Adding torrent URL failed: %s' % str(e)) formatted_lines = traceback.format_exc().splitlines() logger.error('; '.join(formatted_lines)) return False
def torrentAction(method, arguments): host = headphones.TRANSMISSION_HOST username = headphones.TRANSMISSION_USERNAME password = headphones.TRANSMISSION_PASSWORD sessionid = None if not host.startswith('http'): host = 'http://' + host if host.endswith('/'): host = host[:-1] # Either the host ends with a port, or some directory, or rpc # If it ends with /rpc we don't have to do anything # If it ends with a port we add /transmission/rpc # anything else we just add rpc if not host.endswith('/rpc'): # Check if it ends in a port number i = host.rfind(':') if i >= 0: possible_port = host[i + 1:] try: port = int(possible_port) host = host + "/transmission/rpc" except ValueError: host = host + "/rpc" else: logger.error('Transmission port missing') return request = urllib2.Request(host) if username and password: base64string = base64.encodestring( '%s:%s' % (username, password)).replace('\n', '') request.add_header("Authorization", "Basic %s" % base64string) opener = urllib2.build_opener() try: data = opener.open(request).read() except urllib2.HTTPError, e: if e.code == 409: sessionid = e.hdrs['x-transmission-session-id'] else: logger.error('Could not connect to Transmission. Error: ' + str(e))
def request_response(url, method="get", auto_raise=True, whitelist_status_code=None, **kwargs): """ Convenient wrapper for `requests.get', which will capture the exceptions and log them. On success, the Response object is returned. In case of a exception, None is returned. """ # Convert whitelist_status_code to a list if needed if whitelist_status_code and type(whitelist_status_code) != list: whitelist_status_code = [whitelist_status_code] # Disable verification of SSL certificates if requested. Note: this could # pose a security issue! kwargs["verify"] = headphones.VERIFY_SSL_CERT # Map method to the request.XXX method. This is a simple hack, but it allows # requests to apply more magic per method. See lib/requests/api.py. request_method = getattr(requests, method.lower()) try: # Request the URL logger.debug("Requesting URL via %s method: %s", method.upper(), url) response = request_method(url, **kwargs) # If status code != OK, then raise exception, except if the status code # is white listed. if whitelist_status_code and auto_raise: if response.status_code not in whitelist_status_code: try: response.raise_for_status() except: logger.debug("Response status code %d is not white listed, raised exception", response.status_code) raise elif auto_raise: response.raise_for_status() return response except requests.ConnectionError: logger.error("Unable to connect to remote host.") except requests.Timeout: logger.error("Request timed out.") except requests.HTTPError, e: if e.response is not None: if e.response.status_code >= 500: cause = "remote server error" elif e.response.status_code >= 400: cause = "local request error" else: # I don't think we will end up here, but for completeness cause = "unknown" logger.error("Request raise HTTP error with status code %d (%s).", e.response.status_code, cause) else: logger.error("Request raised HTTP error.")
def runGit(args): if headphones.GIT_PATH: git_locations = ['"' + headphones.GIT_PATH + '"'] else: git_locations = ['git'] if platform.system().lower() == 'darwin': git_locations.append('/usr/local/git/bin/git') output = err = None for cur_git in git_locations: cmd = cur_git + ' ' + args try: logger.debug('Trying to execute: "' + cmd + '" with shell in ' + headphones.PROG_DIR) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=headphones.PROG_DIR) output, err = p.communicate() output = output.strip() logger.debug('Git output: ' + output) except OSError: logger.debug('Command failed: %s', cmd) continue if 'not found' in output or "not recognized as an internal or external command" in output: logger.debug('Unable to find git with command ' + cmd) output = None elif 'fatal:' in output or err: logger.error( 'Git returned bad info. Are you sure this is a git installation?' ) output = None elif output: break return (output, err)
def select(self, query, args=None): logger.info("select Query is " + query) #sqlResults = self.action(query, args).fetchall() try: with self.connection.cursor() as c: if args is None: logger.debug("select Args are None") c.execute(query) sqlResults = c.fetchall() else: logger.debug("select Args are " + args) c.execute(query, args) sqlResults = c.fetchall() except psycopg2.OperationalError, e: logger.error('Database error: %s', e) raise
def _add_torrent_magnet(result): logger.debug('Deluge: Adding magnet') if not any(delugeweb_auth): _get_auth() try: post_data = json.dumps({ "method": "core.add_torrent_magnet", "params": [result['url'], {}], "id": 2 }) response = requests.post(delugeweb_url, data=post_data.encode('utf-8'), cookies=delugeweb_auth) result['hash'] = json.loads(response.text)['result'] logger.debug('Deluge: Response was %s' % str(json.loads(response.text)['result'])) return json.loads(response.text)['result'] except Exception as e: logger.error('Deluge: Adding torrent magnet failed: %s' % str(e))
def getVersion(): if version.HEADPHONES_VERSION.startswith('build '): headphones.INSTALL_TYPE = 'win' # Don't have a way to update exe yet, but don't want to set VERSION to None return 'Windows Install' elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')): headphones.INSTALL_TYPE = 'git' output, err = runGit('rev-parse HEAD') if not output: logger.error('Couldn\'t find latest installed version.') return None cur_commit_hash = output.strip() if not re.match('^[a-z0-9]+$', cur_commit_hash): logger.error('Output doesn\'t look like a hash, not using it') return None return cur_commit_hash else: headphones.INSTALL_TYPE = 'source' version_file = os.path.join(headphones.PROG_DIR, 'version.txt') if not os.path.isfile(version_file): return None fp = open(version_file, 'r') current_version = fp.read().strip(' \n\r') fp.close() if current_version: return current_version else: return None
def notify(self, artist, album, albumartpath): hosts = [x.strip() for x in self.client_hosts.split(',')] header = "Headphones" message = "%s - %s added to your library" % (artist, album) time = "3000" # in ms for host in hosts: logger.info('Sending notification command to Plex client @ ' + host) try: version = self._sendjson( host, 'Application.GetProperties', {'properties': ['version']})['version']['major'] if version < 12: # Eden notification = header + "," + message + "," + time + \ "," + albumartpath notifycommand = { 'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')' } request = self._sendhttp(host, notifycommand) else: # Frodo params = { 'title': header, 'message': message, 'displaytime': int(time), 'image': albumartpath } request = self._sendjson(host, 'GUI.ShowNotification', params) if not request: raise Exception except Exception: logger.error( 'Error sending notification request to Plex client @ ' + host)
def correctMetadata(albumid, release, downloaded_track_list): logger.info('Preparing to write metadata to tracks....') lossy_items = [] lossless_items = [] # Process lossless & lossy media formats separately for downloaded_track in downloaded_track_list: try: if any(downloaded_track.lower().endswith('.' + x.lower()) for x in headphones.LOSSLESS_MEDIA_FORMATS): lossless_items.append(beets.library.Item.from_path(downloaded_track)) elif any(downloaded_track.lower().endswith('.' + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS): lossy_items.append(beets.library.Item.from_path(downloaded_track)) else: logger.warn("Skipping: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " because it is not a mutagen friendly file format") except Exception, e: logger.error("Beets couldn't create an Item from: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " - not a media file?" + str(e))
def action(self, query, args=None): if query == None: return sqlResult = None try: with self.connection as c: if args == None: sqlResult = c.execute(query) else: sqlResult = c.execute(query, args) except sqlite3.OperationalError, e: if "unable to open database file" in e.message or "database is locked" in e.message: logger.warn('Database Error: %s', e) else: logger.error('Database error: %s', e) raise
def split_baby(split_file, split_cmd): '''Let's split baby''' logger.info('Splitting %s...', split_file.decode(headphones.SYS_ENCODING, 'replace')) logger.debug(subprocess.list2cmdline(split_cmd)) # Prevent Windows from opening a terminal window startupinfo = None if headphones.SYS_PLATFORM == "win32": startupinfo = subprocess.STARTUPINFO() try: startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW except AttributeError: startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW env = os.environ.copy() if 'xld' in split_cmd: env['PATH'] += os.pathsep + '/Applications' elif headphones.CONFIG.CUE_SPLIT_FLAC_PATH: env['PATH'] += os.pathsep + headphones.CONFIG.CUE_SPLIT_FLAC_PATH process = subprocess.Popen(split_cmd, startupinfo=startupinfo, stdin=open(os.devnull, 'rb'), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) stdout, stderr = process.communicate() if process.returncode: logger.error('Split failed for %s', split_file.decode(headphones.SYS_ENCODING, 'replace')) out = stdout if stdout else stderr logger.error('Error details: %s', out.decode(headphones.SYS_ENCODING, 'replace')) return False else: logger.info('Split success %s', split_file.decode(headphones.SYS_ENCODING, 'replace')) return True
def get_torrent(self, url, savelocation=None): torrent_id = dict( [part.split('=') for part in urlparse(url)[4].split('&')])['t'] self.cookiejar.set_cookie( cookielib.Cookie(version=0, name='bb_dl', value=torrent_id, port=None, port_specified=False, domain='.rutracker.org', domain_specified=False, domain_initial_dot=False, path='/', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False)) downloadurl = 'http://dl.rutracker.org/forum/dl.php?t=' + torrent_id torrent_name = torrent_id + '.torrent' try: prev = os.umask(headphones.UMASK) page = self.opener.open(downloadurl) torrent = page.read() if savelocation: download_path = os.path.join(savelocation, torrent_name) else: tempdir = mkdtemp(suffix='_rutracker_torrents') download_path = os.path.join(tempdir, torrent_name) fp = open(download_path, 'wb') fp.write(torrent) fp.close() os.umask(prev) except Exception, e: logger.error('Error getting torrent: %s' % e) return False
def getArtists(): myDB = db.DBConnection() results = myDB.select('SELECT ArtistID from artists') if not headphones.LASTFM_USERNAME: return else: username = headphones.LASTFM_USERNAME url = 'http://ws.audioscrobbler.com/2.0/?method=library.getartists&limit=10000&api_key=%s&user=%s' % ( api_key, username) data = urllib2.urlopen(url, timeout=20).read() try: d = minidom.parseString(data) except: logger.error("Could not parse artist list from last.fm data") return artists = d.getElementsByTagName("artist") artistlist = [] for artist in artists: mbidnode = artist.getElementsByTagName("mbid")[0].childNodes for node in mbidnode: artist_mbid = node.data try: if not any(artist_mbid in x for x in results): artistlist.append(artist_mbid) except: continue from headphones import importer for artistid in artistlist: importer.addArtisttoDB(artistid)
def action(self, query, args=None): if query is None: return sqlResult = None logger.info("Query is " + query) try: with self.connection.cursor() as c: if args is None: logger.debug("action Args are None") sqlResult = c.execute(query) else: logger.debug("action Args are " + args) sqlResult = c.execute(query, args) except psycopg2.OperationalError, e: logger.error('Database error: %s', e) raise