Implemented quality select

This commit is contained in:
cool.gitter.choco
2025-01-29 12:40:26 -06:00
parent 11d769aac7
commit a89a236f46
9 changed files with 542 additions and 545 deletions

View File

@@ -27,7 +27,7 @@ class FlushingFileWrapper:
def flush(self):
self.file.flush()
def download_task(service, url, main, fallback, prg_path):
def download_task(service, url, main, fallback, quality, fall_quality, prg_path):
try:
from routes.utils.album import download_album
with open(prg_path, 'w') as f:
@@ -40,7 +40,9 @@ def download_task(service, url, main, fallback, prg_path):
service=service,
url=url,
main=main,
fallback=fallback
fallback=fallback,
quality=quality,
fall_quality=fall_quality
)
flushing_file.write(json.dumps({"status": "complete"}) + "\n")
except Exception as e:
@@ -67,6 +69,14 @@ def handle_download():
url = request.args.get('url')
main = request.args.get('main')
fallback = request.args.get('fallback')
quality = request.args.get('quality')
fall_quality = request.args.get('fall_quality')
# Sanitize main and fallback to prevent directory traversal
if main:
main = os.path.basename(main)
if fallback:
fallback = os.path.basename(fallback)
if not all([service, url, main]):
return Response(
@@ -75,6 +85,56 @@ def handle_download():
mimetype='application/json'
)
# Validate credentials based on service and fallback
try:
if service == 'spotify':
if fallback:
# Validate Deezer main and Spotify fallback credentials
deezer_creds_path = os.path.abspath(os.path.join('./creds/deezer', main, 'credentials.json'))
if not os.path.isfile(deezer_creds_path):
return Response(
json.dumps({"error": "Invalid Deezer credentials directory"}),
status=400,
mimetype='application/json'
)
spotify_fallback_path = os.path.abspath(os.path.join('./creds/spotify', fallback, 'credentials.json'))
if not os.path.isfile(spotify_fallback_path):
return Response(
json.dumps({"error": "Invalid Spotify fallback credentials directory"}),
status=400,
mimetype='application/json'
)
else:
# Validate Spotify main credentials
spotify_creds_path = os.path.abspath(os.path.join('./creds/spotify', main, 'credentials.json'))
if not os.path.isfile(spotify_creds_path):
return Response(
json.dumps({"error": "Invalid Spotify credentials directory"}),
status=400,
mimetype='application/json'
)
elif service == 'deezer':
# Validate Deezer main credentials
deezer_creds_path = os.path.abspath(os.path.join('./creds/deezer', main, 'credentials.json'))
if not os.path.isfile(deezer_creds_path):
return Response(
json.dumps({"error": "Invalid Deezer credentials directory"}),
status=400,
mimetype='application/json'
)
else:
return Response(
json.dumps({"error": "Unsupported service"}),
status=400,
mimetype='application/json'
)
except Exception as e:
return Response(
json.dumps({"error": f"Credential validation failed: {str(e)}"}),
status=500,
mimetype='application/json'
)
filename = generate_random_filename()
prg_dir = './prgs'
os.makedirs(prg_dir, exist_ok=True)
@@ -82,7 +142,7 @@ def handle_download():
Process(
target=download_task,
args=(service, url, main, fallback, prg_path)
args=(service, url, main, fallback, quality, fall_quality, prg_path)
).start()
return Response(

View File

@@ -26,7 +26,7 @@ class FlushingFileWrapper:
def flush(self):
self.file.flush()
def download_task(service, url, main, fallback, prg_path):
def download_task(service, url, main, fallback, quality, fall_quality, prg_path):
try:
from routes.utils.playlist import download_playlist
with open(prg_path, 'w') as f:
@@ -39,7 +39,9 @@ def download_task(service, url, main, fallback, prg_path):
service=service,
url=url,
main=main,
fallback=fallback
fallback=fallback,
quality=quality,
fall_quality=fall_quality
)
flushing_file.write(json.dumps({"status": "complete"}) + "\n")
except Exception as e:
@@ -66,6 +68,8 @@ def handle_download():
url = request.args.get('url')
main = request.args.get('main')
fallback = request.args.get('fallback')
quality = request.args.get('quality')
fall_quality = request.args.get('fall_quality')
if not all([service, url, main]):
return Response(
@@ -81,7 +85,7 @@ def handle_download():
Process(
target=download_task,
args=(service, url, main, fallback, prg_path)
args=(service, url, main, fallback, quality, fall_quality, prg_path)
).start()
return Response(

View File

@@ -26,7 +26,7 @@ class FlushingFileWrapper:
def flush(self):
self.file.flush()
def download_task(service, url, main, fallback, prg_path):
def download_task(service, url, main, fallback, quality, fall_quality, prg_path):
try:
from routes.utils.track import download_track
with open(prg_path, 'w') as f:
@@ -39,7 +39,9 @@ def download_task(service, url, main, fallback, prg_path):
service=service,
url=url,
main=main,
fallback=fallback
fallback=fallback,
quality=quality,
fall_quality=fall_quality
)
flushing_file.write(json.dumps({"status": "complete"}) + "\n")
except Exception as e:
@@ -66,6 +68,8 @@ def handle_download():
url = request.args.get('url')
main = request.args.get('main')
fallback = request.args.get('fallback')
quality = request.args.get('quality')
fall_quality = request.args.get('fall_quality')
if not all([service, url, main]):
return Response(
@@ -81,7 +85,7 @@ def handle_download():
Process(
target=download_task,
args=(service, url, main, fallback, prg_path)
args=(service, url, main, fallback, quality, fall_quality, prg_path)
).start()
return Response(

View File

@@ -4,10 +4,15 @@ import traceback
from deezspot.spotloader import SpoLogin
from deezspot.deezloader import DeeLogin
def download_album(service, url, main, fallback=None):
def download_album(service, url, main, fallback=None, quality=None, fall_quality=None):
try:
if service == 'spotify':
if fallback:
if quality is None:
quality = 'FLAC'
if fall_quality is None:
fall_quality='HIGH'
# First attempt: use DeeLogin's download_albumspo with the 'main' (Deezer credentials)
try:
# Load Deezer credentials from 'main' under deezer directory
@@ -23,7 +28,7 @@ def download_album(service, url, main, fallback=None):
dl.download_albumspo(
link_album=url,
output_dir="./downloads",
quality_download="FLAC",
quality_download=quality,
recursive_quality=True,
recursive_download=False,
not_interface=False,
@@ -39,7 +44,7 @@ def download_album(service, url, main, fallback=None):
spo.download_album(
link_album=url,
output_dir="./downloads",
quality_download="HIGH",
quality_download=fall_quality,
recursive_quality=True,
recursive_download=False,
not_interface=False,
@@ -54,13 +59,15 @@ def download_album(service, url, main, fallback=None):
) from e2
else:
# Original behavior: use Spotify main
if quality is None:
quality ='HIGH'
creds_dir = os.path.join('./creds/spotify', main)
credentials_path = os.path.abspath(os.path.join(creds_dir, 'credentials.json'))
spo = SpoLogin(credentials_path=credentials_path)
spo.download_album(
link_album=url,
output_dir="./downloads",
quality_download="HIGH",
quality_download=quality,
recursive_quality=True,
recursive_download=False,
not_interface=False,
@@ -68,6 +75,8 @@ def download_album(service, url, main, fallback=None):
make_zip=False
)
elif service == 'deezer':
if quality is None:
quality='FLAC'
# Existing code remains the same, ignoring fallback
creds_dir = os.path.join('./creds/deezer', main)
creds_path = os.path.abspath(os.path.join(creds_dir, 'credentials.json'))
@@ -79,7 +88,7 @@ def download_album(service, url, main, fallback=None):
dl.download_albumdee(
link_album=url,
output_dir="./downloads",
quality_download="FLAC",
quality_download=quality,
recursive_quality=True,
recursive_download=False,
method_save=1,

View File

@@ -4,10 +4,15 @@ import traceback
from deezspot.spotloader import SpoLogin
from deezspot.deezloader import DeeLogin
def download_playlist(service, url, main, fallback=None):
def download_playlist(service, url, main, fallback=None, quality=None, fall_quality=None):
try:
if service == 'spotify':
if fallback:
if quality is None:
quality = 'FLAC'
if fall_quality is None:
fall_quality='HIGH'
# First attempt: use DeeLogin's download_playlistspo with the 'main' (Deezer credentials)
try:
# Load Deezer credentials from 'main' under deezer directory
@@ -23,7 +28,7 @@ def download_playlist(service, url, main, fallback=None):
dl.download_playlistspo(
link_playlist=url,
output_dir="./downloads",
quality_download="FLAC",
quality_download=quality,
recursive_quality=True,
recursive_download=False,
not_interface=False,
@@ -39,7 +44,7 @@ def download_playlist(service, url, main, fallback=None):
spo.download_playlist(
link_playlist=url,
output_dir="./downloads",
quality_download="HIGH",
quality_download=fall_quality,
recursive_quality=True,
recursive_download=False,
not_interface=False,
@@ -54,13 +59,15 @@ def download_playlist(service, url, main, fallback=None):
) from e2
else:
# Original behavior: use Spotify main
if quality is None:
quality='HIGH'
creds_dir = os.path.join('./creds/spotify', main)
credentials_path = os.path.abspath(os.path.join(creds_dir, 'credentials.json'))
spo = SpoLogin(credentials_path=credentials_path)
spo.download_playlist(
link_playlist=url,
output_dir="./downloads",
quality_download="HIGH",
quality_download=quality,
recursive_quality=True,
recursive_download=False,
not_interface=False,
@@ -68,6 +75,8 @@ def download_playlist(service, url, main, fallback=None):
make_zip=False
)
elif service == 'deezer':
if quality is None:
quality='FLAC'
# Existing code for Deezer, using main as Deezer account
creds_dir = os.path.join('./creds/deezer', main)
creds_path = os.path.abspath(os.path.join(creds_dir, 'credentials.json'))
@@ -79,7 +88,7 @@ def download_playlist(service, url, main, fallback=None):
dl.download_playlistdee(
link_playlist=url,
output_dir="./downloads",
quality_download="FLAC",
quality_download=quality,
recursive_quality=False,
recursive_download=False,
method_save=1,

View File

@@ -4,10 +4,15 @@ import traceback
from deezspot.spotloader import SpoLogin
from deezspot.deezloader import DeeLogin
def download_track(service, url, main, fallback=None):
def download_track(service, url, main, fallback=None, quality=None, fall_quality=None):
try:
if service == 'spotify':
if fallback:
if quality is None:
quality = 'FLAC'
if fall_quality is None:
fall_quality='HIGH'
# First attempt: use Deezer's download_trackspo with 'main' (Deezer credentials)
try:
deezer_creds_dir = os.path.join('./creds/deezer', main)
@@ -20,7 +25,7 @@ def download_track(service, url, main, fallback=None):
dl.download_trackspo(
link_track=url,
output_dir="./downloads",
quality_download="FLAC",
quality_download=quality,
recursive_quality=False,
recursive_download=False,
not_interface=False,
@@ -33,7 +38,7 @@ def download_track(service, url, main, fallback=None):
spo.download_track(
link_track=url,
output_dir="./downloads",
quality_download="HIGH",
quality_download=fall_quality,
recursive_quality=False,
recursive_download=False,
not_interface=False,
@@ -41,19 +46,23 @@ def download_track(service, url, main, fallback=None):
)
else:
# Directly use Spotify main account
if quality is None:
quality='HIGH'
creds_dir = os.path.join('./creds/spotify', main)
credentials_path = os.path.abspath(os.path.join(creds_dir, 'credentials.json'))
spo = SpoLogin(credentials_path=credentials_path)
spo.download_track(
link_track=url,
output_dir="./downloads",
quality_download="HIGH",
quality_download=quality,
recursive_quality=False,
recursive_download=False,
not_interface=False,
method_save=1
)
elif service == 'deezer':
if quality is None:
quality='FLAC'
# Deezer download logic remains unchanged
creds_dir = os.path.join('./creds/deezer', main)
creds_path = os.path.abspath(os.path.join(creds_dir, 'credentials.json'))
@@ -65,7 +74,7 @@ def download_track(service, url, main, fallback=None):
dl.download_trackdee(
link_track=url,
output_dir="./downloads",
quality_download="FLAC",
quality_download=quality,
recursive_quality=False,
recursive_download=False,
method_save=1

File diff suppressed because it is too large Load Diff

View File

@@ -76,23 +76,40 @@ document.addEventListener('DOMContentLoaded', () => {
async function initConfig() {
loadConfig();
console.log(loadConfig())
await updateAccountSelectors();
// Event listeners
document.getElementById('fallbackToggle').addEventListener('change', () => {
saveConfig();
updateAccountSelectors();
});
const accountSelects = ['spotifyAccountSelect', 'deezerAccountSelect'];
accountSelects.forEach(id => {
document.getElementById(id).addEventListener('change', () => {
// Existing listeners
const fallbackToggle = document.getElementById('fallbackToggle');
if (fallbackToggle) {
fallbackToggle.addEventListener('change', () => {
saveConfig();
updateAccountSelectors();
});
}
const accountSelects = ['spotifyAccountSelect', 'deezerAccountSelect'];
accountSelects.forEach(id => {
const element = document.getElementById(id);
if (element) {
element.addEventListener('change', () => {
saveConfig();
updateAccountSelectors();
});
}
});
// Add quality select listeners with null checks
const spotifyQuality = document.getElementById('spotifyQualitySelect');
if (spotifyQuality) {
spotifyQuality.addEventListener('change', saveConfig);
}
const deezerQuality = document.getElementById('deezerQualitySelect');
if (deezerQuality) {
deezerQuality.addEventListener('change', saveConfig);
}
}
async function updateAccountSelectors() {
try {
@@ -273,23 +290,43 @@ async function startDownload(url, type, item) {
const spotifyAccount = document.getElementById('spotifyAccountSelect').value;
const deezerAccount = document.getElementById('deezerAccountSelect').value;
let apiUrl = `/api/${type}/download?service=spotify&url=${encodeURIComponent(url)}`;
if (fallbackEnabled) {
apiUrl += `&main=${deezerAccount}&fallback=${spotifyAccount}`;
// Determine service from URL
let service;
if (url.includes('open.spotify.com')) {
service = 'spotify';
} else if (url.includes('deezer.com')) {
service = 'deezer';
} else {
apiUrl += `&main=${spotifyAccount}`;
showError('Unsupported service URL');
return;
}
let apiUrl = `/api/${type}/download?service=${service}&url=${encodeURIComponent(url)}`;
// Get quality settings
const spotifyQuality = document.getElementById('spotifyQualitySelect').value;
const deezerQuality = document.getElementById('deezerQualitySelect').value;
if (fallbackEnabled && service === 'spotify') {
// Deezer fallback for Spotify URLs
apiUrl += `&main=${deezerAccount}&fallback=${spotifyAccount}`;
apiUrl += `&quality=${encodeURIComponent(deezerQuality)}`;
apiUrl += `&fall_quality=${encodeURIComponent(spotifyQuality)}`;
} else {
// Standard download without fallback
const mainAccount = service === 'spotify' ? spotifyAccount : deezerAccount;
apiUrl += `&main=${mainAccount}`;
apiUrl += `&quality=${encodeURIComponent(service === 'spotify' ? spotifyQuality : deezerQuality)}`;
}
try {
const response = await fetch(apiUrl);
const data = await response.json();
addToQueue(item, type, data.prg_file);
const response = await fetch(apiUrl);
const data = await response.json();
addToQueue(item, type, data.prg_file);
} catch (error) {
showError('Download failed: ' + error.message);
showError('Download failed: ' + error.message);
}
}
}
function addToQueue(item, type, prgFile) {
const queueId = Date.now().toString() + Math.random().toString(36).substr(2, 9);
@@ -630,9 +667,11 @@ function getStatusMessage(data) {
function saveConfig() {
const config = {
spotify: document.getElementById('spotifyAccountSelect').value,
deezer: document.getElementById('deezerAccountSelect').value,
fallback: document.getElementById('fallbackToggle').checked
spotify: document.getElementById('spotifyAccountSelect').value,
deezer: document.getElementById('deezerAccountSelect').value,
fallback: document.getElementById('fallbackToggle').checked,
spotifyQuality: document.getElementById('spotifyQualitySelect').value,
deezerQuality: document.getElementById('deezerQualitySelect').value
};
localStorage.setItem('activeConfig', JSON.stringify(config));
}
@@ -641,16 +680,24 @@ function saveConfig() {
function loadConfig() {
const saved = JSON.parse(localStorage.getItem('activeConfig')) || {};
// Set values only if they exist in the DOM
// Account selects
const spotifySelect = document.getElementById('spotifyAccountSelect');
const deezerSelect = document.getElementById('deezerAccountSelect');
if (spotifySelect) spotifySelect.value = saved.spotify || '';
const deezerSelect = document.getElementById('deezerAccountSelect');
if (deezerSelect) deezerSelect.value = saved.deezer || '';
// Fallback toggle
const fallbackToggle = document.getElementById('fallbackToggle');
if (fallbackToggle) fallbackToggle.checked = !!saved.fallback;
}
// Quality selects
const spotifyQuality = document.getElementById('spotifyQualitySelect');
if (spotifyQuality) spotifyQuality.value = saved.spotifyQuality || 'NORMAL';
const deezerQuality = document.getElementById('deezerQualitySelect');
if (deezerQuality) deezerQuality.value = saved.deezerQuality || 'MP3_128';
}
function isSpotifyUrl(url) {
return url.startsWith('https://open.spotify.com/');

View File

@@ -19,10 +19,26 @@
<label>Active Spotify Account:</label>
<select id="spotifyAccountSelect"></select>
</div>
<div class="config-item">
<label>Spotify Quality:</label>
<select id="spotifyQualitySelect">
<option value="NORMAL">Normal</option>
<option value="HIGH">High</option>
<option value="VERY_HIGH">Very High</option>
</select>
</div>
<div class="config-item">
<label>Active Deezer Account:</label>
<select id="deezerAccountSelect"></select>
</div>
<div class="config-item">
<label>Deezer Quality:</label>
<select id="deezerQualitySelect">
<option value="MP3_128">MP3 128</option>
<option value="MP3_320">MP3 320</option>
<option value="FLAC">FLAC</option>
</select>
</div>
<div class="config-item">
<label>Download Fallback:</label>
<label class="switch">