Skip to content
Snippets Groups Projects
SpotifyBackup.py 4.23 KiB
Newer Older
  • Learn to ignore specific revisions
  • Robert Goldmann's avatar
    Robert Goldmann committed
    import csv
    import json
    import logging
    import os
    import sys
    from datetime import datetime
    
    import spotipy
    from spotipy.oauth2 import SpotifyClientCredentials
    
    
    def prepare_logging() -> logging.Logger:
        LOG_FORMAT = '[%(levelname)-7s] - %(asctime)s - %(message)s'
        DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
    
        LOG_FORMATTER = logging.Formatter(fmt=LOG_FORMAT, datefmt=DATE_FORMAT)
    
        logger = logging.getLogger('SpotifyBackup')
        logger.setLevel(logging.DEBUG)
    
        outHandler = logging.StreamHandler(sys.stdout)
        outHandler.setFormatter(LOG_FORMATTER)
        outHandler.setLevel(logging.DEBUG)
        outHandler.addFilter(lambda record: record.levelno <= logging.INFO)
        logger.addHandler(outHandler)
    
        errHandler = logging.StreamHandler(sys.stderr)
        errHandler.setFormatter(LOG_FORMATTER)
        errHandler.setLevel(logging.WARNING)
        logger.addHandler(errHandler)
        return logger
    
    
    LOGGER = prepare_logging()
    
    
    class SpotifyBackup:
        DATE_FORMAT = '%Y-%m-%d_%H-%M-%S'
        INVALID_CHARS = [' ', '\t', '\n']
        REPLACE_CHAR = '_'
    
        def __init__(self, clientID: str, clientSecret: str, exportFolder: str):
            self._exportFolder = exportFolder
            if self._exportFolder:
                os.makedirs(self._exportFolder, exist_ok=True)
    
            client_credentials_manager = SpotifyClientCredentials(client_id=clientID, client_secret=clientSecret)
            self._spotify = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
    
        def backup_playlist(self, username: str, playlistID: str):
            playlist = self.__get_playlist(username, playlistID)
            tracks = self.__get_tracks(playlist)
    
            exportPath = self.__determine_export_path(playlist['name'])
    
            LOGGER.info(f'Exporting tracks to "{exportPath}"...')
            self.__export_csv(exportPath, tracks)
            LOGGER.info('Exporting DONE')
    
        def __get_playlist(self, username: str, playlistID: str):
            LOGGER.info(f'Fetching playlist with ID: {playlistID} by {username}...')
            identifier = f'spotify:user:{username}:playlist:{playlistID}'
            playlist = self._spotify.playlist(identifier)
            LOGGER.info(f'Found playlist "{playlist["name"]}"')
            return playlist
    
        def __get_tracks(self, playlist):
            tracks = playlist['tracks']
            results = tracks['items']
            while tracks['next']:
                tracks = self._spotify.next(tracks)
                results.extend(tracks['items'])
    
            LOGGER.info(f'Fetched {len(results)} tracks')
            return results
    
        def __determine_export_path(self, playlistName):
            for item in self.INVALID_CHARS:
                playlistName = playlistName.replace(item, self.REPLACE_CHAR)
            fileName = f'{datetime.strftime(datetime.now(), self.DATE_FORMAT)}_{playlistName}.csv'
            exportPath = os.path.join(self._exportFolder, fileName)
            return exportPath
    
        def __export_csv(self, exportPath, tracks):
            with open(exportPath, 'w', newline='', encoding='utf-8') as f:
                writer = csv.writer(f, delimiter=';', quotechar='|', quoting=csv.QUOTE_MINIMAL)
                writer.writerow(('title', 'artists', 'album', 'addedBy', 'addedAt', 'url'))
    
                for track in tracks:
                    try:
                        trackInfo = track['track']
                        title = trackInfo['name']
                        artists = trackInfo['artists']
                        artists = ' & '.join(artist['name'] for artist in artists)
                        album = trackInfo['album']['name']
                        author = track['added_by']['id']
                        addedAt = track['added_at']
                        url = trackInfo['external_urls'].get('spotify', '')
    
                        writer.writerow((title, artists, album, author, addedAt, url))
                    except Exception:
                        LOGGER.exception(f'Error while exporting track "{track}"')
    
    
    if __name__ == '__main__':
        with open('settings.json', 'r', encoding='utf-8') as f:
            SETTINGS = json.load(f)
    
        spotifyBackup = SpotifyBackup(SETTINGS['spotifyAPI']['clientID'],
                                      SETTINGS['spotifyAPI']['clientSecret'],
                                      SETTINGS['exportFolder'])
    
        for playlist in SETTINGS['playlists']:
            spotifyBackup.backup_playlist(playlist['user'], playlist['id'])
    
        LOGGER.info('### DONE ###')