parent
6e955ee01f
commit
798dcdd3d9
|
@ -1,3 +1,3 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
__version__ = "1.4.3"
|
__version__ = "1.5.0"
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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', {
|
||||||
|
|
|
@ -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%",
|
||||||
|
@ -97,16 +91,24 @@ class Settings:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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'])
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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()
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue