code maintenance and removal of spotify username requirement

This commit is contained in:
deeplydrumming
2024-08-02 16:03:44 +01:00
parent c58bb4adf1
commit 9ddd7fea0e
26 changed files with 272 additions and 394 deletions

View File

@@ -1,13 +0,0 @@
{
"env": {
"commonjs": true,
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
}
}

View File

@@ -1,49 +1,49 @@
const got = require('got')
const {CookieJar} = require('tough-cookie')
const {_md5} = require('./crypto.js')
const { CookieJar } = require('tough-cookie')
const { _md5 } = require('./crypto.js')
const { USER_AGENT_HEADER } = require('./index.js')
const CLIENT_ID = "172365"
const CLIENT_SECRET = "fb0bec7ccc063dab0417eb7b0d847f34"
const CLIENT_ID = '172365'
const CLIENT_SECRET = 'fb0bec7ccc063dab0417eb7b0d847f34'
async function getAccessToken(email, password){
async function getAccessToken (email, password) {
let accessToken = null
password = _md5(password, 'utf8')
const hash = _md5([CLIENT_ID, email, password, CLIENT_SECRET].join(''), 'utf8')
try {
let response = await got.get("https://api.deezer.com/auth/token",{
const response = await got.get('https://api.deezer.com/auth/token', {
searchParams: {
app_id: CLIENT_ID,
login: email,
password: password,
password,
hash
},
https: {rejectUnauthorized: false},
headers: {"User-Agent": USER_AGENT_HEADER}
https: { rejectUnauthorized: false },
headers: { 'User-Agent': USER_AGENT_HEADER }
}).json()
accessToken = response.access_token
if (accessToken == "undefined") accessToken = null
} catch { /*empty*/ }
if (accessToken === 'undefined') accessToken = null
} catch { /* empty */ }
return accessToken
}
async function getArlFromAccessToken(accessToken){
async function getArlFromAccessToken (accessToken) {
if (!accessToken) return null
let arl = null
let cookieJar = new CookieJar()
const cookieJar = new CookieJar()
try {
await got.get("https://api.deezer.com/platform/generic/track/3135556", {
headers: {"Authorization": `Bearer ${accessToken}`, "User-Agent": USER_AGENT_HEADER},
https: {rejectUnauthorized: false},
await got.get('https://api.deezer.com/platform/generic/track/3135556', {
headers: { Authorization: `Bearer ${accessToken}`, 'User-Agent': USER_AGENT_HEADER },
https: { rejectUnauthorized: false },
cookieJar
})
let response = await got.get('https://www.deezer.com/ajax/gw-light.php?method=user.getArl&input=3&api_version=1.0&api_token=null', {
headers: {"User-Agent": USER_AGENT_HEADER},
https: {rejectUnauthorized: false},
const response = await got.get('https://www.deezer.com/ajax/gw-light.php?method=user.getArl&input=3&api_version=1.0&api_token=null', {
headers: { 'User-Agent': USER_AGENT_HEADER },
https: { rejectUnauthorized: false },
cookieJar
}).json()
arl = response.results
} catch { /*empty*/ }
} catch { /* empty */ }
return arl
}

View File

@@ -1,32 +1,32 @@
const stream = require('stream')
const {promisify} = require('util')
const { promisify } = require('util')
const pipeline = promisify(stream.pipeline)
const { accessSync, constants } = require('fs')
const { ErrorMessages } = require('../errors.js')
const USER_AGENT_HEADER = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"
const USER_AGENT_HEADER = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
function canWrite(path){
try{
function canWrite (path) {
try {
accessSync(path, constants.R_OK | constants.W_OK)
}catch{
} catch {
return false
}
return true
}
function generateReplayGainString(trackGain){
return `${Math.round((parseFloat(trackGain) + 18.4)*-100)/100} dB`
function generateReplayGainString (trackGain) {
return `${Math.round((parseFloat(trackGain) + 18.4) * -100) / 100} dB`
}
function changeCase(txt, type){
function changeCase (txt, type) {
switch (type) {
case 'lower': return txt.toLowerCase()
case 'upper': return txt.toUpperCase()
case 'start':
txt = txt.trim().split(" ")
txt = txt.trim().split(' ')
for (let i = 0; i < txt.length; i++) {
if (['(', '{', '[', "'", '"'].some(bracket => ( txt[i].length > 1 && txt[i].startsWith(bracket) ) )) {
if (['(', '{', '[', "'", '"'].some(bracket => (txt[i].length > 1 && txt[i].startsWith(bracket)))) {
txt[i] = txt[i][0] + txt[i][1].toUpperCase() + txt[i].substr(2).toLowerCase()
} else if (txt[i].length > 1) {
txt[i] = txt[i][0].toUpperCase() + txt[i].substr(1).toLowerCase()
@@ -34,58 +34,56 @@ function changeCase(txt, type){
txt[i] = txt[i][0].toUpperCase()
}
}
return txt.join(" ")
return txt.join(' ')
case 'sentence': return txt.charAt(0).toUpperCase() + txt.slice(1).toLowerCase()
default: return txt
}
}
function removeFeatures(title){
function removeFeatures (title) {
let clean = title
let found = false
let pos
if (clean.search(/[\s(]\(?\s?feat\.?\s/gi) != -1){
if (clean.search(/[\s(]\(?\s?feat\.?\s/gi) !== -1) {
pos = clean.search(/[\s(]\(?\s?feat\.?\s/gi)
found = true
}
if (clean.search(/[\s(]\(?\s?ft\.?\s/gi) != -1){
if (clean.search(/[\s(]\(?\s?ft\.?\s/gi) !== -1) {
pos = clean.search(/[\s(]\(?\s?ft\.?\s/gi)
found = true
}
const openBracket = clean[pos] == '(' || clean[pos+1] == '('
const otherBracket = clean.indexOf('(', pos+2)
const openBracket = clean[pos] === '(' || clean[pos + 1] === '('
const otherBracket = clean.indexOf('(', pos + 2)
if (found) {
let tempTrack = clean.slice(0, pos)
if (clean.includes(')') && openBracket)
tempTrack += clean.slice(clean.indexOf(')', pos+2)+1)
if (!openBracket && otherBracket != -1)
tempTrack += ` ${clean.slice(otherBracket)}`
if (clean.includes(')') && openBracket) { tempTrack += clean.slice(clean.indexOf(')', pos + 2) + 1) }
if (!openBracket && otherBracket !== -1) { tempTrack += ` ${clean.slice(otherBracket)}` }
clean = tempTrack.trim()
clean = clean.replace(/\s\s+/g, ' ') // remove extra spaces
}
return clean
}
function andCommaConcat(lst){
function andCommaConcat (lst) {
const tot = lst.length
let result = ""
let result = ''
lst.forEach((art, i) => {
result += art
if (tot != i+1){
if (tot - 1 == i+1){
result += " & "
if (tot !== i + 1) {
if (tot - 1 === i + 1) {
result += ' & '
} else {
result += ", "
result += ', '
}
}
})
return result
}
function uniqueArray(arr){
function uniqueArray (arr) {
arr.forEach((namePrinc, iPrinc) => {
arr.forEach((nameRest, iRest) => {
if (iPrinc != iRest && nameRest.toLowerCase().includes(namePrinc.toLowerCase())){
if (iPrinc !== iRest && nameRest.toLowerCase().includes(namePrinc.toLowerCase())) {
arr.splice(iRest, 1)
}
})
@@ -93,13 +91,13 @@ function uniqueArray(arr){
return arr
}
function shellEscape(s){
function shellEscape (s) {
if (typeof s !== 'string') return ''
if (!(/[^\w@%+=:,./-]/g.test(s))) return s
return "'" + s.replaceAll("'", "'\"'\"'") + "'"
}
function removeDuplicateArtists(artist, artists){
function removeDuplicateArtists (artist, artists) {
artists = uniqueArray(artists)
Object.keys(artist).forEach((role) => {
artist[role] = uniqueArray(artist[role])
@@ -107,55 +105,55 @@ function removeDuplicateArtists(artist, artists){
return [artist, artists]
}
function formatListener(key, data){
let message = ""
function formatListener (key, data) {
let message = ''
switch (key) {
case "startAddingArtist": return `Started gathering ${data.name}'s albums (${data.id})`
case "finishAddingArtist": return `Finished gathering ${data.name}'s albums (${data.id})`
case "updateQueue":
message = `[${data['uuid']}]`
if (data.downloaded) message += ` Completed download of ${data.downloadPath.slice(data.extrasPath.length+1)}`
case 'startAddingArtist': return `Started gathering ${data.name}'s albums (${data.id})`
case 'finishAddingArtist': return `Finished gathering ${data.name}'s albums (${data.id})`
case 'updateQueue':
message = `[${data.uuid}]`
if (data.downloaded) message += ` Completed download of ${data.downloadPath.slice(data.extrasPath.length + 1)}`
if (data.failed) message += ` ${data.data.artist} - ${data.data.title} :: ${data.error}`
if (data.progress) message += ` Download at ${data.progress}%`
if (data.conversion) message += ` Conversion at ${data.conversion}%`
return message
case "downloadInfo":
case 'downloadInfo':
message = data.state
switch (data.state) {
case "getTags": message = "Getting tags."; break;
case "gotTags": message = "Tags got."; break;
case "getBitrate": message = "Getting download URL."; break;
case "bitrateFallback": message = "Desired bitrate not found, falling back to lower bitrate."; break;
case "searchFallback": message = "This track has been searched for, result might not be 100% exact."; break;
case "gotBitrate": message = "Download URL got."; break;
case "getAlbumArt": message = "Downloading album art."; break;
case "gotAlbumArt": message = "Album art downloaded."; break;
case "downloading":
message = "Downloading track.";
if (data.alreadyStarted) message += ` Recovering download from ${data.value}.`
else message += ` Downloading ${data.value} bytes.`
break;
case "downloadTimeout": message = "Deezer timedout when downloading track, retrying..."; break;
case "downloaded": message = "Track downloaded."; break;
case "alreadyDownloaded": message = "Track already downloaded."; break;
case "tagging": message = "Tagging track."; break;
case "tagged": message = "Track tagged."; break;
case "stderr": return `ExecuteCommand Error: ${data.data.stderr}`
case "stdout": return `ExecuteCommand Output: ${data.data.stdout}`
case 'getTags': message = 'Getting tags.'; break
case 'gotTags': message = 'Tags got.'; break
case 'getBitrate': message = 'Getting download URL.'; break
case 'bitrateFallback': message = 'Desired bitrate not found, falling back to lower bitrate.'; break
case 'searchFallback': message = 'This track has been searched for, result might not be 100% exact.'; break
case 'gotBitrate': message = 'Download URL got.'; break
case 'getAlbumArt': message = 'Downloading album art.'; break
case 'gotAlbumArt': message = 'Album art downloaded.'; break
case 'downloading':
message = 'Downloading track.'
if (data.alreadyStarted) message += ` Recovering download from ${data.value}.`
else message += ` Downloading ${data.value} bytes.`
break
case 'downloadTimeout': message = 'Deezer timedout when downloading track, retrying...'; break
case 'downloaded': message = 'Track downloaded.'; break
case 'alreadyDownloaded': message = 'Track already downloaded.'; break
case 'tagging': message = 'Tagging track.'; break
case 'tagged': message = 'Track tagged.'; break
case 'stderr': return `ExecuteCommand Error: ${data.data.stderr}`
case 'stdout': return `ExecuteCommand Output: ${data.data.stdout}`
}
return `[${data.uuid}] ${data.data.artist} - ${data.data.title} :: ${message}`
case "downloadWarn":
case 'downloadWarn':
message = `[${data.uuid}] ${data.data.artist} - ${data.data.title} :: ${ErrorMessages[data.state]} `
switch (data.solution) {
case 'fallback': message += "Using fallback id."; break;
case 'search': message += "Searching for alternative."; break;
case 'fallback': message += 'Using fallback id.'; break
case 'search': message += 'Searching for alternative.'; break
}
return message
case "currentItemCancelled": return `Current item cancelled (${data})`
case "removedFromQueue": return `[${data}] Removed from the queue`
case "finishDownload": return `[${data}] Finished downloading`
case "startConversion": return `[${data}] Started converting`
case "finishConversion": return `[${data.uuid}] Finished converting`
case 'currentItemCancelled': return `Current item cancelled (${data})`
case 'removedFromQueue': return `[${data}] Removed from the queue`
case 'finishDownload': return `[${data}] Finished downloading`
case 'startConversion': return `[${data}] Started converting`
case 'finishConversion': return `[${data.uuid}] Finished converting`
default: return message
}
}

View File

@@ -3,80 +3,80 @@ const { homedir } = require('os')
const fs = require('fs')
const { canWrite } = require('./index.js')
let homedata = homedir()
let userdata = ""
let musicdata = ""
const homedata = homedir()
let userdata = ''
let musicdata = ''
function checkPath(path){
if (path === "") return ""
if (!fs.existsSync(path)) return ""
if (!canWrite(path)) return ""
function checkPath (path) {
if (path === '') return ''
if (!fs.existsSync(path)) return ''
if (!canWrite(path)) return ''
return path
}
function getConfigFolder(){
if (userdata != "") return userdata
if (process.env.XDG_CONFIG_HOME && userdata === ""){
function getConfigFolder () {
if (userdata !== '') return userdata
if (process.env.XDG_CONFIG_HOME && userdata === '') {
userdata = `${process.env.XDG_CONFIG_HOME}${sep}`
userdata = checkPath(userdata)
}
if (process.env.APPDATA && userdata === ""){
if (process.env.APPDATA && userdata === '') {
userdata = `${process.env.APPDATA}${sep}`
userdata = checkPath(userdata)
}
if (process.platform == "darwin" && userdata === ""){
if (process.platform === 'darwin' && userdata === '') {
userdata = `${homedata}/Library/Application Support/`
userdata = checkPath(userdata)
}
if (userdata === ""){
if (userdata === '') {
userdata = `${homedata}${sep}.config${sep}`
userdata = checkPath(userdata)
}
if (userdata === "") userdata = `${process.cwd()}${sep}config${sep}`
if (userdata === '') userdata = `${process.cwd()}${sep}config${sep}`
else userdata += `deemix${sep}`
if (process.env.DEEMIX_DATA_DIR) userdata = process.env.DEEMIX_DATA_DIR
return userdata
}
function getMusicFolder(){
if (musicdata != "") return musicdata
if (process.env.XDG_MUSIC_DIR && musicdata === ""){
function getMusicFolder () {
if (musicdata !== '') return musicdata
if (process.env.XDG_MUSIC_DIR && musicdata === '') {
musicdata = `${process.env.XDG_MUSIC_DIR}${sep}`
musicdata = checkPath(musicdata)
}
if (fs.existsSync(`${homedata}${sep}.config${sep}user-dirs.dirs`)){
if (fs.existsSync(`${homedata}${sep}.config${sep}user-dirs.dirs`)) {
const userDirs = fs.readFileSync(`${homedata}${sep}.config${sep}user-dirs.dirs`).toString()
musicdata = userDirs.match(/XDG_MUSIC_DIR="(.*)"/)[1]
musicdata = musicdata.replace(/\$([A-Z_]+[A-Z0-9_]*)/ig, (_, envName) => process.env[envName])
musicdata += sep
musicdata = checkPath(musicdata)
}
if (process.platform == 'win32' && musicdata === ""){
if (process.platform === 'win32' && musicdata === '') {
try {
const { execSync } = require('child_process')
const musicKeys = ["My Music", "{4BD8D571-6D19-48D3-BE97-422220080E43}"]
let regData = execSync('reg.exe query "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"').toString().split('\r\n')
for (let i = 0; i < regData.length; i++){
const musicKeys = ['My Music', '{4BD8D571-6D19-48D3-BE97-422220080E43}']
const regData = execSync('reg.exe query "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"').toString().split('\r\n')
for (let i = 0; i < regData.length; i++) {
let line = regData[i]
if (line === "") continue
if (i == 1) continue
if (line === '') continue
if (i === 1) continue
line = line.split(' ')
if (musicKeys.includes(line[1])){
if (musicKeys.includes(line[1])) {
musicdata = line[3] + sep
break;
break
}
}
musicdata = checkPath(musicdata)
} catch {/* empty */}
} catch { /* empty */ }
}
if (musicdata === ""){
if (musicdata === '') {
musicdata = `${homedata}${sep}Music${sep}`
musicdata = checkPath(musicdata)
}
if (musicdata === "") musicdata = `${process.cwd()}${sep}music${sep}`
if (musicdata === '') musicdata = `${process.cwd()}${sep}music${sep}`
else musicdata += `deemix Music${sep}`
if (process.env.DEEMIX_MUSIC_DIR) musicdata = process.env.DEEMIX_MUSIC_DIR

View File

@@ -2,26 +2,26 @@ const { TrackFormats } = require('deezer-js')
const { Date: dzDate } = require('../types/Date.js')
const bitrateLabels = {
[TrackFormats.MP4_RA3]: "360 HQ",
[TrackFormats.MP4_RA2]: "360 MQ",
[TrackFormats.MP4_RA1]: "360 LQ",
[TrackFormats.FLAC] : "FLAC",
[TrackFormats.MP3_320]: "320",
[TrackFormats.MP3_128]: "128",
[TrackFormats.DEFAULT]: "128",
[TrackFormats.LOCAL] : "MP3"
[TrackFormats.MP4_RA3]: '360 HQ',
[TrackFormats.MP4_RA2]: '360 MQ',
[TrackFormats.MP4_RA1]: '360 LQ',
[TrackFormats.FLAC]: 'FLAC',
[TrackFormats.MP3_320]: '320',
[TrackFormats.MP3_128]: '128',
[TrackFormats.DEFAULT]: '128',
[TrackFormats.LOCAL]: 'MP3'
}
function fixName(txt, char='_'){
txt = txt+""
function fixName (txt, char = '_') {
txt = txt + ''
txt = txt.replace(/[\0/\\:*?"<>|]/g, char)
return txt.normalize('NFC')
}
function fixLongName(name){
if (name.includes('/')){
let sepName = name.split('/')
name = ""
function fixLongName (name) {
if (name.includes('/')) {
const sepName = name.split('/')
name = ''
sepName.forEach((txt) => {
txt = fixLongName(txt)
name += `${txt}/`
@@ -33,37 +33,37 @@ function fixLongName(name){
return name
}
function antiDot(str){
while(str[str.length-1] == "." || str[str.length-1] == " " || str[str.length-1] == "\n"){
str = str.slice(0,-1)
}
if(str.length < 1){
str = "dot"
}
return str
}
function pad(num, max_val, settings) {
let paddingSize;
if (parseInt(settings.paddingSize) == 0) {
paddingSize = (max_val+"").length
} else{
paddingSize = ((10 ** (parseInt(settings.paddingSize) - 1))+"").length
function antiDot (str) {
while (str[str.length - 1] === '.' || str[str.length - 1] === ' ' || str[str.length - 1] === '\n') {
str = str.slice(0, -1)
}
if (settings.padSingleDigit && paddingSize == 1) paddingSize = 2
if (settings.padTracks) return (num+"").padStart(paddingSize, "0")
return (num+"")
if (str.length < 1) {
str = 'dot'
}
return str
}
function generatePath(track, downloadObject, settings){
let filenameTemplate = "%artist% - %title%";
function pad (num, max_val, settings) {
let paddingSize
if (parseInt(settings.paddingSize) === 0) {
paddingSize = (max_val + '').length
} else {
paddingSize = ((10 ** (parseInt(settings.paddingSize) - 1)) + '').length
}
if (settings.padSingleDigit && paddingSize === 1) paddingSize = 2
if (settings.padTracks) return (num + '').padStart(paddingSize, '0')
return (num + '')
}
function generatePath (track, downloadObject, settings) {
let filenameTemplate = '%artist% - %title%'
let singleTrack = false
if (downloadObject.type === "track"){
if (downloadObject.type === 'track') {
if (settings.createSingleFolder) filenameTemplate = settings.albumTracknameTemplate
else filenameTemplate = settings.tracknameTemplate
singleTrack = true
} else if (downloadObject.type === "album") {
} else if (downloadObject.type === 'album') {
filenameTemplate = settings.albumTracknameTemplate
} else {
filenameTemplate = settings.playlistTracknameTemplate
@@ -72,31 +72,28 @@ function generatePath(track, downloadObject, settings){
let filename = generateTrackName(filenameTemplate, track, settings)
let filepath, artistPath, coverPath, extrasPath
filepath = settings.downloadLocation || "."
filepath = settings.downloadLocation || '.'
if (settings.createPlaylistFolder && track.playlist && !settings.tags.savePlaylistAsCompilation)
filepath += `/${generatePlaylistName(settings.playlistNameTemplate, track.playlist, settings)}`
if (settings.createPlaylistFolder && track.playlist && !settings.tags.savePlaylistAsCompilation) { filepath += `/${generatePlaylistName(settings.playlistNameTemplate, track.playlist, settings)}` }
if (track.playlist && !settings.tags.savePlaylistAsCompilation)
extrasPath = filepath
if (track.playlist && !settings.tags.savePlaylistAsCompilation) { extrasPath = filepath }
if (
(settings.createArtistFolder && !track.playlist) ||
(settings.createArtistFolder && track.playlist && settings.tags.savePlaylistAsCompilation) ||
(settings.createArtistFolder && track.playlist && settings.createStructurePlaylist)
){
) {
filepath += `/${generateArtistName(settings.artistNameTemplate, track.album.mainArtist, settings, track.album.rootArtist)}`
artistPath = filepath
}
if (settings.createAlbumFolder &&
(!singleTrack || singleTrack && settings.createSingleFolder) &&
(!singleTrack || (singleTrack && settings.createSingleFolder)) &&
(!track.playlist ||
(track.playlist && settings.tags.savePlaylistAsCompilation) ||
(track.playlist && settings.createStructurePlaylist)
)
){
) {
filepath += `/${generateAlbumName(settings.albumNameTemplate, track.album, settings, track.playlist)}`
coverPath = filepath
}
@@ -107,18 +104,15 @@ function generatePath(track, downloadObject, settings){
parseInt(track.album.discTotal) > 1 && (
(settings.createAlbumFolder && settings.createCDFolder) &&
(!singleTrack || (singleTrack && settings.createSingleFolder)) &&
(!track.playlist ||
(track.playlist && settings.tags.savePlaylistAsCompilation)) ||
(track.playlist && settings.createStructurePlaylist)
((!track.playlist || (track.playlist && settings.tags.savePlaylistAsCompilation)) || (track.playlist && settings.createStructurePlaylist))
)
)
filepath += `/CD${track.discNumber}`
) { filepath += `/CD${track.discNumber}` }
// Remove Subfolders from filename and add it to filepath
if (filename.includes('/')){
let tempPath = filename.slice(0, filename.indexOf('/'))
if (filename.includes('/')) {
const tempPath = filename.slice(0, filename.indexOf('/'))
filepath += `/${tempPath}`
filename = filename.slice(tempPath.length+1)
filename = filename.slice(tempPath.length + 1)
}
return {
@@ -130,121 +124,121 @@ function generatePath(track, downloadObject, settings){
}
}
function generateTrackName(filename, track, settings){
let c = settings.illegalCharacterReplacer
filename = filename.replaceAll("%title%", fixName(track.title, c))
filename = filename.replaceAll("%artist%", fixName(track.mainArtist.name, c))
filename = filename.replaceAll("%artists%", fixName(track.artists.join(", "), c))
filename = filename.replaceAll("%tagsartists%", fixName(track.artistsString, c))
filename = filename.replaceAll("%allartists%", fixName(track.fullArtistsString, c))
filename = filename.replaceAll("%mainartists%", fixName(track.mainArtistsString, c))
if (track.featArtistsString) filename = filename.replaceAll("%featartists%", fixName('('+track.featArtistsString+')', c))
else filename = filename.replaceAll(" %featartists%", '').replaceAll("%featartists%", '')
filename = filename.replaceAll("%album%", fixName(track.album.title, c))
filename = filename.replaceAll("%albumartist%", fixName(track.album.mainArtist.name, c))
filename = filename.replaceAll("%tracknumber%", pad(track.trackNumber, track.album.trackTotal, settings))
filename = filename.replaceAll("%tracktotal%", track.album.trackTotal)
filename = filename.replaceAll("%discnumber%", track.discNumber)
filename = filename.replaceAll("%disctotal%", track.album.discTotal)
if (track.album.genre.length) filename = filename.replaceAll("%genre%", fixName(track.album.genre[0], c))
else filename = filename.replaceAll("%genre%", "Unknown")
filename = filename.replaceAll("%year%", track.date.year)
filename = filename.replaceAll("%date%", track.dateString)
filename = filename.replaceAll("%bpm%", track.bpm)
filename = filename.replaceAll("%label%", fixName(track.album.label, c))
filename = filename.replaceAll("%isrc%", track.ISRC)
filename = filename.replaceAll("%upc%", track.album.barcode)
if (track.explicit) filename = filename.replaceAll("%explicit%", "(Explicit)")
else filename = filename.replaceAll(" %explicit%", "").replaceAll("%explicit%", "")
function generateTrackName (filename, track, settings) {
const c = settings.illegalCharacterReplacer
filename = filename.replaceAll('%title%', fixName(track.title, c))
filename = filename.replaceAll('%artist%', fixName(track.mainArtist.name, c))
filename = filename.replaceAll('%artists%', fixName(track.artists.join(', '), c))
filename = filename.replaceAll('%tagsartists%', fixName(track.artistsString, c))
filename = filename.replaceAll('%allartists%', fixName(track.fullArtistsString, c))
filename = filename.replaceAll('%mainartists%', fixName(track.mainArtistsString, c))
if (track.featArtistsString) filename = filename.replaceAll('%featartists%', fixName('(' + track.featArtistsString + ')', c))
else filename = filename.replaceAll(' %featartists%', '').replaceAll('%featartists%', '')
filename = filename.replaceAll('%album%', fixName(track.album.title, c))
filename = filename.replaceAll('%albumartist%', fixName(track.album.mainArtist.name, c))
filename = filename.replaceAll('%tracknumber%', pad(track.trackNumber, track.album.trackTotal, settings))
filename = filename.replaceAll('%tracktotal%', track.album.trackTotal)
filename = filename.replaceAll('%discnumber%', track.discNumber)
filename = filename.replaceAll('%disctotal%', track.album.discTotal)
if (track.album.genre.length) filename = filename.replaceAll('%genre%', fixName(track.album.genre[0], c))
else filename = filename.replaceAll('%genre%', 'Unknown')
filename = filename.replaceAll('%year%', track.date.year)
filename = filename.replaceAll('%date%', track.dateString)
filename = filename.replaceAll('%bpm%', track.bpm)
filename = filename.replaceAll('%label%', fixName(track.album.label, c))
filename = filename.replaceAll('%isrc%', track.ISRC)
filename = filename.replaceAll('%upc%', track.album.barcode)
if (track.explicit) filename = filename.replaceAll('%explicit%', '(Explicit)')
else filename = filename.replaceAll(' %explicit%', '').replaceAll('%explicit%', '')
filename = filename.replaceAll("%track_id%", track.id)
filename = filename.replaceAll("%album_id%", track.album.id)
filename = filename.replaceAll("%artist_id%", track.mainArtist.id)
if (track.playlist){
filename = filename.replaceAll("%playlist_id%", track.playlist.playlistID)
filename = filename.replaceAll("%position%", pad(track.position, track.playlist.trackTotal, settings))
filename = filename.replaceAll('%track_id%', track.id)
filename = filename.replaceAll('%album_id%', track.album.id)
filename = filename.replaceAll('%artist_id%', track.mainArtist.id)
if (track.playlist) {
filename = filename.replaceAll('%playlist_id%', track.playlist.playlistID)
filename = filename.replaceAll('%position%', pad(track.position, track.playlist.trackTotal, settings))
} else {
filename = filename.replaceAll("%playlist_id%", '')
filename = filename.replaceAll("%position%", pad(track.trackNumber, track.album.trackTotal, settings))
filename = filename.replaceAll('%playlist_id%', '')
filename = filename.replaceAll('%position%', pad(track.trackNumber, track.album.trackTotal, settings))
}
filename = filename.replaceAll('\\', '/')
return antiDot(fixLongName(filename))
}
function generateAlbumName(foldername, album, settings, playlist){
let c = settings.illegalCharacterReplacer
if (playlist && settings.tags.savePlaylistAsCompilation){
foldername = foldername.replaceAll("%album_id%", "pl_" + playlist.playlistID)
foldername = foldername.replaceAll("%genre%", "Compile")
function generateAlbumName (foldername, album, settings, playlist) {
const c = settings.illegalCharacterReplacer
if (playlist && settings.tags.savePlaylistAsCompilation) {
foldername = foldername.replaceAll('%album_id%', 'pl_' + playlist.playlistID)
foldername = foldername.replaceAll('%genre%', 'Compile')
} else {
foldername = foldername.replaceAll("%album_id%", album.id)
if (album.genre.length) foldername = foldername.replaceAll("%genre%", fixName(album.genre[0], c))
else foldername = foldername.replaceAll("%genre%", "Unknown")
foldername = foldername.replaceAll('%album_id%', album.id)
if (album.genre.length) foldername = foldername.replaceAll('%genre%', fixName(album.genre[0], c))
else foldername = foldername.replaceAll('%genre%', 'Unknown')
}
foldername = foldername.replaceAll("%album%", fixName(album.title, c))
foldername = foldername.replaceAll("%artist%", fixName(album.mainArtist.name, c))
foldername = foldername.replaceAll("%artists%", fixName(album.artists.join(", "), c))
foldername = foldername.replaceAll("%artist_id%", album.mainArtist.id)
if (album.rootArtist){
foldername = foldername.replaceAll("%root_artist%", fixName(album.rootArtist.name, c))
foldername = foldername.replaceAll("%root_artist_id%", album.rootArtist.id)
foldername = foldername.replaceAll('%album%', fixName(album.title, c))
foldername = foldername.replaceAll('%artist%', fixName(album.mainArtist.name, c))
foldername = foldername.replaceAll('%artists%', fixName(album.artists.join(', '), c))
foldername = foldername.replaceAll('%artist_id%', album.mainArtist.id)
if (album.rootArtist) {
foldername = foldername.replaceAll('%root_artist%', fixName(album.rootArtist.name, c))
foldername = foldername.replaceAll('%root_artist_id%', album.rootArtist.id)
} else {
foldername = foldername.replaceAll("%root_artist%", fixName(album.mainArtist.name, c))
foldername = foldername.replaceAll("%root_artist_id%", album.mainArtist.id)
foldername = foldername.replaceAll('%root_artist%', fixName(album.mainArtist.name, c))
foldername = foldername.replaceAll('%root_artist_id%', album.mainArtist.id)
}
foldername = foldername.replaceAll("%tracktotal%", album.trackTotal)
foldername = foldername.replaceAll("%disctotal%", album.discTotal)
foldername = foldername.replaceAll("%type%", fixName(album.recordType.charAt(0).toUpperCase() + album.recordType.slice(1), c))
foldername = foldername.replaceAll("%upc%", album.barcode)
foldername = foldername.replaceAll("%explicit%", album.explicit ? "(Explicit)" : "")
foldername = foldername.replaceAll("%label%", fixName(album.label, c))
foldername = foldername.replaceAll("%year%", album.date.year)
foldername = foldername.replaceAll("%date%", album.dateString)
foldername = foldername.replaceAll("%bitrate%", bitrateLabels[parseInt(album.bitrate)])
foldername = foldername.replaceAll('%tracktotal%', album.trackTotal)
foldername = foldername.replaceAll('%disctotal%', album.discTotal)
foldername = foldername.replaceAll('%type%', fixName(album.recordType.charAt(0).toUpperCase() + album.recordType.slice(1), c))
foldername = foldername.replaceAll('%upc%', album.barcode)
foldername = foldername.replaceAll('%explicit%', album.explicit ? '(Explicit)' : '')
foldername = foldername.replaceAll('%label%', fixName(album.label, c))
foldername = foldername.replaceAll('%year%', album.date.year)
foldername = foldername.replaceAll('%date%', album.dateString)
foldername = foldername.replaceAll('%bitrate%', bitrateLabels[parseInt(album.bitrate)])
foldername = foldername.replaceAll('\\', '/')
return antiDot(fixLongName(foldername))
}
function generateArtistName(foldername, artist, settings, rootArtist){
let c = settings['illegalCharacterReplacer']
foldername = foldername.replaceAll("%artist%", fixName(artist.name, c))
foldername = foldername.replaceAll("%artist_id%", artist.id)
if (rootArtist){
foldername = foldername.replaceAll("%root_artist%", fixName(rootArtist.name, c))
foldername = foldername.replaceAll("%root_artist_id%", rootArtist.id)
function generateArtistName (foldername, artist, settings, rootArtist) {
const c = settings.illegalCharacterReplacer
foldername = foldername.replaceAll('%artist%', fixName(artist.name, c))
foldername = foldername.replaceAll('%artist_id%', artist.id)
if (rootArtist) {
foldername = foldername.replaceAll('%root_artist%', fixName(rootArtist.name, c))
foldername = foldername.replaceAll('%root_artist_id%', rootArtist.id)
} else {
foldername = foldername.replaceAll("%root_artist%", fixName(artist.name, c))
foldername = foldername.replaceAll("%root_artist_id%", artist.id)
foldername = foldername.replaceAll('%root_artist%', fixName(artist.name, c))
foldername = foldername.replaceAll('%root_artist_id%', artist.id)
}
foldername = foldername.replaceAll('\\', '/')
return antiDot(fixLongName(foldername))
}
function generatePlaylistName(foldername, playlist, settings){
let c = settings['illegalCharacterReplacer']
let today = new Date()
let today_dz = new dzDate(String(today.getDate()).padStart(2, '0'), String(today.getMonth()+1).padStart(2, '0'), String(today.getFullYear()))
foldername = foldername.replaceAll("%playlist%", fixName(playlist.title, c))
foldername = foldername.replaceAll("%playlist_id%", fixName(playlist.playlistID, c))
foldername = foldername.replaceAll("%owner%", fixName(playlist.owner['name'], c))
foldername = foldername.replaceAll("%owner_id%", playlist.owner['id'])
foldername = foldername.replaceAll("%year%", playlist.date.year)
foldername = foldername.replaceAll("%date%", playlist.dateString)
foldername = foldername.replaceAll("%explicit%", playlist.explicit ? "(Explicit)" : "")
foldername = foldername.replaceAll("%today%", today_dz.format(settings['dateFormat']))
function generatePlaylistName (foldername, playlist, settings) {
const c = settings.illegalCharacterReplacer
const today = new Date()
const today_dz = new dzDate(String(today.getDate()).padStart(2, '0'), String(today.getMonth() + 1).padStart(2, '0'), String(today.getFullYear()))
foldername = foldername.replaceAll('%playlist%', fixName(playlist.title, c))
foldername = foldername.replaceAll('%playlist_id%', fixName(playlist.playlistID, c))
foldername = foldername.replaceAll('%owner%', fixName(playlist.owner.name, c))
foldername = foldername.replaceAll('%owner_id%', playlist.owner.id)
foldername = foldername.replaceAll('%year%', playlist.date.year)
foldername = foldername.replaceAll('%date%', playlist.dateString)
foldername = foldername.replaceAll('%explicit%', playlist.explicit ? '(Explicit)' : '')
foldername = foldername.replaceAll('%today%', today_dz.format(settings.dateFormat))
foldername = foldername.replaceAll('\\', '/')
return antiDot(fixLongName(foldername))
}
function generateDownloadObjectName(foldername, queueItem, settings){
let c = settings['illegalCharacterReplacer']
foldername = foldername.replaceAll("%title%", fixName(queueItem.title, c))
foldername = foldername.replaceAll("%artist%", fixName(queueItem.artist, c))
foldername = foldername.replaceAll("%size%", queueItem.size)
foldername = foldername.replaceAll("%type%", fixName(queueItem.type, c))
foldername = foldername.replaceAll("%id%", fixName(queueItem.id, c))
foldername = foldername.replaceAll("%bitrate%", bitrateLabels[parseInt(queueItem.bitrate)])
function generateDownloadObjectName (foldername, queueItem, settings) {
const c = settings.illegalCharacterReplacer
foldername = foldername.replaceAll('%title%', fixName(queueItem.title, c))
foldername = foldername.replaceAll('%artist%', fixName(queueItem.artist, c))
foldername = foldername.replaceAll('%size%', queueItem.size)
foldername = foldername.replaceAll('%type%', fixName(queueItem.type, c))
foldername = foldername.replaceAll('%id%', fixName(queueItem.id, c))
foldername = foldername.replaceAll('%bitrate%', bitrateLabels[parseInt(queueItem.bitrate)])
foldername = foldername.replaceAll('\\', '/').replace('/', c)
return antiDot(fixLongName(foldername))
}

View File

@@ -1,6 +1,6 @@
{
"name": "deemix",
"version": "3.6.17",
"version": "3.6.20",
"description": "a barebones deezer downloader library",
"main": "deemix/index.js",
"scripts": {
@@ -22,8 +22,5 @@
"metaflac-js2": "^1.0.8",
"spotify-web-api-node": "../spotify-web-api-node",
"tough-cookie": "^4.0.0"
},
"devDependencies": {
"eslint": "^9.7.0"
}
}

View File

@@ -1,13 +0,0 @@
{
"env": {
"commonjs": true,
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
}
}

View File

@@ -15,8 +15,5 @@
"dependencies": {
"got": "11.8.2",
"tough-cookie": "^4.0.0"
},
"devDependencies": {
"eslint": "^7.23.0"
}
}

View File

@@ -1 +0,0 @@
dist/

View File

@@ -1,16 +0,0 @@
---
extends:
- "@nuxtjs"
- plugin:prettier/recommended
plugins:
- "@typescript-eslint"
parserOptions:
parser: "@typescript-eslint/parser"
rules:
"@typescript-eslint/no-unused-vars":
- error
- args: all
argsIgnorePattern: ^_
no-unused-vars: off
no-console: off
camelcase: off

View File

@@ -1,8 +0,0 @@
tabWidth: 2
printWidth: 120
useTabs: true
semi: false
singleQuote: true
bracketSpacing: true
arrowParens: avoid
trailingComma: none

View File

@@ -6,10 +6,7 @@
"start": "node dist/app.js",
"build": "webpack --env production",
"sourcemap": "webpack --env production sourcemap",
"prewatch": "pnpm lint-build",
"watch": "webpack --watch",
"lint": "eslint \"./{src, tests}/**\" --fix",
"lint-build": "eslint \"./src/**\" --fix",
"test": "jest",
"test-watch": "jest --watch"
},
@@ -66,13 +63,7 @@
"devDependencies": {
"@types/jest": "29.5.12",
"@types/supertest": "6.0.2",
"@typescript-eslint/eslint-plugin": "4.21.0",
"@typescript-eslint/parser": "4.21.0",
"eslint": "7.23.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^3.3.1",
"jest": "26.6.3",
"prettier": "2.2.1",
"supertest": "6.1.3",
"ts-jest": "26.5.4",
"ts-node": "9.1.1",

View File

@@ -21,7 +21,7 @@ export function loadLoginCredentials() {
try {
loginData = JSON.parse(fs.readFileSync(configFolder + 'login.json').toString())
} catch (e) {
} catch (e:any) {
if (e.name === 'SyntaxError') resetLoginCredentials()
}
}

View File

@@ -107,7 +107,7 @@ const handler: ApiHandler['handler'] = async (req, res) => {
let results
try {
results = await dz.gw.search(term)
} catch (e) {
} catch (e:any) {
results = { ...emptyResult }
results.QUERY = term
results.ERROR = e.message

View File

@@ -47,7 +47,7 @@ const handler: ApiHandler['handler'] = async (req, res) => {
data = await dz.api.search(term, { limit: nb, index: start })
break
}
} catch (e) {
} catch (e:any) {
data = { ...emptyResult }
data.error = e.message
}

View File

@@ -19,7 +19,7 @@ const handler: ApiHandler['handler'] = async (req, res) => {
try {
obj = await deemix.addToQueue(dz, url, bitrate)
} catch (e) {
} catch (e:any) {
res.send({ result: false, errid: e.name, data: { url, bitrate } })
switch (e.name) {
case 'NotLoggedIn':

View File

@@ -32,7 +32,7 @@ const handler: ApiHandler['handler'] = async (req, res) => {
try {
obj = await deemix.addToQueue(dz, [url], bitrate, true)
} catch (e) {
} catch (e:any) {
res.send({ result: false, errid: e.name, data: { url, bitrate } })
switch (e.name) {
case 'NotLoggedIn':

View File

@@ -1,6 +1,6 @@
{
"name": "spotify-web-api-node",
"version": "5.0.3",
"version": "5.0.4",
"homepage": "https://github.com/thelinmichael/spotify-web-api-node",
"description": "A Node.js wrapper for Spotify's Web API",
"main": "./src/server.js",
@@ -29,12 +29,6 @@
"verbose": true,
"testURL": "http://localhost/"
},
"lint-staged": {
"*.{js,json,css,md}": [
"prettier --single-quote --write",
"git add"
]
},
"dependencies": {
"superagent": "^6.1.0"
},
@@ -42,8 +36,6 @@
"coveralls": "^3.1.0",
"husky": "^4.3.0",
"jest": "^26.6.3",
"lint-staged": "^10.4.0",
"prettier": "^2.1.2",
"sinon": "^9.0.3",
"canvas": "^2.6.1",
"bufferutil": "^4.0.1",

View File

@@ -1,6 +1,5 @@
'use strict'
const AuthenticationRequest = require('./authentication-request')
const WebApiRequest = require('./webapi-request')
const HttpManager = require('./http-manager')
@@ -91,19 +90,11 @@ SpotifyWebApi.prototype = {
},
_getCredential: function (credentialKey) {
if (!this._credentials) {
} else {
return this._credentials[credentialKey]
}
return this._credentials[credentialKey]
},
_resetCredential: function (credentialKey) {
if (!this._credentials) {
} else {
this._credentials[credentialKey] = null
}
this._credentials[credentialKey] = null
},
/**

View File

@@ -1,17 +0,0 @@
---
extends:
- "@nuxtjs"
- plugin:prettier/recommended
plugins:
- "@typescript-eslint"
parserOptions:
parser: "@typescript-eslint/parser"
rules:
"@typescript-eslint/no-unused-vars":
- error
- args: all
argsIgnorePattern: ^_
no-unused-vars: off
no-console: off
camelcase: off
vue/no-v-html: off

View File

@@ -1,10 +0,0 @@
---
useTabs: true
tabWidth: 2
semi: false
singleQuote: true
bracketSpacing: true
trailingComma: none
printWidth: 120
arrowParens: avoid
vueIndentScriptAndStyle: false

View File

@@ -1,6 +1,6 @@
{
"name": "deemix-webui",
"version": "1.9.6",
"version": "1.9.7",
"scripts": {
"clean": "rimraf public/js/bundle.js public/js/bundle.temp.js public/js/bundle.js.map",
"clean-temp": "rimraf public/js/bundle.temp.js",
@@ -11,8 +11,6 @@
"watch:server": "pnpm -C ../server watch",
"watch:js": "rollup -c -w",
"dev": "npm-run-all --parallel watch:server watch:js",
"lint": "eslint src/**/*.{js,vue,mjs} --fix",
"lint-tests": "eslint src/**/*.js --fix",
"test": "jest",
"test-watch": "jest --watch",
"testlang": "node ./tests/testlang.js"
@@ -24,7 +22,7 @@
"@rollup/plugin-replace": "3.0.0",
"@vue/composition-api": "1.0.6",
"esbuild": "0.12.19",
"flag-icon-css": "3.5.0",
"flag-icon-css": "4.1.7",
"lodash-es": "4.17.21",
"postcss": "8.4.39",
"rollup": "2.56.1",
@@ -43,18 +41,11 @@
"devDependencies": {
"@babel/core": "7.24.9",
"@babel/plugin-transform-modules-commonjs": "7.24.8",
"@nuxtjs/eslint-config": "6.0.1",
"@types/jest": "26.0.24",
"@types/node": "14.14.37",
"@typescript-eslint/eslint-plugin": "4.29.0",
"@typescript-eslint/parser": "4.29.0",
"babel-jest": "27.0.6",
"eslint": "7.32.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-prettier": "3.4.0",
"jest": "27.0.6",
"npm-run-all": "^4.1.5",
"prettier": "2.3.2",
"rimraf": "3.0.2",
"typescript": "4.3.5",
"vue-template-compiler": "2.6.14"

View File

@@ -37,6 +37,11 @@
<h2>Changelog</h2>
<ul class="no-dots" style="font-size: 15px;">
<h3>02/08/2024</h3>
- Removed outdated linters and formatters<br>
- Few fixes in API ts types<br>
- Removed Spotify UserName requirement and instructions from settings<br>
<br>
<h3>31/07/2024</h3>
- Reverted to spotify-web-api-node<br>
- Fixed (again) the Buffer method in spotify-web-api-node<br>

View File

@@ -1,7 +1,7 @@
<template>
<div id="home_tab">
<h1 class="mb-8 text-5xl">{{ $t('globals.welcome') }}</h1>
Version published 31/07/2024, see About section for changelog.
Version published 02/08/2024, see About section for changelog.
<section v-if="!isLoggedIn" ref="notLogged" class="py-6 border-0 border-t border-solid border-grayscale-500">
<p id="home_not_logged_text" class="mb-4">{{ $t('home.needTologin') }}</p>
<router-link custom v-slot="{ navigate }" class="btn btn-primary" name="button" :to="{ name: 'Settings' }">

View File

@@ -28,12 +28,12 @@
</p>
<p class="mb-4 text-base">{{ $t('settings.spotify.howTo.clientSecretQuestion.step5') }}</p>
<h2 class="mt-6 text-3xl">{{ $t('settings.spotify.howTo.usernameQuestion.title') }}</h2>
<!-- <h2 class="mt-6 text-3xl">{{ $t('settings.spotify.howTo.usernameQuestion.title') }}</h2>
<i18n path="settings.spotify.howTo.usernameQuestion.step1.text" tag="p" class="mb-4 text-base">
<template #overviewPage>
<a href="https://www.spotify.com/it/account/overview/" target="_blank">{{ $t('settings.spotify.howTo.usernameQuestion.step1.overviewPage') }}</a>
</template>
</i18n>
</i18n> -->
</div>
</template>

View File

@@ -711,10 +711,10 @@
<input v-model="spotifyFeatures.clientSecret" type="password" />
</div>
<div class="input-group">
<!-- <div class="input-group">
<p class="input-group-text">{{ $t('settings.spotify.username') }}</p>
<input v-model="spotifyUser" type="text" />
</div>
</div> -->
<label class="with-checkbox">
<input v-model="spotifyFeatures.fallbackSearch" type="checkbox" />