// jQuery 1.12.4 Legacy Support
$(document).ready(function () {
var currentApiUrl = ""; // Will be set from instances.json
var isHttpFallback = false;
var FALLBACK_INSTANCES = [
"https://triton.squid.wtf",
"https://wolf.qqdl.site",
"https://maus.qqdl.site",
"https://vogel.qqdl.site",
"https://katze.qqdl.site",
"https://hund.qqdl.site",
"https://tidal.kinoplus.online",
"https://tidal-api.binimum.org",
];
var audioPlayer = $("#audio-player")[0];
var currentTrackInfo = $("#now-playing-info");
// Initial Load
fetchInstances(function (url) {
currentApiUrl = url;
loadRecentTracks();
});
// Event Bindings
$("#btn-home").click(function (e) {
e.preventDefault();
loadRecentTracks();
});
$("#search-form").submit(function (e) {
e.preventDefault();
var query = $("#search-input").val();
performSearch(query);
});
// Global functions exposed for inline onclicks
// Global functions exposed for inline onclicks
window.playTrack = function (id, attemptFallback) {
var quality = attemptFallback ? "HIGH" : "LOSSLESS";
apiRequest(
"/track/?id=" + id + "&quality=" + quality,
function (data) {
var success = false;
if (data && data.data && data.data.manifest) {
try {
var manifestStr = base64Decode(data.data.manifest);
var manifest = JSON.parse(manifestStr);
if (manifest.urls && manifest.urls.length > 0) {
var streamUrl = manifest.urls[0];
// Check if HTML5 audio is supported and has play method
if (audioPlayer && typeof audioPlayer.play === 'function') {
audioPlayer.src = streamUrl;
audioPlayer.play();
} else {
playWithEmbed(streamUrl);
}
if (currentTrackInfo.length) {
var qualityLabel = attemptFallback ? " (AAC)" : " (FLAC)";
currentTrackInfo.html("Now Playing..." + qualityLabel);
}
success = true;
}
} catch (e) {
// Fall through to fallback
}
}
if (!success) {
if (!attemptFallback) {
// Try fallback to HIGH (AAC)
window.playTrack(id, true);
} else {
alert("No stream URLs found or invalid manifest.");
}
}
},
function (err) {
if (!attemptFallback) {
// Try fallback to HIGH (AAC) on request error too
window.playTrack(id, true);
} else {
alert("Error playing track: " + err);
}
}
);
};
function loadRecentTracks() {
setContent("Loading recent tracks...");
apiRequest(
"/search/?s=a&limit=20",
function (data) {
if (data && data.data && data.data.items) {
renderTracks(data.data.items, "Recently Added / Popular");
} else {
setContent("No recent tracks found.");
}
},
function (err) {
setContent("Error loading tracks: " + err);
}
);
}
function fetchInstances(callback) {
// using $.ajax directly to handle errors robustly
$.ajax({
url: "instances.json",
dataType: "json",
success: function (instances) {
if (instances && instances.length > 0) {
var randomUrl =
instances[Math.floor(Math.random() * instances.length)];
if (randomUrl.charAt(randomUrl.length - 1) === "/") {
randomUrl = randomUrl.substring(0, randomUrl.length - 1);
}
callback(randomUrl);
} else {
useFallback(callback);
}
},
error: function () {
useFallback(callback);
}
});
}
function useFallback(callback) {
var randomUrl =
FALLBACK_INSTANCES[Math.floor(Math.random() * FALLBACK_INSTANCES.length)];
callback(randomUrl);
}
function performSearch(query) {
var resultsDiv = $("#search-results");
if (resultsDiv.length === 0) {
setContent('
Searching...
');
resultsDiv = $("#search-results");
} else {
resultsDiv.html("Searching...");
}
apiRequest(
"/search/?s=" + encodeURIComponent(query) + "&limit=25",
function (data) {
var tracks = (data && data.data && data.data.items) ? data.data.items : [];
if (tracks.length === 0) {
resultsDiv.html("No results found.");
return;
}
var html =
'
';
html +=
'
Play
Title
Artist
Album
';
$.each(tracks, function (i, t) {
var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title);
html += '
';
html +=
'
";
html += "
" + safeTitle + "
";
html += "
" + safeArtist + "
";
html += "
" + safeAlbum + "
";
html += "
";
});
html += "
";
resultsDiv.html(html);
},
function (err) {
resultsDiv.html("Error: " + err);
}
);
}
function renderTracks(tracks, title) {
var html = "
" + title + "
";
html += '
';
html +=
'
Play
Title
Artist
Album
';
$.each(tracks, function (i, t) {
var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title);
html += '
';
html +=
'
";
html += "
" + safeTitle + "
";
html += "
" + safeArtist + "
";
html += "
" + safeAlbum + "
";
html += "
";
});
html += "
";
setContent(html);
}
function setContent(html) {
$("#main-content").html(html);
}
function apiRequest(endpoint, success, error) {
var finalUrl = currentApiUrl;
if (isHttpFallback && finalUrl.indexOf("https://") === 0) {
finalUrl = "http://" + finalUrl.substring(8);
}
try {
$.ajax({
url: finalUrl + endpoint,
method: "GET",
dataType: "json",
success: function (data) {
success(data);
},
error: function (xhr, status, errorThrown) {
if (!isHttpFallback && window.location.protocol !== "https:") {
isHttpFallback = true;
// Retry with fallback logic (recursive call will pick up isHttpFallback)
apiRequest(endpoint, success, error);
} else {
error("Request Failed: " + status + " (" + errorThrown + ")");
}
}
});
} catch (e) {
if (!isHttpFallback && window.location.protocol !== "https:") {
isHttpFallback = true;
apiRequest(endpoint, success, error);
} else {
error("Exception: " + e.message);
}
}
}
function playWithEmbed(url) {
var container = $("#audio-container");
if (container.length === 0) {
if (audioPlayer && audioPlayer.parentNode) {
$(audioPlayer.parentNode).attr("id", "audio-container");
container = $("#audio-container");
}
}
if (container.length) {
var embedDiv = $("#embed-container");
if (embedDiv.length === 0) {
embedDiv = $('');
container.append(embedDiv);
}
// Use html() to set innerHTML properly
var embedHtml = '';
embedDiv.html(embedHtml);
}
}
// Helpers
function escapeHtml(text) {
if (!text) return "";
return text
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function base64Decode(str) {
if (window.atob) {
return window.atob(str);
}
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var output = "";
str = String(str).replace(/=+$/, '');
if (str.length % 4 == 1) {
throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
}
for (
var bc = 0, bs = 0, buffer, i = 0;
buffer = str.charAt(i++);
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
) {
buffer = chars.indexOf(buffer);
}
return output;
}
});