From 8afdfc7042504731e76f1604187ada318c3ab8b8 Mon Sep 17 00:00:00 2001 From: RemixDev Date: Fri, 14 Aug 2020 20:31:37 +0200 Subject: [PATCH] Started reworking the library --- deemix/__main__.py | 11 ++- deemix/app/Settings.py | 168 +++++++++++++++++++++++++++++++++++++ deemix/app/__init__.py | 4 + deemix/app/default.json | 75 ----------------- deemix/app/settings.py | 103 ----------------------- deemix/utils/localpaths.py | 6 +- deemix/utils/misc.py | 9 -- deemix/utils/taggers.py | 20 ++++- 8 files changed, 199 insertions(+), 197 deletions(-) create mode 100644 deemix/app/Settings.py delete mode 100644 deemix/app/default.json delete mode 100644 deemix/app/settings.py diff --git a/deemix/__main__.py b/deemix/__main__.py index 029cecd..df63226 100644 --- a/deemix/__main__.py +++ b/deemix/__main__.py @@ -4,6 +4,12 @@ import click import deemix.app.cli as app from deemix.app.settings import initSettings from os.path import isfile +import random +import string + +def randomString(stringLength=8): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(stringLength)) @click.command() @@ -26,8 +32,5 @@ def download(bitrate, local, url): if local: click.echo(settings['downloadLocation']) #folder name output -def main(): - download() - if __name__ == '__main__': - main() + download() diff --git a/deemix/app/Settings.py b/deemix/app/Settings.py new file mode 100644 index 0000000..52628b9 --- /dev/null +++ b/deemix/app/Settings.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +import json +import os.path as path +from os import makedirs, listdir, remove +from deemix import __version__ as deemixVersion +import logging +import datetime +import platform + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger('deemix') + +import deemix.utils.localpaths as localpaths + +class Settings: + def __init__(self, configFolder=None): + self.settings = {} + self.configFolder = configFolder + if not self.configFolder: + self.configFolder = localpaths.getConfigFolder() + self.defaultSettings = { + "downloadLocation": path.join(localpaths.getHomeFolder(), 'deemix Music'), + "tracknameTemplate": "%artist% - %title%", + "albumTracknameTemplate": "%tracknumber% - %title%", + "playlistTracknameTemplate": "%position% - %artist% - %title%", + "createPlaylistFolder": True, + "playlistNameTemplate": "%playlist%", + "createArtistFolder": False, + "artistNameTemplate": "%artist%", + "createAlbumFolder": True, + "albumNameTemplate": "%artist% - %album%", + "createCDFolder": True, + "createStructurePlaylist": False, + "createSingleFolder": False, + "padTracks": True, + "paddingSize": "0", + "illegalCharacterReplacer": "_", + "queueConcurrency": 3, + "maxBitrate": "3", + "fallbackBitrate": True, + "fallbackSearch": False, + "logErrors": True, + "logSearched": False, + "saveDownloadQueue": False, + "overwriteFile": "n", + "createM3U8File": False, + "playlistFilenameTemplate": "playlist", + "syncedLyrics": False, + "embeddedArtworkSize": 800, + "localArtworkSize": 1400, + "localArtworkFormat": "jpg", + "saveArtwork": True, + "coverImageTemplate": "cover", + "saveArtworkArtist": False, + "artistImageTemplate": "folder", + "jpegImageQuality": 80, + "dateFormat": "Y-M-D", + "albumVariousArtists": True, + "removeAlbumVersion": False, + "removeDuplicateArtists": False, + "featuredToTitle": "0", + "titleCasing": "nothing", + "artistCasing": "nothing", + "executeCommand": "", + "tags": { + "title": True, + "artist": True, + "album": True, + "cover": True, + "trackNumber": True, + "trackTotal": False, + "discNumber": True, + "discTotal": False, + "albumArtist": True, + "genre": True, + "year": True, + "date": True, + "explicit": False, + "isrc": True, + "length": True, + "barcode": True, + "bpm": True, + "replayGain": False, + "label": True, + "lyrics": False, + "copyright": False, + "composer": False, + "involvedPeople": False, + "savePlaylistAsCompilation": False, + "useNullSeparator": False, + "saveID3v1": True, + "multiArtistSeparator": "default", + "singleAlbumArtist": False + } + } + + # Create config folder if it doesn't exsist + makedirs(self.configFolder, exist_ok=True) + + # Create config file if it doesn't exsist + if not path.isfile(path.join(self.configFolder, 'config.json')): + with open(path.join(self.configFolder, 'config.json'), 'w') as f: + json.dump(self.defaultSettings, f, indent=2) + + # Read config file + with open(path.join(self.configFolder, 'config.json'), 'r') as configFile: + self.settings = json.load(configFile) + + self.settingsCheck() + + # Make sure the download path exsits + makedirs(self.settings['downloadLocation'], exist_ok=True) + + # LOGFILES + + # Create logfile name and path + logspath = path.join(self.configFolder, 'logs') + now = datetime.datetime.now() + logfile = now.strftime("%Y-%m-%d_%H%M%S")+".log" + makedirs(logspath, exist_ok=True) + + # Add handler for logging + fh = logging.FileHandler(path.join(logspath, logfile)) + fh.setLevel(logging.DEBUG) + fh.setFormatter(logging.Formatter('%(asctime)s - [%(levelname)s] %(message)s')) + logger.addHandler(fh) + logger.info(f"{platform.platform(True, True)} - Python {platform.python_version()}, deemix {deemixVersion}") + + # Only keep last 5 logfiles (to preserve disk space) + logslist = listdir(logspath) + logslist.sort() + if len(logslist)>5: + for i in range(len(logslist)-5): + remove(path.join(logspath, logslist[i])) + + def getSettings(self): + return self.settings + + def getDefaultSettings(self): + return self.defaultSettings + + # Saves the settings + def saveSettings(self, newSettings=None): + if newSettings: + self.settings = newSettings + with open(path.join(self.configFolder, 'config.json'), 'w') as configFile: + json.dump(self.settings, configFile, indent=2) + + # Checks if the default settings have changed + def settingsCheck(self): + changes = 0 + for x in self.defaultSettings: + if not x in self.settings or type(self.settings[x]) != type(self.defaultSettings[x]): + self.settings[x] = self.defaultSettings[x] + changes += 1 + for x in self.defaultSettings['tags']: + if not x in self.settings['tags'] or type(self.settings['tags'][x]) != type(self.defaultSettings['tags'][x]): + self.settings['tags'][x] = self.defaultSettings['tags'][x] + changes += 1 + if self.settings['downloadLocation'] == "": + self.settings['downloadLocation'] = path.join(localpaths.getHomeFolder(), 'deemix Music') + changes += 1 + for template in ['tracknameTemplate', 'albumTracknameTemplate', 'playlistTracknameTemplate', 'playlistNameTemplate', 'artistNameTemplate', 'albumNameTemplate', 'playlistFilenameTemplate', 'coverImageTemplate', 'artistImageTemplate']: + if self.settings[template] == "": + self.settings[template] = self.defaultSettings[template] + changes += 1 + if changes > 0: + saveSettings() diff --git a/deemix/app/__init__.py b/deemix/app/__init__.py index 9d389f1..106d316 100644 --- a/deemix/app/__init__.py +++ b/deemix/app/__init__.py @@ -1,2 +1,6 @@ #!/usr/bin/env python3 # Empty File + +class deemix: + def __init__(self): + diff --git a/deemix/app/default.json b/deemix/app/default.json deleted file mode 100644 index ea927f8..0000000 --- a/deemix/app/default.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "downloadLocation": "", - "tracknameTemplate": "%artist% - %title%", - "albumTracknameTemplate": "%tracknumber% - %title%", - "playlistTracknameTemplate": "%position% - %artist% - %title%", - "createPlaylistFolder": true, - "playlistNameTemplate": "%playlist%", - "createArtistFolder": false, - "artistNameTemplate": "%artist%", - "createAlbumFolder": true, - "albumNameTemplate": "%artist% - %album%", - "createCDFolder": true, - "createStructurePlaylist": false, - "createSingleFolder": false, - "padTracks": true, - "paddingSize": "0", - "illegalCharacterReplacer": "_", - "queueConcurrency": 3, - "maxBitrate": "3", - "fallbackBitrate": true, - "fallbackSearch": false, - "logErrors": true, - "logSearched": false, - "saveDownloadQueue": false, - "overwriteFile": "n", - "createM3U8File": false, - "playlistFilenameTemplate": "playlist", - "syncedLyrics": false, - "embeddedArtworkSize": 800, - "localArtworkSize": 1400, - "localArtworkFormat": "jpg", - "saveArtwork": true, - "coverImageTemplate": "cover", - "saveArtworkArtist": false, - "artistImageTemplate": "folder", - "jpegImageQuality": 80, - "dateFormat": "Y-M-D", - "albumVariousArtists": true, - "removeAlbumVersion": false, - "removeDuplicateArtists": false, - "featuredToTitle": "0", - "titleCasing": "nothing", - "artistCasing": "nothing", - "executeCommand": "", - "tags": { - "title": true, - "artist": true, - "album": true, - "cover": true, - "trackNumber": true, - "trackTotal": false, - "discNumber": true, - "discTotal": false, - "albumArtist": true, - "genre": true, - "year": true, - "date": true, - "explicit": false, - "isrc": true, - "length": true, - "barcode": true, - "bpm": true, - "replayGain": false, - "label": true, - "lyrics": false, - "copyright": false, - "composer": false, - "involvedPeople": false, - "savePlaylistAsCompilation": false, - "useNullSeparator": false, - "saveID3v1": true, - "multiArtistSeparator": "default", - "singleAlbumArtist": false - } -} diff --git a/deemix/app/settings.py b/deemix/app/settings.py deleted file mode 100644 index e55e9b7..0000000 --- a/deemix/app/settings.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python3 -import json -import os.path as path -from os import makedirs, listdir, remove -from deemix import __version__ as deemixVersion -import random -import string -import logging -import datetime -import platform - -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger('deemix') - -import deemix.utils.localpaths as localpaths - -settings = {} -defaultSettings = {} -configDir = "" - -def initSettings(configFolder = None): - global settings - global defaultSettings - global configDir - currentFolder = path.abspath(path.dirname(__file__)) - if not configFolder: - configFolder = localpaths.getConfigFolder() - configDir = configFolder - makedirs(configFolder, exist_ok=True) - with open(path.join(currentFolder, 'default.json'), 'r') as d: - defaultSettings = json.load(d) - defaultSettings['downloadLocation'] = path.join(localpaths.getHomeFolder(), 'deemix Music') - if not path.isfile(path.join(configFolder, 'config.json')): - with open(path.join(configFolder, 'config.json'), 'w') as f: - json.dump(defaultSettings, f, indent=2) - with open(path.join(configFolder, 'config.json'), 'r') as configFile: - settings = json.load(configFile) - settingsCheck() - - if settings['downloadLocation'] == "": - settings['downloadLocation'] = path.join(localpaths.getHomeFolder(), 'deemix Music') - saveSettings(settings) - makedirs(settings['downloadLocation'], exist_ok=True) - - # logfiles - # logfile name - logspath = path.join(configFolder, 'logs') - now = datetime.datetime.now() - logfile = now.strftime("%Y-%m-%d_%H%M%S")+".log" - makedirs(logspath, exist_ok=True) - # add handler for logfile - fh = logging.FileHandler(path.join(logspath, logfile)) - fh.setLevel(logging.DEBUG) - fh.setFormatter(logging.Formatter('%(asctime)s - [%(levelname)s] %(message)s')) - logger.addHandler(fh) - logger.info(f"{platform.platform(True, True)} - Python {platform.python_version()}, deemix {deemixVersion}") - #delete old logfiles - logslist = listdir(logspath) - logslist.sort() - if len(logslist)>5: - for i in range(len(logslist)-5): - remove(path.join(logspath, logslist[i])) - - return settings - - -def getSettings(): - global settings - return settings - - -def getDefaultSettings(): - global defaultSettings - return defaultSettings - - -def saveSettings(newSettings): - global settings - settings = newSettings - with open(path.join(configDir, 'config.json'), 'w') as configFile: - json.dump(settings, configFile, indent=2) - return True - - -def settingsCheck(): - global settings - global defaultSettings - changes = 0 - for x in defaultSettings: - if not x in settings or type(settings[x]) != type(defaultSettings[x]): - settings[x] = defaultSettings[x] - changes += 1 - for x in defaultSettings['tags']: - if not x in settings['tags'] or type(settings['tags'][x]) != type(defaultSettings['tags'][x]): - settings['tags'][x] = defaultSettings['tags'][x] - changes += 1 - if changes > 0: - saveSettings(settings) - - -def randomString(stringLength=8): - letters = string.ascii_lowercase - return ''.join(random.choice(letters) for i in range(stringLength)) diff --git a/deemix/utils/localpaths.py b/deemix/utils/localpaths.py index 5b71e6a..624099d 100644 --- a/deemix/utils/localpaths.py +++ b/deemix/utils/localpaths.py @@ -11,14 +11,12 @@ if getenv("APPDATA"): elif sys.platform.startswith('darwin'): userdata = homedata + '/Library/Application Support/deemix/' elif getenv("XDG_CONFIG_HOME"): - userdata = getenv("XDG_CONFIG_HOME") + '/deemix/'; + userdata = getenv("XDG_CONFIG_HOME") + '/deemix/' else: - userdata = homedata + '/.config/deemix/'; - + userdata = homedata + '/.config/deemix/' def getHomeFolder(): return homedata - def getConfigFolder(): return userdata diff --git a/deemix/utils/misc.py b/deemix/utils/misc.py index 376a674..aa42c0e 100644 --- a/deemix/utils/misc.py +++ b/deemix/utils/misc.py @@ -94,12 +94,3 @@ def uniqueArray(arr): if iPrinc!=iRest and namePrinc.lower() in nRest.lower(): del arr[iRest] return arr - - -def isValidLink(text): - if text.lower().startswith("http"): - if "deezer.com" in text.lower() or "open.spotify.com" in text.lower(): - return True - elif text.lower().startswith("spotify:"): - return True - return False diff --git a/deemix/utils/taggers.py b/deemix/utils/taggers.py index 1cfa420..7f54730 100644 --- a/deemix/utils/taggers.py +++ b/deemix/utils/taggers.py @@ -3,8 +3,9 @@ from mutagen.flac import FLAC, Picture from mutagen.id3 import ID3, ID3NoHeaderError, TXXX, TIT2, TPE1, TALB, TPE2, TRCK, TPOS, TCON, TYER, TDAT, TLEN, TBPM, \ TPUB, TSRC, USLT, APIC, IPLS, TCOM, TCOP, TCMP - +# Adds tags to a MP3 file def tagID3(stream, track, save): + # Delete exsisting tags try: tag = ID3(stream) tag.delete() @@ -13,6 +14,7 @@ def tagID3(stream, track, save): if save['title']: tag.add(TIT2(text=track['title'])) + if save['artist'] and len(track['artists']): if save['multiArtistSeparator'] != "default": if save['multiArtistSeparator'] == "nothing": @@ -22,13 +24,16 @@ def tagID3(stream, track, save): tag.add(TXXX(desc="ARTISTS", text=track['artists'])) else: tag.add(TPE1(text=track['artists'])) + if save['album']: tag.add(TALB(text=track['album']['title'])) + if save['albumArtist'] and len(track['album']['artists']): if save['singleAlbumArtist'] and track['album']['mainArtist']['save']: tag.add(TPE2(text=track['album']['mainArtist']['name'])) else: tag.add(TPE2(text=track['album']['artists'])) + if save['trackNumber']: tag.add(TRCK( text=str(track['trackNumber']) + ("/" + str(track['album']['trackTotal']) if save['trackTotal'] else ""))) @@ -57,6 +62,7 @@ def tagID3(stream, track, save): tag.add(TXXX(desc="REPLAYGAIN_TRACK_GAIN", text=track['replayGain'])) if 'unsync' in track['lyrics'] and save['lyrics']: tag.add(USLT(text=track['lyrics']['unsync'])) + involved_people = [] for role in track['contributors']: if role in ['author', 'engineer', 'mixer', 'producer', 'writer']: @@ -66,10 +72,12 @@ def tagID3(stream, track, save): tag.add(TCOM(text=track['contributors']['composer'])) if len(involved_people) > 0 and save['involvedPeople']: tag.add(IPLS(people=involved_people)) + if save['copyright']: tag.add(TCOP(text=track['copyright'])) if save['savePlaylistAsCompilation'] and "playlist" in track: tag.add(TCMP(text="1")) + if save['cover'] and track['album']['picPath']: with open(track['album']['picPath'], 'rb') as f: tag.add( @@ -78,13 +86,16 @@ def tagID3(stream, track, save): tag.save(stream, v1=2 if save['saveID3v1'] else 0, v2_version=3, v23_sep=None if save['useNullSeparator'] else '/') - +# Adds tags to a FLAC file def tagFLAC(stream, track, save): + # Delete exsisting tags tag = FLAC(stream) tag.delete() tag.clear_pictures() + if save['title']: tag["TITLE"] = track['title'] + if save['artist'] and len(track['artists']): if save['multiArtistSeparator'] != "default": if save['multiArtistSeparator'] == "nothing": @@ -94,13 +105,16 @@ def tagFLAC(stream, track, save): tag["ARTISTS"] = track['artists'] else: tag["ARTIST"] = track['artists'] + if save['album']: tag["ALBUM"] = track['album']['title'] + if save['albumArtist'] and len(track['album']['artists']): if save['singleAlbumArtist']: tag["ALBUMARTIST"] = track['album']['mainArtist']['name'] else: tag["ALBUMARTIST"] = track['album']['artists'] + if save['trackNumber']: tag["TRACKNUMBER"] = str(track['trackNumber']) if save['trackTotal']: @@ -131,12 +145,14 @@ def tagFLAC(stream, track, save): tag["REPLAYGAIN_TRACK_GAIN"] = track['replayGain'] if 'unsync' in track['lyrics'] and save['lyrics']: tag["LYRICS"] = track['lyrics']['unsync'] + for role in track['contributors']: if role in ['author', 'engineer', 'mixer', 'producer', 'writer', 'composer']: if save['involvedPeople'] and role != 'composer' or role == 'composer' and save['composer']: tag[role] = track['contributors'][role] elif role == 'musicpublisher' and save['involvedPeople']: tag["ORGANIZATION"] = track['contributors']['musicpublisher'] + if save['copyright']: tag["COPYRIGHT"] = track['copyright'] if save['savePlaylistAsCompilation'] and "playlist" in track: