use old jquery

This commit is contained in:
uimaxbai 2025-12-30 18:12:09 +00:00
parent b3bfbc3ac7
commit ed67ac61cb
3 changed files with 175 additions and 207 deletions

View file

@ -4,6 +4,7 @@
<title>Monochrome Legacy</title> <title>Monochrome Legacy</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="legacy.css"> <link rel="stylesheet" type="text/css" href="legacy.css">
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="legacy.js"></script> <script type="text/javascript" src="legacy.js"></script>
</head> </head>
<body> <body>

32
legacy/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
// strictly ES5/Legacy JS // jQuery 1.12.4 Legacy Support
(function () { $(document).ready(function () {
var currentApiUrl = ""; // Will be set from instances.json var currentApiUrl = ""; // Will be set from instances.json
var isHttpFallback = false; var isHttpFallback = false;
var FALLBACK_INSTANCES = [ var FALLBACK_INSTANCES = [
@ -12,34 +12,63 @@
"https://tidal.kinoplus.online", "https://tidal.kinoplus.online",
"https://tidal-api.binimum.org", "https://tidal-api.binimum.org",
]; ];
var audioPlayer; var audioPlayer = $("#audio-player")[0];
var currentTrackInfo; var currentTrackInfo = $("#now-playing-info");
window.onload = function () { // Initial Load
audioPlayer = document.getElementById("audio-player"); fetchInstances(function (url) {
currentTrackInfo = document.getElementById("now-playing-info"); currentApiUrl = url;
loadRecentTracks();
});
fetchInstances(function (url) { // Event Bindings
currentApiUrl = url; $("#btn-home").click(function (e) {
loadRecentTracks(); e.preventDefault();
}); loadRecentTracks();
});
// Simple event delegation if we wanted, but explicit bindings are safer for old browsers $("#search-form").submit(function (e) {
var btnHome = document.getElementById("btn-home"); e.preventDefault();
if (btnHome) { var query = $("#search-input").val();
btnHome.onclick = function () { performSearch(query);
loadRecentTracks(); });
return false;
};
}
// Search button removed, using persistent form now
var searchForm = document.getElementById("search-form"); // Global functions exposed for inline onclicks
searchForm.onsubmit = function () { window.playTrack = function (id) {
var query = document.getElementById("search-input").value; apiRequest(
performSearch(query); "/track/?id=" + id + "&quality=HIGH",
return false; function (data) {
}; 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) {
currentTrackInfo.html("Now Playing...");
}
} else {
alert("No stream URLs found.");
}
} catch (e) {
alert("Error parsing playback manifest: " + e.message);
}
} else {
alert("Invalid track data received.");
}
},
function (err) {
alert("Error playing track: " + err);
}
);
}; };
function loadRecentTracks() { function loadRecentTracks() {
@ -48,9 +77,9 @@
"/search/?s=a&limit=20", "/search/?s=a&limit=20",
function (data) { function (data) {
if (data && data.data && data.data.items) { if (data && data.data && data.data.items) {
renderTracks(data.data.items, "Recently Added / Popular"); renderTracks(data.data.items, "Recently Added / Popular");
} else { } else {
setContent("No recent tracks found."); setContent("No recent tracks found.");
} }
}, },
function (err) { function (err) {
@ -60,36 +89,26 @@
} }
function fetchInstances(callback) { function fetchInstances(callback) {
var xhr = createXHR(); // using $.ajax directly to handle errors robustly
xhr.open("GET", "instances.json", true); $.ajax({
xhr.onreadystatechange = function () { url: "instances.json",
if (xhr.readyState === 4) { dataType: "json",
if (xhr.status >= 200 && xhr.status < 300) { success: function (instances) {
try { if (instances && instances.length > 0) {
var instances = JSON.parse(xhr.responseText); var randomUrl =
if (instances && instances.length > 0) { instances[Math.floor(Math.random() * instances.length)];
var randomUrl = if (randomUrl.charAt(randomUrl.length - 1) === "/") {
instances[Math.floor(Math.random() * instances.length)]; randomUrl = randomUrl.substring(0, randomUrl.length - 1);
// Remove trailing slash if present
if (randomUrl.charAt(randomUrl.length - 1) === "/") {
randomUrl = randomUrl.substring(0, randomUrl.length - 1);
}
callback(randomUrl);
} else {
useFallback(callback);
}
} catch (e) {
useFallback(callback);
} }
callback(randomUrl);
} else { } else {
useFallback(callback); useFallback(callback);
} }
},
error: function () {
useFallback(callback);
} }
}; });
xhr.onerror = function () {
useFallback(callback);
};
xhr.send();
} }
function useFallback(callback) { function useFallback(callback) {
@ -99,12 +118,12 @@
} }
function performSearch(query) { function performSearch(query) {
var resultsDiv = document.getElementById("search-results"); var resultsDiv = $("#search-results");
if (!resultsDiv) { if (resultsDiv.length === 0) {
setContent('<div id="search-results">Searching...</div>'); setContent('<div id="search-results">Searching...</div>');
resultsDiv = document.getElementById("search-results"); resultsDiv = $("#search-results");
} else { } else {
resultsDiv.innerHTML = "Searching..."; resultsDiv.html("Searching...");
} }
apiRequest( apiRequest(
@ -112,17 +131,16 @@
function (data) { function (data) {
var tracks = (data && data.data && data.data.items) ? data.data.items : []; var tracks = (data && data.data && data.data.items) ? data.data.items : [];
if (tracks.length === 0) { if (tracks.length === 0) {
resultsDiv.innerHTML = "No results found."; resultsDiv.html("No results found.");
return; return;
} }
// Manually render table string to avoid complex DOM manipulation
var html = var html =
'<table width="100%" border="1" cellpadding="2" cellspacing="0">'; '<table width="100%" border="1" cellpadding="2" cellspacing="0">';
html += html +=
'<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>'; '<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>';
for (var i = 0; i < tracks.length; i++) { $.each(tracks, function (i, t) {
var t = tracks[i];
var safeTitle = escapeHtml(t.title); var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name); var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title); var safeAlbum = escapeHtml(t.album.title);
@ -136,13 +154,13 @@
html += "<td>" + safeArtist + "</td>"; html += "<td>" + safeArtist + "</td>";
html += "<td>" + safeAlbum + "</td>"; html += "<td>" + safeAlbum + "</td>";
html += "</tr>"; html += "</tr>";
} });
html += "</table>"; html += "</table>";
resultsDiv.innerHTML = html; resultsDiv.html(html);
}, },
function (err) { function (err) {
resultsDiv.innerHTML = "Error: " + err; resultsDiv.html("Error: " + err);
} }
); );
} }
@ -153,8 +171,7 @@
html += html +=
'<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>'; '<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>';
for (var i = 0; i < tracks.length; i++) { $.each(tracks, function (i, t) {
var t = tracks[i];
var safeTitle = escapeHtml(t.title); var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name); var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title); var safeAlbum = escapeHtml(t.album.title);
@ -168,99 +185,63 @@
html += "<td>" + safeArtist + "</td>"; html += "<td>" + safeArtist + "</td>";
html += "<td>" + safeAlbum + "</td>"; html += "<td>" + safeAlbum + "</td>";
html += "</tr>"; html += "</tr>";
} });
html += "</table>"; html += "</table>";
setContent(html); setContent(html);
} }
// Global player function
window.playTrack = function (id) {
apiRequest(
"/track/?id=" + id + "&quality=HIGH",
function (data) {
if (data && data.data && data.data.manifest) {
try {
// Manifest is Base64 encoded JSON
var manifestStr = base64Decode(data.data.manifest);
var manifest = JSON.parse(manifestStr);
if (manifest.urls && manifest.urls.length > 0) {
var streamUrl = manifest.urls[0];
if (audioPlayer.play) {
audioPlayer.src = streamUrl;
audioPlayer.play();
} else {
// Fallback for IE/Older browsers
playWithEmbed(streamUrl);
}
if (currentTrackInfo) {
// We don't get full track info in playback response easily without another call or passing it,
// but for legacy we might accept just "Now Playing..." or maybe we pass it?
// For now simplicity:
currentTrackInfo.innerHTML = "Now Playing...";
}
} else {
alert("No stream URLs found in manifest.");
}
} catch (e) {
alert("Error parsing playback manifest: " + e.message);
}
} else {
alert("Invalid track data received.");
}
},
function (err) {
alert("Error playing track: " + err);
}
);
};
function setContent(html) { function setContent(html) {
var content = document.getElementById("main-content"); $("#main-content").html(html);
content.innerHTML = html;
} }
function apiRequest(endpoint, success, error) { function apiRequest(endpoint, success, error) {
var xhr = createXHR();
// Use fallback HTTP if needed logic
var finalUrl = currentApiUrl; var finalUrl = currentApiUrl;
if (isHttpFallback && finalUrl.indexOf("https://") === 0) { if (isHttpFallback && finalUrl.indexOf("https://") === 0) {
finalUrl = "http://" + finalUrl.substring(8); finalUrl = "http://" + finalUrl.substring(8);
} }
xhr.open("GET", finalUrl + endpoint, true); $.ajax({
xhr.onreadystatechange = function () { url: finalUrl + endpoint,
if (xhr.readyState === 4) { method: "GET",
if (xhr.status >= 200 && xhr.status < 300) { dataType: "json",
try { success: function (data) {
var data = JSON.parse(xhr.responseText); success(data);
success(data); },
} catch (e) { error: function (xhr, status, err) {
error("JSON Parse Error"); if (!isHttpFallback) {
} isHttpFallback = true;
// Retry with fallback logic (recursive call will pick up isHttpFallback)
apiRequest(endpoint, success, error);
} else { } else {
// If failed and not yet fallback, try fallback error("Request Failed: " + status);
if(!isHttpFallback) {
isHttpFallback = true;
apiRequest(endpoint, success, error);
} else {
error("HTTP " + xhr.status);
}
} }
} }
}; });
xhr.onerror = function () {
if(!isHttpFallback) {
isHttpFallback = true;
apiRequest(endpoint, success, error);
} else {
error("Network Error");
}
};
xhr.send();
} }
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 = $('<div id="embed-container"></div>');
container.append(embedDiv);
}
// Use html() to set innerHTML properly
var embedHtml = '<embed type="application/x-mplayer2" src="' + url + '" autostart="true" width="0" height="0" enablejavascript="true"></embed>';
embedDiv.html(embedHtml);
}
}
// Helpers
function escapeHtml(text) { function escapeHtml(text) {
if (!text) return ""; if (!text) return "";
return text return text
@ -271,70 +252,24 @@
.replace(/'/g, "&#039;"); .replace(/'/g, "&#039;");
} }
function createXHR() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
}
// IE5/6 support
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {}
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
alert("Your browser does not support AJAX!");
return null;
}
function base64Decode(str) { function base64Decode(str) {
if (window.atob) { if (window.atob) {
return window.atob(str); return window.atob(str);
} }
// Polyfill for IE var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var output = "";
var output = ""; str = String(str).replace(/=+$/, '');
str = String(str).replace(/=+$/, ''); if (str.length % 4 == 1) {
if (str.length % 4 == 1) { throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
throw new Error("'atob' failed: The string to be decoded is not correctly encoded."); }
} for (
for ( var bc = 0, bs = 0, buffer, i = 0;
var bc = 0, bs = 0, buffer, i = 0; buffer = str.charAt(i++);
buffer = str.charAt(i++); ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 ) {
) { buffer = chars.indexOf(buffer);
buffer = chars.indexOf(buffer); }
} return output;
return output;
} }
});
function playWithEmbed(url) {
var container = document.getElementById("audio-container");
if (!container) {
// If no container, try to find parent of audio player
if (audioPlayer && audioPlayer.parentNode) {
container = audioPlayer.parentNode;
// Give it an ID for future reference
container.id = "audio-container";
}
}
if (container) {
// Clear previous embeds
// Removing innerHTML is the brute force way but effective for legacy
// However, we want to keep the text status if it's in there (it's not, status is sibling in .controls)
// The audio player is in .controls.
// Let's create a specific div for embed if it doesn't exist, appended to container
var embedDiv = document.getElementById("embed-container");
if (!embedDiv) {
embedDiv = document.createElement("div");
embedDiv.id = "embed-container";
container.appendChild(embedDiv);
}
var html = '<embed type="application/x-mplayer2" src="' + url + '" autostart="true" width="0" height="0" enablejavascript="true"></embed>';
embedDiv.innerHTML = html;
}
}
})();