Changed all os.path to pathlib + cleanup

Bumped to 1.5.0
This commit is contained in:
RemixDev 2020-09-27 23:44:37 +02:00
parent 6e955ee01f
commit 798dcdd3d9
13 changed files with 285 additions and 294 deletions

View File

@ -1,3 +1,3 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
__version__ = "1.4.3" __version__ = "1.5.0"

View File

@ -2,7 +2,7 @@
import click import click
from deemix.app.cli import cli from deemix.app.cli import cli
import os.path from pathlib import Path
@click.command() @click.command()
@click.option('--portable', is_flag=True, help='Creates the config folder in the same directory where the script is launched') @click.option('--portable', is_flag=True, help='Creates the config folder in the same directory where the script is launched')
@ -11,17 +11,17 @@ import os.path
@click.argument('url', nargs=-1, required=True) @click.argument('url', nargs=-1, required=True)
def download(url, bitrate, portable, path): def download(url, bitrate, portable, path):
localpath = os.path.realpath('.') localpath = Path('.')
configFolder = os.path.join(localpath, 'config') if portable else None configFolder = localpath / 'config' if portable else None
if path is not None: if path is not None:
if path == '': path = '.' if path == '': path = '.'
path = os.path.realpath(path) path = Path(path)
app = cli(path, configFolder) app = cli(path, configFolder)
app.login() app.login()
url = list(url) url = list(url)
if os.path.isfile(url[0]): if Path(url[0]).is_file():
filename = url[0] filename = url[0]
with open(filename) as f: with open(filename) as f:
url = f.readlines() url = f.readlines()

View File

@ -215,7 +215,7 @@ class Deezer:
user_data = self.gw_api_call("deezer.getUserData") user_data = self.gw_api_call("deezer.getUserData")
if user_data["results"]["USER"]["USER_ID"] == 0: if user_data["results"]["USER"]["USER_ID"] == 0:
self.logged_in = False self.logged_in = False
return 0 return False
self.family = user_data["results"]["USER"]["MULTI_ACCOUNT"]["ENABLED"] self.family = user_data["results"]["USER"]["MULTI_ACCOUNT"]["ENABLED"]
if self.family: if self.family:
self.childs = self.get_child_accounts_gw() self.childs = self.get_child_accounts_gw()
@ -242,7 +242,7 @@ class Deezer:
"USER"] else "" "USER"] else ""
} }
self.logged_in = True self.logged_in = True
return 1 return True
def change_account(self, child): def change_account(self, child):
if len(self.childs)-1 >= child: if len(self.childs)-1 >= child:

View File

@ -1,14 +1,14 @@
import os.path as path from pathlib import Path
from os import makedirs from os import makedirs
from deemix.app import deemix from deemix.app import deemix
class cli(deemix): class cli(deemix):
def __init__(self, path, configFolder=None): def __init__(self, downloadpath, configFolder=None):
super().__init__(configFolder) super().__init__(configFolder)
if path: if downloadpath:
self.set.settings['downloadLocation'] = str(path) self.set.settings['downloadLocation'] = str(downloadpath)
makedirs(path, exist_ok=True) makedirs(downloadpath, exist_ok=True)
print("Using folder: "+self.set.settings['downloadLocation']) print("Using folder: "+self.set.settings['downloadLocation'])
def downloadLink(self, url, bitrate=None): def downloadLink(self, url, bitrate=None):
@ -27,15 +27,15 @@ class cli(deemix):
return arl return arl
def login(self): def login(self):
configFolder = self.set.configFolder configFolder = Path(self.set.configFolder)
if not path.isdir(configFolder): if not configFolder.is_dir():
makedirs(configFolder, exist_ok=True) makedirs(configFolder, exist_ok=True)
if path.isfile(path.join(configFolder, '.arl')): if (configFolder / '.arl').is_file():
with open(path.join(configFolder, '.arl'), 'r') as f: with open(configFolder / '.arl', 'r') as f:
arl = f.readline().rstrip("\n") arl = f.readline().rstrip("\n")
if not self.dz.login_via_arl(arl): if not self.dz.login_via_arl(arl):
arl = self.requestValidArl() arl = self.requestValidArl()
else: else:
arl = self.requestValidArl() arl = self.requestValidArl()
with open(path.join(configFolder, '.arl'), 'w') as f: with open(configFolder / '.arl', 'w') as f:
f.write(arl) f.write(arl)

View File

@ -1,5 +1,6 @@
import eventlet import eventlet
import os.path from os.path import sep as pathSep
from pathlib import Path
import re import re
import errno import errno
@ -25,8 +26,8 @@ import logging
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('deemix') logger = logging.getLogger('deemix')
TEMPDIR = os.path.join(gettempdir(), 'deemix-imgs') TEMPDIR = Path(gettempdir()) / 'deemix-imgs'
if not os.path.isdir(TEMPDIR): if not TEMPDIR.is_dir():
makedirs(TEMPDIR) makedirs(TEMPDIR)
extensions = { extensions = {
@ -52,8 +53,9 @@ errorMessages = {
'noSpaceLeft': "No space left on target drive, clean up some space for the tracks", 'noSpaceLeft': "No space left on target drive, clean up some space for the tracks",
'albumDoesntExsists': "Track's album does not exsist, failed to gather info" 'albumDoesntExsists': "Track's album does not exsist, failed to gather info"
} }
def downloadImage(url, path, overwrite="n"): def downloadImage(url, path, overwrite="n"):
if not os.path.isfile(path) or overwrite in ['y', 't', 'b']: if not path.is_file() or overwrite in ['y', 't', 'b']:
try: try:
image = get(url, headers={'User-Agent': USER_AGENT_HEADER}, timeout=30) image = get(url, headers={'User-Agent': USER_AGENT_HEADER}, timeout=30)
image.raise_for_status() image.raise_for_status()
@ -81,7 +83,7 @@ def downloadImage(url, path, overwrite="n"):
logger.exception(f"Error while downloading an image, you should report this to the developers: {str(e)}") logger.exception(f"Error while downloading an image, you should report this to the developers: {str(e)}")
except Exception as e: except Exception as e:
logger.exception(f"Error while downloading an image, you should report this to the developers: {str(e)}") logger.exception(f"Error while downloading an image, you should report this to the developers: {str(e)}")
if os.path.isfile(path): remove(path) if path.is_file(): path.unlink()
return None return None
else: else:
return path return path
@ -108,7 +110,7 @@ class DownloadJob:
self.downloadPercentage = 0 self.downloadPercentage = 0
self.lastPercentage = 0 self.lastPercentage = 0
self.extrasPath = None self.extrasPath = None
self.playlistPath = None self.playlistCoverName = None
self.playlistURLs = [] self.playlistURLs = []
def start(self): def start(self):
@ -134,18 +136,18 @@ class DownloadJob:
def singleAfterDownload(self, result): def singleAfterDownload(self, result):
if not self.extrasPath: if not self.extrasPath:
self.extrasPath = self.settings['downloadLocation'] self.extrasPath = Path(self.settings['downloadLocation'])
# Save Album Cover # Save Album Cover
if self.settings['saveArtwork'] and 'albumPath' in result: if self.settings['saveArtwork'] and 'albumPath' in result:
for image in result['albumURLs']: for image in result['albumURLs']:
downloadImage(image['url'], f"{result['albumPath']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['albumPath'] / f"{result['albumFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Save Artist Artwork # Save Artist Artwork
if self.settings['saveArtworkArtist'] and 'artistPath' in result: if self.settings['saveArtworkArtist'] and 'artistPath' in result:
for image in result['artistURLs']: for image in result['artistURLs']:
downloadImage(image['url'], f"{result['artistPath']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['artistPath'] / f"{result['artistFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Create searched logfile # Create searched logfile
if self.settings['logSearched'] and 'searched' in result: if self.settings['logSearched'] and 'searched' in result:
with open(os.path.join(self.extrasPath, 'searched.txt'), 'wb+') as f: with open(self.extrasPath / 'searched.txt', 'wb+') as f:
orig = f.read().decode('utf-8') orig = f.read().decode('utf-8')
if not result['searched'] in orig: if not result['searched'] in orig:
if orig != "": if orig != "":
@ -154,11 +156,11 @@ class DownloadJob:
f.write(orig.encode('utf-8')) f.write(orig.encode('utf-8'))
# Execute command after download # Execute command after download
if self.settings['executeCommand'] != "": if self.settings['executeCommand'] != "":
execute(self.settings['executeCommand'].replace("%folder%", self.extrasPath).replace("%filename%", result['filename'])) execute(self.settings['executeCommand'].replace("%folder%", str(self.extrasPath)).replace("%filename%", result['filename']))
def collectionAfterDownload(self, tracks): def collectionAfterDownload(self, tracks):
if not self.extrasPath: if not self.extrasPath:
self.extrasPath = self.settings['downloadLocation'] self.extrasPath = Path(self.settings['downloadLocation'])
playlist = [None] * len(tracks) playlist = [None] * len(tracks)
errors = "" errors = ""
searched = "" searched = ""
@ -179,11 +181,11 @@ class DownloadJob:
# Save Album Cover # Save Album Cover
if self.settings['saveArtwork'] and 'albumPath' in result: if self.settings['saveArtwork'] and 'albumPath' in result:
for image in result['albumURLs']: for image in result['albumURLs']:
downloadImage(image['url'], f"{result['albumPath']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['albumPath'] / f"{result['albumFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Save Artist Artwork # Save Artist Artwork
if self.settings['saveArtworkArtist'] and 'artistPath' in result: if self.settings['saveArtworkArtist'] and 'artistPath' in result:
for image in result['artistURLs']: for image in result['artistURLs']:
downloadImage(image['url'], f"{result['artistPath']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['artistPath'] / f"{result['artistFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Save filename for playlist file # Save filename for playlist file
playlist[index] = "" playlist[index] = ""
if 'filename' in result: if 'filename' in result:
@ -191,20 +193,20 @@ class DownloadJob:
# Create errors logfile # Create errors logfile
if self.settings['logErrors'] and errors != "": if self.settings['logErrors'] and errors != "":
with open(os.path.join(self.extrasPath, 'errors.txt'), 'wb') as f: with open(self.extrasPath / 'errors.txt', 'wb') as f:
f.write(errors.encode('utf-8')) f.write(errors.encode('utf-8'))
# Create searched logfile # Create searched logfile
if self.settings['logSearched'] and searched != "": if self.settings['logSearched'] and searched != "":
with open(os.path.join(self.extrasPath, 'searched.txt'), 'wb') as f: with open(self.extrasPath / 'searched.txt', 'wb') as f:
f.write(searched.encode('utf-8')) f.write(searched.encode('utf-8'))
# Save Playlist Artwork # Save Playlist Artwork
if self.settings['saveArtwork'] and self.playlistPath and not self.settings['tags']['savePlaylistAsCompilation']: if self.settings['saveArtwork'] and self.playlistCoverName and not self.settings['tags']['savePlaylistAsCompilation']:
for image in self.playlistURLs: for image in self.playlistURLs:
downloadImage(image['url'], os.path.join(self.extrasPath, self.playlistPath)+f".{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], self.extrasPath / f"{self.playlistCoverName}.{image['ext']}", self.settings['overwriteFile'])
# Create M3U8 File # Create M3U8 File
if self.settings['createM3U8File']: if self.settings['createM3U8File']:
filename = settingsRegexPlaylistFile(self.settings['playlistFilenameTemplate'], self.queueItem, self.settings) or "playlist" filename = settingsRegexPlaylistFile(self.settings['playlistFilenameTemplate'], self.queueItem, self.settings) or "playlist"
with open(os.path.join(self.extrasPath, filename+'.m3u8'), 'wb') as f: with open(self.extrasPath / f'{filename}.m3u8', 'wb') as f:
for line in playlist: for line in playlist:
f.write((line + "\n").encode('utf-8')) f.write((line + "\n").encode('utf-8'))
# Execute command after download # Execute command after download
@ -310,7 +312,7 @@ class DownloadJob:
ext = track.playlist['picUrl'][-4:] ext = track.playlist['picUrl'][-4:]
if ext[0] != ".": if ext[0] != ".":
ext = ".jpg" ext = ".jpg"
track.album['picPath'] = os.path.join(TEMPDIR, f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{self.settings['embeddedArtworkSize']}{ext}") track.album['picPath'] = TEMPDIR / f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{self.settings['embeddedArtworkSize']}{ext}"
else: else:
if track.album['date']: if track.album['date']:
track.date = track.album['date'] track.date = track.album['date']
@ -319,11 +321,12 @@ class DownloadJob:
self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'],
'none-100-0-0.png' if self.settings['embeddedArtworkPNG'] else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg' 'none-100-0-0.png' if self.settings['embeddedArtworkPNG'] else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg'
) )
track.album['picPath'] = os.path.join(TEMPDIR, f"alb{track.album['id']}_{self.settings['embeddedArtworkSize']}{track.album['picUrl'][-4:]}") track.album['picPath'] = TEMPDIR / f"alb{track.album['id']}_{self.settings['embeddedArtworkSize']}{track.album['picUrl'][-4:]}"
track.album['bitrate'] = selectedFormat track.album['bitrate'] = selectedFormat
track.dateString = formatDate(track.date, self.settings['dateFormat']) track.dateString = formatDate(track.date, self.settings['dateFormat'])
track.album['dateString'] = formatDate(track.album['date'], self.settings['dateFormat']) track.album['dateString'] = formatDate(track.album['date'], self.settings['dateFormat'])
if track.playlist: track.playlist['dateString'] = formatDate(track.playlist['date'], self.settings['dateFormat'])
# Check if user wants the feat in the title # Check if user wants the feat in the title
# 0 => do not change # 0 => do not change
@ -356,19 +359,19 @@ class DownloadJob:
track.generateMainFeatStrings() track.generateMainFeatStrings()
# Generate artist tag if needed # Generate artist tag if needed
if self.settings['tags']['multiArtistSeparator'] != "default": if self.settings['tags']['multiArtistSeparator'] == "default":
if self.settings['tags']['multiArtistSeparator'] == "andFeat": track.artistsString = ", ".join(track.artists)
elif self.settings['tags']['multiArtistSeparator'] == "andFeat":
track.artistsString = track.mainArtistsString track.artistsString = track.mainArtistsString
if track.featArtistsString and str(self.settings['featuredToTitle']) != "2": if track.featArtistsString and str(self.settings['featuredToTitle']) != "2":
track.artistsString += " " + track.featArtistsString track.artistsString += " " + track.featArtistsString
else: else:
track.artistsString = self.settings['tags']['multiArtistSeparator'].join(track.artists) track.artistsString = self.settings['tags']['multiArtistSeparator'].join(track.artists)
else:
track.artistsString = ", ".join(track.artists)
# Generate filename and filepath from metadata # Generate filename and filepath from metadata
filename = generateFilename(track, trackAPI_gw, self.settings) filename = generateFilename(track, self.settings, trackAPI_gw['FILENAME_TEMPLATE'])
(filepath, artistPath, coverPath, extrasPath) = generateFilepath(track, trackAPI_gw, self.settings) (filepath, artistPath, coverPath, extrasPath) = generateFilepath(track, self.settings)
if self.queueItem.cancel: raise DownloadCancelled if self.queueItem.cancel: raise DownloadCancelled
@ -400,8 +403,8 @@ class DownloadJob:
'none-100-0-0.png' if format == "png" else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg' 'none-100-0-0.png' if format == "png" else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg'
) )
result['albumURLs'].append({'url': url, 'ext': format}) result['albumURLs'].append({'url': url, 'ext': format})
result['albumPath'] = os.path.join(coverPath, result['albumPath'] = coverPath
f"{settingsRegexAlbum(self.settings['coverImageTemplate'], track.album, self.settings, trackAPI_gw['_EXTRA_PLAYLIST'] if'_EXTRA_PLAYLIST' in trackAPI_gw else None)}") result['albumFilename'] = f"{settingsRegexAlbum(self.settings['coverImageTemplate'], track.album, self.settings, track.playlist)}"
# Save artist art # Save artist art
if artistPath: if artistPath:
@ -418,50 +421,47 @@ class DownloadJob:
self.settings['localArtworkSize'], self.settings['localArtworkSize'], f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg') self.settings['localArtworkSize'], self.settings['localArtworkSize'], f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg')
if url: if url:
result['artistURLs'].append({'url': url, 'ext': format}) result['artistURLs'].append({'url': url, 'ext': format})
result['artistPath'] = os.path.join(artistPath, result['artistPath'] = artistPath
f"{settingsRegexArtist(self.settings['artistImageTemplate'], track.album['mainArtist'], self.settings)}") result['artistFilename'] = f"{settingsRegexArtist(self.settings['artistImageTemplate'], track.album['mainArtist'], self.settings)}"
# Remove subfolders from filename and add it to filepath # Remove subfolders from filename and add it to filepath
if os.path.sep in filename: if pathSep in filename:
tempPath = filename[:filename.rfind(os.path.sep)] tempPath = filename[:filename.rfind(pathSep)]
filepath = os.path.join(filepath, tempPath) filepath = filepath / tempPath
filename = filename[filename.rfind(os.path.sep) + len(os.path.sep):] filename = filename[filename.rfind(pathSep) + len(pathSep):]
# Make sure the filepath exsists # Make sure the filepath exsists
makedirs(filepath, exist_ok=True) makedirs(filepath, exist_ok=True)
writepath = os.path.join(filepath, filename + extensions[track.selectedFormat]) writepath = filepath / f"{filename}{extensions[track.selectedFormat]}"
# Save lyrics in lrc file # Save lyrics in lrc file
if self.settings['syncedLyrics'] and track.lyrics['sync']: if self.settings['syncedLyrics'] and track.lyrics['sync']:
if not os.path.isfile(os.path.join(filepath, filename + '.lrc')) or self.settings['overwriteFile'] in ['y', 't']: if not (filepath / f"{filename}.lrc").is_file() or self.settings['overwriteFile'] in ['y', 't']:
with open(os.path.join(filepath, filename + '.lrc'), 'wb') as f: with open(filepath / f"{filename}.lrc", 'wb') as f:
f.write(track.lyrics['sync'].encode('utf-8')) f.write(track.lyrics['sync'].encode('utf-8'))
trackAlreadyDownloaded = os.path.isfile(writepath) trackAlreadyDownloaded = writepath.is_file()
if not trackAlreadyDownloaded and self.settings['overwriteFile'] == 'e': if not trackAlreadyDownloaded and self.settings['overwriteFile'] == 'e':
exts = ['.mp3', '.flac', '.opus', '.m4a'] exts = ['.mp3', '.flac', '.opus', '.m4a']
baseFilename = os.path.join(filepath, filename) baseFilename = str(filepath / filename)
for ext in exts: for ext in exts:
trackAlreadyDownloaded = os.path.isfile(baseFilename+ext) trackAlreadyDownloaded = Path(baseFilename+ext).is_file()
if trackAlreadyDownloaded: if trackAlreadyDownloaded:
break break
if trackAlreadyDownloaded and self.settings['overwriteFile'] == 'b': if trackAlreadyDownloaded and self.settings['overwriteFile'] == 'b':
baseFilename = os.path.join(filepath, filename) baseFilename = str(filepath / filename)
i = 1 i = 1
currentFilename = baseFilename+' ('+str(i)+')'+ extensions[track.selectedFormat] currentFilename = baseFilename+' ('+str(i)+')'+ extensions[track.selectedFormat]
while os.path.isfile(currentFilename): while Path(currentFilename).is_file():
i += 1 i += 1
currentFilename = baseFilename+' ('+str(i)+')'+ extensions[track.selectedFormat] currentFilename = baseFilename+' ('+str(i)+')'+ extensions[track.selectedFormat]
trackAlreadyDownloaded = False trackAlreadyDownloaded = False
writepath = currentFilename writepath = Path(currentFilename)
if extrasPath: if extrasPath:
if not self.extrasPath: if not self.extrasPath: self.extrasPath = extrasPath
self.extrasPath = extrasPath result['filename'] = str(writepath)[len(str(extrasPath)):]
# Data for m3u file
result['filename'] = writepath[len(extrasPath):]
# Save playlist cover # Save playlist cover
if track.playlist: if track.playlist:
@ -478,12 +478,12 @@ class DownloadJob:
self.playlistURLs.append({'url': url, 'ext': format}) self.playlistURLs.append({'url': url, 'ext': format})
else: else:
self.playlistURLs.append({'url': track.playlist['pic'], 'ext': 'jpg'}) self.playlistURLs.append({'url': track.playlist['pic'], 'ext': 'jpg'})
if not self.playlistPath: if not self.playlistCoverName:
track.playlist['id'] = "pl_" + str(trackAPI_gw['_EXTRA_PLAYLIST']['id']) track.playlist['id'] = "pl_" + str(trackAPI_gw['_EXTRA_PLAYLIST']['id'])
track.playlist['genre'] = ["Compilation", ] track.playlist['genre'] = ["Compilation", ]
track.playlist['bitrate'] = selectedFormat track.playlist['bitrate'] = selectedFormat
track.playlist['dateString'] = formatDate(track.playlist['date'], self.settings['dateFormat']) track.playlist['dateString'] = formatDate(track.playlist['date'], self.settings['dateFormat'])
self.playlistPath = f"{settingsRegexAlbum(self.settings['coverImageTemplate'], track.playlist, self.settings, trackAPI_gw['_EXTRA_PLAYLIST'])}" self.playlistCoverName = f"{settingsRegexAlbum(self.settings['coverImageTemplate'], track.playlist, self.settings, track.playlist)}"
if not trackAlreadyDownloaded or self.settings['overwriteFile'] == 'y': if not trackAlreadyDownloaded or self.settings['overwriteFile'] == 'y':
logger.info(f"[{track.mainArtist['name']} - {track.title}] Downloading the track") logger.info(f"[{track.mainArtist['name']} - {track.title}] Downloading the track")
@ -494,10 +494,10 @@ class DownloadJob:
with open(writepath, 'wb') as stream: with open(writepath, 'wb') as stream:
self.streamTrack(stream, track) self.streamTrack(stream, track)
except DownloadCancelled: except DownloadCancelled:
if os.path.isfile(writepath): remove(writepath) if writepath.is_file(): writepath.unlink()
raise DownloadCancelled raise DownloadCancelled
except (request_exception.HTTPError, DownloadEmpty): except (request_exception.HTTPError, DownloadEmpty):
if os.path.isfile(writepath): remove(writepath) if writepath.is_file(): writepath.unlink()
if track.fallbackId != "0": if track.fallbackId != "0":
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available, using fallback id") logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available, using fallback id")
newTrack = self.dz.get_track_gw(track.fallbackId) newTrack = self.dz.get_track_gw(track.fallbackId)
@ -526,7 +526,7 @@ class DownloadJob:
else: else:
raise DownloadFailed("notAvailable") raise DownloadFailed("notAvailable")
except (request_exception.ConnectionError, request_exception.ChunkedEncodingError) as e: except (request_exception.ConnectionError, request_exception.ChunkedEncodingError) as e:
if os.path.isfile(writepath): remove(writepath) if writepath.is_file(): writepath.unlink()
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, trying again in 5s...") logger.warn(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, trying again in 5s...")
eventlet.sleep(5) eventlet.sleep(5)
return downloadMusic(track, trackAPI_gw) return downloadMusic(track, trackAPI_gw)
@ -534,11 +534,11 @@ class DownloadJob:
if e.errno == errno.ENOSPC: if e.errno == errno.ENOSPC:
raise DownloadFailed("noSpaceLeft") raise DownloadFailed("noSpaceLeft")
else: else:
if os.path.isfile(writepath): remove(writepath) if writepath.is_file(): writepath.unlink()
logger.exception(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}") logger.exception(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}")
raise e raise e
except Exception as e: except Exception as e:
if os.path.isfile(writepath): remove(writepath) if writepath.is_file(): writepath.unlink()
logger.exception(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}") logger.exception(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}")
raise e raise e
return True return True
@ -565,7 +565,7 @@ class DownloadJob:
try: try:
tagFLAC(writepath, track, self.settings['tags']) tagFLAC(writepath, track, self.settings['tags'])
except FLACNoHeaderError: except FLACNoHeaderError:
if os.path.isfile(writepath): remove(writepath) if writepath.is_file(): writepath.unlink()
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available in FLAC, falling back if necessary") logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available in FLAC, falling back if necessary")
self.removeTrackPercentage() self.removeTrackPercentage()
track.filesizes['FILESIZE_FLAC'] = "0" track.filesizes['FILESIZE_FLAC'] = "0"
@ -574,11 +574,11 @@ class DownloadJob:
if track.searched: if track.searched:
result['searched'] = f"{track.mainArtist['name']} - {track.title}" result['searched'] = f"{track.mainArtist['name']} - {track.title}"
logger.info(f"[{track.mainArtist['name']} - {track.title}] Track download completed\n{writepath}") logger.info(f"[{track.mainArtist['name']} - {track.title}] Track download completed\n{str(writepath)}")
self.queueItem.downloaded += 1 self.queueItem.downloaded += 1
self.queueItem.files.append(writepath) self.queueItem.files.append(str(writepath))
if self.interface: if self.interface:
self.interface.send("updateQueue", {'uuid': self.queueItem.uuid, 'downloaded': True, 'downloadPath': writepath}) self.interface.send("updateQueue", {'uuid': self.queueItem.uuid, 'downloaded': True, 'downloadPath': str(writepath)})
return result return result
def getPreferredBitrate(self, track): def getPreferredBitrate(self, track):

View File

@ -4,7 +4,7 @@ from deemix.api.deezer import APIError
from spotipy.exceptions import SpotifyException from spotipy.exceptions import SpotifyException
from deemix.app.queueitem import QueueItem, QISingle, QICollection, QIConvertable from deemix.app.queueitem import QueueItem, QISingle, QICollection, QIConvertable
import logging import logging
import os.path as path from pathlib import Path
import json import json
from os import remove from os import remove
import eventlet import eventlet
@ -434,7 +434,7 @@ class QueueManager:
if len(self.queueList) > 0: if len(self.queueList) > 0:
if self.currentItem != "": if self.currentItem != "":
self.queue.insert(0, self.currentItem) self.queue.insert(0, self.currentItem)
with open(path.join(configFolder, 'queue.json'), 'w') as f: with open(Path(configFolder) / 'queue.json', 'w') as f:
json.dump({ json.dump({
'queue': self.queue, 'queue': self.queue,
'queueComplete': self.queueComplete, 'queueComplete': self.queueComplete,
@ -457,12 +457,13 @@ class QueueManager:
return queueList return queueList
def loadQueue(self, configFolder, settings, interface=None): def loadQueue(self, configFolder, settings, interface=None):
if path.isfile(path.join(configFolder, 'queue.json')) and not len(self.queue): configFolder = Path(configFolder)
if (configFolder / 'queue.json').is_file() and not len(self.queue):
if interface: if interface:
interface.send('restoringQueue') interface.send('restoringQueue')
with open(path.join(configFolder, 'queue.json'), 'r') as f: with open(configFolder / 'queue.json', 'r') as f:
qd = json.load(f) qd = json.load(f)
remove(path.join(configFolder, 'queue.json')) remove(configFolder / 'queue.json')
self.restoreQueue(qd['queue'], qd['queueComplete'], qd['queueList'], settings) self.restoreQueue(qd['queue'], qd['queueComplete'], qd['queueList'], settings)
if interface: if interface:
interface.send('init_downloadQueue', { interface.send('init_downloadQueue', {

View File

@ -1,6 +1,6 @@
import json import json
import os.path as path from pathlib import Path
from os import makedirs, listdir, remove from os import makedirs, listdir
from deemix import __version__ as deemixVersion from deemix import __version__ as deemixVersion
import logging import logging
import datetime import datetime
@ -11,14 +11,8 @@ logger = logging.getLogger('deemix')
import deemix.utils.localpaths as localpaths import deemix.utils.localpaths as localpaths
class Settings: DEFAULT_SETTINGS = {
def __init__(self, configFolder=None): "downloadLocation": str(localpaths.getHomeFolder() / 'deemix Music'),
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%", "tracknameTemplate": "%artist% - %title%",
"albumTracknameTemplate": "%tracknumber% - %title%", "albumTracknameTemplate": "%tracknumber% - %title%",
"playlistTracknameTemplate": "%position% - %artist% - %title%", "playlistTracknameTemplate": "%position% - %artist% - %title%",
@ -95,18 +89,26 @@ class Settings:
"singleAlbumArtist": False, "singleAlbumArtist": False,
"coverDescriptionUTF8": False "coverDescriptionUTF8": False
} }
} }
class Settings:
def __init__(self, configFolder=None):
self.settings = {}
self.configFolder = configFolder
if not self.configFolder:
self.configFolder = localpaths.getConfigFolder()
self.configFolder = Path(self.configFolder)
# Create config folder if it doesn't exsist # Create config folder if it doesn't exsist
makedirs(self.configFolder, exist_ok=True) makedirs(self.configFolder, exist_ok=True)
# Create config file if it doesn't exsist # Create config file if it doesn't exsist
if not path.isfile(path.join(self.configFolder, 'config.json')): if not (self.configFolder / 'config.json').is_file():
with open(path.join(self.configFolder, 'config.json'), 'w') as f: with open(self.configFolder / 'config.json', 'w') as f:
json.dump(self.defaultSettings, f, indent=2) json.dump(DEFAULT_SETTINGS, f, indent=2)
# Read config file # Read config file
with open(path.join(self.configFolder, 'config.json'), 'r') as configFile: with open(self.configFolder / 'config.json', 'r') as configFile:
self.settings = json.load(configFile) self.settings = json.load(configFile)
self.settingsCheck() self.settingsCheck()
@ -117,13 +119,13 @@ class Settings:
# LOGFILES # LOGFILES
# Create logfile name and path # Create logfile name and path
logspath = path.join(self.configFolder, 'logs') logspath = self.configFolder / 'logs'
now = datetime.datetime.now() now = datetime.datetime.now()
logfile = now.strftime("%Y-%m-%d_%H%M%S")+".log" logfile = now.strftime("%Y-%m-%d_%H%M%S")+".log"
makedirs(logspath, exist_ok=True) makedirs(logspath, exist_ok=True)
# Add handler for logging # Add handler for logging
fh = logging.FileHandler(path.join(logspath, logfile), 'w', 'utf-8') fh = logging.FileHandler(logspath / logfile, 'w', 'utf-8')
fh.setLevel(logging.DEBUG) fh.setLevel(logging.DEBUG)
fh.setFormatter(logging.Formatter('%(asctime)s - [%(levelname)s] %(message)s')) fh.setFormatter(logging.Formatter('%(asctime)s - [%(levelname)s] %(message)s'))
logger.addHandler(fh) logger.addHandler(fh)
@ -134,33 +136,33 @@ class Settings:
logslist.sort() logslist.sort()
if len(logslist)>5: if len(logslist)>5:
for i in range(len(logslist)-5): for i in range(len(logslist)-5):
remove(path.join(logspath, logslist[i])) (logspath / logslist[i]).unlink()
# Saves the settings # Saves the settings
def saveSettings(self, newSettings=None, dz=None): def saveSettings(self, newSettings=None, dz=None):
if newSettings: if newSettings:
if dz and newSettings.get('tagsLanguage') != self.settings.get('tagsLanguage'): dz.set_accept_language(newSettings.get('tagsLanguage')) if dz and newSettings.get('tagsLanguage') != self.settings.get('tagsLanguage'): dz.set_accept_language(newSettings.get('tagsLanguage'))
self.settings = newSettings self.settings = newSettings
with open(path.join(self.configFolder, 'config.json'), 'w') as configFile: with open(self.configFolder / 'config.json', 'w') as configFile:
json.dump(self.settings, configFile, indent=2) json.dump(self.settings, configFile, indent=2)
# Checks if the default settings have changed # Checks if the default settings have changed
def settingsCheck(self): def settingsCheck(self):
changes = 0 changes = 0
for x in self.defaultSettings: for x in DEFAULT_SETTINGS:
if not x in self.settings or type(self.settings[x]) != type(self.defaultSettings[x]): if not x in self.settings or type(self.settings[x]) != type(DEFAULT_SETTINGS[x]):
self.settings[x] = self.defaultSettings[x] self.settings[x] = DEFAULT_SETTINGS[x]
changes += 1 changes += 1
for x in self.defaultSettings['tags']: for x in DEFAULT_SETTINGS['tags']:
if not x in self.settings['tags'] or type(self.settings['tags'][x]) != type(self.defaultSettings['tags'][x]): if not x in self.settings['tags'] or type(self.settings['tags'][x]) != type(DEFAULT_SETTINGS['tags'][x]):
self.settings['tags'][x] = self.defaultSettings['tags'][x] self.settings['tags'][x] = DEFAULT_SETTINGS['tags'][x]
changes += 1 changes += 1
if self.settings['downloadLocation'] == "": if self.settings['downloadLocation'] == "":
self.settings['downloadLocation'] = path.join(localpaths.getHomeFolder(), 'deemix Music') self.settings['downloadLocation'] = str(localpaths.getHomeFolder() / 'deemix Music')
changes += 1 changes += 1
for template in ['tracknameTemplate', 'albumTracknameTemplate', 'playlistTracknameTemplate', 'playlistNameTemplate', 'artistNameTemplate', 'albumNameTemplate', 'playlistFilenameTemplate', 'coverImageTemplate', 'artistImageTemplate', 'paddingSize']: for template in ['tracknameTemplate', 'albumTracknameTemplate', 'playlistTracknameTemplate', 'playlistNameTemplate', 'artistNameTemplate', 'albumNameTemplate', 'playlistFilenameTemplate', 'coverImageTemplate', 'artistImageTemplate', 'paddingSize']:
if self.settings[template] == "": if self.settings[template] == "":
self.settings[template] = self.defaultSettings[template] self.settings[template] = DEFAULT_SETTINGS[template]
changes += 1 changes += 1
if changes > 0: if changes > 0:
self.saveSettings() self.saveSettings()

View File

@ -1,7 +1,6 @@
import eventlet import eventlet
import json import json
import os.path as path from pathlib import Path
from os import mkdir, remove
eventlet.import_patched('requests.adapters') eventlet.import_patched('requests.adapters')
@ -38,33 +37,34 @@ class SpotifyHelper:
# Make sure config folder exsists # Make sure config folder exsists
if not self.configFolder: if not self.configFolder:
self.configFolder = getConfigFolder() self.configFolder = getConfigFolder()
if not path.isdir(self.configFolder): self.configFolder = Path(self.configFolder)
mkdir(self.configFolder) if not self.configFolder.is_dir():
self.configFolder.mkdir()
# Make sure authCredentials exsits # Make sure authCredentials exsits
if not path.isfile(path.join(self.configFolder, 'authCredentials.json')): if not (self.configFolder / 'authCredentials.json').is_file():
with open(path.join(self.configFolder, 'authCredentials.json'), 'w') as f: with open(self.configFolder / 'authCredentials.json', 'w') as f:
json.dump({'clientId': "", 'clientSecret': ""}, f, indent=2) json.dump({'clientId': "", 'clientSecret': ""}, f, indent=2)
# Load spotify id and secret and check if they are usable # Load spotify id and secret and check if they are usable
with open(path.join(self.configFolder, 'authCredentials.json'), 'r') as credentialsFile: with open(self.configFolder / 'authCredentials.json', 'r') as credentialsFile:
self.credentials = json.load(credentialsFile) self.credentials = json.load(credentialsFile)
self.checkCredentials() self.checkCredentials()
self.checkValidCache() self.checkValidCache()
def checkValidCache(self): def checkValidCache(self):
if path.isfile(path.join(self.configFolder, 'spotifyCache.json')): if (self.configFolder / 'spotifyCache.json').is_file():
with open(path.join(self.configFolder, 'spotifyCache.json'), 'r') as spotifyCache: with open(self.configFolder / 'spotifyCache.json', 'r') as spotifyCache:
try: try:
cache = json.load(spotifyCache) cache = json.load(spotifyCache)
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
remove(path.join(self.configFolder, 'spotifyCache.json')) (self.configFolder / 'spotifyCache.json').unlink()
return return
# Remove old versions of cache # Remove old versions of cache
if len(cache['tracks'].values()) and isinstance(list(cache['tracks'].values())[0], int) or \ if len(cache['tracks'].values()) and isinstance(list(cache['tracks'].values())[0], int) or \
len(cache['albums'].values()) and isinstance(list(cache['albums'].values())[0], int): len(cache['albums'].values()) and isinstance(list(cache['albums'].values())[0], int):
remove(path.join(self.configFolder, 'spotifyCache.json')) (self.configFolder / 'spotifyCache.json').unlink()
def checkCredentials(self): def checkCredentials(self):
if self.credentials['clientId'] == "" or self.credentials['clientSecret'] == "": if self.credentials['clientId'] == "" or self.credentials['clientSecret'] == "":
@ -89,7 +89,7 @@ class SpotifyHelper:
spotifyCredentials['clientSecret'] = spotifyCredentials['clientSecret'].strip() spotifyCredentials['clientSecret'] = spotifyCredentials['clientSecret'].strip()
# Save them to disk # Save them to disk
with open(path.join(self.configFolder, 'authCredentials.json'), 'w') as f: with open(self.configFolder / 'authCredentials.json', 'w') as f:
json.dump(spotifyCredentials, f, indent=2) json.dump(spotifyCredentials, f, indent=2)
# Check if they are usable # Check if they are usable
@ -143,8 +143,8 @@ class SpotifyHelper:
raise spotifyFeaturesNotEnabled raise spotifyFeaturesNotEnabled
singleTrack = False singleTrack = False
if not spotifyTrack: if not spotifyTrack:
if path.isfile(path.join(self.configFolder, 'spotifyCache.json')): if (self.configFolder / 'spotifyCache.json').is_file():
with open(path.join(self.configFolder, 'spotifyCache.json'), 'r') as spotifyCache: with open(self.configFolder / 'spotifyCache.json', 'r') as spotifyCache:
cache = json.load(spotifyCache) cache = json.load(spotifyCache)
else: else:
cache = {'tracks': {}, 'albums': {}} cache = {'tracks': {}, 'albums': {}}
@ -175,7 +175,7 @@ class SpotifyHelper:
spotify_track['album']['name']) spotify_track['album']['name'])
if singleTrack: if singleTrack:
cache['tracks'][str(track_id)] = {'id': dz_id, 'isrc': isrc} cache['tracks'][str(track_id)] = {'id': dz_id, 'isrc': isrc}
with open(path.join(self.configFolder, 'spotifyCache.json'), 'w') as spotifyCache: with open(self.configFolder / 'spotifyCache.json', 'w') as spotifyCache:
json.dump(cache, spotifyCache) json.dump(cache, spotifyCache)
return (dz_id, dz_track, isrc) return (dz_id, dz_track, isrc)
@ -183,8 +183,8 @@ class SpotifyHelper:
def get_albumid_spotify(self, dz, album_id): def get_albumid_spotify(self, dz, album_id):
if not self.spotifyEnabled: if not self.spotifyEnabled:
raise spotifyFeaturesNotEnabled raise spotifyFeaturesNotEnabled
if path.isfile(path.join(self.configFolder, 'spotifyCache.json')): if (self.configFolder / 'spotifyCache.json').is_file():
with open(path.join(self.configFolder, 'spotifyCache.json'), 'r') as spotifyCache: with open(self.configFolder / 'spotifyCache.json', 'r') as spotifyCache:
cache = json.load(spotifyCache) cache = json.load(spotifyCache)
else: else:
cache = {'tracks': {}, 'albums': {}} cache = {'tracks': {}, 'albums': {}}
@ -205,7 +205,7 @@ class SpotifyHelper:
except: except:
dz_album = "0" dz_album = "0"
cache['albums'][str(album_id)] = {'id': dz_album, 'upc': upc} cache['albums'][str(album_id)] = {'id': dz_album, 'upc': upc}
with open(path.join(self.configFolder, 'spotifyCache.json'), 'w') as spotifyCache: with open(self.configFolder / 'spotifyCache.json', 'w') as spotifyCache:
json.dump(cache, spotifyCache) json.dump(cache, spotifyCache)
return dz_album return dz_album
@ -255,8 +255,8 @@ class SpotifyHelper:
def convert_spotify_playlist(self, dz, queueItem, interface=None): def convert_spotify_playlist(self, dz, queueItem, interface=None):
convertPercentage = 0 convertPercentage = 0
lastPercentage = 0 lastPercentage = 0
if path.isfile(path.join(self.configFolder, 'spotifyCache.json')): if (self.configFolder / 'spotifyCache.json').is_file():
with open(path.join(self.configFolder, 'spotifyCache.json'), 'r') as spotifyCache: with open(self.configFolder / 'spotifyCache.json', 'r') as spotifyCache:
cache = json.load(spotifyCache) cache = json.load(spotifyCache)
else: else:
cache = {'tracks': {}, 'albums': {}} cache = {'tracks': {}, 'albums': {}}
@ -309,7 +309,7 @@ class SpotifyHelper:
queueItem.extra = None queueItem.extra = None
queueItem.collection = collection queueItem.collection = collection
with open(path.join(self.configFolder, 'spotifyCache.json'), 'w') as spotifyCache: with open(self.configFolder / 'spotifyCache.json', 'w') as spotifyCache:
json.dump(cache, spotifyCache) json.dump(cache, spotifyCache)
if interface: if interface:
interface.send("startDownload", queueItem.uuid) interface.send("startDownload", queueItem.uuid)

View File

@ -43,6 +43,8 @@ class Track:
if "_EXTRA_PLAYLIST" in trackAPI_gw: if "_EXTRA_PLAYLIST" in trackAPI_gw:
self.parsePlaylistData(trackAPI_gw["_EXTRA_PLAYLIST"], settings) self.parsePlaylistData(trackAPI_gw["_EXTRA_PLAYLIST"], settings)
self.singleDownload = trackAPI_gw.get('SINGLE_TRACK', False)
self.generateMainFeatStrings() self.generateMainFeatStrings()
# Bits useful for later # Bits useful for later
@ -367,6 +369,8 @@ class Track:
'year': playlist["creation_date"][0:4] 'year': playlist["creation_date"][0:4]
} }
self.playlist['discTotal'] = "1" self.playlist['discTotal'] = "1"
self.playlist['playlistId'] = playlist['id']
self.playlist['owner'] = playlist['creator']
# Removes featuring from the title # Removes featuring from the title
def getCleanTitle(self): def getCleanTitle(self):
@ -383,7 +387,7 @@ class Track:
def generateMainFeatStrings(self): def generateMainFeatStrings(self):
self.mainArtistsString = andCommaConcat(self.artist['Main']) self.mainArtistsString = andCommaConcat(self.artist['Main'])
self.featArtistsString = None self.featArtistsString = ""
if 'Featured' in self.artist: if 'Featured' in self.artist:
self.featArtistsString = "feat. "+andCommaConcat(self.artist['Featured']) self.featArtistsString = "feat. "+andCommaConcat(self.artist['Featured'])

View File

@ -1,18 +1,18 @@
import os.path as path from pathlib import Path
import sys import sys
from os import getenv from os import getenv
userdata = "" userdata = ""
homedata = path.expanduser("~") homedata = Path.home()
if getenv("APPDATA"): if getenv("APPDATA"):
userdata = getenv("APPDATA") + path.sep + "deemix" + path.sep userdata = Path(getenv("APPDATA")) / "deemix"
elif sys.platform.startswith('darwin'): elif sys.platform.startswith('darwin'):
userdata = homedata + '/Library/Application Support/deemix/' userdata = homedata / 'Library' / 'Application Support' / 'deemix'
elif getenv("XDG_CONFIG_HOME"): elif getenv("XDG_CONFIG_HOME"):
userdata = getenv("XDG_CONFIG_HOME") + '/deemix/' userdata = Path(getenv("XDG_CONFIG_HOME")) / 'deemix'
else: else:
userdata = homedata + '/.config/deemix/' userdata = homedata / '.config' / 'deemix'
def getHomeFolder(): def getHomeFolder():
return homedata return homedata

View File

@ -1,5 +1,6 @@
import re import re
from os.path import sep as pathSep from os.path import sep as pathSep
from pathlib import Path
from unicodedata import normalize from unicodedata import normalize
bitrateLabels = { bitrateLabels = {
@ -13,7 +14,6 @@ bitrateLabels = {
0: "MP3" 0: "MP3"
} }
def fixName(txt, char='_'): def fixName(txt, char='_'):
txt = str(txt) txt = str(txt)
txt = re.sub(r'[\0\/\\:*?"<>|]', char, txt) txt = re.sub(r'[\0\/\\:*?"<>|]', char, txt)
@ -29,13 +29,10 @@ def fixEndOfData(bString):
def fixLongName(name): def fixLongName(name):
if pathSep in name: if pathSep in name:
name2 = name.split(pathSep) sepName = name.split(pathSep)
name = "" name = ""
for txt in name2: for txt in sepName:
txt = txt.encode('utf-8')[:200] txt = fixLongName(txt)
while not fixEndOfData(txt):
txt = txt[:-1]
txt = txt.decode()
name += txt + pathSep name += txt + pathSep
name = name[:-1] name = name[:-1]
else: else:
@ -54,92 +51,82 @@ def antiDot(string):
return string return string
def pad(num, max, dopad=True): def pad(num, max, settings):
paddingsize = len(str(max)) if int(settings['paddingSize']) == 0:
if paddingsize == 1: paddingSize = len(str(max))
paddingsize = 2 else:
if dopad: paddingSize = 10 ** (int(settings['paddingSize']) - 1)
return str(num).zfill(paddingsize) if paddingSize == 1:
paddingSize = 2
if settings['padTracks']:
return str(num).zfill(paddingSize)
else: else:
return str(num) return str(num)
def generateFilename(track, settings, template):
filename = template or "%artist% - %title%"
return settingsRegex(filename, track, settings)
def generateFilename(track, trackAPI, settings): def generateFilepath(track, settings):
if trackAPI['FILENAME_TEMPLATE'] == "": filepath = Path(settings['downloadLocation'])
filename = "%artist% - %title%"
else:
filename = trackAPI['FILENAME_TEMPLATE']
return settingsRegex(filename, track, settings,
trackAPI['_EXTRA_PLAYLIST'] if '_EXTRA_PLAYLIST' in trackAPI else None)
def generateFilepath(track, trackAPI, settings):
filepath = settings['downloadLocation']
if filepath[-1:] != pathSep:
filepath += pathSep
artistPath = None artistPath = None
coverPath = None coverPath = None
extrasPath = None extrasPath = None
if settings['createPlaylistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and not settings['tags'][ if settings['createPlaylistFolder'] and track.playlist and not settings['tags']['savePlaylistAsCompilation']:
'savePlaylistAsCompilation']: filepath = filepath / settingsRegexPlaylist(settings['playlistNameTemplate'], track.playlist, settings)
filepath += antiDot(
settingsRegexPlaylist(settings['playlistNameTemplate'], trackAPI['_EXTRA_PLAYLIST'], settings)) + pathSep
if '_EXTRA_PLAYLIST' in trackAPI and not settings['tags']['savePlaylistAsCompilation']: if track.playlist and not settings['tags']['savePlaylistAsCompilation']:
extrasPath = filepath extrasPath = filepath
if ( if (
settings['createArtistFolder'] and not '_EXTRA_PLAYLIST' in trackAPI or (settings['createArtistFolder'] and not track.playlist) or
(settings['createArtistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and settings['tags'][ (settings['createArtistFolder'] and track.playlist and settings['tags']['savePlaylistAsCompilation']) or
'savePlaylistAsCompilation']) or (settings['createArtistFolder'] and track.playlist and settings['createStructurePlaylist'])
(settings['createArtistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist'])
): ):
if (int(track.id) < 0 and not 'mainArtist' in track.album): filepath = filepath / settingsRegexArtist(settings['artistNameTemplate'], track.album['mainArtist'], settings)
track.album['mainArtist'] = track.mainArtist
filepath += antiDot(
settingsRegexArtist(settings['artistNameTemplate'], track.album['mainArtist'], settings)) + pathSep
artistPath = filepath artistPath = filepath
if (settings['createAlbumFolder'] and if (settings['createAlbumFolder'] and
(not 'SINGLE_TRACK' in trackAPI or ('SINGLE_TRACK' in trackAPI and settings['createSingleFolder'])) and (not track.singleDownload or (track.singleDownload and settings['createSingleFolder'])) and
(not '_EXTRA_PLAYLIST' in trackAPI or ( (not track.playlist or
'_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']) or ( (track.playlist and settings['tags']['savePlaylistAsCompilation']) or
'_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist'])) (track.playlist and settings['createStructurePlaylist'])
)
): ):
filepath += antiDot( filepath = filepath / settingsRegexAlbum(settings['albumNameTemplate'], track.album, settings, track.playlist if track.playlist else None)
settingsRegexAlbum(settings['albumNameTemplate'], track.album, settings,
trackAPI['_EXTRA_PLAYLIST'] if'_EXTRA_PLAYLIST' in trackAPI else None)) + pathSep
coverPath = filepath coverPath = filepath
if not ('_EXTRA_PLAYLIST' in trackAPI and not settings['tags']['savePlaylistAsCompilation']): if not (track.playlist and not settings['tags']['savePlaylistAsCompilation']):
extrasPath = filepath extrasPath = filepath
if ( if (
int(track.album['discTotal']) > 1 and ( int(track.album['discTotal']) > 1 and (
(settings['createAlbumFolder'] and settings['createCDFolder']) and (settings['createAlbumFolder'] and settings['createCDFolder']) and
(not 'SINGLE_TRACK' in trackAPI or ('SINGLE_TRACK' in trackAPI and settings['createSingleFolder'])) and (not track.singleDownload or (track.singleDownload and settings['createSingleFolder'])) and
(not '_EXTRA_PLAYLIST' in trackAPI or ( (not track.playlist or
'_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']) or ( (track.playlist and settings['tags']['savePlaylistAsCompilation']) or
'_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist'])) (track.playlist and settings['createStructurePlaylist'])
)
)): )):
filepath += 'CD' + str(track.discNumber) + pathSep filepath = filepath / 'CD' + str(track.discNumber)
return (filepath, artistPath, coverPath, extrasPath) return (filepath, artistPath, coverPath, extrasPath)
def settingsRegex(filename, track, settings, playlist=None): def settingsRegex(filename, track, settings):
filename = filename.replace("%title%", fixName(track.title, settings['illegalCharacterReplacer'])) filename = filename.replace("%title%", fixName(track.title, settings['illegalCharacterReplacer']))
filename = filename.replace("%artist%", fixName(track.mainArtist['name'], settings['illegalCharacterReplacer'])) filename = filename.replace("%artist%", fixName(track.mainArtist['name'], settings['illegalCharacterReplacer']))
filename = filename.replace("%artists%", fixName(", ".join(track.artists), settings['illegalCharacterReplacer'])) filename = filename.replace("%artists%", fixName(", ".join(track.artists), settings['illegalCharacterReplacer']))
filename = filename.replace("%allartists%", fixName(track.artistsString, settings['illegalCharacterReplacer'])) filename = filename.replace("%allartists%", fixName(track.artistsString, settings['illegalCharacterReplacer']))
filename = filename.replace("%mainartists%", fixName(track.mainArtistsString, settings['illegalCharacterReplacer'])) filename = filename.replace("%mainartists%", fixName(track.mainArtistsString, settings['illegalCharacterReplacer']))
filename = filename.replace("%featartists%", fixName('('+track.featArtistsString+')', settings['illegalCharacterReplacer']) if track.featArtistsString else "") if track.featArtistsString:
filename = filename.replace("%featartists%", fixName('('+track.featArtistsString+')', settings['illegalCharacterReplacer']))
else:
filename = filename.replace("%featartists%", '')
filename = filename.replace("%album%", fixName(track.album['title'], settings['illegalCharacterReplacer'])) filename = filename.replace("%album%", fixName(track.album['title'], settings['illegalCharacterReplacer']))
filename = filename.replace("%albumartist%", filename = filename.replace("%albumartist%", fixName(track.album['mainArtist']['name'], settings['illegalCharacterReplacer']))
fixName(track.album['mainArtist']['name'], settings['illegalCharacterReplacer'])) filename = filename.replace("%tracknumber%", pad(track.trackNumber, track.album['trackTotal'], settings))
filename = filename.replace("%tracknumber%", pad(track.trackNumber, track.album['trackTotal'] if int(
settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize']) - 1), settings['padTracks']))
filename = filename.replace("%tracktotal%", str(track.album['trackTotal'])) filename = filename.replace("%tracktotal%", str(track.album['trackTotal']))
filename = filename.replace("%discnumber%", str(track.discNumber)) filename = filename.replace("%discnumber%", str(track.discNumber))
filename = filename.replace("%disctotal%", str(track.album['discTotal'])) filename = filename.replace("%disctotal%", str(track.album['discTotal']))
@ -159,21 +146,20 @@ def settingsRegex(filename, track, settings, playlist=None):
filename = filename.replace("%track_id%", str(track.id)) filename = filename.replace("%track_id%", str(track.id))
filename = filename.replace("%album_id%", str(track.album['id'])) filename = filename.replace("%album_id%", str(track.album['id']))
filename = filename.replace("%artist_id%", str(track.mainArtist['id'])) filename = filename.replace("%artist_id%", str(track.mainArtist['id']))
if playlist: if track.playlist:
filename = filename.replace("%playlist_id%", str(playlist['id'])) filename = filename.replace("%playlist_id%", str(track.playlist['playlistId']))
filename = filename.replace("%position%", pad(track.position, playlist['nb_tracks'] if int( filename = filename.replace("%position%", pad(track.position, track.playlist['trackTotal'], settings))
settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize']) - 1), settings['padTracks']))
else: else:
filename = filename.replace("%position%", pad(track.trackNumber, track.album['trackTotal'] if int( filename = filename.replace("%playlist_id%", '')
settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize']) - 1), settings['padTracks'])) filename = filename.replace("%position%", pad(track.trackNumber, track.album['trackTotal'], settings))
filename = filename.replace('\\', pathSep).replace('/', pathSep) filename = filename.replace('\\', pathSep).replace('/', pathSep)
return antiDot(fixLongName(filename)) return antiDot(fixLongName(filename))
def settingsRegexAlbum(foldername, album, settings, playlist=None): def settingsRegexAlbum(foldername, album, settings, playlist=None):
if playlist and settings['tags']['savePlaylistAsCompilation']: if playlist and settings['tags']['savePlaylistAsCompilation']:
foldername = foldername.replace("%album_id%", "pl_" + str(playlist['id'])) foldername = foldername.replace("%album_id%", "pl_" + str(playlist['playlistId']))
foldername = foldername.replace("%genre%", "Compilation") foldername = foldername.replace("%genre%", "Compile")
else: else:
foldername = foldername.replace("%album_id%", str(album['id'])) foldername = foldername.replace("%album_id%", str(album['id']))
if len(album['genre']) > 0: if len(album['genre']) > 0:
@ -186,8 +172,7 @@ def settingsRegexAlbum(foldername, album, settings, playlist=None):
foldername = foldername.replace("%artist_id%", str(album['mainArtist']['id'])) foldername = foldername.replace("%artist_id%", str(album['mainArtist']['id']))
foldername = foldername.replace("%tracktotal%", str(album['trackTotal'])) foldername = foldername.replace("%tracktotal%", str(album['trackTotal']))
foldername = foldername.replace("%disctotal%", str(album['discTotal'])) foldername = foldername.replace("%disctotal%", str(album['discTotal']))
foldername = foldername.replace("%type%", fixName(album['recordType'][0].upper() + album['recordType'][1:].lower(), foldername = foldername.replace("%type%", fixName(album['recordType'].capitalize(), settings['illegalCharacterReplacer']))
settings['illegalCharacterReplacer']))
foldername = foldername.replace("%upc%", album['barcode']) foldername = foldername.replace("%upc%", album['barcode'])
foldername = foldername.replace("%explicit%", "(Explicit)" if album['explicit'] else "") foldername = foldername.replace("%explicit%", "(Explicit)" if album['explicit'] else "")
foldername = foldername.replace("%label%", fixName(album['label'], settings['illegalCharacterReplacer'])) foldername = foldername.replace("%label%", fixName(album['label'], settings['illegalCharacterReplacer']))
@ -208,12 +193,11 @@ def settingsRegexArtist(foldername, artist, settings):
def settingsRegexPlaylist(foldername, playlist, settings): def settingsRegexPlaylist(foldername, playlist, settings):
foldername = foldername.replace("%playlist%", fixName(playlist['title'], settings['illegalCharacterReplacer'])) foldername = foldername.replace("%playlist%", fixName(playlist['title'], settings['illegalCharacterReplacer']))
foldername = foldername.replace("%playlist_id%", fixName(playlist['id'], settings['illegalCharacterReplacer'])) foldername = foldername.replace("%playlist_id%", fixName(playlist['playlistId'], settings['illegalCharacterReplacer']))
foldername = foldername.replace("%owner%", foldername = foldername.replace("%owner%", fixName(playlist['owner']['name'], settings['illegalCharacterReplacer']))
fixName(playlist['creator']['name'], settings['illegalCharacterReplacer'])) foldername = foldername.replace("%owner_id%", str(playlist['owner']['id']))
foldername = foldername.replace("%owner_id%", str(playlist['creator']['id'])) foldername = foldername.replace("%year%", str(playlist['date']['year']))
foldername = foldername.replace("%year%", str(playlist['creation_date'][:4])) foldername = foldername.replace("%date%", str(playlist['dateString']))
foldername = foldername.replace("%date%", str(playlist['creation_date'][:10]))
foldername = foldername.replace("%explicit%", "(Explicit)" if playlist['explicit'] else "") foldername = foldername.replace("%explicit%", "(Explicit)" if playlist['explicit'] else "")
foldername = foldername.replace('\\', pathSep).replace('/', pathSep) foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
return antiDot(fixLongName(foldername)) return antiDot(fixLongName(foldername))

View File

@ -101,7 +101,7 @@ def tagID3(stream, track, save):
descEncoding = Encoding.UTF8 descEncoding = Encoding.UTF8
mimeType = 'image/jpeg' mimeType = 'image/jpeg'
if track.album['picPath'].endswith('png'): if str(track.album['picPath']).endswith('png'):
mimeType = 'image/png' mimeType = 'image/png'
with open(track.album['picPath'], 'rb') as f: with open(track.album['picPath'], 'rb') as f:
@ -195,7 +195,7 @@ def tagFLAC(stream, track, save):
image = Picture() image = Picture()
image.type = PictureType.COVER_FRONT image.type = PictureType.COVER_FRONT
image.mime = 'image/jpeg' image.mime = 'image/jpeg'
if track.album['picPath'].endswith('png'): if str(track.album['picPath']).endswith('png'):
image.mime = 'image/png' image.mime = 'image/png'
with open(track.album['picPath'], 'rb') as f: with open(track.album['picPath'], 'rb') as f:
image.data = f.read() image.data = f.read()

View File

@ -7,7 +7,7 @@ README = (HERE / "README.md").read_text()
setup( setup(
name="deemix", name="deemix",
version="1.4.3", version="1.5.0",
description="A barebone deezer downloader library", description="A barebone deezer downloader library",
long_description=README, long_description=README,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",