diff --git a/.gitignore b/.gitignore index 1d8cdf7ce5b95878e19c15637a28071d4a5f0891..82abe5994053479d3db95488b91f79b132d94ea2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,12 @@ exports/ config/settings.json config/settings-import.json -config/settings-creator.json +config/settings-creator-latest.json +config/settings-creator-random.json config/settings-recorder.json .cache .cache_creator .cache_recorder +.cache_spotify_creator recorder/ diff --git a/SpotifyAutoPlaylistCreator.py b/SpotifyAutoPlaylistCreator.py index d27bbff83fd7446feeee8d38ad2c80ad6db52107..7eb826bdaaa82a6533101cfc3dfa8dc64e0eefd6 100644 --- a/SpotifyAutoPlaylistCreator.py +++ b/SpotifyAutoPlaylistCreator.py @@ -1,6 +1,8 @@ import json +import random from typing import Dict, List +import click import spotipy from TheCodeLabs_BaseUtils.DefaultLogger import DefaultLogger from spotipy import CacheFileHandler @@ -10,12 +12,17 @@ LOG_FORMAT = '[%(levelname)-7s] - %(asctime)s - %(message)s' LOGGER = DefaultLogger().create_logger_if_not_exists('SpotifyAutoPlaylistCreator', logFormat=LOG_FORMAT) +MODE_LATEST = 'LATEST' +MODE_RANDOM = 'RANDOM' + + class SpotifyAutoPlaylistCreator: def __init__(self, clientID: str, clientSecret: str, playlistInfo: List[Dict[str, str]], destinationPlaylistInfo: Dict[str, str], numberOfTracks: int, + mode: str, redirectUrl: str, openBrowser: bool, cacheFilePath: str): @@ -24,6 +31,7 @@ class SpotifyAutoPlaylistCreator: self._playlistInfo = playlistInfo self._destinationPlaylistInfo = destinationPlaylistInfo self._numberOfTracks = numberOfTracks + self._mode = mode self._redirectUrl = redirectUrl self._openBrowser = openBrowser self._cacheFilePath = cacheFilePath @@ -47,10 +55,19 @@ class SpotifyAutoPlaylistCreator: LOGGER.info(f'>>> Fetching tracks for all source playlists...') allTracks = [] - for playlistInfo in SETTINGS['playlists']: + for playlistInfo in self._playlistInfo: playlist = self.__get_playlist(playlistInfo['user'], playlistInfo['id']) allTracks.extend(self.__get_tracks(playlist)) + LOGGER.info(f'>>> Run mode {self._mode}...') + if self._mode == MODE_LATEST: + self.__RunModeLatestTracks(allTracks, destinationPlaylist) + elif self._mode == MODE_RANDOM: + self.__RunModeRandom(allTracks, destinationPlaylist) + else: + raise RuntimeError(f'Unknown mode {self._mode}') + + def __RunModeLatestTracks(self, allTracks: List, destinationPlaylist) -> None: sortedTracks = sorted(allTracks, key=lambda d: d['added_at'], reverse=True) LOGGER.info(f'>>> Collecting latest tracks (limit: {self._numberOfTracks})...') @@ -61,6 +78,20 @@ class SpotifyAutoPlaylistCreator: LOGGER.info(f'>>> Adding tracks to destination playlist "{destinationPlaylist["name"]}"...') self._spotify.playlist_add_items(self._destinationPlaylistInfo['id'], latestTrackUris) + def __RunModeRandom(self, allTracks: List, destinationPlaylist) -> None: + randomTracks = [] + filteredTracks = [t for t in allTracks if not t['is_local']] + + while len(randomTracks) < self._numberOfTracks: + numberOfExercisesToGenerate = self._numberOfTracks - len(randomTracks) + randomTracks.extend(random.sample(filteredTracks, min(len(filteredTracks), numberOfExercisesToGenerate))) + + LOGGER.info(f'>>> Found {len(randomTracks)} random tracks (limit: {self._numberOfTracks})') + + LOGGER.info(f'>>> Adding tracks to destination playlist "{destinationPlaylist["name"]}"...') + randomTrackUris = self.__extract_track_uris(randomTracks) + self._spotify.playlist_add_items(self._destinationPlaylistInfo['id'], randomTrackUris) + def __CollectLatestTracks(self, sortedTracks): tracksToAdd = [] for track in sortedTracks: @@ -83,7 +114,8 @@ class SpotifyAutoPlaylistCreator: LOGGER.info(f'>>> Removing {len(existingTracks)} tracks from destination ' f'playlist "{destinationPlaylist["name"]}"...') existingTracksUris = self.__extract_track_uris(existingTracks) - self._spotify.playlist_remove_all_occurrences_of_items(self._destinationPlaylistInfo['id'], existingTracksUris) + if existingTracksUris: + self._spotify.playlist_remove_all_occurrences_of_items(self._destinationPlaylistInfo['id'], existingTracksUris) def __get_playlist(self, username: str, playlistID: str) -> Dict: LOGGER.info(f'>>> Fetching playlist with ID: {playlistID} by {username}...') @@ -107,8 +139,10 @@ class SpotifyAutoPlaylistCreator: return [track['track']['uri'] for track in tracks] -if __name__ == '__main__': - with open('config/settings-creator.json', 'r', encoding='utf-8') as f: +@click.command() +@click.option('--settings-path', '-s', 'settingsPath', help='Path to the settings file.', required=True) +def start(settingsPath) -> None: + with open(settingsPath, 'r', encoding='utf-8') as f: SETTINGS = json.load(f) spotifyBackup = SpotifyAutoPlaylistCreator(SETTINGS['spotifyAPI']['clientID'], @@ -116,6 +150,7 @@ if __name__ == '__main__': SETTINGS['playlists'], SETTINGS['destinationPlaylist'], SETTINGS['numberOfTracks'], + SETTINGS['mode'], SETTINGS['redirectUrl'], SETTINGS['openBrowser'], SETTINGS['cacheFilePath']) @@ -123,3 +158,7 @@ if __name__ == '__main__': spotifyBackup.run() LOGGER.info('### DONE ###') + + +if __name__ == '__main__': + start() diff --git a/config/settings-creator-example.json b/config/settings-creator-example.json index 1979a8e14ba888781550de21c2807af3133b7c77..43fe304854a051923900d7e744b2701905b83240 100644 --- a/config/settings-creator-example.json +++ b/config/settings-creator-example.json @@ -18,5 +18,6 @@ "numberOfTracks": 10, "redirectUrl": "http://localhost:8080", "openBrowser": false, - "cacheFilePath": ".cache" + "cacheFilePath": ".cache", + "mode": "LATEST or RANDOM" } \ No newline at end of file