fix: Robust Deezer URL generation with direct track links and sanitized search paths to prevent HTTP_NOT_FOUND
This commit is contained in:
1 parent
fc1adda97d
commit
867cc191cd
5 files changed
+59
-9
No files matched your search
+1
-1
@@ -243,7 +243,7 @@
|
||||
|
||||
<script src="wheel.js?v=2.1.0"></script>
|
||||
<script src="cover.js?v=2.1.0"></script>
|
||||
<script src="search.js?v=2.1.0"></script>
|
||||
<script src="search.js?v=2.1.1"></script>
|
||||
<script src="app.js?v=2.1.0"></script>
|
||||
</body>
|
||||
</html>
|
||||
+38
-7
@@ -112,6 +112,28 @@ function formatDuration(sec) {
|
||||
return `${m}:${s < 10 ? '0' : ''}${s}`;
|
||||
}
|
||||
|
||||
function getCleanSearchTerm(artist, title) {
|
||||
const raw = `${artist || ''} ${title || ''}`;
|
||||
return raw.replace(/[/\\?#%&"'\(\)\[\]]/g, ' ').replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function getDeezerUrl(track) {
|
||||
if (track && track.deezer_link) return track.deezer_link;
|
||||
if (track && track.deezer_id) return `https://www.deezer.com/track/${track.deezer_id}`;
|
||||
const term = getCleanSearchTerm(track ? track.artist : '', track ? track.title : '');
|
||||
return `https://www.deezer.com/search/${encodeURIComponent(term)}/track`;
|
||||
}
|
||||
|
||||
function getSpotifyUrl(track) {
|
||||
const term = getCleanSearchTerm(track ? track.artist : '', track ? track.title : '');
|
||||
return `https://open.spotify.com/search/${encodeURIComponent(term)}`;
|
||||
}
|
||||
|
||||
function getYoutubeUrl(track) {
|
||||
const term = getCleanSearchTerm(track ? track.artist : '', track ? track.title : '');
|
||||
return `https://www.youtube.com/results?search_query=${encodeURIComponent(term)}`;
|
||||
}
|
||||
|
||||
async function selectTrack(track) {
|
||||
// Update Hero UI
|
||||
document.getElementById('track-title').textContent = track.title;
|
||||
@@ -137,13 +159,12 @@ async function selectTrack(track) {
|
||||
const trackActions = document.getElementById('track-actions');
|
||||
if (trackActions) {
|
||||
trackActions.style.display = 'flex';
|
||||
const query = encodeURIComponent(`${track.artist} ${track.title}`);
|
||||
const spotEl = document.getElementById('action-spotify');
|
||||
const deezEl = document.getElementById('action-deezer');
|
||||
const ytEl = document.getElementById('action-youtube');
|
||||
if (spotEl) spotEl.href = `https://open.spotify.com/search/${query}`;
|
||||
if (deezEl) deezEl.href = `https://www.deezer.com/search/${query}`;
|
||||
if (ytEl) ytEl.href = `https://www.youtube.com/results?search_query=${query}`;
|
||||
if (spotEl) spotEl.href = getSpotifyUrl(track);
|
||||
if (deezEl) deezEl.href = getDeezerUrl(track);
|
||||
if (ytEl) ytEl.href = getYoutubeUrl(track);
|
||||
}
|
||||
|
||||
// Fetch or apply metadata
|
||||
@@ -155,6 +176,8 @@ async function selectTrack(track) {
|
||||
let energy = track.energy || null;
|
||||
let danceability = track.danceability || null;
|
||||
let happiness = track.happiness || null;
|
||||
let deezerLink = track.deezer_link || (track.deezer_id ? `https://www.deezer.com/track/${track.deezer_id}` : null);
|
||||
let deezerId = track.deezer_id || null;
|
||||
|
||||
if (!key || !bpm || !energy) {
|
||||
// Query metadata route to get key, bpm, and persist into PostgreSQL
|
||||
@@ -171,6 +194,14 @@ async function selectTrack(track) {
|
||||
energy = d.energy;
|
||||
danceability = d.danceability;
|
||||
happiness = d.happiness;
|
||||
if (d.deezer_link || d.deezer_id) {
|
||||
deezerLink = d.deezer_link || deezerLink;
|
||||
deezerId = d.deezer_id || deezerId;
|
||||
track.deezer_link = deezerLink;
|
||||
track.deezer_id = deezerId;
|
||||
const deezEl = document.getElementById('action-deezer');
|
||||
if (deezEl) deezEl.href = getDeezerUrl(track);
|
||||
}
|
||||
document.getElementById('stat-match').textContent = d.is_corrected ? '100%' : (d.source === 'postgresql' ? '100%' : 'Online');
|
||||
document.getElementById('stat-source-sub').textContent = d.source === 'postgresql' ? (d.is_corrected ? 'PostgreSQL (Fix)' : 'PostgreSQL') : 'PostgreSQL (Neu)';
|
||||
}
|
||||
@@ -350,13 +381,13 @@ function applySuggestionsFilter() {
|
||||
<div class="sug-bottom-row">
|
||||
<div class="sug-compat">${s.compatLabel || 'KOMPATIBEL'}</div>
|
||||
<div class="sug-links">
|
||||
<a href="https://open.spotify.com/search/${encodeURIComponent(s.artist + ' ' + s.title)}" target="_blank" rel="noopener" class="sug-link-icon sug-link-spotify" onclick="event.stopPropagation()" title="Auf Spotify öffnen">
|
||||
<a href="${getSpotifyUrl(s)}" target="_blank" rel="noopener" class="sug-link-icon sug-link-spotify" onclick="event.stopPropagation()" title="Auf Spotify öffnen">
|
||||
<i class="fa-brands fa-spotify"></i>
|
||||
</a>
|
||||
<a href="https://www.deezer.com/search/${encodeURIComponent(s.artist + ' ' + s.title)}" target="_blank" rel="noopener" class="sug-link-icon sug-link-deezer" onclick="event.stopPropagation()" title="Auf Deezer öffnen">
|
||||
<a href="${getDeezerUrl(s)}" target="_blank" rel="noopener" class="sug-link-icon sug-link-deezer" onclick="event.stopPropagation()" title="Auf Deezer öffnen">
|
||||
<i class="fa-brands fa-deezer"></i>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/results?search_query=${encodeURIComponent(s.artist + ' ' + s.title)}" target="_blank" rel="noopener" class="sug-link-icon sug-link-youtube" onclick="event.stopPropagation()" title="Auf YouTube suchen">
|
||||
<a href="${getYoutubeUrl(s)}" target="_blank" rel="noopener" class="sug-link-icon sug-link-youtube" onclick="event.stopPropagation()" title="Auf YouTube suchen">
|
||||
<i class="fa-brands fa-youtube"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -122,6 +122,8 @@ router.get('/', async (req, res) => {
|
||||
is_corrected: !!local.is_corrected,
|
||||
cover_url: local.cover_url || null,
|
||||
preview_url: local.preview_url || null,
|
||||
deezer_id: local.deezer_id || null,
|
||||
deezer_link: local.deezer_link || (local.deezer_id ? `https://www.deezer.com/track/${local.deezer_id}` : null),
|
||||
duration_sec: local.duration_sec || 210,
|
||||
energy: local.energy || est.energy,
|
||||
danceability: local.danceability || est.danceability,
|
||||
@@ -193,6 +195,8 @@ router.get('/', async (req, res) => {
|
||||
// 4. Query Deezer for cover, duration, preview, and genre fallback
|
||||
let durationSec = 210;
|
||||
let previewUrl = null;
|
||||
let deezerLink = null;
|
||||
let deezerId = null;
|
||||
try {
|
||||
const deezerRes = await axios.get(`https://api.deezer.com/search?q=${encodeURIComponent(artist + ' ' + track)}&limit=1`, {
|
||||
timeout: 3000
|
||||
@@ -208,6 +212,13 @@ router.get('/', async (req, res) => {
|
||||
if (dTrack.preview) {
|
||||
previewUrl = dTrack.preview;
|
||||
}
|
||||
if (dTrack.link) {
|
||||
deezerLink = dTrack.link;
|
||||
}
|
||||
if (dTrack.id) {
|
||||
deezerId = dTrack.id;
|
||||
if (!deezerLink) deezerLink = `https://www.deezer.com/track/${dTrack.id}`;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
@@ -250,6 +261,8 @@ router.get('/', async (req, res) => {
|
||||
cover_url: coverUrl,
|
||||
preview_url: previewUrl,
|
||||
duration_sec: durationSec,
|
||||
deezer_id: deezerId,
|
||||
deezer_link: deezerLink,
|
||||
energy: audioAttrs.energy,
|
||||
danceability: audioAttrs.danceability,
|
||||
happiness: audioAttrs.happiness,
|
||||
|
||||
@@ -35,7 +35,8 @@ router.get('/', async (req, res) => {
|
||||
cover_url: item.album && item.album.cover_medium ? item.album.cover_medium : (item.album ? item.album.cover : null),
|
||||
preview_url: item.preview || null,
|
||||
duration_sec: item.duration || 210,
|
||||
deezer_id: item.id
|
||||
deezer_id: item.id,
|
||||
deezer_link: item.link || (item.id ? `https://www.deezer.com/track/${item.id}` : null)
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -63,6 +64,8 @@ router.get('/', async (req, res) => {
|
||||
energy: lt.energy,
|
||||
danceability: lt.danceability,
|
||||
happiness: lt.happiness,
|
||||
deezer_id: lt.deezer_id || null,
|
||||
deezer_link: lt.deezer_link || (lt.deezer_id ? `https://www.deezer.com/track/${lt.deezer_id}` : null),
|
||||
is_local: true,
|
||||
is_corrected: lt.is_corrected
|
||||
});
|
||||
@@ -81,6 +84,8 @@ router.get('/', async (req, res) => {
|
||||
cover_url: ot.cover_url,
|
||||
preview_url: ot.preview_url,
|
||||
duration_sec: ot.duration_sec,
|
||||
deezer_id: ot.deezer_id,
|
||||
deezer_link: ot.deezer_link,
|
||||
camelot_key: existingLocal ? existingLocal.camelot_key : null,
|
||||
bpm: existingLocal ? existingLocal.bpm : null,
|
||||
music_key: existingLocal ? existingLocal.music_key : null,
|
||||
|
||||
@@ -80,6 +80,7 @@ router.get('/', async (req, res) => {
|
||||
compatLabel: compatLabel,
|
||||
cover_url: t.cover_url || null,
|
||||
preview_url: t.preview_url || null,
|
||||
deezer_link: t.deezer_link || (t.deezer_id ? `https://www.deezer.com/track/${t.deezer_id}` : null),
|
||||
duration_sec: t.duration_sec || 215,
|
||||
energy: t.energy || defaultEnergy,
|
||||
danceability: t.danceability || defaultDance,
|
||||
|
||||
Reference in new issue
Block a user