def verifyresult(title, artistterm, term): title = re.sub('[\.\-\/\_]', ' ', title) #if artistterm != 'Various Artists': # # if not re.search('^' + re.escape(artistterm), title, re.IGNORECASE): # #logger.info("Removed from results: " + title + " (artist not at string start).") # #return False # elif re.search(re.escape(artistterm) + '\w', title, re.IGNORECASE | re.UNICODE): # logger.info("Removed from results: " + title + " (post substring result).") # return False # elif re.search('\w' + re.escape(artistterm), title, re.IGNORECASE | re.UNICODE): # logger.info("Removed from results: " + title + " (pre substring result).") # return False #another attempt to weed out substrings. We don't want "Vol III" when we were looking for "Vol II" tokens = re.split('\W', term, re.IGNORECASE | re.UNICODE) for token in tokens: if not token: continue if token == 'Various' or token == 'Artists' or token == 'VA': continue if not re.search('(?:\W|^)+' + token + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE): cleantoken = ''.join(c for c in token if c not in string.punctuation) if not not re.search('(?:\W|^)+' + cleantoken + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE): dic = {'!':'i', '$':'s'} dumbtoken = helpers.replace_all(token, dic) if not not re.search('(?:\W|^)+' + dumbtoken + '(?:\W|$)+', title, re.IGNORECASE | re.UNICODE): logger.info("Removed from results: " + title + " (missing tokens: " + token + " and " + cleantoken + ")") return False return True
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 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 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).replace('/', '_') + ".jpg" album_art_name = album_art_name.replace('?', '_').replace(':', '_').encode( headphones.SYS_ENCODING, 'replace') if album_art_name.startswith('.'): album_art_name = album_art_name.replace(0, '_') prev = os.umask(headphones.UMASK) file = open(os.path.join(albumpath, album_art_name), 'wb') file.write(artwork) file.close() os.umask(prev)
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).replace('/','_') + ".jpg" album_art_name = album_art_name.replace('?','_').replace(':', '_').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, '_') prev = os.umask(headphones.UMASK) file = open(os.path.join(albumpath, album_art_name), 'wb') file.write(artwork) file.close() os.umask(prev)
def update(artist_name,release_groups): """ Pretty simple and crude function to find the artist page on metacritic, then parse that page to get critic & user scores for albums""" # First let's modify the artist name to fit the metacritic convention. # We could just do a search, then take the top result, but at least this will # cut down on api calls. If it's ineffective then we'll switch to search replacements = {" & " : " ", "." : ""} mc_artist_name = helpers.replace_all(artist_name.lower(),replacements) mc_artist_name = mc_artist_name.replace(" ","-") url = "http://www.metacritic.com/person/" + mc_artist_name + "?filter-options=music&sort_options=date&num_items=100" res = request.request_soup(url, parser='html.parser') try: rows = res.tbody.find_all('tr') except: logger.info("Unable to get metacritic scores for: %s" % artist_name) return myDB = db.DBConnection() for row in rows: title = row.a.string for rg in release_groups: if rg['title'].lower() == title.lower(): scores = row.find_all("span") critic_score = scores[0].string user_score = scores[1].string controlValueDict = {"AlbumID": rg['id']} newValueDict = {'CriticScore':critic_score,'UserScore':user_score} myDB.upsert("albums", newValueDict, controlValueDict)
def renameFiles(albumpath, downloaded_track_list, release): logger.info('Renaming files') try: year = release['ReleaseDate'][:4] except TypeError: year = '' # Until tagging works better I'm going to rely on the already provided metadata for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.info("MediaFile couldn't parse: " + downloaded_track) continue if not f.track: tracknumber = '' else: tracknumber = '%02d' % f.track if not f.title: basename = unicode(os.path.basename(downloaded_track), headphones.SYS_ENCODING, errors='replace') title = os.path.splitext(basename)[0] ext = os.path.splitext(basename)[1] new_file_name = helpers.cleanTitle(title) + ext else: title = f.title values = { 'tracknumber': tracknumber, 'title': title, 'artist': release['ArtistName'], 'album': release['AlbumTitle'], 'year': year } ext = os.path.splitext(downloaded_track)[1] new_file_name = helpers.replace_all(headphones.FILE_FORMAT, values).replace('/', '_') + ext new_file_name = new_file_name.replace('?', '_').replace( ':', '_').encode(headphones.SYS_ENCODING) new_file = os.path.join(albumpath, new_file_name) logger.debug('Renaming %s ---> %s' % (downloaded_track, new_file_name)) try: os.rename(downloaded_track, new_file) except Exception, e: logger.error('Error renaming file: %s. Error: %s' % (downloaded_track, e)) continue
def renameFiles(albumpath, downloaded_track_list, release): logger.info('Renaming files') try: year = release['ReleaseDate'][:4] except TypeError: year = '' # Until tagging works better I'm going to rely on the already provided metadata for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.info("MediaFile couldn't parse: " + downloaded_track) continue if not f.track: tracknumber = '' else: tracknumber = '%02d' % f.track if not f.title: basename = unicode(os.path.basename(downloaded_track), headphones.SYS_ENCODING, errors='replace') title = os.path.splitext(basename)[0] ext = os.path.splitext(basename)[1] new_file_name = helpers.cleanTitle(title) + ext else: title = f.title values = { 'Track': tracknumber, 'Title': title, 'Artist': release['ArtistName'], 'Album': release['AlbumTitle'], 'Year': year, 'track': tracknumber, 'title': title.lower(), 'artist': release['ArtistName'].lower(), 'album': release['AlbumTitle'].lower(), 'year': year } ext = os.path.splitext(downloaded_track)[1] new_file_name = helpers.replace_all(headphones.FILE_FORMAT, values).replace('/','_') + ext new_file_name = new_file_name.replace('?','_').replace(':', '_').encode(headphones.SYS_ENCODING) new_file = os.path.join(albumpath, new_file_name) logger.debug('Renaming %s ---> %s' % (downloaded_track, new_file_name)) try: os.rename(downloaded_track, new_file) except Exception, e: logger.error('Error renaming file: %s. Error: %s' % (downloaded_track, e)) continue
def renameFiles(albumpath, downloaded_track_list, release): logger.info("Renaming files") try: year = release["ReleaseDate"][:4] except TypeError: year = "" # Until tagging works better I'm going to rely on the already provided metadata for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.info("MediaFile couldn't parse: " + downloaded_track) continue if not f.track: tracknumber = "" else: tracknumber = "%02d" % f.track if not f.title: basename = unicode(os.path.basename(downloaded_track), headphones.SYS_ENCODING, errors="replace") title = os.path.splitext(basename)[0] ext = os.path.splitext(basename)[1] new_file_name = helpers.cleanTitle(title) + ext else: title = f.title values = { "tracknumber": tracknumber, "title": title, "artist": release["ArtistName"], "album": release["AlbumTitle"], "year": year, } ext = os.path.splitext(downloaded_track)[1] new_file_name = helpers.replace_all(headphones.FILE_FORMAT, values).replace("/", "_") + ext new_file_name = new_file_name.replace("?", "_").replace(":", "_").encode(headphones.SYS_ENCODING) new_file = os.path.join(albumpath, new_file_name) logger.debug("Renaming %s ---> %s" % (downloaded_track, new_file_name)) try: os.rename(downloaded_track, new_file) except Exception, e: logger.error("Error renaming file: %s. Error: %s" % (downloaded_track, e)) continue
def moveFiles(albumpath, release, tracks): try: year = release["ReleaseDate"][:4] except TypeError: year = "" values = {"artist": release["ArtistName"], "album": release["AlbumTitle"], "year": year} folder = helpers.replace_all(headphones.FOLDER_FORMAT, values) destination_path = os.path.join(headphones.DESTINATION_DIR, folder) destination_path = destination_path.replace("?", "_") if os.path.exists(destination_path): i = 1 while True: new_folder_name = destination_path + "[%i]" % i if os.path.exists(new_folder_name): i += 1 else: destination_path = new_folder_name break logger.info("Moving files from %s to %s" % (folder, destination_path)) try: os.makedirs(destination_path) # Chmod the directories using the folder_format (script courtesy of premiso!) folder_list = folder.split("/") temp_f = os.path.join(headphones.DESTINATION_DIR) for f in folder_list: temp_f = os.path.join(temp_f, f) os.chmod(temp_f, 0755) except Exception, e: logger.error("Could not create folder for %s. Not moving" % release["AlbumName"]) return albumpath
def test_album_metadata_with_None(self): """metadata: check handling of None metadata values""" row = _MockDatabaseRow({ 'ArtistName': 'artist', 'AlbumTitle': 'Album', 'Type': None, 'ReleaseDate': None, }) mb = _md.AlbumMetadataBuilder() f1 = _MockMediaFile('artist', None, None, None, None, None) mb.add_media_file(f1) f2 = _MockMediaFile('artist', None, None, 2, 'track2', None) mb.add_media_file(f2) md = _md.album_metadata("/music/Artist - Album [2002]", row, mb.build()) # tests don't undergo normal Headphones init, SYS_ENCODING is not set if not _h.SYS_ENCODING: _h.SYS_ENCODING = 'UTF-8' res = _hp.replace_all( "/music/$First/$Artist/$Artist - $Album{ [$Year]}", md, True) self.assertEqual(res, u"/music/A/artist/artist - Album", "check correct rendering of None via replace_all()")
def initialize(): with INIT_LOCK: global __INITIALIZED__, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, SYS_PLATFORM, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, \ HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, HTTP_PROXY, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, GIT_USER, GIT_BRANCH, \ CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, \ LOSSLESS_DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, \ RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, FILE_UNDERSCORES, CLEANUP_FILES, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, KEEP_TORRENT_FILES, \ ADD_ALBUM_ART, ALBUM_ART_FORMAT, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \ TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, PIRATEBAY, PIRATEBAY_PROXY_URL, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, \ RUTRACKER, RUTRACKER_USER, RUTRACKER_PASSWORD, WHATCD, WHATCD_USERNAME, WHATCD_PASSWORD, DOWNLOAD_TORRENT_DIR, \ LIBRARYSCAN, LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \ NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_HOST, HEADPHONES_INDEXER, NZBMATRIX, TRANSMISSION_HOST, TRANSMISSION_USERNAME, TRANSMISSION_PASSWORD, \ UTORRENT_HOST, UTORRENT_USERNAME, UTORRENT_PASSWORD, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, EXTRA_NEWZNABS, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NZBSRUS, NZBSRUS_UID, NZBSRUS_APIKEY, OMGWTFNZBS, OMGWTFNZBS_UID, OMGWTFNZBS_APIKEY, \ NZB_DOWNLOADER, TORRENT_DOWNLOADER, PREFERRED_WORDS, REQUIRED_WORDS, IGNORED_WORDS, LASTFM_USERNAME, \ INTERFACE, FOLDER_PERMISSIONS, FILE_PERMISSIONS, ENCODERFOLDER, ENCODER_PATH, ENCODER, XLDPROFILE, BITRATE, SAMPLINGFREQUENCY, \ MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, ENCODERLOSSLESS, DELETE_LOSSLESS_FILES, \ PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, PUSHOVER_ENABLED, PUSHOVER_PRIORITY, PUSHOVER_KEYS, PUSHOVER_ONSNATCH, MIRRORLIST, \ MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \ XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \ PREFERRED_BITRATE_LOW_BUFFER, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB, JOURNAL_MODE, UMASK, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY if __INITIALIZED__: return False # Make sure all the config sections exist CheckSection('General') CheckSection('SABnzbd') CheckSection('NZBget') CheckSection('Transmission') CheckSection('uTorrent') CheckSection('Headphones') CheckSection('Newznab') CheckSection('NZBsorg') CheckSection('NZBsRus') CheckSection('omgwtfnzbs') CheckSection('Waffles') CheckSection('Rutracker') CheckSection('What.cd') CheckSection('Prowl') CheckSection('Pushover') CheckSection('XBMC') CheckSection('NMA') CheckSection('Synoindex') CheckSection('Advanced') # Set global variables based on config file or use defaults CONFIG_VERSION = check_setting_str(CFG, 'General', 'config_version', '0') try: HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8181) except: HTTP_PORT = 8181 if HTTP_PORT < 21 or HTTP_PORT > 65535: HTTP_PORT = 8181 HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0') HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '') HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '') HTTP_ROOT = check_setting_str(CFG, 'General', 'http_root', '/') HTTP_PROXY = bool(check_setting_int(CFG, 'General', 'http_proxy', 0)) ENABLE_HTTPS = bool(check_setting_int(CFG, 'General', 'enable_https', 0)) HTTPS_CERT = check_setting_str(CFG, 'General', 'https_cert', os.path.join(DATA_DIR, 'server.crt')) HTTPS_KEY = check_setting_str(CFG, 'General', 'https_key', os.path.join(DATA_DIR, 'server.key')) LAUNCH_BROWSER = bool(check_setting_int(CFG, 'General', 'launch_browser', 1)) API_ENABLED = bool(check_setting_int(CFG, 'General', 'api_enabled', 0)) API_KEY = check_setting_str(CFG, 'General', 'api_key', '') GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '') GIT_USER = check_setting_str(CFG, 'General', 'git_user', 'rembo10') GIT_BRANCH = check_setting_str(CFG, 'General', 'git_branch', 'master') LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', '') CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', '') CHECK_GITHUB = bool(check_setting_int(CFG, 'General', 'check_github', 1)) CHECK_GITHUB_ON_STARTUP = bool(check_setting_int(CFG, 'General', 'check_github_on_startup', 1)) CHECK_GITHUB_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360) MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '') DESTINATION_DIR = check_setting_str(CFG, 'General', 'destination_dir', '') LOSSLESS_DESTINATION_DIR = check_setting_str(CFG, 'General', 'lossless_destination_dir', '') PREFERRED_QUALITY = check_setting_int(CFG, 'General', 'preferred_quality', 0) PREFERRED_BITRATE = check_setting_str(CFG, 'General', 'preferred_bitrate', '') PREFERRED_BITRATE_HIGH_BUFFER = check_setting_int(CFG, 'General', 'preferred_bitrate_high_buffer', '') PREFERRED_BITRATE_LOW_BUFFER = check_setting_int(CFG, 'General', 'preferred_bitrate_low_buffer', '') PREFERRED_BITRATE_ALLOW_LOSSLESS = bool(check_setting_int(CFG, 'General', 'preferred_bitrate_allow_lossless', 0)) DETECT_BITRATE = bool(check_setting_int(CFG, 'General', 'detect_bitrate', 0)) ADD_ARTISTS = bool(check_setting_int(CFG, 'General', 'auto_add_artists', 1)) CORRECT_METADATA = bool(check_setting_int(CFG, 'General', 'correct_metadata', 0)) MOVE_FILES = bool(check_setting_int(CFG, 'General', 'move_files', 0)) RENAME_FILES = bool(check_setting_int(CFG, 'General', 'rename_files', 0)) FOLDER_FORMAT = check_setting_str(CFG, 'General', 'folder_format', 'Artist/Album [Year]') FILE_FORMAT = check_setting_str(CFG, 'General', 'file_format', 'Track Artist - Album [Year] - Title') FILE_UNDERSCORES = bool(check_setting_int(CFG, 'General', 'file_underscores', 0)) CLEANUP_FILES = bool(check_setting_int(CFG, 'General', 'cleanup_files', 0)) ADD_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'add_album_art', 0)) ALBUM_ART_FORMAT = check_setting_str(CFG, 'General', 'album_art_format', 'folder') EMBED_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'embed_album_art', 0)) EMBED_LYRICS = bool(check_setting_int(CFG, 'General', 'embed_lyrics', 0)) NZB_DOWNLOADER = check_setting_int(CFG, 'General', 'nzb_downloader', 0) TORRENT_DOWNLOADER = check_setting_int(CFG, 'General', 'torrent_downloader', 0) DOWNLOAD_DIR = check_setting_str(CFG, 'General', 'download_dir', '') BLACKHOLE = bool(check_setting_int(CFG, 'General', 'blackhole', 0)) BLACKHOLE_DIR = check_setting_str(CFG, 'General', 'blackhole_dir', '') USENET_RETENTION = check_setting_int(CFG, 'General', 'usenet_retention', '1500') INCLUDE_EXTRAS = bool(check_setting_int(CFG, 'General', 'include_extras', 0)) EXTRAS = check_setting_str(CFG, 'General', 'extras', '') AUTOWANT_UPCOMING = bool(check_setting_int(CFG, 'General', 'autowant_upcoming', 1)) AUTOWANT_ALL = bool(check_setting_int(CFG, 'General', 'autowant_all', 0)) KEEP_TORRENT_FILES = bool(check_setting_int(CFG, 'General', 'keep_torrent_files', 0)) SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 1440) LIBRARYSCAN = bool(check_setting_int(CFG, 'General', 'libraryscan', 1)) LIBRARYSCAN_INTERVAL = check_setting_int(CFG, 'General', 'libraryscan_interval', 300) DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, 'General', 'download_scan_interval', 5) TORRENTBLACKHOLE_DIR = check_setting_str(CFG, 'General', 'torrentblackhole_dir', '') NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10') ISOHUNT = bool(check_setting_int(CFG, 'General', 'isohunt', 0)) KAT = bool(check_setting_int(CFG, 'General', 'kat', 0)) PIRATEBAY = bool(check_setting_int(CFG, 'General', 'piratebay', 0)) PIRATEBAY_PROXY_URL = check_setting_str(CFG, 'General', 'piratebay_proxy_url', '') MININOVA = bool(check_setting_int(CFG, 'General', 'mininova', 0)) DOWNLOAD_TORRENT_DIR = check_setting_str(CFG, 'General', 'download_torrent_dir', '') WAFFLES = bool(check_setting_int(CFG, 'Waffles', 'waffles', 0)) WAFFLES_UID = check_setting_str(CFG, 'Waffles', 'waffles_uid', '') WAFFLES_PASSKEY = check_setting_str(CFG, 'Waffles', 'waffles_passkey', '') RUTRACKER = bool(check_setting_int(CFG, 'Rutracker', 'rutracker', 0)) RUTRACKER_USER = check_setting_str(CFG, 'Rutracker', 'rutracker_user', '') RUTRACKER_PASSWORD = check_setting_str(CFG, 'Rutracker', 'rutracker_password', '') WHATCD = bool(check_setting_int(CFG, 'What.cd', 'whatcd', 0)) WHATCD_USERNAME = check_setting_str(CFG, 'What.cd', 'whatcd_username', '') WHATCD_PASSWORD = check_setting_str(CFG, 'What.cd', 'whatcd_password', '') SAB_HOST = check_setting_str(CFG, 'SABnzbd', 'sab_host', '') SAB_USERNAME = check_setting_str(CFG, 'SABnzbd', 'sab_username', '') SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '') SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '') SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', '') NZBGET_USERNAME = check_setting_str(CFG, 'NZBget', 'nzbget_username', 'nzbget') NZBGET_PASSWORD = check_setting_str(CFG, 'NZBget', 'nzbget_password', '') NZBGET_CATEGORY = check_setting_str(CFG, 'NZBget', 'nzbget_category', '') NZBGET_HOST = check_setting_str(CFG, 'NZBget', 'nzbget_host', '') HEADPHONES_INDEXER = bool(check_setting_int(CFG, 'Headphones', 'headphones_indexer', 0)) TRANSMISSION_HOST = check_setting_str(CFG, 'Transmission', 'transmission_host', '') TRANSMISSION_USERNAME = check_setting_str(CFG, 'Transmission', 'transmission_username', '') TRANSMISSION_PASSWORD = check_setting_str(CFG, 'Transmission', 'transmission_password', '') UTORRENT_HOST = check_setting_str(CFG, 'uTorrent', 'utorrent_host', '') UTORRENT_USERNAME = check_setting_str(CFG, 'uTorrent', 'utorrent_username', '') UTORRENT_PASSWORD = check_setting_str(CFG, 'uTorrent', 'utorrent_password', '') NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0)) NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '') NEWZNAB_ENABLED = bool(check_setting_int(CFG, 'Newznab', 'newznab_enabled', 1)) # Need to pack the extra newznabs back into a list of tuples flattened_newznabs = check_setting_str(CFG, 'Newznab', 'extra_newznabs', [], log=False) EXTRA_NEWZNABS = list(itertools.izip(*[itertools.islice(flattened_newznabs, i, None, 3) for i in range(3)])) NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0)) NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') NZBSORG_HASH = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_hash', '') NZBSRUS = bool(check_setting_int(CFG, 'NZBsRus', 'nzbsrus', 0)) NZBSRUS_UID = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_uid', '') NZBSRUS_APIKEY = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_apikey', '') OMGWTFNZBS = bool(check_setting_int(CFG, 'omgwtfnzbs', 'omgwtfnzbs', 0)) OMGWTFNZBS_UID = check_setting_str(CFG, 'omgwtfnzbs', 'omgwtfnzbs_uid', '') OMGWTFNZBS_APIKEY = check_setting_str(CFG, 'omgwtfnzbs', 'omgwtfnzbs_apikey', '') PREFERRED_WORDS = check_setting_str(CFG, 'General', 'preferred_words', '') IGNORED_WORDS = check_setting_str(CFG, 'General', 'ignored_words', '') REQUIRED_WORDS = check_setting_str(CFG, 'General', 'required_words', '') LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '') INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default') FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755') FILE_PERMISSIONS = check_setting_str(CFG, 'General', 'file_permissions', '0644') ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '') ENCODER_PATH = check_setting_str(CFG, 'General', 'encoder_path', '') ENCODER = check_setting_str(CFG, 'General', 'encoder', 'ffmpeg') XLDPROFILE = check_setting_str(CFG, 'General', 'xldprofile', '') BITRATE = check_setting_int(CFG, 'General', 'bitrate', 192) SAMPLINGFREQUENCY= check_setting_int(CFG, 'General', 'samplingfrequency', 44100) MUSIC_ENCODER = bool(check_setting_int(CFG, 'General', 'music_encoder', 0)) ADVANCEDENCODER = check_setting_str(CFG, 'General', 'advancedencoder', '') ENCODEROUTPUTFORMAT = check_setting_str(CFG, 'General', 'encoderoutputformat', 'mp3') ENCODERQUALITY = check_setting_int(CFG, 'General', 'encoderquality', 2) ENCODERVBRCBR = check_setting_str(CFG, 'General', 'encodervbrcbr', 'cbr') ENCODERLOSSLESS = bool(check_setting_int(CFG, 'General', 'encoderlossless', 1)) DELETE_LOSSLESS_FILES = bool(check_setting_int(CFG, 'General', 'delete_lossless_files', 1)) PROWL_ENABLED = bool(check_setting_int(CFG, 'Prowl', 'prowl_enabled', 0)) PROWL_KEYS = check_setting_str(CFG, 'Prowl', 'prowl_keys', '') PROWL_ONSNATCH = bool(check_setting_int(CFG, 'Prowl', 'prowl_onsnatch', 0)) PROWL_PRIORITY = check_setting_int(CFG, 'Prowl', 'prowl_priority', 0) XBMC_ENABLED = bool(check_setting_int(CFG, 'XBMC', 'xbmc_enabled', 0)) XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '') XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '') XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '') XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0)) XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0)) NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0)) NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '') NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0) NMA_ONSNATCH = bool(check_setting_int(CFG, 'NMA', 'nma_onsnatch', 0)) SYNOINDEX_ENABLED = bool(check_setting_int(CFG, 'Synoindex', 'synoindex_enabled', 0)) PUSHOVER_ENABLED = bool(check_setting_int(CFG, 'Pushover', 'pushover_enabled', 0)) PUSHOVER_KEYS = check_setting_str(CFG, 'Pushover', 'pushover_keys', '') PUSHOVER_ONSNATCH = bool(check_setting_int(CFG, 'Pushover', 'pushover_onsnatch', 0)) PUSHOVER_PRIORITY = check_setting_int(CFG, 'Pushover', 'pushover_priority', 0) MIRROR = check_setting_str(CFG, 'General', 'mirror', 'musicbrainz.org') CUSTOMHOST = check_setting_str(CFG, 'General', 'customhost', 'localhost') CUSTOMPORT = check_setting_int(CFG, 'General', 'customport', 5000) CUSTOMSLEEP = check_setting_int(CFG, 'General', 'customsleep', 1) HPUSER = check_setting_str(CFG, 'General', 'hpuser', '') HPPASS = check_setting_str(CFG, 'General', 'hppass', '') CACHE_SIZEMB = check_setting_int(CFG,'Advanced','cache_sizemb',32) JOURNAL_MODE = check_setting_int(CFG,'Advanced', 'journal_mode', 'wal') ALBUM_COMPLETION_PCT = check_setting_int(CFG, 'Advanced', 'album_completion_pct', 80) # update folder formats in the config & bump up config version if CONFIG_VERSION == '0': from headphones.helpers import replace_all file_values = { 'tracknumber': 'Track', 'title': 'Title','artist' : 'Artist', 'album' : 'Album', 'year' : 'Year' } folder_values = { 'artist' : 'Artist', 'album':'Album', 'year' : 'Year', 'releasetype' : 'Type', 'first' : 'First', 'lowerfirst' : 'first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '1' if CONFIG_VERSION == '1': from headphones.helpers import replace_all file_values = { 'Track': '$Track', 'Title': '$Title', 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'track': '$track', 'title': '$title', 'artist': '$artist', 'album': '$album', 'year': '$year' } folder_values = { 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'Type': '$Type', 'First': '$First', 'artist': '$artist', 'album': '$album', 'year': '$year', 'type': '$type', 'first': '$first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '2' if CONFIG_VERSION == '2': # Update the config to use direct path to the encoder rather than the encoder folder if ENCODERFOLDER: ENCODER_PATH = os.path.join(ENCODERFOLDER, ENCODER) CONFIG_VERSION = '3' if CONFIG_VERSION == '3': #Update the BLACKHOLE option to the NZB_DOWNLOADER format if BLACKHOLE: NZB_DOWNLOADER = 2 CONFIG_VERSION = '4' # Enable Headphones Indexer if they have a VIP account if CONFIG_VERSION == '4': if HPUSER and HPPASS: HEADPHONES_INDEXER = True CONFIG_VERSION = '5' if not LOG_DIR: LOG_DIR = os.path.join(DATA_DIR, 'logs') if not os.path.exists(LOG_DIR): try: os.makedirs(LOG_DIR) except OSError: if VERBOSE: print 'Unable to create the log directory. Logging to screen only.' # Start the logger, silence console logging if we need to logger.headphones_log.initLogger(verbose=VERBOSE) if not CACHE_DIR: # Put the cache dir in the data dir for now CACHE_DIR = os.path.join(DATA_DIR, 'cache') if not os.path.exists(CACHE_DIR): try: os.makedirs(CACHE_DIR) except OSError: logger.error('Could not create cache dir. Check permissions of datadir: ' + DATA_DIR) # Sanity check for search interval. Set it to at least 6 hours if SEARCH_INTERVAL < 360: logger.info("Search interval too low. Resetting to 6 hour minimum") SEARCH_INTERVAL = 360 # Initialize the database logger.info('Checking to see if the database has all tables....') try: dbcheck() except Exception, e: logger.error("Can't connect to the database: %s" % e) # Get the currently installed version - returns None, 'win32' or the git hash # Also sets INSTALL_TYPE variable to 'win', 'git' or 'source' CURRENT_VERSION = versioncheck.getVersion() # Check for new versions if CHECK_GITHUB_ON_STARTUP: try: LATEST_VERSION = versioncheck.checkGithub() except: LATEST_VERSION = CURRENT_VERSION else: LATEST_VERSION = CURRENT_VERSION # Store the original umask UMASK = os.umask(0) os.umask(UMASK) __INITIALIZED__ = True return True
def renameFiles(albumpath, downloaded_track_list, release): logger.info('Renaming files') try: year = release['ReleaseDate'][:4] except TypeError: year = '' # Until tagging works better I'm going to rely on the already provided metadata for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.info("MediaFile couldn't parse: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) continue if not f.disc: discnumber = '' else: discnumber = '%d' % f.disc if not f.track: tracknumber = '' else: tracknumber = '%02d' % f.track if not f.title: basename = os.path.basename(downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) title = os.path.splitext(basename)[0] ext = os.path.splitext(basename)[1] new_file_name = helpers.cleanTitle(title) + ext else: title = f.title if release['ArtistName'] == "Various Artists" and f.artist: artistname = f.artist else: artistname = release['ArtistName'] if artistname.startswith('The '): sortname = artistname[4:] + ", The" else: sortname = artistname values = { '$Disc': discnumber, '$Track': tracknumber, '$Title': title, '$Artist': artistname, '$SortArtist': sortname, '$Album': release['AlbumTitle'], '$Year': year, '$disc': discnumber, '$track': tracknumber, '$title': title.lower(), '$artist': artistname.lower(), '$sortartist': sortname.lower(), '$album': release['AlbumTitle'].lower(), '$year': year } ext = os.path.splitext(downloaded_track)[1] new_file_name = helpers.replace_all(headphones.FILE_FORMAT.strip(), values).replace('/','_') + ext new_file_name = new_file_name.replace('?','_').replace(':', '_').encode(headphones.SYS_ENCODING, 'replace') if headphones.FILE_UNDERSCORES: new_file_name = new_file_name.replace(' ', '_') if new_file_name.startswith('.'): new_file_name = new_file_name.replace(0, '_') new_file = os.path.join(albumpath, new_file_name) if downloaded_track == new_file_name: logger.debug("Renaming for: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " is not neccessary") continue logger.debug('Renaming %s ---> %s' % (downloaded_track.decode(headphones.SYS_ENCODING,'replace'), new_file_name.decode(headphones.SYS_ENCODING,'replace'))) try: os.rename(downloaded_track, new_file) except Exception, e: logger.error('Error renaming file: %s. Error: %s' % (downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), e)) continue
def searchNZB(albumid=None, new=False, losslessOnly=False): myDB = db.DBConnection() if albumid: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE AlbumID=?', [albumid]) else: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE Status="Wanted" OR Status="Wanted Lossless"') new = True for albums in results: albumid = albums[2] reldate = albums[3] try: year = reldate[:4] except TypeError: year = '' dic = {'...':'', ' & ':' ', ' = ': ' ', '?':'', '$':'s', ' + ':' ', '"':'', ',':'', '*':'', '.':'', ':':''} cleanalbum = helpers.latinToAscii(helpers.replace_all(albums[1], dic)) cleanartist = helpers.latinToAscii(helpers.replace_all(albums[0], dic)) # FLAC usually doesn't have a year for some reason so I'll leave it out # Various Artist albums might be listed as VA, so I'll leave that out too # Only use the year if the term could return a bunch of different albums, i.e. self-titled albums if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4: term = cleanartist + ' ' + cleanalbum + ' ' + year elif albums[0] == 'Various Artists': term = cleanalbum + ' ' + year else: term = cleanartist + ' ' + cleanalbum # Replace bad characters in the term and unicode it term = re.sub('[\.\-\/]', ' ', term).encode('utf-8') artistterm = re.sub('[\.\-\/]', ' ', cleanartist).encode('utf-8') logger.info("Searching for %s since it was marked as wanted" % term) resultlist = [] if headphones.NZBMATRIX: provider = "nzbmatrix" if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "23" maxsize = 10000000000 elif headphones.PREFERRED_QUALITY: categories = "23,22" maxsize = 2000000000 else: categories = "22" maxsize = 300000000 # For some reason NZBMatrix is erroring out/timing out when the term starts with a "The" right now # so we'll strip it out for the time being. This may get fixed on their end, it may not, but # hopefully this will fix it for now. If you notice anything else it gets stuck on, please post it # on Github so it can be added if term.lower().startswith("the "): term = term[4:] params = { "page": "download", "username": headphones.NZBMATRIX_USERNAME, "apikey": headphones.NZBMATRIX_APIKEY, "subcat": categories, "maxage": headphones.USENET_RETENTION, "english": 1, "ssl": 1, "scenename": 1, "term": term } searchURL = "http://rss.nzbmatrix.com/rss.php?" + urllib.urlencode(params) logger.info(u'Parsing results from <a href="%s">NZBMatrix</a>' % searchURL) try: data = urllib2.urlopen(searchURL, timeout=20).read() except urllib2.URLError, e: logger.warn('Error fetching data from NZBMatrix: %s' % e) data = False if data: d = feedparser.parse(data) for item in d.entries: try: url = item.link title = item.title size = int(item.links[1]['length']) if size < maxsize: resultlist.append((title, size, url, provider)) logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) else: logger.info('%s is larger than the maxsize for this category, skipping. (Size: %i bytes)' % (title, size)) except AttributeError, e: logger.info(u"No results found from NZBMatrix for %s" % term)
def renameFiles(albumpath, downloaded_track_list, release): logger.info("Renaming files") try: year = release["ReleaseDate"][:4] except TypeError: year = "" # Until tagging works better I'm going to rely on the already provided metadata for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.info("MediaFile couldn't parse: " + downloaded_track.decode(headphones.SYS_ENCODING, "replace")) continue if not f.track: tracknumber = "" else: tracknumber = "%02d" % f.track if not f.title: basename = os.path.basename(downloaded_track.decode(headphones.SYS_ENCODING, "replace")) title = os.path.splitext(basename)[0] ext = os.path.splitext(basename)[1] new_file_name = helpers.cleanTitle(title) + ext else: title = f.title values = { "$Track": tracknumber, "$Title": title, "$Artist": release["ArtistName"], "$Album": release["AlbumTitle"], "$Year": year, "$track": tracknumber, "$title": title.lower(), "$artist": release["ArtistName"].lower(), "$album": release["AlbumTitle"].lower(), "$year": year, } ext = os.path.splitext(downloaded_track)[1] new_file_name = helpers.replace_all(headphones.FILE_FORMAT.strip(), values).replace("/", "_") + ext new_file_name = new_file_name.replace("?", "_").replace(":", "_").encode(headphones.SYS_ENCODING, "replace") if new_file_name.startswith("."): new_file_name = new_file_name.replace(0, "_") new_file = os.path.join(albumpath, new_file_name) if downloaded_track == new_file_name: logger.debug( "Renaming for: " + downloaded_track.decode(headphones.SYS_ENCODING, "replace") + " is not neccessary" ) continue logger.debug( "Renaming %s ---> %s" % ( downloaded_track.decode(headphones.SYS_ENCODING, "replace"), new_file_name.decode(headphones.SYS_ENCODING, "replace"), ) ) try: os.rename(downloaded_track, new_file) except Exception, e: logger.error( "Error renaming file: %s. Error: %s" % (downloaded_track.decode(headphones.SYS_ENCODING, "replace"), e) ) continue
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:] + ", The" else: sortname = release['ArtistName'] if sortname[0].isdigit(): firstchar = '0-9' else: firstchar = sortname[0] values = { '$Artist': artist, '$SortArtist': sortname, '$Album': album, '$Year': year, '$Type': releasetype, '$First': firstchar.upper(), '$artist': artist.lower(), '$sortartist': sortname.lower(), '$album': album.lower(), '$year': year, '$type': releasetype.lower(), '$first': firstchar.lower() } folder = helpers.replace_all(headphones.FOLDER_FORMAT.strip(), values) folder = folder.replace('./', '_/').replace(':', '_').replace( '?', '_').replace('/.', '/_').replace('<', '_').replace('>', '_') if folder.endswith('.'): folder = folder.replace(folder[len(folder) - 1], '_') if folder.startswith('.'): folder = folder.replace(0, '_') # Grab our list of files early on so we can determine if we need to create # the lossy_dest_dir, lossless_dest_dir, or both files_to_move = [] lossy_media = False lossless_media = False for r, d, f in os.walk(albumpath): for files in f: files_to_move.append(os.path.join(r, files)) if any(files.lower().endswith('.' + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS): lossy_media = True if any(files.lower().endswith('.' + x.lower()) for x in headphones.LOSSLESS_MEDIA_FORMATS): lossless_media = True # Do some sanity checking to see what directories we need to create: make_lossy_folder = False make_lossless_folder = False lossy_destination_path = os.path.normpath( os.path.join(headphones.DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING, 'replace') lossless_destination_path = os.path.normpath( os.path.join(headphones.LOSSLESS_DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING, 'replace') # If they set a destination dir for lossless media, only create the lossy folder if there is lossy media if headphones.LOSSLESS_DESTINATION_DIR: if lossy_media: make_lossy_folder = True if lossless_media: make_lossless_folder = True # If they haven't set a lossless dest_dir, just create the "lossy" folder else: make_lossy_folder = True last_folder = headphones.FOLDER_FORMAT.strip().split('/')[-1] if make_lossless_folder: # Only rename the folder if they use the album name, otherwise merge into existing folder if os.path.exists( lossless_destination_path) and 'album' in last_folder.lower(): temp_folder = folder i = 1 while True: newfolder = temp_folder + '[%i]' % i lossless_destination_path = os.path.normpath( os.path.join(headphones.LOSSLESS_DESTINATION_DIR, newfolder)).encode(headphones.SYS_ENCODING, 'replace') if os.path.exists(lossless_destination_path): i += 1 else: temp_folder = newfolder break if not os.path.exists(lossless_destination_path): try: os.makedirs(lossless_destination_path) except Exception, e: logger.error( 'Could not create lossless folder for %s. (Error: %s)' % (release['AlbumTitle'], e)) if not make_lossy_folder: return [albumpath]
def update(artistid, artist_name, release_groups): """ Pretty simple and crude function to find the artist page on metacritic, then parse that page to get critic & user scores for albums""" # First let's modify the artist name to fit the metacritic convention. # We could just do a search, then take the top result, but at least this will # cut down on api calls. If it's ineffective then we'll switch to search replacements = {" & ": " ", ".": ""} mc_artist_name = helpers.replace_all(artist_name.lower(), replacements) mc_artist_name = mc_artist_name.replace(" ", "-") headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2243.2 Safari/537.36' } url = "http://www.metacritic.com/person/" + mc_artist_name + "?filter-options=music&sort_options=date&num_items=100" res = request.request_soup(url, headers=headers) rows = None try: table = res.find("table", class_="credits person_credits") rows = table.tbody.find_all('tr') except: logger.info("Unable to get metacritic scores for: %s" % artist_name) myDB = db.DBConnection() artist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [artistid]).fetchone() score_list = [] # If we couldn't get anything from MetaCritic for whatever reason, # let's try to load scores from the db if not rows: if artist['MetaCritic']: score_list = json.loads(artist['MetaCritic']) else: return # If we did get scores, let's update the db with them else: for row in rows: title = row.a.string scores = row.find_all("span") critic_score = scores[0].string user_score = scores[1].string score_dict = { 'title': title, 'critic_score': critic_score, 'user_score': user_score } score_list.append(score_dict) # Save scores to the database controlValueDict = {"ArtistID": artistid} newValueDict = {'MetaCritic': json.dumps(score_list)} myDB.upsert("artists", newValueDict, controlValueDict) for score in score_list: title = score['title'] # Iterate through the release groups we got passed to see if we can find # a match for rg in release_groups: if rg['title'].lower() == title.lower(): critic_score = score['critic_score'] user_score = score['user_score'] controlValueDict = {"AlbumID": rg['id']} newValueDict = { 'CriticScore': critic_score, 'UserScore': user_score } myDB.upsert("albums", newValueDict, controlValueDict)
def update(artistid, artist_name,release_groups): """ Pretty simple and crude function to find the artist page on metacritic, then parse that page to get critic & user scores for albums""" # First let's modify the artist name to fit the metacritic convention. # We could just do a search, then take the top result, but at least this will # cut down on api calls. If it's ineffective then we'll switch to search replacements = {" & " : " ", "." : ""} mc_artist_name = helpers.replace_all(artist_name.lower(),replacements) mc_artist_name = mc_artist_name.replace(" ","-") headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2243.2 Safari/537.36'} url = "http://www.metacritic.com/person/" + mc_artist_name + "?filter-options=music&sort_options=date&num_items=100" res = request.request_soup(url, headers=headers, parser='html.parser') rows = None try: rows = res.tbody.find_all('tr') except: logger.info("Unable to get metacritic scores for: %s" % artist_name) myDB = db.DBConnection() artist = myDB.action('SELECT * FROM artists WHERE ArtistID=?', [artistid]).fetchone() score_list = [] # If we couldn't get anything from MetaCritic for whatever reason, # let's try to load scores from the db if not rows: if artist['MetaCritic']: score_list = json.loads(artist['MetaCritic']) else: return # If we did get scores, let's update the db with them else: for row in rows: title = row.a.string scores = row.find_all("span") critic_score = scores[0].string user_score = scores[1].string score_dict = {'title':title,'critic_score':critic_score,'user_score':user_score} score_list.append(score_dict) # Save scores to the database controlValueDict = {"ArtistID": artistid} newValueDict = {'MetaCritic':json.dumps(score_list)} myDB.upsert("artists", newValueDict, controlValueDict) for score in score_list: title = score['title'] # Iterate through the release groups we got passed to see if we can find # a match for rg in release_groups: if rg['title'].lower() == title.lower(): critic_score = score['critic_score'] user_score = score['user_score'] controlValueDict = {"AlbumID": rg['id']} newValueDict = {'CriticScore':critic_score,'UserScore':user_score} myDB.upsert("albums", newValueDict, controlValueDict)
def moveFiles(albumpath, release, tracks): try: year = release['ReleaseDate'][:4] except TypeError: year = '' artist = release['ArtistName'].replace('/', '_') album = release['AlbumTitle'].replace('/', '_') if release['ArtistName'].startswith('The '): sortname = release['ArtistName'][4:] else: sortname = release['ArtistName'] if sortname.isdigit(): firstchar = '0-9' else: firstchar = sortname[0] values = { 'artist': artist, 'album': album, 'year': year, 'first': firstchar, } 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)) if os.path.exists(destination_path): i = 1 while True: new_folder_name = destination_path + '[%i]' % i if os.path.exists(new_folder_name): i += 1 else: destination_path = new_folder_name break logger.info('Moving files from %s to %s' % (albumpath, destination_path)) try: os.makedirs(destination_path) # Chmod the directories using the folder_format (script courtesy of premiso!) folder_list = folder.split('/') temp_f = os.path.join(headphones.DESTINATION_DIR); for f in folder_list: temp_f = os.path.join(temp_f, f) os.chmod(temp_f, int(headphones.FOLDER_PERMISSIONS, 8)) except Exception, e: logger.error('Could not create folder for %s. Not moving: %s' % (release['AlbumTitle'], e)) return albumpath
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] values = { '$Artist': artist, '$Album': album, '$Year': year, '$Type': releasetype, '$First': firstchar, '$artist': artist.lower(), '$album': album.lower(), '$year': year, '$type': releasetype.lower(), '$first': firstchar.lower() } folder = helpers.replace_all(headphones.FOLDER_FORMAT, values) folder = folder.replace('./', '_/').replace(':','_').replace('?','_').replace('/.','/_') if folder.endswith('.'): folder = folder.replace(folder[len(folder)-1], '_') if folder.startswith('.'): folder = folder.replace(0, '_') destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING) last_folder = headphones.FOLDER_FORMAT.split('/')[-1] # Only rename the folder if they use the album name, otherwise merge into existing folder if os.path.exists(destination_path) and 'album' in last_folder.lower(): 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"))) # Basically check if generic/non-album folders already exist, since we're going to merge if not os.path.exists(destination_path): 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 getReleaseGroup(rgid): """ Returns a dictionary of the best stuff from a release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True, artist=True) releaseGroup = None attempt = 0 while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve information from MusicBrainz for release group "%s" failed. Sleeping 5 seconds' % rgid) attempt += 1 time.sleep(5) if not releaseGroup: return False time.sleep(1) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) releaseResult = None attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve release information for %s from MusicBrainz failed: %s. Sleeping 5 seconds' % (releaseResult.title, e)) attempt += 1 time.sleep(5) if not releaseResult: continue # Release filter for non-official live albums types = releaseResult.getTypes() if any('Live' in type for type in types): if not any('Official' in type for type in types): logger.debug('%s is not an official live album. Skipping' % releaseResult.name) continue time.sleep(1) formats = { '2xVinyl': '2', 'Vinyl': '2', 'CD': '0', 'Cassette': '3', '2xCD': '1', 'Digital Media': '0' } country = { 'US': '0', 'GB': '1', 'JP': '2', } try: format = int( replace_all( u.extractFragment( releaseResult.releaseEvents[0].format), formats)) except: format = 3 try: country = int( replace_all(releaseResult.releaseEvents[0].country, country)) except: country = 3 release_dict = { 'hasasin': bool(releaseResult.asin), 'asin': releaseResult.asin, 'trackscount': len(releaseResult.getTracks()), 'releaseid': u.extractUuid(releaseResult.id), 'releasedate': releaseResult.getEarliestReleaseDate(), 'format': format, 'country': country } tracks = [] i = 1 for track in releaseResult.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release_dict['tracks'] = tracks releaselist.append(release_dict)
def libraryScan(dir=None): if not dir: dir = headphones.MUSIC_DIR try: dir = str(dir) except UnicodeEncodeError: dir = unicode(dir).encode('unicode_escape') if not os.path.isdir(dir): logger.warn('Cannot find directory: %s. Not scanning' % dir) return myDB = db.DBConnection() # Clean up bad filepaths tracks = myDB.select('SELECT Location, TrackID from tracks WHERE Location IS NOT NULL') for track in tracks: if not os.path.isfile(track['Location'].encode(headphones.SYS_ENCODING)): myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [None, None, None, track['TrackID']]) logger.info('Scanning music directory: %s' % dir) new_artists = [] bitrates = [] myDB.action('DELETE from have') for r,d,f in os.walk(dir): for files in f: # MEDIA_FORMATS = music file extensions, e.g. mp3, flac, etc if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS): song = os.path.join(r, files) file = unicode(os.path.join(r, files), headphones.SYS_ENCODING, errors='replace') # Try to read the metadata try: f = MediaFile(song) except: logger.error('Cannot read file: ' + file) continue # Grab the bitrates for the auto detect bit rate option if f.bitrate: bitrates.append(f.bitrate) # Try to find a match based on artist/album/tracktitle if f.albumartist: f_artist = f.albumartist elif f.artist: f_artist = f.artist else: continue if f_artist and f.album and f.title: track = myDB.action('SELECT TrackID from tracks WHERE CleanName LIKE ?', [helpers.cleanName(f_artist +' '+f.album+' '+f.title)]).fetchone() if not track: track = myDB.action('SELECT TrackID from tracks WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [f_artist, f.album, f.title]).fetchone() if track: myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']]) continue # Try to match on mbid if available and we couldn't find a match based on metadata if f.mb_trackid: # Wondering if theres a better way to do this -> do one thing if the row exists, # do something else if it doesn't track = myDB.action('SELECT TrackID from tracks WHERE TrackID=?', [f.mb_trackid]).fetchone() if track: myDB.action('UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']]) continue # if we can't find a match in the database on a track level, it might be a new artist or it might be on a non-mb release new_artists.append(f_artist) # The have table will become the new database for unmatched tracks (i.e. tracks with no associated links in the database myDB.action('INSERT INTO have (ArtistName, AlbumTitle, TrackNumber, TrackTitle, TrackLength, BitRate, Genre, Date, TrackID, Location, CleanName, Format) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [f_artist, f.album, f.track, f.title, f.length, f.bitrate, f.genre, f.date, f.mb_trackid, file, helpers.cleanName(f_artist+' '+f.album+' '+f.title), f.format]) logger.info('Completed scanning of directory: %s' % dir) logger.info('Checking filepaths to see if we can find any matches') # Now check empty file paths to see if we can find a match based on their folder format tracks = myDB.select('SELECT * from tracks WHERE Location IS NULL') for track in tracks: release = myDB.action('SELECT * from albums WHERE AlbumID=?', [track['AlbumID']]).fetchone() try: year = release['ReleaseDate'][:4] except TypeError: year = '' artist = release['ArtistName'].replace('/', '_') album = release['AlbumTitle'].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() albumvalues = { 'artist': artist, 'album': album, 'year': year, 'first': firstchar, 'lowerfirst': lowerfirst } folder = helpers.replace_all(headphones.FOLDER_FORMAT, albumvalues) folder = folder.replace('./', '_/').replace(':','_').replace('?','_') if folder.endswith('.'): folder = folder.replace(folder[len(folder)-1], '_') if not track['TrackNumber']: tracknumber = '' else: tracknumber = '%02d' % track['TrackNumber'] trackvalues = { 'tracknumber': tracknumber, 'title': track['TrackTitle'], 'artist': release['ArtistName'], 'album': release['AlbumTitle'], 'year': year } new_file_name = helpers.replace_all(headphones.FILE_FORMAT, trackvalues).replace('/','_') + '.*' new_file_name = new_file_name.replace('?','_').replace(':', '_') full_path_to_file = os.path.normpath(os.path.join(headphones.MUSIC_DIR, folder, new_file_name)).encode(headphones.SYS_ENCODING, 'replace') match = glob.glob(full_path_to_file) if match: logger.info('Found a match: %s. Writing MBID to metadata' % match[0]) unipath = unicode(match[0], headphones.SYS_ENCODING, errors='replace') myDB.action('UPDATE tracks SET Location=? WHERE TrackID=?', [unipath, track['TrackID']]) myDB.action('DELETE from have WHERE Location=?', [unipath]) # Try to insert the appropriate track id so we don't have to keep doing this try: f = MediaFile(match[0]) f.mb_trackid = track['TrackID'] f.save() myDB.action('UPDATE tracks SET BitRate=?, Format=? WHERE TrackID=?', [f.bitrate, f.format, track['TrackID']]) logger.debug('Wrote mbid to track: %s' % match[0]) except: logger.error('Error embedding track id into: %s' % match[0]) continue logger.info('Done checking empty filepaths') logger.info('Done syncing library with directory: %s' % dir) # Clean up the new artist list unique_artists = {}.fromkeys(new_artists).keys() current_artists = myDB.select('SELECT ArtistName, ArtistID from artists') artist_list = [f for f in unique_artists if f.lower() not in [x[0].lower() for x in current_artists]] # Update track counts logger.info('Updating track counts') for artist in current_artists: havetracks = len(myDB.select('SELECT TrackTitle from tracks WHERE ArtistID like ? AND Location IS NOT NULL', [artist['ArtistID']])) + len(myDB.select('SELECT TrackTitle from have WHERE ArtistName like ?', [artist['ArtistName']])) myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, artist['ArtistID']]) logger.info('Found %i new artists' % len(artist_list)) if len(artist_list): if headphones.ADD_ARTISTS: logger.info('Importing %i new artists' % len(artist_list)) importer.artistlist_to_mbids(artist_list) else: logger.info('To add these artists, go to Manage->Manage New Artists') headphones.NEW_ARTISTS = artist_list if headphones.DETECT_BITRATE: headphones.PREFERRED_BITRATE = sum(bitrates)/len(bitrates)/1000
def _upgrade(self): """ Update folder formats in the config & bump up config version """ if self.CONFIG_VERSION == "0": from headphones.helpers import replace_all file_values = { "tracknumber": "Track", "title": "Title", "artist": "Artist", "album": "Album", "year": "Year", } folder_values = { "artist": "Artist", "album": "Album", "year": "Year", "releasetype": "Type", "first": "First", "lowerfirst": "first", } self.FILE_FORMAT = replace_all(self.FILE_FORMAT, file_values) self.FOLDER_FORMAT = replace_all(self.FOLDER_FORMAT, folder_values) self.CONFIG_VERSION = "1" if self.CONFIG_VERSION == "1": from headphones.helpers import replace_all file_values = { "Track": "$Track", "Title": "$Title", "Artist": "$Artist", "Album": "$Album", "Year": "$Year", "track": "$track", "title": "$title", "artist": "$artist", "album": "$album", "year": "$year", } folder_values = { "Artist": "$Artist", "Album": "$Album", "Year": "$Year", "Type": "$Type", "First": "$First", "artist": "$artist", "album": "$album", "year": "$year", "type": "$type", "first": "$first", } self.FILE_FORMAT = replace_all(self.FILE_FORMAT, file_values) self.FOLDER_FORMAT = replace_all(self.FOLDER_FORMAT, folder_values) self.CONFIG_VERSION = "2" if self.CONFIG_VERSION == "2": # Update the config to use direct path to the encoder rather than the encoder folder if self.ENCODERFOLDER: self.ENCODER_PATH = os.path.join(self.ENCODERFOLDER, self.ENCODER) self.CONFIG_VERSION = "3" if self.CONFIG_VERSION == "3": # Update the BLACKHOLE option to the NZB_DOWNLOADER format if self.BLACKHOLE: self.NZB_DOWNLOADER = 2 self.CONFIG_VERSION = "4" # Enable Headphones Indexer if they have a VIP account if self.CONFIG_VERSION == "4": if self.HPUSER and self.HPPASS: self.HEADPHONES_INDEXER = True self.CONFIG_VERSION = "5" if self.CONFIG_VERSION == "5": if self.OPEN_MAGNET_LINKS: self.MAGNET_LINKS = 2 self.CONFIG_VERSION = "5"
def searchNZB(albumid=None, new=False): myDB = db.DBConnection() if albumid: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE Status="Wanted" AND AlbumID=?', [albumid]) else: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE Status="Wanted"') new = True for albums in results: albumid = albums[2] reldate = albums[3] try: year = reldate[:4] except TypeError: year = '' dic = {'...':'', ' & ':' ', ' = ': ' ', '?':'', '$':'s', ' + ':' ', '"':'', ',':''} cleanartistalbum = helpers.latinToAscii(helpers.replace_all(albums[0]+' '+albums[1], dic)) # FLAC usually doesn't have a year for some reason so I'll leave it out: term = re.sub('[\.\-\/]', ' ', '%s' % (cleanartistalbum)).encode('utf-8') altterm = re.sub('[\.\-\/]', ' ', '%s %s' % (cleanartistalbum, year)).encode('utf-8') # Only use the year if the term could return a bunch of different albums, i.e. self-titled albums if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4: term = altterm logger.info("Searching for %s since it was marked as wanted" % term) resultlist = [] if headphones.NZBMATRIX: provider = "nzbmatrix" if headphones.PREFERRED_QUALITY == 3: categories = "23" maxsize = 10000000000 elif headphones.PREFERRED_QUALITY: categories = "23,22" maxsize = 2000000000 else: categories = "22" maxsize = 300000000 params = { "page": "download", "username": headphones.NZBMATRIX_USERNAME, "apikey": headphones.NZBMATRIX_APIKEY, "subcat": categories, "age": headphones.USENET_RETENTION, "english": 1, "ssl": 1, "scenename": 1, "term": term } searchURL = "http://rss.nzbmatrix.com/rss.php?" + urllib.urlencode(params) logger.info(u"Parsing results from "+searchURL) try: data = urllib2.urlopen(searchURL, timeout=20).read() except urllib2.URLError, e: logger.warn('Error fetching data from NZBMatrix: %s' % e) data = False if data: d = feedparser.parse(data) for item in d.entries: try: url = item.link title = item.title size = int(item.links[1]['length']) if size < maxsize: resultlist.append((title, size, url, provider)) logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) else: logger.info('%s is larger than the maxsize for this category, skipping. (Size: %i bytes)' % (title, size)) except AttributeError, e: logger.info(u"No results found from NZBMatrix for %s" % term)
def initialize(): with INIT_LOCK: global __INITIALIZED__, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, HTTP_PROXY, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, LOSSLESS_DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, ADD_ALBUM_ART, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, WHATCD, WHATCD_USERNAME, WHATCD_PASSWORD, DOWNLOAD_TORRENT_DIR, LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, EXTRA_NEWZNABS, NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, ENCODERLOSSLESS, DELETE_LOSSLESS_FILES, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, MIRRORLIST, MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, PREFERRED_BITRATE_LOW_BUFFER, CACHE_SIZEMB if __INITIALIZED__: return False # Make sure all the config sections exist CheckSection("General") CheckSection("SABnzbd") CheckSection("NZBMatrix") CheckSection("Newznab") CheckSection("NZBsorg") CheckSection("Newzbin") CheckSection("Waffles") CheckSection("What.cd") CheckSection("Prowl") CheckSection("XBMC") CheckSection("NMA") CheckSection("Synoindex") CheckSection("Advanced") # Set global variables based on config file or use defaults CONFIG_VERSION = check_setting_str(CFG, "General", "config_version", "0") try: HTTP_PORT = check_setting_int(CFG, "General", "http_port", 8181) except: HTTP_PORT = 8181 if HTTP_PORT < 21 or HTTP_PORT > 65535: HTTP_PORT = 8181 HTTP_HOST = check_setting_str(CFG, "General", "http_host", "0.0.0.0") HTTP_USERNAME = check_setting_str(CFG, "General", "http_username", "") HTTP_PASSWORD = check_setting_str(CFG, "General", "http_password", "") HTTP_ROOT = check_setting_str(CFG, "General", "http_root", "/") HTTP_PROXY = bool(check_setting_int(CFG, "General", "http_proxy", 0)) LAUNCH_BROWSER = bool(check_setting_int(CFG, "General", "launch_browser", 1)) API_ENABLED = bool(check_setting_int(CFG, "General", "api_enabled", 0)) API_KEY = check_setting_str(CFG, "General", "api_key", "") GIT_PATH = check_setting_str(CFG, "General", "git_path", "") LOG_DIR = check_setting_str(CFG, "General", "log_dir", "") CHECK_GITHUB = bool(check_setting_int(CFG, "General", "check_github", 1)) CHECK_GITHUB_ON_STARTUP = bool(check_setting_int(CFG, "General", "check_github_on_startup", 1)) CHECK_GITHUB_INTERVAL = check_setting_int(CFG, "General", "check_github_interval", 360) MUSIC_DIR = check_setting_str(CFG, "General", "music_dir", "") DESTINATION_DIR = check_setting_str(CFG, "General", "destination_dir", "") LOSSLESS_DESTINATION_DIR = check_setting_str(CFG, "General", "lossless_destination_dir", "") PREFERRED_QUALITY = check_setting_int(CFG, "General", "preferred_quality", 0) PREFERRED_BITRATE = check_setting_int(CFG, "General", "preferred_bitrate", "") PREFERRED_BITRATE_HIGH_BUFFER = check_setting_int(CFG, "General", "preferred_bitrate_high_buffer", "") PREFERRED_BITRATE_LOW_BUFFER = check_setting_int(CFG, "General", "preferred_bitrate_low_buffer", "") DETECT_BITRATE = bool(check_setting_int(CFG, "General", "detect_bitrate", 0)) ADD_ARTISTS = bool(check_setting_int(CFG, "General", "auto_add_artists", 1)) CORRECT_METADATA = bool(check_setting_int(CFG, "General", "correct_metadata", 0)) MOVE_FILES = bool(check_setting_int(CFG, "General", "move_files", 0)) RENAME_FILES = bool(check_setting_int(CFG, "General", "rename_files", 0)) FOLDER_FORMAT = check_setting_str(CFG, "General", "folder_format", "Artist/Album [Year]") FILE_FORMAT = check_setting_str(CFG, "General", "file_format", "Track Artist - Album [Year]- Title") CLEANUP_FILES = bool(check_setting_int(CFG, "General", "cleanup_files", 0)) ADD_ALBUM_ART = bool(check_setting_int(CFG, "General", "add_album_art", 0)) EMBED_ALBUM_ART = bool(check_setting_int(CFG, "General", "embed_album_art", 0)) EMBED_LYRICS = bool(check_setting_int(CFG, "General", "embed_lyrics", 0)) DOWNLOAD_DIR = check_setting_str(CFG, "General", "download_dir", "") BLACKHOLE = bool(check_setting_int(CFG, "General", "blackhole", 0)) BLACKHOLE_DIR = check_setting_str(CFG, "General", "blackhole_dir", "") USENET_RETENTION = check_setting_int(CFG, "General", "usenet_retention", "1500") INCLUDE_EXTRAS = bool(check_setting_int(CFG, "General", "include_extras", 0)) EXTRAS = check_setting_str(CFG, "General", "extras", "") AUTOWANT_UPCOMING = bool(check_setting_int(CFG, "General", "autowant_upcoming", 1)) AUTOWANT_ALL = bool(check_setting_int(CFG, "General", "autowant_all", 0)) SEARCH_INTERVAL = check_setting_int(CFG, "General", "search_interval", 360) LIBRARYSCAN_INTERVAL = check_setting_int(CFG, "General", "libraryscan_interval", 300) DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, "General", "download_scan_interval", 5) TORRENTBLACKHOLE_DIR = check_setting_str(CFG, "General", "torrentblackhole_dir", "") NUMBEROFSEEDERS = check_setting_str(CFG, "General", "numberofseeders", "10") ISOHUNT = bool(check_setting_int(CFG, "General", "isohunt", 0)) KAT = bool(check_setting_int(CFG, "General", "kat", 0)) MININOVA = bool(check_setting_int(CFG, "General", "mininova", 0)) DOWNLOAD_TORRENT_DIR = check_setting_str(CFG, "General", "download_torrent_dir", "") WAFFLES = bool(check_setting_int(CFG, "Waffles", "waffles", 0)) WAFFLES_UID = check_setting_str(CFG, "Waffles", "waffles_uid", "") WAFFLES_PASSKEY = check_setting_str(CFG, "Waffles", "waffles_passkey", "") WHATCD = bool(check_setting_int(CFG, "What.cd", "whatcd", 0)) WHATCD_USERNAME = check_setting_str(CFG, "What.cd", "whatcd_username", "") WHATCD_PASSWORD = check_setting_str(CFG, "What.cd", "whatcd_password", "") SAB_HOST = check_setting_str(CFG, "SABnzbd", "sab_host", "") SAB_USERNAME = check_setting_str(CFG, "SABnzbd", "sab_username", "") SAB_PASSWORD = check_setting_str(CFG, "SABnzbd", "sab_password", "") SAB_APIKEY = check_setting_str(CFG, "SABnzbd", "sab_apikey", "") SAB_CATEGORY = check_setting_str(CFG, "SABnzbd", "sab_category", "") NZBMATRIX = bool(check_setting_int(CFG, "NZBMatrix", "nzbmatrix", 0)) NZBMATRIX_USERNAME = check_setting_str(CFG, "NZBMatrix", "nzbmatrix_username", "") NZBMATRIX_APIKEY = check_setting_str(CFG, "NZBMatrix", "nzbmatrix_apikey", "") NEWZNAB = bool(check_setting_int(CFG, "Newznab", "newznab", 0)) NEWZNAB_HOST = check_setting_str(CFG, "Newznab", "newznab_host", "") NEWZNAB_APIKEY = check_setting_str(CFG, "Newznab", "newznab_apikey", "") NEWZNAB_ENABLED = bool(check_setting_int(CFG, "Newznab", "newznab_enabled", 1)) # Need to pack the extra newznabs back into a list of tuples flattened_newznabs = check_setting_str(CFG, "Newznab", "extra_newznabs", [], log=False) EXTRA_NEWZNABS = list(itertools.izip(*[itertools.islice(flattened_newznabs, i, None, 3) for i in range(3)])) NZBSORG = bool(check_setting_int(CFG, "NZBsorg", "nzbsorg", 0)) NZBSORG_UID = check_setting_str(CFG, "NZBsorg", "nzbsorg_uid", "") NZBSORG_HASH = check_setting_str(CFG, "NZBsorg", "nzbsorg_hash", "") NEWZBIN = bool(check_setting_int(CFG, "Newzbin", "newzbin", 0)) NEWZBIN_UID = check_setting_str(CFG, "Newzbin", "newzbin_uid", "") NEWZBIN_PASSWORD = check_setting_str(CFG, "Newzbin", "newzbin_password", "") LASTFM_USERNAME = check_setting_str(CFG, "General", "lastfm_username", "") INTERFACE = check_setting_str(CFG, "General", "interface", "default") FOLDER_PERMISSIONS = check_setting_str(CFG, "General", "folder_permissions", "0755") ENCODERFOLDER = check_setting_str(CFG, "General", "encoderfolder", "") ENCODER = check_setting_str(CFG, "General", "encoder", "ffmpeg") BITRATE = check_setting_int(CFG, "General", "bitrate", 192) SAMPLINGFREQUENCY = check_setting_int(CFG, "General", "samplingfrequency", 44100) MUSIC_ENCODER = bool(check_setting_int(CFG, "General", "music_encoder", 0)) ADVANCEDENCODER = check_setting_str(CFG, "General", "advancedencoder", "") ENCODEROUTPUTFORMAT = check_setting_str(CFG, "General", "encoderoutputformat", "mp3") ENCODERQUALITY = check_setting_int(CFG, "General", "encoderquality", 2) ENCODERVBRCBR = check_setting_str(CFG, "General", "encodervbrcbr", "cbr") ENCODERLOSSLESS = bool(check_setting_int(CFG, "General", "encoderlossless", 1)) DELETE_LOSSLESS_FILES = bool(check_setting_int(CFG, "General", "delete_lossless_files", 1)) PROWL_ENABLED = bool(check_setting_int(CFG, "Prowl", "prowl_enabled", 0)) PROWL_KEYS = check_setting_str(CFG, "Prowl", "prowl_keys", "") PROWL_ONSNATCH = bool(check_setting_int(CFG, "Prowl", "prowl_onsnatch", 0)) PROWL_PRIORITY = check_setting_int(CFG, "Prowl", "prowl_priority", 0) XBMC_ENABLED = bool(check_setting_int(CFG, "XBMC", "xbmc_enabled", 0)) XBMC_HOST = check_setting_str(CFG, "XBMC", "xbmc_host", "") XBMC_USERNAME = check_setting_str(CFG, "XBMC", "xbmc_username", "") XBMC_PASSWORD = check_setting_str(CFG, "XBMC", "xbmc_password", "") XBMC_UPDATE = bool(check_setting_int(CFG, "XBMC", "xbmc_update", 0)) XBMC_NOTIFY = bool(check_setting_int(CFG, "XBMC", "xbmc_notify", 0)) NMA_ENABLED = bool(check_setting_int(CFG, "NMA", "nma_enabled", 0)) NMA_APIKEY = check_setting_str(CFG, "NMA", "nma_apikey", "") NMA_PRIORITY = check_setting_int(CFG, "NMA", "nma_priority", 0) NMA_ONSNATCH = bool(check_setting_int(CFG, "NMA", "nma_onsnatch", 0)) SYNOINDEX_ENABLED = bool(check_setting_int(CFG, "Synoindex", "synoindex_enabled", 0)) MIRROR = check_setting_str(CFG, "General", "mirror", "musicbrainz.org") CUSTOMHOST = check_setting_str(CFG, "General", "customhost", "localhost") CUSTOMPORT = check_setting_int(CFG, "General", "customport", 5000) CUSTOMSLEEP = check_setting_int(CFG, "General", "customsleep", 1) HPUSER = check_setting_str(CFG, "General", "hpuser", "") HPPASS = check_setting_str(CFG, "General", "hppass", "") CACHE_SIZEMB = check_setting_int(CFG, "Advanced", "cache_sizemb", 32) ALBUM_COMPLETION_PCT = check_setting_int(CFG, "Advanced", "album_completion_pct", 80) # update folder formats in the config & bump up config version if CONFIG_VERSION == "0": from headphones.helpers import replace_all file_values = { "tracknumber": "Track", "title": "Title", "artist": "Artist", "album": "Album", "year": "Year", } folder_values = { "artist": "Artist", "album": "Album", "year": "Year", "releasetype": "Type", "first": "First", "lowerfirst": "first", } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = "1" if CONFIG_VERSION == "1": from headphones.helpers import replace_all file_values = { "Track": "$Track", "Title": "$Title", "Artist": "$Artist", "Album": "$Album", "Year": "$Year", "track": "$track", "title": "$title", "artist": "$artist", "album": "$album", "year": "$year", } folder_values = { "Artist": "$Artist", "Album": "$Album", "Year": "$Year", "Type": "$Type", "First": "$First", "artist": "$artist", "album": "$album", "year": "$year", "type": "$type", "first": "$first", } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = "2" if not LOG_DIR: LOG_DIR = os.path.join(DATA_DIR, "logs") if not os.path.exists(LOG_DIR): try: os.makedirs(LOG_DIR) except OSError: if VERBOSE: print "Unable to create the log directory. Logging to screen only." # Start the logger, silence console logging if we need to logger.headphones_log.initLogger(verbose=VERBOSE) # Put the cache dir in the data dir for now CACHE_DIR = os.path.join(DATA_DIR, "cache") if not os.path.exists(CACHE_DIR): try: os.makedirs(CACHE_DIR) except OSError: logger.error("Could not create cache dir. Check permissions of datadir: " + DATA_DIR) # Initialize the database logger.info("Checking to see if the database has all tables....") try: dbcheck() except Exception, e: logger.error("Can't connect to the database: %s" % e) # Get the currently installed version - returns None, 'win32' or the git hash # Also sets INSTALL_TYPE variable to 'win', 'git' or 'source' CURRENT_VERSION = versioncheck.getVersion() # Check for new versions if CHECK_GITHUB_ON_STARTUP: try: LATEST_VERSION = versioncheck.checkGithub() except: LATEST_VERSION = CURRENT_VERSION else: LATEST_VERSION = CURRENT_VERSION __INITIALIZED__ = True return True
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] values = { 'Artist': artist, 'Album': album, 'Year': year, 'Type': releasetype, 'First': firstchar, 'artist': artist.lower(), 'album': album.lower(), 'year': year, 'type': releasetype.lower(), 'first': firstchar.lower() } 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) last_folder = headphones.FOLDER_FORMAT.split('/')[-1] # Only rename the folder if they use the album name, otherwise merge into existing folder if os.path.exists(destination_path) and 'album' in last_folder.lower(): 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"))) # Basically check if generic/non-album folders already exist, since we're going to merge if not os.path.exists(destination_path): 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 searchNZB(albumid=None, new=False, losslessOnly=False): myDB = db.DBConnection() if albumid: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate, Type from albums WHERE AlbumID=?', [albumid]) else: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate, Type from albums WHERE Status="Wanted" OR Status="Wanted Lossless"') new = True for albums in results: albumid = albums[2] reldate = albums[3] try: year = reldate[:4] except TypeError: year = '' dic = {'...':'', ' & ':' ', ' = ': ' ', '?':'', '$':'s', ' + ':' ', '"':'', ',':'', '*':'', '.':'', ':':''} cleanalbum = helpers.latinToAscii(helpers.replace_all(albums[1], dic)) cleanartist = helpers.latinToAscii(helpers.replace_all(albums[0], dic)) # FLAC usually doesn't have a year for some reason so I'll leave it out # Various Artist albums might be listed as VA, so I'll leave that out too # Only use the year if the term could return a bunch of different albums, i.e. self-titled albums if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4: term = cleanartist + ' ' + cleanalbum + ' ' + year elif albums[0] == 'Various Artists': term = cleanalbum + ' ' + year else: term = cleanartist + ' ' + cleanalbum # Replace bad characters in the term and unicode it term = re.sub('[\.\-\/]', ' ', term).encode('utf-8') artistterm = re.sub('[\.\-\/]', ' ', cleanartist).encode('utf-8') logger.info("Searching for %s since it was marked as wanted" % term) resultlist = [] if headphones.NZBMATRIX: provider = "nzbmatrix" if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "23" elif headphones.PREFERRED_QUALITY: categories = "23,22" else: categories = "22" # Search Audiobooks/Singles/etc if albums['Type'] == "Other": categories = "49" logger.info("Album type is audiobook/spokenword. Using audiobook category") if albums['Type'] == "Single": categories = "47" logger.info("Album type is 'Single'. Using singles category") # For some reason NZBMatrix is erroring out/timing out when the term starts with a "The" right now # so we'll strip it out for the time being. This may get fixed on their end, it may not, but # hopefully this will fix it for now. If you notice anything else it gets stuck on, please post it # on Github so it can be added if term.lower().startswith("the "): term = term[4:] params = { "page": "download", "username": headphones.NZBMATRIX_USERNAME, "apikey": headphones.NZBMATRIX_APIKEY, "subcat": categories, "maxage": headphones.USENET_RETENTION, "english": 1, "ssl": 1, "scenename": 1, "term": term } searchURL = "http://rss.nzbmatrix.com/rss.php?" + urllib.urlencode(params) logger.info(u'Parsing results from <a href="%s">NZBMatrix</a>' % searchURL) try: data = urllib2.urlopen(searchURL, timeout=20).read() except urllib2.URLError, e: logger.warn('Error fetching data from NZBMatrix: %s' % e) data = False if data: d = feedparser.parse(data) for item in d.entries: try: url = item.link title = item.title size = int(item.links[1]['length']) resultlist.append((title, size, url, provider)) logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) except AttributeError, e: logger.info(u"No results found from NZBMatrix for %s" % term)
def _upgrade(self): """ Update folder formats in the config & bump up config version """ if self.CONFIG_VERSION == '0': from headphones.helpers import replace_all file_values = { 'tracknumber': 'Track', 'title': 'Title', 'artist': 'Artist', 'album': 'Album', 'year': 'Year' } folder_values = { 'artist': 'Artist', 'album': 'Album', 'year': 'Year', 'releasetype': 'Type', 'first': 'First', 'lowerfirst': 'first' } self.FILE_FORMAT = replace_all(self.FILE_FORMAT, file_values) self.FOLDER_FORMAT = replace_all(self.FOLDER_FORMAT, folder_values) self.CONFIG_VERSION = '1' if self.CONFIG_VERSION == '1': from headphones.helpers import replace_all file_values = { 'Track': '$Track', 'Title': '$Title', 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'track': '$track', 'title': '$title', 'artist': '$artist', 'album': '$album', 'year': '$year' } folder_values = { 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'Type': '$Type', 'First': '$First', 'artist': '$artist', 'album': '$album', 'year': '$year', 'type': '$type', 'first': '$first' } self.FILE_FORMAT = replace_all(self.FILE_FORMAT, file_values) self.FOLDER_FORMAT = replace_all(self.FOLDER_FORMAT, folder_values) self.CONFIG_VERSION = '2' if self.CONFIG_VERSION == '2': # Update the config to use direct path to the encoder rather than the encoder folder if self.ENCODERFOLDER: self.ENCODER_PATH = os.path.join(self.ENCODERFOLDER, self.ENCODER) self.CONFIG_VERSION = '3' if self.CONFIG_VERSION == '3': # Update the BLACKHOLE option to the NZB_DOWNLOADER format if self.BLACKHOLE: self.NZB_DOWNLOADER = 2 self.CONFIG_VERSION = '4' # Enable Headphones Indexer if they have a VIP account if self.CONFIG_VERSION == '4': if self.HPUSER and self.HPPASS: self.HEADPHONES_INDEXER = True self.CONFIG_VERSION = '5' if self.CONFIG_VERSION == '5': if self.OPEN_MAGNET_LINKS: self.MAGNET_LINKS = 2 self.CONFIG_VERSION = '5'
def getReleaseGroup(rgid): """ Returns a dictionary of the best stuff from a release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True, artist=True) releaseGroup = None attempt = 0 while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn( 'Attempt to retrieve information from MusicBrainz for release group "%s" failed. Sleeping 5 seconds' % rgid ) attempt += 1 time.sleep(5) if not releaseGroup: return False time.sleep(1) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) releaseResult = None attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn( "Attempt to retrieve release information for %s from MusicBrainz failed: %s. Sleeping 5 seconds" % (releaseResult.title, e) ) attempt += 1 time.sleep(5) if not releaseResult: continue # Release filter for non-official live albums types = releaseResult.getTypes() if any("Live" in type for type in types): if not any("Official" in type for type in types): logger.debug("%s is not an official live album. Skipping" % releaseResult.name) continue time.sleep(1) formats = {"2xVinyl": "2", "Vinyl": "2", "CD": "0", "Cassette": "3", "2xCD": "1", "Digital Media": "0"} country = {"US": "0", "GB": "1", "JP": "2"} try: format = int(replace_all(u.extractFragment(releaseResult.releaseEvents[0].format), formats)) except: format = 3 try: country = int(replace_all(releaseResult.releaseEvents[0].country, country)) except: country = 3 release_dict = { "hasasin": bool(releaseResult.asin), "asin": releaseResult.asin, "trackscount": len(releaseResult.getTracks()), "releaseid": u.extractUuid(releaseResult.id), "releasedate": releaseResult.getEarliestReleaseDate(), "format": format, "country": country, } tracks = [] i = 1 for track in releaseResult.tracks: tracks.append( { "number": i, "title": track.title, "id": u.extractUuid(track.id), "url": track.id, "duration": track.duration, } ) i += 1 release_dict["tracks"] = tracks releaselist.append(release_dict)
def getReleaseGroup(rgid): """ Returns a dictionary of the best stuff from a release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True, artist=True) releaseGroup = None attempt = 0 q, sleepytime = startmb() while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz for release group "%s" failed (%s)' % (rgid, str(e))) attempt += 1 time.sleep(5) if not releaseGroup: return False time.sleep(sleepytime) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) releaseResult = None attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve release information for %s from MusicBrainz failed (%s)' % (releaseResult.title, str(e))) attempt += 1 time.sleep(5) if not releaseResult: continue # Release filter for non-official live albums types = releaseResult.getTypes() if any('Live' in type for type in types): if not any('Official' in type for type in types): logger.debug('%s is not an official live album. Skipping' % releaseResult.name) continue time.sleep(sleepytime) formats = { '2xVinyl': '2', 'Vinyl': '2', 'CD': '0', 'Cassette': '3', '2xCD': '1', 'Digital Media': '0' } country = { 'US': '0', 'GB': '1', 'JP': '2', } try: format = int(replace_all(u.extractFragment(releaseResult.releaseEvents[0].format), formats)) except: format = 3 try: country = int(replace_all(releaseResult.releaseEvents[0].country, country)) except: country = 3 release_dict = { 'hasasin': bool(releaseResult.asin), 'asin': releaseResult.asin, 'trackscount': len(releaseResult.getTracks()), 'releaseid': u.extractUuid(releaseResult.id), 'releasedate': releaseResult.getEarliestReleaseDate(), 'format': format, 'country': country } tracks = [] i = 1 for track in releaseResult.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release_dict['tracks'] = tracks releaselist.append(release_dict)
def searchTorrent(albumid=None, new=False, losslessOnly=False): myDB = db.DBConnection() if albumid: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE AlbumID=?', [albumid]) else: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE Status="Wanted" OR Status="Wanted Lossless"') new = True for albums in results: albumid = albums[2] reldate = albums[3] try: year = reldate[:4] except TypeError: year = '' dic = {'...':'', ' & ':' ', ' = ': ' ', '?':'', '$':'s', ' + ':' ', '"':'', ',':'', '*':''} cleanalbum = helpers.latinToAscii(helpers.replace_all(albums[1], dic)) cleanartist = helpers.latinToAscii(helpers.replace_all(albums[0], dic)) # FLAC usually doesn't have a year for some reason so I'll leave it out # Various Artist albums might be listed as VA, so I'll leave that out too # Only use the year if the term could return a bunch of different albums, i.e. self-titled albums if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4: term = cleanartist + ' ' + cleanalbum + ' ' + year elif albums[0] == 'Various Artists': term = cleanalbum + ' ' + year else: term = cleanartist + ' ' + cleanalbum # Replace bad characters in the term and unicode it term = re.sub('[\.\-\/]', ' ', term).encode('utf-8') artistterm = re.sub('[\.\-\/]', ' ', cleanartist).encode('utf-8') albumterm = re.sub('[\.\-\/]', ' ', cleanalbum).encode('utf-8') logger.info("Searching torrents for %s since it was marked as wanted" % term) resultlist = [] minimumseeders = int(headphones.NUMBEROFSEEDERS) - 1 if headphones.KAT: provider = "Kick Ass Torrent" providerurl = url_fix("http://www.kat.ph/search/" + term) if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "7" #music format = "2" #flac maxsize = 10000000000 elif headphones.PREFERRED_QUALITY: categories = "7" #music format = "10" #mp3+flac maxsize = 10000000000 else: categories = "7" #music format = "8" #mp3 maxsize = 300000000 params = { "categories[0]": "music", "field": "seeders", "sorder": "desc", "rss": "1" } searchURL = providerurl + "/?%s" % urllib.urlencode(params) try: data = urllib2.urlopen(searchURL, timeout=20).read() except urllib2.URLError, e: logger.warn('Error fetching data from %s: %s' % (provider, e)) data = False if data: logger.info(u'Parsing results from <a href="%s">KAT</a>' % searchURL) d = feedparser.parse(data) if not len(d.entries): logger.info(u"No results found from %s for %s" % (provider, term)) pass else: for item in d.entries: try: rightformat = True title = item.title seeders = item.seeds url = item.links[1]['url'] size = int(item.links[1]['length']) try: if format == "2": request = urllib2.Request(url) request.add_header('Accept-encoding', 'gzip') 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() if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1: rightformat = False except Exception, e: rightformat = False if rightformat == True and size < maxsize and minimumseeders < int(seeders): resultlist.append((title, size, url, provider)) logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) else: logger.info('%s is larger than the maxsize, the wrong format or has too little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeders), rightformat)) except Exception, e: logger.error(u"An unknown error occurred in the KAT parser: %s" % e)
def renameFiles(albumpath, downloaded_track_list, release): logger.info('Renaming files') try: year = release['ReleaseDate'][:4] except TypeError: year = '' # Until tagging works better I'm going to rely on the already provided metadata for downloaded_track in downloaded_track_list: try: f = MediaFile(downloaded_track) except: logger.info( "MediaFile couldn't parse: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) continue if not f.disc: discnumber = '' else: discnumber = '%d' % f.disc if not f.track: tracknumber = '' else: tracknumber = '%02d' % f.track if not f.title: basename = os.path.basename( downloaded_track.decode(headphones.SYS_ENCODING, 'replace')) title = os.path.splitext(basename)[0] ext = os.path.splitext(basename)[1] new_file_name = helpers.cleanTitle(title) + ext else: title = f.title if release['ArtistName'] == "Various Artists" and f.artist: artistname = f.artist else: artistname = release['ArtistName'] if artistname.startswith('The '): sortname = artistname[4:] + ", The" else: sortname = artistname values = { '$Disc': discnumber, '$Track': tracknumber, '$Title': title, '$Artist': artistname, '$SortArtist': sortname, '$Album': release['AlbumTitle'], '$Year': year, '$disc': discnumber, '$track': tracknumber, '$title': title.lower(), '$artist': artistname.lower(), '$sortartist': sortname.lower(), '$album': release['AlbumTitle'].lower(), '$year': year } ext = os.path.splitext(downloaded_track)[1] new_file_name = helpers.replace_all(headphones.FILE_FORMAT.strip(), values).replace('/', '_') + ext new_file_name = new_file_name.replace('?', '_').replace( ':', '_').encode(headphones.SYS_ENCODING, 'replace') if new_file_name.startswith('.'): new_file_name = new_file_name.replace(0, '_') new_file = os.path.join(albumpath, new_file_name) if downloaded_track == new_file_name: logger.debug( "Renaming for: " + downloaded_track.decode(headphones.SYS_ENCODING, 'replace') + " is not neccessary") continue logger.debug( 'Renaming %s ---> %s' % (downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), new_file_name.decode(headphones.SYS_ENCODING, 'replace'))) try: os.rename(downloaded_track, new_file) except Exception, e: logger.error('Error renaming file: %s. Error: %s' % (downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), e)) continue
def libraryScan(dir=None): if not dir: dir = headphones.MUSIC_DIR try: dir = str(dir) except UnicodeEncodeError: dir = unicode(dir).encode('unicode_escape') if not os.path.isdir(dir): logger.warn('Cannot find directory: %s. Not scanning' % dir) return myDB = db.DBConnection() # Clean up bad filepaths tracks = myDB.select( 'SELECT Location, TrackID from tracks WHERE Location IS NOT NULL') for track in tracks: if not os.path.isfile(track['Location'].encode( headphones.SYS_ENCODING)): myDB.action( 'UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [None, None, None, track['TrackID']]) logger.info('Scanning music directory: %s' % dir) new_artists = [] bitrates = [] myDB.action('DELETE from have') for r, d, f in os.walk(dir): for files in f: # MEDIA_FORMATS = music file extensions, e.g. mp3, flac, etc if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS): song = os.path.join(r, files) file = unicode(os.path.join(r, files), headphones.SYS_ENCODING, errors='replace') # Try to read the metadata try: f = MediaFile(song) except: logger.error('Cannot read file: ' + file) continue # Grab the bitrates for the auto detect bit rate option if f.bitrate: bitrates.append(f.bitrate) # Try to find a match based on artist/album/tracktitle if f.albumartist: f_artist = f.albumartist elif f.artist: f_artist = f.artist else: continue if f_artist and f.album and f.title: track = myDB.action( 'SELECT TrackID from tracks WHERE CleanName LIKE ?', [ helpers.cleanName(f_artist + ' ' + f.album + ' ' + f.title) ]).fetchone() if not track: track = myDB.action( 'SELECT TrackID from tracks WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?', [f_artist, f.album, f.title]).fetchone() if track: myDB.action( 'UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']]) continue # Try to match on mbid if available and we couldn't find a match based on metadata if f.mb_trackid: # Wondering if theres a better way to do this -> do one thing if the row exists, # do something else if it doesn't track = myDB.action( 'SELECT TrackID from tracks WHERE TrackID=?', [f.mb_trackid]).fetchone() if track: myDB.action( 'UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?', [file, f.bitrate, f.format, track['TrackID']]) continue # if we can't find a match in the database on a track level, it might be a new artist or it might be on a non-mb release new_artists.append(f_artist) # The have table will become the new database for unmatched tracks (i.e. tracks with no associated links in the database myDB.action( 'INSERT INTO have (ArtistName, AlbumTitle, TrackNumber, TrackTitle, TrackLength, BitRate, Genre, Date, TrackID, Location, CleanName, Format) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [ f_artist, f.album, f.track, f.title, f.length, f.bitrate, f.genre, f.date, f.mb_trackid, file, helpers.cleanName(f_artist + ' ' + f.album + ' ' + f.title), f.format ]) logger.info('Completed scanning of directory: %s' % dir) logger.info('Checking filepaths to see if we can find any matches') # Now check empty file paths to see if we can find a match based on their folder format tracks = myDB.select('SELECT * from tracks WHERE Location IS NULL') for track in tracks: release = myDB.action('SELECT * from albums WHERE AlbumID=?', [track['AlbumID']]).fetchone() 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] albumvalues = { '$Artist': artist, '$Album': album, '$Year': year, '$Type': releasetype, '$First': firstchar, '$artist': artist.lower(), '$album': album.lower(), '$year': year, '$type': releasetype.lower(), '$first': firstchar.lower() } folder = helpers.replace_all(headphones.FOLDER_FORMAT, albumvalues) folder = folder.replace('./', '_/').replace(':', '_').replace('?', '_') if folder.endswith('.'): folder = folder.replace(folder[len(folder) - 1], '_') if not track['TrackNumber']: tracknumber = '' else: tracknumber = '%02d' % track['TrackNumber'] title = track['TrackTitle'] trackvalues = { '$Track': tracknumber, '$Title': title, '$Artist': release['ArtistName'], '$Album': release['AlbumTitle'], '$Year': year, '$track': tracknumber, '$title': title.lower(), '$artist': release['ArtistName'].lower(), '$album': release['AlbumTitle'].lower(), '$year': year } new_file_name = helpers.replace_all( headphones.FILE_FORMAT, trackvalues).replace('/', '_') + '.*' new_file_name = new_file_name.replace('?', '_').replace(':', '_') full_path_to_file = os.path.normpath( os.path.join(headphones.MUSIC_DIR, folder, new_file_name)).encode(headphones.SYS_ENCODING, 'replace') match = glob.glob(full_path_to_file) if match: logger.info('Found a match: %s. Writing MBID to metadata' % match[0]) unipath = unicode(match[0], headphones.SYS_ENCODING, errors='replace') myDB.action('UPDATE tracks SET Location=? WHERE TrackID=?', [unipath, track['TrackID']]) myDB.action('DELETE from have WHERE Location=?', [unipath]) # Try to insert the appropriate track id so we don't have to keep doing this try: f = MediaFile(match[0]) f.mb_trackid = track['TrackID'] f.save() myDB.action( 'UPDATE tracks SET BitRate=?, Format=? WHERE TrackID=?', [f.bitrate, f.format, track['TrackID']]) logger.debug('Wrote mbid to track: %s' % match[0]) except: logger.error('Error embedding track id into: %s' % match[0]) continue logger.info('Done checking empty filepaths') logger.info('Done syncing library with directory: %s' % dir) # Clean up the new artist list unique_artists = {}.fromkeys(new_artists).keys() current_artists = myDB.select('SELECT ArtistName, ArtistID from artists') artist_list = [ f for f in unique_artists if f.lower() not in [x[0].lower() for x in current_artists] ] # Update track counts logger.info('Updating track counts') for artist in current_artists: havetracks = len( myDB.select( 'SELECT TrackTitle from tracks WHERE ArtistID like ? AND Location IS NOT NULL', [artist['ArtistID']])) + len( myDB.select( 'SELECT TrackTitle from have WHERE ArtistName like ?', [artist['ArtistName']])) myDB.action('UPDATE artists SET HaveTracks=? WHERE ArtistID=?', [havetracks, artist['ArtistID']]) logger.info('Found %i new artists' % len(artist_list)) if len(artist_list): if headphones.ADD_ARTISTS: logger.info('Importing %i new artists' % len(artist_list)) importer.artistlist_to_mbids(artist_list) else: logger.info( 'To add these artists, go to Manage->Manage New Artists') headphones.NEW_ARTISTS = artist_list if headphones.DETECT_BITRATE: headphones.PREFERRED_BITRATE = sum(bitrates) / len(bitrates) / 1000
def searchTorrent(albumid=None, new=False, losslessOnly=False): myDB = db.DBConnection() if albumid: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE AlbumID=?', [albumid]) else: results = myDB.select('SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE Status="Wanted" OR Status="Wanted Lossless"') new = True for albums in results: albumid = albums[2] reldate = albums[3] try: year = reldate[:4] except TypeError: year = '' dic = {'...':'', ' & ':' ', ' = ': ' ', '?':'', '$':'s', ' + ':' ', '"':'', ',':'', '*':''} cleanalbum = helpers.latinToAscii(helpers.replace_all(albums[1], dic)) cleanartist = helpers.latinToAscii(helpers.replace_all(albums[0], dic)) # FLAC usually doesn't have a year for some reason so I'll leave it out # Various Artist albums might be listed as VA, so I'll leave that out too # Only use the year if the term could return a bunch of different albums, i.e. self-titled albums if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4: term = cleanartist + ' ' + cleanalbum + ' ' + year elif albums[0] == 'Various Artists': term = cleanalbum + ' ' + year else: term = cleanartist + ' ' + cleanalbum # Replace bad characters in the term and unicode it term = re.sub('[\.\-\/]', ' ', term).encode('utf-8') artistterm = re.sub('[\.\-\/]', ' ', cleanartist).encode('utf-8') logger.info("Searching torrents for %s since it was marked as wanted" % term) resultlist = [] minimumseeders = int(headphones.NUMBEROFSEEDERS) - 1 if headphones.KAT: provider = "Kick Ass Torrent" providerurl = url_fix("http://www.kat.ph/search/" + term) if headphones.PREFERRED_QUALITY == 3 or losslessOnly: categories = "7" #music format = "2" #flac maxsize = 10000000000 elif headphones.PREFERRED_QUALITY: categories = "7" #music format = "10" #mp3+flac maxsize = 10000000000 else: categories = "7" #music format = "8" #mp3 maxsize = 300000000 params = { "categories[0]": "music", "field": "seeders", "sorder": "desc", "rss": "1" } searchURL = providerurl + "/?%s" % urllib.urlencode(params) try: data = urllib2.urlopen(searchURL, timeout=20).read() except urllib2.URLError, e: logger.warn('Error fetching data from %s: %s' % (provider, e)) data = False if data: d = feedparser.parse(data) if not len(d.entries): logger.info(u"No results found from %s for %s" % (provider, term)) pass else: for item in d.entries: try: rightformat = True title = item.title seeders = item.seeds url = item.links[1]['url'] size = int(item.links[1]['length']) try: if format == "2": request = urllib2.Request(url) 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() if int(torrent.find(".mp3")) > 0 and int(torrent.find(".flac")) < 1: rightformat = False except Exception, e: rightformat = False if rightformat == True and size < maxsize and minimumseeders < int(seeders): resultlist.append((title, size, url, provider)) logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) else: logger.info('%s is larger than the maxsize, the wrong format or has to little seeders for this category, skipping. (Size: %i bytes, Seeders: %i, Format: %s)' % (title, size, int(seeders), rightformat)) except Exception, e: logger.error(u"An unknown error occured in the KAT parser: %s" % e)
def libraryScan(dir=None): if not dir: dir = headphones.MUSIC_DIR try: dir = str(dir) except UnicodeEncodeError: dir = unicode(dir).encode("unicode_escape") if not os.path.isdir(dir): logger.warn("Cannot find directory: %s. Not scanning" % dir) return myDB = db.DBConnection() # Clean up bad filepaths tracks = myDB.select("SELECT Location, TrackID from tracks WHERE Location IS NOT NULL") for track in tracks: if not os.path.isfile(track["Location"].encode(headphones.SYS_ENCODING)): myDB.action( "UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?", [None, None, None, track["TrackID"]], ) logger.info("Scanning music directory: %s" % dir) new_artists = [] bitrates = [] myDB.action("DELETE from have") for r, d, f in os.walk(dir): for files in f: # MEDIA_FORMATS = music file extensions, e.g. mp3, flac, etc if any(files.lower().endswith("." + x.lower()) for x in headphones.MEDIA_FORMATS): song = os.path.join(r, files) file = unicode(os.path.join(r, files), headphones.SYS_ENCODING, errors="replace") # Try to read the metadata try: f = MediaFile(song) except: logger.error("Cannot read file: " + file) continue # Grab the bitrates for the auto detect bit rate option if f.bitrate: bitrates.append(f.bitrate) # Try to find a match based on artist/album/tracktitle if f.albumartist: f_artist = f.albumartist elif f.artist: f_artist = f.artist else: continue if f_artist and f.album and f.title: track = myDB.action( "SELECT TrackID from tracks WHERE CleanName LIKE ?", [helpers.cleanName(f_artist + " " + f.album + " " + f.title)], ).fetchone() if not track: track = myDB.action( "SELECT TrackID from tracks WHERE ArtistName LIKE ? AND AlbumTitle LIKE ? AND TrackTitle LIKE ?", [f_artist, f.album, f.title], ).fetchone() if track: myDB.action( "UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?", [file, f.bitrate, f.format, track["TrackID"]], ) continue # Try to match on mbid if available and we couldn't find a match based on metadata if f.mb_trackid: # Wondering if theres a better way to do this -> do one thing if the row exists, # do something else if it doesn't track = myDB.action("SELECT TrackID from tracks WHERE TrackID=?", [f.mb_trackid]).fetchone() if track: myDB.action( "UPDATE tracks SET Location=?, BitRate=?, Format=? WHERE TrackID=?", [file, f.bitrate, f.format, track["TrackID"]], ) continue # if we can't find a match in the database on a track level, it might be a new artist or it might be on a non-mb release new_artists.append(f_artist) # The have table will become the new database for unmatched tracks (i.e. tracks with no associated links in the database myDB.action( "INSERT INTO have (ArtistName, AlbumTitle, TrackNumber, TrackTitle, TrackLength, BitRate, Genre, Date, TrackID, Location, CleanName, Format) VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [ f_artist, f.album, f.track, f.title, f.length, f.bitrate, f.genre, f.date, f.mb_trackid, file, helpers.cleanName(f_artist + " " + f.album + " " + f.title), f.format, ], ) logger.info("Completed scanning of directory: %s" % dir) logger.info("Checking filepaths to see if we can find any matches") # Now check empty file paths to see if we can find a match based on their folder format tracks = myDB.select("SELECT * from tracks WHERE Location IS NULL") for track in tracks: release = myDB.action("SELECT * from albums WHERE AlbumID=?", [track["AlbumID"]]).fetchone() 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] albumvalues = { "$Artist": artist, "$Album": album, "$Year": year, "$Type": releasetype, "$First": firstchar, "$artist": artist.lower(), "$album": album.lower(), "$year": year, "$type": releasetype.lower(), "$first": firstchar.lower(), } folder = helpers.replace_all(headphones.FOLDER_FORMAT, albumvalues) folder = folder.replace("./", "_/").replace(":", "_").replace("?", "_") if folder.endswith("."): folder = folder.replace(folder[len(folder) - 1], "_") if not track["TrackNumber"]: tracknumber = "" else: tracknumber = "%02d" % track["TrackNumber"] title = track["TrackTitle"] trackvalues = { "$Track": tracknumber, "$Title": title, "$Artist": release["ArtistName"], "$Album": release["AlbumTitle"], "$Year": year, "$track": tracknumber, "$title": title.lower(), "$artist": release["ArtistName"].lower(), "$album": release["AlbumTitle"].lower(), "$year": year, } new_file_name = helpers.replace_all(headphones.FILE_FORMAT, trackvalues).replace("/", "_") + ".*" new_file_name = new_file_name.replace("?", "_").replace(":", "_") full_path_to_file = os.path.normpath(os.path.join(headphones.MUSIC_DIR, folder, new_file_name)).encode( headphones.SYS_ENCODING, "replace" ) match = glob.glob(full_path_to_file) if match: logger.info("Found a match: %s. Writing MBID to metadata" % match[0]) unipath = unicode(match[0], headphones.SYS_ENCODING, errors="replace") myDB.action("UPDATE tracks SET Location=? WHERE TrackID=?", [unipath, track["TrackID"]]) myDB.action("DELETE from have WHERE Location=?", [unipath]) # Try to insert the appropriate track id so we don't have to keep doing this try: f = MediaFile(match[0]) f.mb_trackid = track["TrackID"] f.save() myDB.action( "UPDATE tracks SET BitRate=?, Format=? WHERE TrackID=?", [f.bitrate, f.format, track["TrackID"]] ) logger.debug("Wrote mbid to track: %s" % match[0]) except: logger.error("Error embedding track id into: %s" % match[0]) continue logger.info("Done checking empty filepaths") logger.info("Done syncing library with directory: %s" % dir) # Clean up the new artist list unique_artists = {}.fromkeys(new_artists).keys() current_artists = myDB.select("SELECT ArtistName, ArtistID from artists") artist_list = [f for f in unique_artists if f.lower() not in [x[0].lower() for x in current_artists]] # Update track counts logger.info("Updating track counts") for artist in current_artists: havetracks = len( myDB.select( "SELECT TrackTitle from tracks WHERE ArtistID like ? AND Location IS NOT NULL", [artist["ArtistID"]] ) ) + len(myDB.select("SELECT TrackTitle from have WHERE ArtistName like ?", [artist["ArtistName"]])) myDB.action("UPDATE artists SET HaveTracks=? WHERE ArtistID=?", [havetracks, artist["ArtistID"]]) logger.info("Found %i new artists" % len(artist_list)) if len(artist_list): if headphones.ADD_ARTISTS: logger.info("Importing %i new artists" % len(artist_list)) importer.artistlist_to_mbids(artist_list) else: logger.info("To add these artists, go to Manage->Manage New Artists") headphones.NEW_ARTISTS = artist_list if headphones.DETECT_BITRATE: headphones.PREFERRED_BITRATE = sum(bitrates) / len(bitrates) / 1000
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] values = { "$Artist": artist, "$Album": album, "$Year": year, "$Type": releasetype, "$First": firstchar.upper(), "$artist": artist.lower(), "$album": album.lower(), "$year": year, "$type": releasetype.lower(), "$first": firstchar.lower(), } folder = helpers.replace_all(headphones.FOLDER_FORMAT.strip(), values) folder = ( folder.replace("./", "_/") .replace(":", "_") .replace("?", "_") .replace("/.", "/_") .replace("<", "_") .replace(">", "_") ) if folder.endswith("."): folder = folder.replace(folder[len(folder) - 1], "_") if folder.startswith("."): folder = folder.replace(0, "_") # Grab our list of files early on so we can determine if we need to create # the lossy_dest_dir, lossless_dest_dir, or both files_to_move = [] lossy_media = False lossless_media = False for r, d, f in os.walk(albumpath): for files in f: files_to_move.append(os.path.join(r, files)) if any(files.lower().endswith("." + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS): lossy_media = True if any(files.lower().endswith("." + x.lower()) for x in headphones.LOSSLESS_MEDIA_FORMATS): lossless_media = True # Do some sanity checking to see what directories we need to create: make_lossy_folder = False make_lossless_folder = False lossy_destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, folder)).encode( headphones.SYS_ENCODING, "replace" ) lossless_destination_path = os.path.normpath(os.path.join(headphones.LOSSLESS_DESTINATION_DIR, folder)).encode( headphones.SYS_ENCODING, "replace" ) # If they set a destination dir for lossless media, only create the lossy folder if there is lossy media if headphones.LOSSLESS_DESTINATION_DIR: if lossy_media: make_lossy_folder = True if lossless_media: make_lossless_folder = True # If they haven't set a lossless dest_dir, just create the "lossy" folder else: make_lossy_folder = True last_folder = headphones.FOLDER_FORMAT.strip().split("/")[-1] if make_lossless_folder: # Only rename the folder if they use the album name, otherwise merge into existing folder if os.path.exists(lossless_destination_path) and "album" in last_folder.lower(): temp_folder = folder i = 1 while True: newfolder = temp_folder + "[%i]" % i lossless_destination_path = os.path.normpath( os.path.join(headphones.LOSSLESS_DESTINATION_DIR, newfolder) ).encode(headphones.SYS_ENCODING, "replace") if os.path.exists(lossless_destination_path): i += 1 else: temp_folder = newfolder break if not os.path.exists(lossless_destination_path): try: os.makedirs(lossless_destination_path) except Exception, e: logger.error("Could not create lossless folder for %s. (Error: %s)" % (release["AlbumTitle"], e)) if not make_lossy_folder: return [albumpath]
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 getReleaseGroup(rgid): """ Returns the best release out of any given release group """ with mb_lock: releaselist = [] inc = ws.ReleaseGroupIncludes(releases=True) releaseGroup = None attempt = 0 while attempt < 5: try: releaseGroup = q.getReleaseGroupById(rgid, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve information from MusicBrainz for release group "%s" failed. Sleeping 5 seconds' % rgid) attempt += 1 time.sleep(5) if not releaseGroup: return False time.sleep(1) # I think for now we have to make separate queries for each release, in order # to get more detailed release info (ASIN, track count, etc.) for release in releaseGroup.releases: inc = ws.ReleaseIncludes(tracks=True, releaseEvents=True) releaseResult = None attempt = 0 while attempt < 5: try: releaseResult = q.getReleaseById(release.id, inc) break except WebServiceError, e: logger.warn('Attempt to retrieve release information for %s from MusicBrainz failed: %s. Sleeping 5 seconds' % (releaseResult.title, e)) attempt += 1 time.sleep(5) if not releaseResult: continue if releaseResult.title.lower() != releaseGroup.title.lower(): continue time.sleep(1) formats = { '2xVinyl': '2', 'Vinyl': '2', 'CD': '0', 'Cassette': '3', '2xCD': '1', 'Digital Media': '0' } country = { 'US': '0', 'GB': '1', 'JP': '1', } try: format = int(replace_all(u.extractFragment(releaseResult.releaseEvents[0].format), formats)) except: format = 3 try: country = int(replace_all(releaseResult.releaseEvents[0].country, country)) except: country = 2 release_dict = { 'hasasin': bool(releaseResult.asin), 'asin': releaseResult.asin, 'trackscount': len(releaseResult.getTracks()), 'releaseid': u.extractUuid(releaseResult.id), 'releasedate': releaseResult.getEarliestReleaseDate(), 'format': format, 'country': country } tracks = [] i = 1 for track in releaseResult.tracks: tracks.append({ 'number': i, 'title': track.title, 'id': u.extractUuid(track.id), 'url': track.id, 'duration': track.duration }) i += 1 release_dict['tracks'] = tracks releaselist.append(release_dict)
def fileSystemScan(self): # Now check empty file paths to see if we can find a match based on their folder format tracks = myDB.select('SELECT * from tracks WHERE Location IS NULL') for track in tracks: release = myDB.action('SELECT * from albums WHERE AlbumID=?', [track['AlbumID']]).fetchone() try: year = release['ReleaseDate'][:4] except TypeError: year = '' artist = release['ArtistName'].replace('/', '_') album = release['AlbumTitle'].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() albumvalues = { 'artist': artist, 'album': album, 'year': year, 'first': firstchar, 'lowerfirst': lowerfirst } folder = helpers.replace_all(headphones.FOLDER_FORMAT, albumvalues) folder = folder.replace('./', '_/').replace(':','_').replace('?','_') if folder.endswith('.'): folder = folder.replace(folder[len(folder)-1], '_') if not track['TrackNumber']: tracknumber = '' else: tracknumber = '%02d' % track['TrackNumber'] trackvalues = { 'tracknumber': tracknumber, 'title': track['TrackTitle'], 'artist': release['ArtistName'], 'album': release['AlbumTitle'], 'year': year } new_file_name = helpers.replace_all(headphones.FILE_FORMAT, trackvalues).replace('/','_') + '.*' new_file_name = new_file_name.replace('?','_').replace(':', '_') full_path_to_file = os.path.normpath(os.path.join(headphones.MUSIC_DIR, folder, new_file_name)).encode(headphones.SYS_ENCODING, 'replace') match = glob.glob(full_path_to_file) if match: logger.info('Found a match: %s. Writing MBID to metadata' % match[0]) unipath = unicode(match[0], headphones.SYS_ENCODING, errors='replace') myDB.action('UPDATE tracks SET Location=? WHERE TrackID=?', [unipath, track['TrackID']]) myDB.action('DELETE from have WHERE Location=?', [unipath]) # Try to insert the appropriate track id so we don't have to keep doing this try: f = MediaFile(match[0]) f.mb_trackid = track['TrackID'] f.save() myDB.action('UPDATE tracks SET BitRate=? WHERE TrackID=?', [f.bitrate, track['TrackID']]) logger.debug('Wrote mbid to track: %s' % match[0]) except: logger.error('Error embedding track id into: %s' % match[0]) continue
def initialize(): with INIT_LOCK: global __INITIALIZED__, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, SYS_PLATFORM, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, \ HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, HTTP_PROXY, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, GIT_USER, GIT_BRANCH, \ CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, \ LOSSLESS_DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, \ RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, KEEP_TORRENT_FILES, \ ADD_ALBUM_ART, ALBUM_ART_FORMAT, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \ TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, \ RUTRACKER, RUTRACKER_USER, RUTRACKER_PASSWORD, WHATCD, WHATCD_USERNAME, WHATCD_PASSWORD, DOWNLOAD_TORRENT_DIR, \ LIBRARYSCAN, LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \ NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_HOST, NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, EXTRA_NEWZNABS, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, NZBSRUS, NZBSRUS_UID, NZBSRUS_APIKEY, NZBX, \ NZB_DOWNLOADER, PREFERRED_WORDS, REQUIRED_WORDS, IGNORED_WORDS, \ LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, ENCODERFOLDER, ENCODER_PATH, ENCODER, XLDPROFILE, BITRATE, SAMPLINGFREQUENCY, \ MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, ENCODERLOSSLESS, DELETE_LOSSLESS_FILES, \ PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, PUSHOVER_ENABLED, PUSHOVER_PRIORITY, PUSHOVER_KEYS, PUSHOVER_ONSNATCH, MIRRORLIST, \ MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \ XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \ PREFERRED_BITRATE_LOW_BUFFER, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB, \ UMASK if __INITIALIZED__: return False # Make sure all the config sections exist CheckSection('General') CheckSection('SABnzbd') CheckSection('NZBget') CheckSection('NZBMatrix') CheckSection('Newznab') CheckSection('NZBsorg') CheckSection('NZBsRus') CheckSection('nzbX') CheckSection('Newzbin') CheckSection('Waffles') CheckSection('Rutracker') CheckSection('What.cd') CheckSection('Prowl') CheckSection('Pushover') CheckSection('XBMC') CheckSection('NMA') CheckSection('Synoindex') CheckSection('Advanced') # Set global variables based on config file or use defaults CONFIG_VERSION = check_setting_str(CFG, 'General', 'config_version', '0') try: HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8181) except: HTTP_PORT = 8181 if HTTP_PORT < 21 or HTTP_PORT > 65535: HTTP_PORT = 8181 HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0') HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '') HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '') HTTP_ROOT = check_setting_str(CFG, 'General', 'http_root', '/') HTTP_PROXY = bool(check_setting_int(CFG, 'General', 'http_proxy', 0)) LAUNCH_BROWSER = bool( check_setting_int(CFG, 'General', 'launch_browser', 1)) API_ENABLED = bool(check_setting_int(CFG, 'General', 'api_enabled', 0)) API_KEY = check_setting_str(CFG, 'General', 'api_key', '') GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '') GIT_USER = check_setting_str(CFG, 'General', 'git_user', 'rembo10') GIT_BRANCH = check_setting_str(CFG, 'General', 'git_branch', 'master') LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', '') CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', '') CHECK_GITHUB = bool( check_setting_int(CFG, 'General', 'check_github', 1)) CHECK_GITHUB_ON_STARTUP = bool( check_setting_int(CFG, 'General', 'check_github_on_startup', 1)) CHECK_GITHUB_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360) MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '') DESTINATION_DIR = check_setting_str(CFG, 'General', 'destination_dir', '') LOSSLESS_DESTINATION_DIR = check_setting_str( CFG, 'General', 'lossless_destination_dir', '') PREFERRED_QUALITY = check_setting_int(CFG, 'General', 'preferred_quality', 0) PREFERRED_BITRATE = check_setting_str(CFG, 'General', 'preferred_bitrate', '') PREFERRED_BITRATE_HIGH_BUFFER = check_setting_int( CFG, 'General', 'preferred_bitrate_high_buffer', '') PREFERRED_BITRATE_LOW_BUFFER = check_setting_int( CFG, 'General', 'preferred_bitrate_low_buffer', '') PREFERRED_BITRATE_ALLOW_LOSSLESS = bool( check_setting_int(CFG, 'General', 'preferred_bitrate_allow_lossless', 0)) DETECT_BITRATE = bool( check_setting_int(CFG, 'General', 'detect_bitrate', 0)) ADD_ARTISTS = bool( check_setting_int(CFG, 'General', 'auto_add_artists', 1)) CORRECT_METADATA = bool( check_setting_int(CFG, 'General', 'correct_metadata', 0)) MOVE_FILES = bool(check_setting_int(CFG, 'General', 'move_files', 0)) RENAME_FILES = bool( check_setting_int(CFG, 'General', 'rename_files', 0)) FOLDER_FORMAT = check_setting_str(CFG, 'General', 'folder_format', 'Artist/Album [Year]') FILE_FORMAT = check_setting_str(CFG, 'General', 'file_format', 'Track Artist - Album [Year]- Title') CLEANUP_FILES = bool( check_setting_int(CFG, 'General', 'cleanup_files', 0)) ADD_ALBUM_ART = bool( check_setting_int(CFG, 'General', 'add_album_art', 0)) ALBUM_ART_FORMAT = check_setting_str(CFG, 'General', 'album_art_format', 'folder') EMBED_ALBUM_ART = bool( check_setting_int(CFG, 'General', 'embed_album_art', 0)) EMBED_LYRICS = bool( check_setting_int(CFG, 'General', 'embed_lyrics', 0)) NZB_DOWNLOADER = check_setting_int(CFG, 'General', 'nzb_downloader', 0) DOWNLOAD_DIR = check_setting_str(CFG, 'General', 'download_dir', '') BLACKHOLE = bool(check_setting_int(CFG, 'General', 'blackhole', 0)) BLACKHOLE_DIR = check_setting_str(CFG, 'General', 'blackhole_dir', '') USENET_RETENTION = check_setting_int(CFG, 'General', 'usenet_retention', '1500') INCLUDE_EXTRAS = bool( check_setting_int(CFG, 'General', 'include_extras', 0)) EXTRAS = check_setting_str(CFG, 'General', 'extras', '') AUTOWANT_UPCOMING = bool( check_setting_int(CFG, 'General', 'autowant_upcoming', 1)) AUTOWANT_ALL = bool( check_setting_int(CFG, 'General', 'autowant_all', 0)) KEEP_TORRENT_FILES = bool( check_setting_int(CFG, 'General', 'keep_torrent_files', 0)) SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 1440) LIBRARYSCAN = bool(check_setting_int(CFG, 'General', 'libraryscan', 1)) LIBRARYSCAN_INTERVAL = check_setting_int(CFG, 'General', 'libraryscan_interval', 300) DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, 'General', 'download_scan_interval', 5) TORRENTBLACKHOLE_DIR = check_setting_str(CFG, 'General', 'torrentblackhole_dir', '') NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10') ISOHUNT = bool(check_setting_int(CFG, 'General', 'isohunt', 0)) KAT = bool(check_setting_int(CFG, 'General', 'kat', 0)) MININOVA = bool(check_setting_int(CFG, 'General', 'mininova', 0)) DOWNLOAD_TORRENT_DIR = check_setting_str(CFG, 'General', 'download_torrent_dir', '') WAFFLES = bool(check_setting_int(CFG, 'Waffles', 'waffles', 0)) WAFFLES_UID = check_setting_str(CFG, 'Waffles', 'waffles_uid', '') WAFFLES_PASSKEY = check_setting_str(CFG, 'Waffles', 'waffles_passkey', '') RUTRACKER = bool(check_setting_int(CFG, 'Rutracker', 'rutracker', 0)) RUTRACKER_USER = check_setting_str(CFG, 'Rutracker', 'rutracker_user', '') RUTRACKER_PASSWORD = check_setting_str(CFG, 'Rutracker', 'rutracker_password', '') WHATCD = bool(check_setting_int(CFG, 'What.cd', 'whatcd', 0)) WHATCD_USERNAME = check_setting_str(CFG, 'What.cd', 'whatcd_username', '') WHATCD_PASSWORD = check_setting_str(CFG, 'What.cd', 'whatcd_password', '') SAB_HOST = check_setting_str(CFG, 'SABnzbd', 'sab_host', '') SAB_USERNAME = check_setting_str(CFG, 'SABnzbd', 'sab_username', '') SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '') SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '') SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', '') NZBGET_USERNAME = check_setting_str(CFG, 'NZBget', 'nzbget_username', 'nzbget') NZBGET_PASSWORD = check_setting_str(CFG, 'NZBget', 'nzbget_password', '') NZBGET_CATEGORY = check_setting_str(CFG, 'NZBget', 'nzbget_category', '') NZBGET_HOST = check_setting_str(CFG, 'NZBget', 'nzbget_host', '') NZBMATRIX = bool(check_setting_int(CFG, 'NZBMatrix', 'nzbmatrix', 0)) NZBMATRIX_USERNAME = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_username', '') NZBMATRIX_APIKEY = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_apikey', '') NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0)) NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '') NEWZNAB_ENABLED = bool( check_setting_int(CFG, 'Newznab', 'newznab_enabled', 1)) # Need to pack the extra newznabs back into a list of tuples flattened_newznabs = check_setting_str(CFG, 'Newznab', 'extra_newznabs', [], log=False) EXTRA_NEWZNABS = list( itertools.izip(*[ itertools.islice(flattened_newznabs, i, None, 3) for i in range(3) ])) NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0)) NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') NZBSORG_HASH = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_hash', '') NEWZBIN = bool(check_setting_int(CFG, 'Newzbin', 'newzbin', 0)) NEWZBIN_UID = check_setting_str(CFG, 'Newzbin', 'newzbin_uid', '') NEWZBIN_PASSWORD = check_setting_str(CFG, 'Newzbin', 'newzbin_password', '') NZBSRUS = bool(check_setting_int(CFG, 'NZBsRus', 'nzbsrus', 0)) NZBSRUS_UID = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_uid', '') NZBSRUS_APIKEY = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_apikey', '') NZBX = bool(check_setting_int(CFG, 'nzbX', 'nzbx', 0)) PREFERRED_WORDS = check_setting_str(CFG, 'General', 'preferred_words', '') IGNORED_WORDS = check_setting_str(CFG, 'General', 'ignored_words', '') REQUIRED_WORDS = check_setting_str(CFG, 'General', 'required_words', '') LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '') INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default') FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755') ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '') ENCODER_PATH = check_setting_str(CFG, 'General', 'encoder_path', '') ENCODER = check_setting_str(CFG, 'General', 'encoder', 'ffmpeg') XLDPROFILE = check_setting_str(CFG, 'General', 'xldprofile', '') BITRATE = check_setting_int(CFG, 'General', 'bitrate', 192) SAMPLINGFREQUENCY = check_setting_int(CFG, 'General', 'samplingfrequency', 44100) MUSIC_ENCODER = bool( check_setting_int(CFG, 'General', 'music_encoder', 0)) ADVANCEDENCODER = check_setting_str(CFG, 'General', 'advancedencoder', '') ENCODEROUTPUTFORMAT = check_setting_str(CFG, 'General', 'encoderoutputformat', 'mp3') ENCODERQUALITY = check_setting_int(CFG, 'General', 'encoderquality', 2) ENCODERVBRCBR = check_setting_str(CFG, 'General', 'encodervbrcbr', 'cbr') ENCODERLOSSLESS = bool( check_setting_int(CFG, 'General', 'encoderlossless', 1)) DELETE_LOSSLESS_FILES = bool( check_setting_int(CFG, 'General', 'delete_lossless_files', 1)) PROWL_ENABLED = bool( check_setting_int(CFG, 'Prowl', 'prowl_enabled', 0)) PROWL_KEYS = check_setting_str(CFG, 'Prowl', 'prowl_keys', '') PROWL_ONSNATCH = bool( check_setting_int(CFG, 'Prowl', 'prowl_onsnatch', 0)) PROWL_PRIORITY = check_setting_int(CFG, 'Prowl', 'prowl_priority', 0) XBMC_ENABLED = bool(check_setting_int(CFG, 'XBMC', 'xbmc_enabled', 0)) XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '') XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '') XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '') XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0)) XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0)) NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0)) NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '') NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0) NMA_ONSNATCH = bool(check_setting_int(CFG, 'NMA', 'nma_onsnatch', 0)) SYNOINDEX_ENABLED = bool( check_setting_int(CFG, 'Synoindex', 'synoindex_enabled', 0)) PUSHOVER_ENABLED = bool( check_setting_int(CFG, 'Pushover', 'pushover_enabled', 0)) PUSHOVER_KEYS = check_setting_str(CFG, 'Pushover', 'pushover_keys', '') PUSHOVER_ONSNATCH = bool( check_setting_int(CFG, 'Pushover', 'pushover_onsnatch', 0)) PUSHOVER_PRIORITY = check_setting_int(CFG, 'Pushover', 'pushover_priority', 0) MIRROR = check_setting_str(CFG, 'General', 'mirror', 'musicbrainz.org') CUSTOMHOST = check_setting_str(CFG, 'General', 'customhost', 'localhost') CUSTOMPORT = check_setting_int(CFG, 'General', 'customport', 5000) CUSTOMSLEEP = check_setting_int(CFG, 'General', 'customsleep', 1) HPUSER = check_setting_str(CFG, 'General', 'hpuser', '') HPPASS = check_setting_str(CFG, 'General', 'hppass', '') CACHE_SIZEMB = check_setting_int(CFG, 'Advanced', 'cache_sizemb', 32) ALBUM_COMPLETION_PCT = check_setting_int(CFG, 'Advanced', 'album_completion_pct', 80) # update folder formats in the config & bump up config version if CONFIG_VERSION == '0': from headphones.helpers import replace_all file_values = { 'tracknumber': 'Track', 'title': 'Title', 'artist': 'Artist', 'album': 'Album', 'year': 'Year' } folder_values = { 'artist': 'Artist', 'album': 'Album', 'year': 'Year', 'releasetype': 'Type', 'first': 'First', 'lowerfirst': 'first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '1' if CONFIG_VERSION == '1': from headphones.helpers import replace_all file_values = { 'Track': '$Track', 'Title': '$Title', 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'track': '$track', 'title': '$title', 'artist': '$artist', 'album': '$album', 'year': '$year' } folder_values = { 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'Type': '$Type', 'First': '$First', 'artist': '$artist', 'album': '$album', 'year': '$year', 'type': '$type', 'first': '$first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '2' if CONFIG_VERSION == '2': # Update the config to use direct path to the encoder rather than the encoder folder if ENCODERFOLDER: ENCODER_PATH = os.path.join(ENCODERFOLDER, ENCODER) CONFIG_VERSION = '3' if CONFIG_VERSION == '3': #Update the BLACKHOLE option to the NZB_DOWNLOADER format if BLACKHOLE: NZB_DOWNLOADER = 2 CONFIG_VERSION = '4' if not LOG_DIR: LOG_DIR = os.path.join(DATA_DIR, 'logs') if not os.path.exists(LOG_DIR): try: os.makedirs(LOG_DIR) except OSError: if VERBOSE: print 'Unable to create the log directory. Logging to screen only.' # Start the logger, silence console logging if we need to logger.headphones_log.initLogger(verbose=VERBOSE) if not CACHE_DIR: # Put the cache dir in the data dir for now CACHE_DIR = os.path.join(DATA_DIR, 'cache') if not os.path.exists(CACHE_DIR): try: os.makedirs(CACHE_DIR) except OSError: logger.error( 'Could not create cache dir. Check permissions of datadir: ' + DATA_DIR) # Sanity check for search interval. Set it to at least 6 hours if SEARCH_INTERVAL < 360: logger.info("Search interval too low. Resetting to 6 hour minimum") SEARCH_INTERVAL = 360 # Initialize the database logger.info('Checking to see if the database has all tables....') try: dbcheck() except Exception, e: logger.error("Can't connect to the database: %s" % e) # Get the currently installed version - returns None, 'win32' or the git hash # Also sets INSTALL_TYPE variable to 'win', 'git' or 'source' CURRENT_VERSION = versioncheck.getVersion() # Check for new versions if CHECK_GITHUB_ON_STARTUP: try: LATEST_VERSION = versioncheck.checkGithub() except: LATEST_VERSION = CURRENT_VERSION else: LATEST_VERSION = CURRENT_VERSION # Store the original umask UMASK = os.umask(0) os.umask(UMASK) __INITIALIZED__ = True return True
def initialize(): with INIT_LOCK: global __INITIALIZED__, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, \ HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, \ CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, \ ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, INCLUDE_EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, \ ADD_ALBUM_ART, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \ TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, MININOVA, DOWNLOAD_TORRENT_DIR, \ LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \ NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \ ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, \ ENCODERLOSSLESS, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, MIRRORLIST, MIRROR, CUSTOMHOST, CUSTOMPORT, \ CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY if __INITIALIZED__: return False # Make sure all the config sections exist CheckSection('General') CheckSection('SABnzbd') CheckSection('NZBMatrix') CheckSection('Newznab') CheckSection('NZBsorg') CheckSection('Newzbin') CheckSection('Prowl') CheckSection('XBMC') CheckSection('NMA') # Set global variables based on config file or use defaults CONFIG_VERSION = check_setting_str(CFG, 'General', 'config_version', '0') try: HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8181) except: HTTP_PORT = 8181 if HTTP_PORT < 21 or HTTP_PORT > 65535: HTTP_PORT = 8181 HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0') HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '') HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '') HTTP_ROOT = check_setting_str(CFG, 'General', 'http_root', '/') LAUNCH_BROWSER = bool( check_setting_int(CFG, 'General', 'launch_browser', 1)) API_ENABLED = bool(check_setting_int(CFG, 'General', 'api_enabled', 0)) API_KEY = check_setting_str(CFG, 'General', 'api_key', '') GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '') LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', '') CHECK_GITHUB = bool( check_setting_int(CFG, 'General', 'check_github', 1)) CHECK_GITHUB_ON_STARTUP = bool( check_setting_int(CFG, 'General', 'check_github_on_startup', 1)) CHECK_GITHUB_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360) MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '') DESTINATION_DIR = check_setting_str(CFG, 'General', 'destination_dir', '') PREFERRED_QUALITY = check_setting_int(CFG, 'General', 'preferred_quality', 0) PREFERRED_BITRATE = check_setting_int(CFG, 'General', 'preferred_bitrate', '') DETECT_BITRATE = bool( check_setting_int(CFG, 'General', 'detect_bitrate', 0)) ADD_ARTISTS = bool( check_setting_int(CFG, 'General', 'auto_add_artists', 1)) CORRECT_METADATA = bool( check_setting_int(CFG, 'General', 'correct_metadata', 0)) MOVE_FILES = bool(check_setting_int(CFG, 'General', 'move_files', 0)) RENAME_FILES = bool( check_setting_int(CFG, 'General', 'rename_files', 0)) FOLDER_FORMAT = check_setting_str(CFG, 'General', 'folder_format', 'Artist/Album [Year]') FILE_FORMAT = check_setting_str(CFG, 'General', 'file_format', 'Track Artist - Album [Year]- Title') CLEANUP_FILES = bool( check_setting_int(CFG, 'General', 'cleanup_files', 0)) ADD_ALBUM_ART = bool( check_setting_int(CFG, 'General', 'add_album_art', 0)) EMBED_ALBUM_ART = bool( check_setting_int(CFG, 'General', 'embed_album_art', 0)) EMBED_LYRICS = bool( check_setting_int(CFG, 'General', 'embed_lyrics', 0)) DOWNLOAD_DIR = check_setting_str(CFG, 'General', 'download_dir', '') BLACKHOLE = bool(check_setting_int(CFG, 'General', 'blackhole', 0)) BLACKHOLE_DIR = check_setting_str(CFG, 'General', 'blackhole_dir', '') USENET_RETENTION = check_setting_int(CFG, 'General', 'usenet_retention', '') INCLUDE_EXTRAS = bool( check_setting_int(CFG, 'General', 'include_extras', 0)) AUTOWANT_UPCOMING = bool( check_setting_int(CFG, 'General', 'autowant_upcoming', 1)) AUTOWANT_ALL = bool( check_setting_int(CFG, 'General', 'autowant_all', 0)) SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 360) LIBRARYSCAN_INTERVAL = check_setting_int(CFG, 'General', 'libraryscan_interval', 300) DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, 'General', 'download_scan_interval', 5) TORRENTBLACKHOLE_DIR = check_setting_str(CFG, 'General', 'torrentblackhole_dir', '') NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10') ISOHUNT = bool(check_setting_int(CFG, 'General', 'isohunt', 0)) KAT = bool(check_setting_int(CFG, 'General', 'kat', 0)) MININOVA = bool(check_setting_int(CFG, 'General', 'mininova', 0)) DOWNLOAD_TORRENT_DIR = check_setting_str(CFG, 'General', 'download_torrent_dir', '') SAB_HOST = check_setting_str(CFG, 'SABnzbd', 'sab_host', '') SAB_USERNAME = check_setting_str(CFG, 'SABnzbd', 'sab_username', '') SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '') SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '') SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', '') NZBMATRIX = bool(check_setting_int(CFG, 'NZBMatrix', 'nzbmatrix', 0)) NZBMATRIX_USERNAME = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_username', '') NZBMATRIX_APIKEY = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_apikey', '') NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0)) NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '') NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0)) NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') NZBSORG_HASH = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_hash', '') NEWZBIN = bool(check_setting_int(CFG, 'Newzbin', 'newzbin', 0)) NEWZBIN_UID = check_setting_str(CFG, 'Newzbin', 'newzbin_uid', '') NEWZBIN_PASSWORD = check_setting_str(CFG, 'Newzbin', 'newzbin_password', '') LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '') INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default') FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755') ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '') ENCODER = check_setting_str(CFG, 'General', 'encoder', 'ffmpeg') BITRATE = check_setting_int(CFG, 'General', 'bitrate', 192) SAMPLINGFREQUENCY = check_setting_int(CFG, 'General', 'samplingfrequency', 44100) MUSIC_ENCODER = bool( check_setting_int(CFG, 'General', 'music_encoder', 0)) ADVANCEDENCODER = check_setting_str(CFG, 'General', 'advancedencoder', '') ENCODEROUTPUTFORMAT = check_setting_str(CFG, 'General', 'encoderoutputformat', 'mp3') ENCODERQUALITY = check_setting_int(CFG, 'General', 'encoderquality', 2) ENCODERVBRCBR = check_setting_str(CFG, 'General', 'encodervbrcbr', 'cbr') ENCODERLOSSLESS = bool( check_setting_int(CFG, 'General', 'encoderlossless', 1)) PROWL_ENABLED = bool( check_setting_int(CFG, 'Prowl', 'prowl_enabled', 0)) PROWL_KEYS = check_setting_str(CFG, 'Prowl', 'prowl_keys', '') PROWL_ONSNATCH = bool( check_setting_int(CFG, 'Prowl', 'prowl_onsnatch', 0)) PROWL_PRIORITY = check_setting_int(CFG, 'Prowl', 'prowl_priority', 0) XBMC_ENABLED = bool(check_setting_int(CFG, 'XBMC', 'xbmc_enabled', 0)) XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '') XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '') XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '') XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0)) XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0)) NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0)) NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '') NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0) MIRROR = check_setting_str(CFG, 'General', 'mirror', 'musicbrainz.org') CUSTOMHOST = check_setting_str(CFG, 'General', 'customhost', 'localhost') CUSTOMPORT = check_setting_int(CFG, 'General', 'customport', 5000) CUSTOMSLEEP = check_setting_int(CFG, 'General', 'customsleep', 1) HPUSER = check_setting_str(CFG, 'General', 'hpuser', 'username') HPPASS = check_setting_str(CFG, 'General', 'hppass', 'password') # update folder formats in the config & bump up config version if CONFIG_VERSION == '0': from headphones.helpers import replace_all file_values = { 'tracknumber': 'Track', 'title': 'Title', 'artist': 'Artist', 'album': 'Album', 'year': 'Year' } folder_values = { 'artist': 'Artist', 'album': 'Album', 'year': 'Year', 'releasetype': 'Type', 'first': 'First', 'lowerfirst': 'first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '1' if CONFIG_VERSION == '1': from headphones.helpers import replace_all file_values = { 'Track': '$Track', 'Title': '$Title', 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'track': '$track', 'title': '$title', 'artist': '$artist', 'album': '$album', 'year': '$year' } folder_values = { 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'Type': '$Type', 'First': '$First', 'artist': '$artist', 'album': '$album', 'year': '$year', 'type': '$type', 'first': '$first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '2' if not LOG_DIR: LOG_DIR = os.path.join(DATA_DIR, 'logs') if not os.path.exists(LOG_DIR): try: os.makedirs(LOG_DIR) except OSError: if VERBOSE: print 'Unable to create the log directory. Logging to screen only.' # Start the logger, silence console logging if we need to logger.headphones_log.initLogger(verbose=VERBOSE) # Put the cache dir in the data dir for now CACHE_DIR = os.path.join(DATA_DIR, 'cache') if not os.path.exists(CACHE_DIR): try: os.makedirs(CACHE_DIR) except OSError: logger.error( 'Could not create cache dir. Check permissions of datadir: ' + DATA_DIR) # Initialize the database logger.info('Checking to see if the database has all tables....') try: dbcheck() except Exception, e: logger.error("Can't connect to the database: %s" % e) # Get the currently installed version - returns None, 'win32' or the git hash # Also sets INSTALL_TYPE variable to 'win', 'git' or 'source' CURRENT_VERSION = versioncheck.getVersion() # Check for new versions if CHECK_GITHUB_ON_STARTUP: try: LATEST_VERSION = versioncheck.checkGithub() except: LATEST_VERSION = CURRENT_VERSION else: LATEST_VERSION = CURRENT_VERSION __INITIALIZED__ = True return True
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] values = { '$Artist': artist, '$Album': album, '$Year': year, '$Type': releasetype, '$First': firstchar, '$artist': artist.lower(), '$album': album.lower(), '$year': year, '$type': releasetype.lower(), '$first': firstchar.lower() } folder = helpers.replace_all(headphones.FOLDER_FORMAT, values) folder = folder.replace('./', '_/').replace(':','_').replace('?','_').replace('/.','/_') if folder.endswith('.'): folder = folder.replace(folder[len(folder)-1], '_') if folder.startswith('.'): folder = folder.replace(0, '_') # Grab our list of files early on so we can determine if we need to create # the lossy_dest_dir, lossless_dest_dir, or both files_to_move = [] lossy_media = False lossless_media = False for r,d,f in os.walk(albumpath): for files in f: files_to_move.append(os.path.join(r, files)) if any(files.lower().endswith('.' + x.lower()) for x in headphones.LOSSY_MEDIA_FORMATS): lossy_media = True if any(files.lower().endswith('.' + x.lower()) for x in headphones.LOSSLESS_MEDIA_FORMATS): lossless_media = True # Do some sanity checking to see what directories we need to create: make_lossy_folder = False make_lossless_folder = False lossy_destination_path = os.path.normpath(os.path.join(headphones.DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING) lossless_destination_path = os.path.normpath(os.path.join(headphones.LOSSLESS_DESTINATION_DIR, folder)).encode(headphones.SYS_ENCODING) # If they set a destination dir for lossless media, only create the lossy folder if there is lossy media if headphones.LOSSLESS_DESTINATION_DIR: if lossy_media: make_lossy_folder = True if lossless_media: make_lossless_folder = True # If they haven't set a lossless dest_dir, just create the "lossy" folder else: make_lossy_folder = True last_folder = headphones.FOLDER_FORMAT.split('/')[-1] if make_lossless_folder: # Only rename the folder if they use the album name, otherwise merge into existing folder if os.path.exists(lossless_destination_path) and 'album' in last_folder.lower(): temp_folder = folder i = 1 while True: newfolder = temp_folder + '[%i]' % i lossless_destination_path = os.path.normpath(os.path.join(headphones.LOSSLESS_DESTINATION_DIR, newfolder)).encode(headphones.SYS_ENCODING) if os.path.exists(lossless_destination_path): i += 1 else: temp_folder = newfolder break if not os.path.exists(lossless_destination_path): try: os.makedirs(lossless_destination_path) except Exception, e: logger.error('Could not create lossless folder for %s. (Error: %s)' % (release['AlbumTitle'], e)) if not make_lossy_folder: return albumpath
def initialize(): with INIT_LOCK: global __INITIALIZED__, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, \ HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, \ CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, \ ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, INCLUDE_EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, \ ADD_ALBUM_ART, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \ TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, MININOVA, DOWNLOAD_TORRENT_DIR, \ LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \ NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, \ ENCODERFOLDER, ENCODER, BITRATE, SAMPLINGFREQUENCY, MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, \ ENCODERLOSSLESS, PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, MIRRORLIST, MIRROR, CUSTOMHOST, CUSTOMPORT, \ CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY if __INITIALIZED__: return False # Make sure all the config sections exist CheckSection('General') CheckSection('SABnzbd') CheckSection('NZBMatrix') CheckSection('Newznab') CheckSection('NZBsorg') CheckSection('Newzbin') CheckSection('Prowl') CheckSection('XBMC') CheckSection('NMA') # Set global variables based on config file or use defaults CONFIG_VERSION = check_setting_str(CFG, 'General', 'config_version', '0') try: HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8181) except: HTTP_PORT = 8181 if HTTP_PORT < 21 or HTTP_PORT > 65535: HTTP_PORT = 8181 HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0') HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '') HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '') HTTP_ROOT = check_setting_str(CFG, 'General', 'http_root', '/') LAUNCH_BROWSER = bool(check_setting_int(CFG, 'General', 'launch_browser', 1)) API_ENABLED = bool(check_setting_int(CFG, 'General', 'api_enabled', 0)) API_KEY = check_setting_str(CFG, 'General', 'api_key', '') GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '') LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', '') CHECK_GITHUB = bool(check_setting_int(CFG, 'General', 'check_github', 1)) CHECK_GITHUB_ON_STARTUP = bool(check_setting_int(CFG, 'General', 'check_github_on_startup', 1)) CHECK_GITHUB_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360) MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '') DESTINATION_DIR = check_setting_str(CFG, 'General', 'destination_dir', '') PREFERRED_QUALITY = check_setting_int(CFG, 'General', 'preferred_quality', 0) PREFERRED_BITRATE = check_setting_int(CFG, 'General', 'preferred_bitrate', '') DETECT_BITRATE = bool(check_setting_int(CFG, 'General', 'detect_bitrate', 0)) ADD_ARTISTS = bool(check_setting_int(CFG, 'General', 'auto_add_artists', 1)) CORRECT_METADATA = bool(check_setting_int(CFG, 'General', 'correct_metadata', 0)) MOVE_FILES = bool(check_setting_int(CFG, 'General', 'move_files', 0)) RENAME_FILES = bool(check_setting_int(CFG, 'General', 'rename_files', 0)) FOLDER_FORMAT = check_setting_str(CFG, 'General', 'folder_format', 'Artist/Album [Year]') FILE_FORMAT = check_setting_str(CFG, 'General', 'file_format', 'Track Artist - Album [Year]- Title') CLEANUP_FILES = bool(check_setting_int(CFG, 'General', 'cleanup_files', 0)) ADD_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'add_album_art', 0)) EMBED_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'embed_album_art', 0)) EMBED_LYRICS = bool(check_setting_int(CFG, 'General', 'embed_lyrics', 0)) DOWNLOAD_DIR = check_setting_str(CFG, 'General', 'download_dir', '') BLACKHOLE = bool(check_setting_int(CFG, 'General', 'blackhole', 0)) BLACKHOLE_DIR = check_setting_str(CFG, 'General', 'blackhole_dir', '') USENET_RETENTION = check_setting_int(CFG, 'General', 'usenet_retention', '') INCLUDE_EXTRAS = bool(check_setting_int(CFG, 'General', 'include_extras', 0)) AUTOWANT_UPCOMING = bool(check_setting_int(CFG, 'General', 'autowant_upcoming', 1)) AUTOWANT_ALL = bool(check_setting_int(CFG, 'General', 'autowant_all', 0)) SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 360) LIBRARYSCAN_INTERVAL = check_setting_int(CFG, 'General', 'libraryscan_interval', 300) DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, 'General', 'download_scan_interval', 5) TORRENTBLACKHOLE_DIR = check_setting_str(CFG, 'General', 'torrentblackhole_dir', '') NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10') ISOHUNT = bool(check_setting_int(CFG, 'General', 'isohunt', 0)) KAT = bool(check_setting_int(CFG, 'General', 'kat', 0)) MININOVA = bool(check_setting_int(CFG, 'General', 'mininova', 0)) DOWNLOAD_TORRENT_DIR = check_setting_str(CFG, 'General', 'download_torrent_dir', '') SAB_HOST = check_setting_str(CFG, 'SABnzbd', 'sab_host', '') SAB_USERNAME = check_setting_str(CFG, 'SABnzbd', 'sab_username', '') SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '') SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '') SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', '') NZBMATRIX = bool(check_setting_int(CFG, 'NZBMatrix', 'nzbmatrix', 0)) NZBMATRIX_USERNAME = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_username', '') NZBMATRIX_APIKEY = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_apikey', '') NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0)) NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '') NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0)) NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') NZBSORG_HASH = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_hash', '') NEWZBIN = bool(check_setting_int(CFG, 'Newzbin', 'newzbin', 0)) NEWZBIN_UID = check_setting_str(CFG, 'Newzbin', 'newzbin_uid', '') NEWZBIN_PASSWORD = check_setting_str(CFG, 'Newzbin', 'newzbin_password', '') LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '') INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default') FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755') ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '') ENCODER = check_setting_str(CFG, 'General', 'encoder', 'ffmpeg') BITRATE = check_setting_int(CFG, 'General', 'bitrate', 192) SAMPLINGFREQUENCY= check_setting_int(CFG, 'General', 'samplingfrequency', 44100) MUSIC_ENCODER = bool(check_setting_int(CFG, 'General', 'music_encoder', 0)) ADVANCEDENCODER = check_setting_str(CFG, 'General', 'advancedencoder', '') ENCODEROUTPUTFORMAT = check_setting_str(CFG, 'General', 'encoderoutputformat', 'mp3') ENCODERQUALITY = check_setting_int(CFG, 'General', 'encoderquality', 2) ENCODERVBRCBR = check_setting_str(CFG, 'General', 'encodervbrcbr', 'cbr') ENCODERLOSSLESS = bool(check_setting_int(CFG, 'General', 'encoderlossless', 1)) PROWL_ENABLED = bool(check_setting_int(CFG, 'Prowl', 'prowl_enabled', 0)) PROWL_KEYS = check_setting_str(CFG, 'Prowl', 'prowl_keys', '') PROWL_ONSNATCH = bool(check_setting_int(CFG, 'Prowl', 'prowl_onsnatch', 0)) PROWL_PRIORITY = check_setting_int(CFG, 'Prowl', 'prowl_priority', 0) XBMC_ENABLED = bool(check_setting_int(CFG, 'XBMC', 'xbmc_enabled', 0)) XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '') XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '') XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '') XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0)) XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0)) NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0)) NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '') NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0) MIRROR = check_setting_str(CFG, 'General', 'mirror', 'musicbrainz.org') CUSTOMHOST = check_setting_str(CFG, 'General', 'customhost', 'localhost') CUSTOMPORT = check_setting_int(CFG, 'General', 'customport', 5000) CUSTOMSLEEP = check_setting_int(CFG, 'General', 'customsleep', 1) HPUSER = check_setting_str(CFG, 'General', 'hpuser', 'username') HPPASS = check_setting_str(CFG, 'General', 'hppass', 'password') # update folder formats in the config & bump up config version if CONFIG_VERSION == '0': from headphones.helpers import replace_all file_values = { 'tracknumber': 'Track', 'title': 'Title','artist' : 'Artist', 'album' : 'Album', 'year' : 'Year' } folder_values = { 'artist' : 'Artist', 'album':'Album', 'year' : 'Year', 'releasetype' : 'Type', 'first' : 'First', 'lowerfirst' : 'first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '1' if CONFIG_VERSION == '1': from headphones.helpers import replace_all file_values = { 'Track': '$Track', 'Title': '$Title', 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'track': '$track', 'title': '$title', 'artist': '$artist', 'album': '$album', 'year': '$year' } folder_values = { 'Artist': '$Artist', 'Album': '$Album', 'Year': '$Year', 'Type': '$Type', 'First': '$First', 'artist': '$artist', 'album': '$album', 'year': '$year', 'type': '$type', 'first': '$first' } FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) CONFIG_VERSION = '2' if not LOG_DIR: LOG_DIR = os.path.join(DATA_DIR, 'logs') if not os.path.exists(LOG_DIR): try: os.makedirs(LOG_DIR) except OSError: if VERBOSE: print 'Unable to create the log directory. Logging to screen only.' # Start the logger, silence console logging if we need to logger.headphones_log.initLogger(verbose=VERBOSE) # Put the cache dir in the data dir for now CACHE_DIR = os.path.join(DATA_DIR, 'cache') if not os.path.exists(CACHE_DIR): try: os.makedirs(CACHE_DIR) except OSError: logger.error('Could not create cache dir. Check permissions of datadir: ' + DATA_DIR) # Initialize the database logger.info('Checking to see if the database has all tables....') try: dbcheck() except Exception, e: logger.error("Can't connect to the database: %s" % e) # Get the currently installed version - returns None, 'win32' or the git hash # Also sets INSTALL_TYPE variable to 'win', 'git' or 'source' CURRENT_VERSION = versioncheck.getVersion() # Check for new versions if CHECK_GITHUB_ON_STARTUP: try: LATEST_VERSION = versioncheck.checkGithub() except: LATEST_VERSION = CURRENT_VERSION else: LATEST_VERSION = CURRENT_VERSION __INITIALIZED__ = True return True
def searchNZB(albumid=None, new=False): myDB = db.DBConnection() if albumid: results = myDB.select( 'SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE Status="Wanted" AND AlbumID=?', [albumid]) else: results = myDB.select( 'SELECT ArtistName, AlbumTitle, AlbumID, ReleaseDate from albums WHERE Status="Wanted"' ) new = True for albums in results: albumid = albums[2] reldate = albums[3] try: year = reldate[:4] except TypeError: year = '' dic = { '...': '', ' & ': ' ', ' = ': ' ', '?': '', '$': 's', ' + ': ' ', '"': '', ',': '', '*': '' } cleanalbum = helpers.latinToAscii(helpers.replace_all(albums[1], dic)) cleanartist = helpers.latinToAscii(helpers.replace_all(albums[0], dic)) # FLAC usually doesn't have a year for some reason so I'll leave it out # Various Artist albums might be listed as VA, so I'll leave that out too # Only use the year if the term could return a bunch of different albums, i.e. self-titled albums if albums[0] in albums[1] or len(albums[0]) < 4 or len(albums[1]) < 4: term = cleanartist + ' ' + cleanalbum + ' ' + year elif albums[0] == 'Various Artists': term = cleanalbum + ' ' + year else: term = cleanartist + ' ' + cleanalbum # Replace bad characters in the term and unicode it term = re.sub('[\.\-\/]', ' ', term).encode('utf-8') artistterm = re.sub('[\.\-\/]', ' ', cleanartist).encode('utf-8') logger.info("Searching for %s since it was marked as wanted" % term) resultlist = [] if headphones.NZBMATRIX: provider = "nzbmatrix" if headphones.PREFERRED_QUALITY == 3: categories = "23" maxsize = 10000000000 elif headphones.PREFERRED_QUALITY: categories = "23,22" maxsize = 2000000000 else: categories = "22" maxsize = 300000000 params = { "page": "download", "username": headphones.NZBMATRIX_USERNAME, "apikey": headphones.NZBMATRIX_APIKEY, "subcat": categories, "age": headphones.USENET_RETENTION, "english": 1, "ssl": 1, "scenename": 1, "term": term } searchURL = "http://rss.nzbmatrix.com/rss.php?" + urllib.urlencode( params) logger.info(u'Parsing results from <a href="%s">NZBMatrix</a>' % searchURL) try: data = urllib2.urlopen(searchURL, timeout=20).read() except urllib2.URLError, e: logger.warn('Error fetching data from NZBMatrix: %s' % e) data = False if data: d = feedparser.parse(data) for item in d.entries: try: url = item.link title = item.title size = int(item.links[1]['length']) if size < maxsize: resultlist.append((title, size, url, provider)) logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size))) else: logger.info( '%s is larger than the maxsize for this category, skipping. (Size: %i bytes)' % (title, size)) except AttributeError, e: logger.info(u"No results found from NZBMatrix for %s" % term)