class Controller: 'The controller implements all application logic.' def __init__(self, arguments): 'Main entry point for iTunes-Discogs.' self.arguments = arguments self.config = Config(arguments.home) self.model = Model(self.config, arguments.database) self.itunes = iTunes(self.model, arguments.library) self.discogs = Discogs(self.model, arguments.junk) if arguments.cli: if not arguments.playlist: arguments.playlist = 'Library' for playlist in self.get_playlists().values(): if playlist.Name == arguments.playlist: self._process_playlist(playlist) else: Window(self) self.shutdown() def search(self, track): 'Search storing results in the database.' track.search = self.discogs.search(track.Artist, track.Name) if track.search: self.model.set_bundle('track.search', track.PersistentID, track.search._id) if track.search.raw_results and not track.release: self.set_release(track, track.search.raw_results[0]) def set_release(self, track, result): 'Sets the track release to the specified result.' track.release = self.discogs.get_release(result) if track.release: self.model.set_bundle('track.release', track.PersistentID, track.release._id) def _process_playlist(self, playlist): 'Resolve releases for the specified playlist.' for tid in playlist.Items: track = self.get_track(tid) if not track.release: self.search(track) if track.search and track.search.results(): self.set_release(track, track.search.results()[0]) def shutdown(self): 'Shutdown the worker thread and flush the database.' self.model.flush(self.arguments.database) def get_tracks(self): return self.itunes.library.tracks def get_track(self, tid): return self.get_tracks()[tid] def get_playlists(self): return self.itunes.library.playlists def get_playlist(self, pid): return self.get_playlists()[pid]
def __init__(self, path_to_excel, debug=False): self.excel = FilenameExcel(path_to_excel) self.file_list = self.excel.get_rows() self.discogs_client = Discogs() self.filtered_list = [] self.full_properties_list = [] self.no_properties_found_list = [] self.debug = debug self.sleep_seconds = 3
def __init__(self, arguments): 'Main entry point for iTunes-Discogs.' self.arguments = arguments self.config = Config(arguments.home) self.model = Model(self.config, arguments.database) self.itunes = iTunes(self.model, arguments.library) self.discogs = Discogs(self.model, arguments.junk) if arguments.cli: if not arguments.playlist: arguments.playlist = 'Library' for playlist in self.get_playlists().values(): if playlist.Name == arguments.playlist: self._process_playlist(playlist) else: Window(self) self.shutdown()
def __init__(self, filepath, delimiter=',', encoding='utf-8', quotechar='"'): self.discogs = Discogs() self.filepath = filepath self.delimiter = delimiter self.encoding = encoding self.quotechar = quotechar self.search_terms = ('title', 'artist', 'format', 'album', 'label', 'year') self.output_csv = 'output.csv' if not os.path.exists('images/'): os.mkdir('images/') self.image_path = 'images/' self.get_columns() self.get_param_dict()
def update_playlist(playlist, logger=None): """ Reads a playlist and attempts to find accurate release data on each song. """ hist = History('history.p') d = Discogs(logger=logger) for song in read_playlist(playlist): if hist.check_recent(song.loc): continue try: artist = song.meta.tag.artist songname = song.meta.tag.title except AttributeError: continue release = d.get_first_release(artist, songname) if release: update = build_update(songname, release) song.update_info(update) song.save() hist.store(song.loc)
def _save_members(self, artist, metadata): for d in metadata.get('members', []): member_metadata = Discogs.get_resource(d['resource_url']) try: member = Artist.objects.get(discogs_id=int(d['id'])) except Artist.DoesNotExist: member = Artist.objects.create(discogs_id=int(d['id']), name=d['name']) member_metadata = self._save_images(member, member_metadata) member.about = member_metadata.get('profile') member_metadata = self._remove_metadata_keys(member_metadata) member.set_metadata_object(member_metadata) member.save() ArtistMembership.objects.create(artist=artist, member=member, active=d['active']) artist.save() metadata = self._remove_metadata_keys(metadata) return metadata
def save(self): data = self.cleaned_data new = True metadata = Discogs.get_resource(data['resource_url']) try: artist = Artist.objects.get(discogs_id=metadata['id']) new = False except Artist.DoesNotExist: artist = Artist.objects.create(discogs_id=metadata['id'], name=metadata['name'], about=metadata.get('profile')) self.is_new = new if not new: return artist metadata = self._save_images(artist, metadata) metadata = self._save_members(artist, metadata) artist.set_metadata_object(metadata) artist.save() return artist
class Converter(object): def __init__(self, path_to_excel, debug=False): self.excel = FilenameExcel(path_to_excel) self.file_list = self.excel.get_rows() self.discogs_client = Discogs() self.filtered_list = [] self.full_properties_list = [] self.no_properties_found_list = [] self.debug = debug self.sleep_seconds = 3 def filter_doubles(self): last_file = None for file in self.file_list: filename = file[0] if filename[:-2] == last_file: # This one needs to be filtered out and the duration added to the previous one. self.filtered_list[-1][1].add_duration(Duration(file[1])) else: self.filtered_list.append([file[0], Duration(file[1])]) last_file = filename[:-2] def add_search_terms(self): if not self.filtered_list: raise ValueError( "filtered_list is still empty. Did you initialize it yet?") for file in self.filtered_list: filename = file[0] # Remove everything after the third last point (extension...) filename_splitted = filename.split('.') search_term = '.'.join(filename_splitted[:-3]) #search_term = filename.split('.', 1)[0] # Convert underscores to spaces search_term = search_term.replace("_", " ") search_term = search_term.replace("-", " ") search_term = search_term.replace("'", "") # remove trailing numbers or spaces. search_term = re.sub(r'^[ \d\.]*', '', search_term) file.append(search_term) def find_track_in_tracklist(self, file, tracks): best_matches = get_close_matches(file[2], tracks) if not best_matches: # Try again with less match terms. filename_without_extension = file[0].split('.', 1)[0] if '_' in filename_without_extension: # Split into pieces new_search_terms = filename_without_extension.split('_') for search_term in new_search_terms: best_matches = get_close_matches(search_term, tracks) if best_matches: break elif '-' in filename_without_extension: # split into pieces new_search_terms = filename_without_extension.split('-') for search_term in new_search_terms: best_matches = get_close_matches(search_term, tracks) if best_matches: break else: # last resort, just split into pieces with spaces new_search_terms = file[2].split(' ') for search_term in new_search_terms: best_matches = get_close_matches(search_term, tracks) if best_matches: break if best_matches: track_title = best_matches[0] return track_title return False @staticmethod def build_tracklist(tracklist): expanded_tracklist = [] for track in tracklist: if 'sub_tracks' in track.data.keys(): # We're dealing with subtracks. Unpack them. for sub_track in track.data['sub_tracks']: expanded_tracklist.append(sub_track) else: expanded_tracklist.append(track.data) return expanded_tracklist def find_properties_with_item(self, file): results = self.discogs_client.search_release(file[2]) print(file[2]) retries = 0 while True: try: # Get the first result, we feel always lucky if not results: # Try with the search term without parentheses content. results = self.discogs_client.search_release( re.sub(r'\(.*\)', '', file[2])) if not results: # Nothing found for this search term, return an empty properties dict with only the filename print("Didn't find any results from discogs") properties = {} properties['Titel'] = file[0] properties['Uitvoerder'] = '' properties['Componist'] = '' properties['Duurtijd'] = '' properties['Label'] = '' return properties release = results[0] break except: # sleep 3 seconds and try again time.sleep(self.sleep_seconds) print("I have tried {0} times for {1} seconds".format( retries, self.sleep_seconds)) if retries > 5: raise RuntimeError( "Cannot get search results after 6 retries!") retries = 0 while True: try: release_tracklist = release.tracklist break except: # sleep 3 seconds and try again time.sleep(self.sleep_seconds) print("I have tried {0} times for {1} seconds".format( retries, self.sleep_seconds)) if retries > 5: raise RuntimeError("Cannot get tracklist after 6 retries!") print("Failed fetching the tracklist. Retry") tracklist = self.build_tracklist(release_tracklist) tracks = [track['title'] for track in tracklist] if self.debug: print("release data and tracks data") print(release.data) print(tracks) track_name = self.find_track_in_tracklist(file, tracks) if not track_name: # If there's still no track found. It might be because the tracklist contains text between () which we don't like! # get this text out and repeat. tracks = [ re.sub(r'\(.*\)', '', track['title']) for track in tracklist ] track_name = self.find_track_in_tracklist(file, tracks) if not track_name: # Nothing found for this search term, return an empty properties dict with only the filename print("Didn't find the correct track!") properties = {} properties['Titel'] = file[0] properties['Uitvoerder'] = '' properties['Componist'] = '' properties['Duurtijd'] = '' properties['Label'] = '' return properties else: for track in tracklist: track_title = re.sub(r'\(.*\)', '', track['title']) if track_title == track_name: break else: for track in tracklist: if track['title'] == track_name: break properties = {} properties['Titel'] = track['title'] properties['Uitvoerder'] = ",".join( set([artist.name for artist in release.artists])) # Get all the writers writers = [] if 'extraartists' in track.keys(): for extra_artist in track['extraartists']: if extra_artist['role'] == 'Written-By' or extra_artist[ 'role'] == 'Written-By, Composed By': writers.append(extra_artist['name']) # if no writers found on the track. Let's get the writers of the release if not writers: if 'extraartists' in release.data.keys(): for extra_artist in release.data['extraartists']: if extra_artist['role'] == 'Written-By' or extra_artist[ 'role'] == 'Written-By, Composed By': writers.append(extra_artist['name']) properties['Componist'] = ",".join(set(writers)) properties['Duurtijd'] = file[1].get_in_minutes_seconds() properties['Label'] = ",".join( set([label.name for label in release.labels])) print(properties) return properties def convert_to_full_properties(self): for file in self.filtered_list: print(file[0]) properties = self.find_properties_with_item(file) if properties: self.full_properties_list.append(properties) else: # No properties found. Append it to another list. self.no_properties_found_list.append(file) # Sleep 1 second because the discogs api doesn't like us time.sleep(1) def export_to_csv(self, file_path, csv_columns=None): if not csv_columns: csv_columns = [ 'Volgnummer', 'Tijdscode', 'Titel', 'Aard', 'Performance', 'Componist', 'Uitvoerder', 'Duurtijd', 'Rechthebbende', 'Hoedanigheid', 'Jaar', 'ISRC', 'Label', 'Album', 'Cat Nr', 'Track' ] try: with open(file_path, 'w') as csv_file: writer = csv.DictWriter(csv_file, fieldnames=csv_columns) writer.writeheader() for data in self.full_properties_list: writer.writerow(data) except IOError: print("I/O error") def export_to_excel(self, file_path, excel_columns=None): if not excel_columns: excel_columns = [ 'Volgnummer', 'Tijdscode', 'Titel', 'Aard', 'Performance', 'Componist', 'Uitvoerder', 'Duurtijd', 'Rechthebbende', 'Hoedanigheid', 'Jaar', 'ISRC', 'Label', 'Album', 'Cat Nr', 'Track' ] excel_writer = ExcelWriter(file_path) excel_writer.create_excel(self.full_properties_list, excel_columns)
import logging import traceback folders = Folder(ENV_PATHS) # print(style.green('\n' + MY_PATH)) for folder in folders: print(style.yellow('\n---\n')) print(style.green(folder)) print() files = File(folder) try: discogs = Discogs(files) except Exception as e: print(style.red('some error happened...')) logging.error(traceback.format_exc()) continue if discogs == ENV_TAGGING_DONE: print(style.yellow(ENV_TAGGING_DONE)) continue if discogs == ENV_TAGGING_TODO: print(style.yellow(ENV_TAGGING_TODO)) continue Tagger(files, discogs)
class ImageScraper: """ Takes CSV file of music releases and searches Discogs API for cover image. Creates a dictionary mapping the column headers to search terms which can be customized. Cover images are saved in 'images' directory using the cover id from Discogs. Creates an output CSV copying each row and adding the cover id of 'Null' if nothing found. """ def __init__(self, filepath, delimiter=',', encoding='utf-8', quotechar='"'): self.discogs = Discogs() self.filepath = filepath self.delimiter = delimiter self.encoding = encoding self.quotechar = quotechar self.search_terms = ('title', 'artist', 'format', 'album', 'label', 'year') self.output_csv = 'output.csv' if not os.path.exists('images/'): os.mkdir('images/') self.image_path = 'images/' self.get_columns() self.get_param_dict() def get_columns(self): """ Returns the columns from CSV file as a list """ with open(self.filepath, 'r', encoding=self.encoding) as file: csv_reader = csv.reader(file, delimiter=self.delimiter, quotechar=self.quotechar) headers = next(csv_reader) self.columns = [col for col in headers] def get_param_dict(self): self.param_dict = {} for i, col in enumerate(self.columns): for param in self.search_terms: if col.lower() == param: self.param_dict[param] = i def confirm_dict(self): update_dict = True while update_dict: for param, col in self.param_dict.items(): print(f'{param} found in column {col}') print('\nTo procede with these settings press Enter.') print('To add an item enter the header-text then col eg: title 1.') print('To delete an item enter the item eg: artist.') update_dict = input('> ') if update_dict: if len(update_dict.split()) == 2: param, col = update_dict.split() self.param_dict[param] = int(col) elif len(update_dict.split()) == 1: del self.param_dict[update_dict] else: print("I didn't understand that, please try again.") def get_search_params(self, row): """ Takes row from csv file and returns a dictionary mapping the search parameters to their values """ params = {} for k, v in self.param_dict.items(): params[k] = row[v].replace(" ", "+") return params def run(self): with open(filepath, 'r', encoding=self.encoding) as input_file: csv_reader = csv.reader(input_file, delimiter=self.delimiter) next(csv_reader) for row in csv_reader: params = self.get_search_params(row) try: response, cover_id = self.discogs.search(params) with open(self.output_csv, 'a') as output_file: output_csv = csv.writer(output_file) output_csv.writerow(row + [cover_id]) with open(self.image_path + cover_id + '.jpg', 'wb') as f: shutil.copyfileobj(response.raw, f) del response except TypeError: with open(self.output_csv, 'a') as output_file: output_csv = csv.writer(output_file) output_csv.writerow(row + ['Null']) time.sleep(1.2)
def main(): if "--version" in sys.argv[1:] or "-v" in sys.argv[1:]: print(f"ytam version {version.version}") exit() if "--check" in sys.argv[1:] or "-k" in sys.argv[1:]: print("Initialising.") urls = Playlist( "https://www.youtube.com/playlist?list=PLOoPqX_q5JAVPMhHjYxcUc2bxTDMyGE-a" ) playlist_title = urls.title start = 0 end = len(urls) album = "Test Album" directory = f"music{SEP}" artist = "Test Artist" is_album = True proxies = None image = f"{BASE}{SEP}check{SEP}check.jpg" titles = f"{BASE}{SEP}check{SEP}check.txt" mp3 = True else: print("Initialising.") args = parse_args(sys.argv[1:]) mp3 = args.mp3 urls = Playlist(args.url) playlist_title = urls.title start = 0 if args.start is None else args.start - 1 end = len(urls) if args.end is None else args.end directory = f"music{SEP}" if args.directory is None else args.directory proxies = None if args.proxy is not None: proxy_strings = [proxy.strip() for proxy in args.proxy.split(" ")] proxies = {} for proxy_string in proxy_strings: p = proxy_string.split("-") proxies[p[0]] = p[1] if args.discogs is not None: # do discogs error checks here try: d = Discogs(args.discogs) d.make_file(DEFAULT_TITLES) if (end - start) != d.num_tracks: raise error.TracknumberMismatchError( playlist_title, d.album) is_album = True album = d.album artist = d.artist image = d.image titles = DEFAULT_TITLES except (error.WrongMetadataLinkError, error.BrokenDiscogsLinkError, error.TracknumberMismatchError) as e: print(f"Error: {e.message}") exit() else: album = playlist_title if args.album is None else args.album artist = "Unknown" if args.artist is None else args.artist is_album = False if args.album is None else True image = args.image titles = args.titles colorama.init() d = None try: if start >= len(urls): raise error.InvalidPlaylistIndexError(start, playlist_title) if end < start: raise error.IndicesOutOfOrderError() downloading_message = f"Downloading songs {font.apply('gb', start+1)} - {font.apply('gb', end)} from playlist {font.apply('gb', playlist_title)}" text_len = (len("Downloading songs ") + len(str(start)) + len(" - ") + len(str(end)) + len(" from playlist ") + len(playlist_title)) print(downloading_message, f"\n{font.apply('gb', '─'*text_len)}") d = Downloader( list(enumerate(urls[start:end])), len(urls), album, directory, artist, is_album, titles, image, proxies, mp3, ) d.start = start retry = True while retry: d.download() print(f"{font.apply('gb', '─'*text_len)}") print( f"{d.successful}/{len(urls[start:end])} downloaded successfully.\n" ) if len(d.retry_urls) > 0: d.set_retries() urls_copy = d.urls.copy() user = input( f"Retry {font.apply('fb', str(len(list(urls_copy))) + ' failed')} downloads? Y/N " ) if not is_affirmative(user): retry = False else: print("\nRetrying.") print(f"{font.apply('gb', '─'*len('Retrying.'))}") else: retry = False except ( error.InvalidPlaylistIndexError, error.IndicesOutOfOrderError, error.TitlesNotFoundError, error.BadTitleFormatError, ) as e: print(f"Error: {e.message}")
from discord.ext import commands import random import requests discordToken = "" filename = "D:/Repos/AudioManiac-Bot/credentials.json" if filename: with open(filename, 'r') as f: data = json.load(f) discordToken = data["discordtoken"] yt = Youtube() yt.Init() dscgs = Discogs() dscgs.Init() description = "An example bot to showcase the discord.ext.commands extension module." bot = commands.Bot(command_prefix='?', description=description) @bot.event async def on_ready(): print('Logged in as') print(bot.user.name) print(bot.user.id) print('------') @bot.command()