Legacy version for old browsers

This commit is contained in:
uimaxbai 2025-12-31 14:34:52 +00:00
parent b3bfbc3ac7
commit 84a2e60fc5
11 changed files with 1576 additions and 281 deletions

BIN
legacy/FlashAudioPlugin.swf Normal file

Binary file not shown.

186
legacy/compatibility.html Normal file
View file

@ -0,0 +1,186 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Monochrome Legacy - Compatibility</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="stylesheet" type="text/css" href="legacy.css" />
<script type="text/javascript" src="jquery-1.6.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
// Simple visual effect or just logging
console.log("Compatibility chart loaded.");
});
</script>
</head>
<body>
<table
width="100%"
height="100%"
border="0"
cellpadding="0"
cellspacing="0"
>
<!-- Header -->
<tr height="80">
<td colspan="2" bgcolor="#000000" align="center">
<font color="#FFFFFF" size="6" face="Comic Sans MS, Arial"
><b>Monochrome Music</b></font
><br />
<font color="#cccccc" size="2">music</font>
</td>
</tr>
<!-- Marquee -->
<tr height="20">
<td colspan="2" class="marquee-container">
<marquee scrollamount="5" scrolldelay="100"
>compatibility information</marquee
>
</td>
</tr>
<!-- Main Body -->
<tr valign="top">
<!-- Sidebar -->
<td width="150" bgcolor="#dddddd" class="beveled-box">
<br />
<center><b>Menu</b></center>
<hr />
<ul style="list-style-type: square; padding-left: 20px">
<li class="sidebar-link">
<a href="html5.html" id="btn-home">Home</a>
</li>
<li class="sidebar-link">
<a href="compatibility.html">Compatibility</a>
</li>
<li class="sidebar-link"><a href="/">Modern Site</a></li>
</ul>
<br />
<center>
<img
src="getie3.gif"
alt="IE Logo"
width="88"
height="31"
/><br /><br />
<font size="1">free and open software</font><br /><br />
<font size="1">made by binimum</font>
</center>
</td>
<!-- Content -->
<td bgcolor="#ffffff">
<div style="padding: 20px">
<center><h3>System Requirements</h3></center>
<hr />
<font face="Verdana" size="2">
<p>
Welcome to the Monochrome Music Legacy Edition connectivity test
center.
</p>
<p>
<b>Requirement:</b> Any browser that supports
<a href="https://caniuse.com/aac">AAC Audio</a> or
<a href="https://caniuse.com/flac">FLAC Audio</a>.
</p>
<div
class="beveled-box"
style="padding: 10px; background-color: #eeeeee"
>
<h4>Officially supported: (HTML5)</h4>
<ul>
<li><b>Internet Explorer</b> 9+</li>
<li><b>Google Chrome</b> 12+</li>
<li><b>Safari</b> 5+</li>
<li>
<b>Firefox</b> 22+ (must have AAC codecs installed - so not
WinXP/Win7 by default until Firefox 51+!)
</li>
</ul>
<p>
<i
>Note: Older browsers (IE 5.5-8) may work if you have Adobe
Flash Player installed.</i
>
</p>
<p>
<i
>Note 2: On many older browsers you will need to visit the
site <b>using HTTP and NOT HTTPS</b> due to outdated SSL.</i
>
</p>
</div>
<br />
<table width="100%" border="1" cellpadding="5" cellspacing="0">
<tr bgcolor="#cccccc">
<th>Browser</th>
<th>Min version</th>
<th>Status</th>
</tr>
<tr>
<td>Internet Explorer</td>
<td>9</td>
<td>
<font color="green"><b>Tested (AAC)</b></font>
</td>
</tr>
<tr>
<td rowspan="2">Google Chrome</td>
<td>15</td>
<td>
<font color="green"><b>Tested (AAC)</b></font>
</td>
</tr>
<tr>
<td>56</td>
<td>
<font color="green"><b>Tested (FLAC)</b></font>
</td>
</tr>
<tr>
<td rowspan="2">Safari</td>
<td>5</td>
<td>
<font color="green"><b>Tested on 5.1 (AAC)</b></font>
</td>
</tr>
<tr>
<td>13</td>
<td>
<font color="green"><b>Tested on 13.1 (FLAC)</b></font>
</td>
</tr>
<tr>
<td rowspan="2">Firefox</td>
<td>22</td>
<td>
<font color="orange"
><b>Partial (AAC requires codecs)</b></font
>
</td>
</tr>
<tr>
<td>52</td>
<td>
<font color="green"><b>Tested (FLAC)</b></font>
</td>
</tr>
</table>
<br />
<p align="center">
<a href="html5.html"><b>&lt;&lt; Return to Player</b></a>
</p>
</font>
</div>
</td>
</tr>
</table>
</body>
</html>

20
legacy/flashplugin.js Normal file

File diff suppressed because one or more lines are too long

113
legacy/html5.html Normal file
View file

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html>
<head>
<title>Monochrome Legacy (HTML5)</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="stylesheet" type="text/css" href="legacy.css" />
<script type="text/javascript" src="jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="html5.js"></script>
</head>
<body>
<table
width="100%"
height="100%"
border="0"
cellpadding="0"
cellspacing="0"
>
<!-- Header -->
<tr height="80">
<td colspan="2" bgcolor="#000000" align="center">
<font color="#FFFFFF" size="6" face="Comic Sans MS, Arial"
><b>Monochrome Music</b></font
><br />
<font color="#cccccc" size="2">music</font>
</td>
</tr>
<!-- Marquee -->
<tr height="20">
<td colspan="2" class="marquee-container">
<marquee scrollamount="5" scrolldelay="100"
>Welcome to Monochrome Music Legacy Edition check out the latest
hits new songs added daily under construction sign
guestbook</marquee
>
</td>
</tr>
<!-- Main Body -->
<tr valign="top">
<!-- Sidebar -->
<td width="150" bgcolor="#dddddd" class="beveled-box">
<br />
<center><b>Menu</b></center>
<hr />
<ul style="list-style-type: square; padding-left: 20px">
<li class="sidebar-link"><a href="#" id="btn-home">Home</a></li>
<li class="sidebar-link">
<a href="compatibility.html">Compatibility</a>
</li>
<!-- Search is now inline below -->
<li class="sidebar-link"><a href="/">Go to Modern Site</a></li>
</ul>
<br />
<!-- Search Form moved to main content -->
<br />
<center>
<img
src="getie3.gif"
alt="IE Logo"
width="88"
height="31"
/><br /><br />
<font size="1">Free and open software</font><br /><br />
<font size="1">made by binimum</font>
</center>
</td>
<!-- Content -->
<td bgcolor="#ffffff">
<div style="padding: 10px">
<!-- Now Playing / Player Control -->
<div class="controls" style="margin-bottom: 20px">
<font face="Verdana" size="2">
<span id="now-playing-info">Status: Ready to play.</span>
</font>
<br /><br />
<audio
id="audio-player"
controls
preload="none"
style="width: 300px; height: 45px"
>
Your browser does not support the audio element.
</audio>
</div>
<!-- Moved Search Form -->
<div
class="beveled-box"
style="margin-bottom: 20px; text-align: center"
>
<b>Search Music: </b>
<form
id="search-form"
onsubmit="return false;"
style="display: inline"
>
<input type="text" id="search-input" size="40" />
<input type="submit" id="btn-search" value="Search" />
</form>
</div>
<div id="main-content">
<center><h3>Loading...</h3></center>
</div>
</div>
</td>
</tr>
</table>
</body>
</html>

571
legacy/html5.js Normal file
View file

@ -0,0 +1,571 @@
// jQuery 1.12.4 Legacy Support
$(document).ready(function () {
// CORS Support for IE8/9 (XDomainRequest)
// Required because IE8/9 do not support CORS via standard XMLHttpRequest
// Note: $.ajaxTransport was added in jQuery 1.5. If using 1.2.6, this will be skipped.
if (window.XDomainRequest && $.ajaxTransport) {
$.ajaxTransport(function(s) {
if (s.crossDomain && s.async) {
if (s.timeout) {
s.xdrTimeout = s.timeout;
delete s.timeout;
}
var xdr;
return {
send: function(_, complete) {
function callback(status, statusText, responses, responseHeaders) {
xdr.onload = xdr.onerror = xdr.ontimeout = $.noop;
xdr = undefined;
complete(status, statusText, responses, responseHeaders);
}
xdr = new XDomainRequest();
try {
xdr.open(s.type, s.url);
xdr.onload = function() {
callback(200, "OK", { text: xdr.responseText }, "Content-Type: " + xdr.contentType);
};
xdr.onerror = function() {
callback(404, "Not Found");
};
xdr.ontimeout = function() {
callback(0, "timeout");
};
xdr.timeout = s.xdrTimeout || Number.MAX_VALUE;
xdr.send((s.hasContent && s.data) || null);
} catch(e) {
// Protocol Mismatch generally throws here in IE
callback(500, "Protocol/Access Error", { text: e.message });
}
},
abort: function() {
if (xdr) {
xdr.onerror = $.noop;
xdr.abort();
}
}
};
}
});
}
// REMOVED: $.support.cors = true;
// We MUST NOT set this for IE9. If we do, jQuery tries to use standard XHR for cross-domain,
// which fails ("Access is denied"). Leaving it false forces jQuery to use our custom XDR transport.
var apiInstances = [];
var currentInstanceIndex = 0;
var isHttpFallback = false;
var FALLBACK_INSTANCES = [
"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");
// HTML5 Version - No Flash/SoundJS (Cleared)
// Initial Load
// Run HTTPS probe first
checkHttpsSupport(function() {
fetchInstances(function () {
loadRecentTracks();
});
});
function checkHttpsSupport(callback) {
if (window.location.protocol === "http:") {
// If we are already on HTTP, we might want to check if HTTPS is possible?
// Or just assume if user loaded via HTTP, we might need HTTP for APIs too.
// But user might be on HTTP because they typed it, but API supports HTTPS.
// Let's Probe.
// However, if we are on HTTPS, mixed content blocking might prevent HTTP fallback checking?
// Actually, we want to know if Client supports HTTPS.
}
// Probe a known HTTPS endpoint (one of our instances)
// Use a known stable one, or just try the first instance later?
// Better to fail fast now.
var probeUrl = "https://tidal.kinoplus.online/";
console.log("Probing HTTPS support...");
var probeSuccess = false;
var probeFinished = false;
function finishProbe(success) {
if (probeFinished) return;
probeFinished = true;
if (success) {
console.log("HTTPS Probe Successful.");
isHttpFallback = false;
} else {
console.log("HTTPS Probe Failed. Defaulting to HTTP fallback.");
isHttpFallback = true;
}
callback();
}
var timeout = setTimeout(function() {
finishProbe(false);
}, 5000); // 3s timeout for HTTPS check
try {
$.ajax({
url: probeUrl,
dataType: "json",
timeout: 2500, // jQuery timeout
success: function() {
finishProbe(true);
},
error: function() {
finishProbe(false); // XHR Error or Timeout
}
});
} catch(e) {
finishProbe(false);
}
}
// 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
// Global Stop function to prevent overlap
function stopAllAudio() {
// 1. Stop SoundJS (Removed in HTML5 ver)
// 2. Stop DOM Player
if (audioPlayer) {
try {
audioPlayer.pause();
audioPlayer.currentTime = 0;
// Don't clear src immediately as it might flash, just pause.
} catch(e) { }
}
}
window.playTrack = function (id, attemptFallback) {
var quality = attemptFallback ? "HIGH" : "LOSSLESS";
apiRequest(
"/track/?id=" + id + "&quality=" + quality,
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];
// Unified Playback Strategy:
// 1. Stop Everything
stopAllAudio();
// 2. Try Native DOM Player (Visible Interface)
// If this works, user gets controls. If it fails (IE), we fallback to SoundJS.
playNativeFirst(streamUrl, id, quality);
}
} catch (e) {
console.log("Manifest error: " + e);
}
} else {
handleError("Invalid track data");
}
},
function (err) {
handleError(err);
}
);
function playNativeFirst(url, id, quality, isRetry) {
var domPlayer = $("#audio-player")[0];
var playbackTimer = null;
// Quality Label
var qLabel = (quality === "LOSSLESS") ? " (FLAC)" : " (AAC)";
if (attemptFallback) qLabel = " (AAC)";
// Basic check for audio support
if (domPlayer && typeof domPlayer.play === 'function') {
// Explicitly check for Codec support
if (quality === "LOSSLESS") {
// FLAC check
var canPlay = "";
try {
canPlay = domPlayer.canPlayType("audio/flac");
} catch(e) {}
if (canPlay === "" || canPlay === "no") {
console.log("Browser reports no FLAC support. Fallback to AAC.");
if (!attemptFallback) {
window.playTrack(id, true);
return;
}
}
}
updateStatus("Starting Native Playback" + qLabel + ((isRetry) ? " (HTTP)..." : "..."));
// Helper to handle retry vs legacy fallback
function triggerRetryOrLegacy(msg) {
if (playbackTimer) {
clearTimeout(playbackTimer);
playbackTimer = null;
}
// Try HTTP fallback if SSL failed
if (!isRetry && url.indexOf("https://") === 0) {
console.log("HTTPS failed/timeout (" + msg + "), retrying with HTTP...");
var httpUrl = "http://" + url.substring(8);
playNativeFirst(httpUrl, id, quality, true);
return;
}
// If native fails on HTML5 site, we have no Flash fallback.
handleError("Playback Failed - No Flash Fallback Available (" + msg + ")");
}
// Set error handler for THIS attempt
domPlayer.onerror = function() {
var errCode = domPlayer.error ? domPlayer.error.code : 0;
console.log("Native Error Code: " + errCode);
triggerRetryOrLegacy("onerror: " + errCode);
};
try {
domPlayer.src = url;
domPlayer.preload = "auto";
domPlayer.load(); // Force reload/buffering
var playPromise = domPlayer.play();
// Set a safety timeout for "forever pending" requests (common in Chrome 15 with SSL issues)
playbackTimer = setTimeout(function() {
console.log("Playback timeout - stalling detected.");
triggerRetryOrLegacy("timeout");
}, 5000); // 5 seconds to start playing
// If playback starts, clear timeout
domPlayer.onplaying = function() {
if (playbackTimer) {
clearTimeout(playbackTimer);
playbackTimer = null;
}
updateStatus("Now Playing..." + qLabel);
};
if (playPromise !== undefined) {
playPromise
.then(function() {
// Promise resolved doesn't always mean playing started (buffering)
// But usually it means intent is accepted.
// We keep timer running until 'onplaying' checks in?
// Actually promise resolve just means "accepted".
// Chrome 15 won't have promise.
// Modern browsers: resolve -> wait for data -> playing.
// If data hangs, promise resolved but playing never fires.
// So we keep timer.
})
.catch(function(e) {
console.log("Native Play Promise Rejected: " + e.name);
triggerRetryOrLegacy("promise rejection: " + e.name);
});
} else {
// Legacy browser (no promise)
// Wait for onplaying or timeout
}
} catch (e) {
console.log("Native Exception: " + e.message);
triggerRetryOrLegacy("exception: " + e.message);
}
} else {
// No native audio support (IE < 9)
handleError("No Native Audio Support");
}
}
function updateStatus(msg) {
if (currentTrackInfo.length) {
currentTrackInfo.html(msg);
}
}
function handleError(msg) {
if (!attemptFallback) {
window.playTrack(id, true);
} else {
// alert("Playback Error: " + (msg || "Unknown"));
updateStatus("Error: " + msg);
}
}
};
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) {
apiInstances = shuffleArray(instances);
// Clean URLs
for (var i = 0; i < apiInstances.length; i++) {
if (apiInstances[i].charAt(apiInstances[i].length - 1) === "/") {
apiInstances[i] = apiInstances[i].substring(0, apiInstances[i].length - 1);
}
}
currentInstanceIndex = 0;
callback();
} else {
useFallback(callback);
}
},
error: function () {
useFallback(callback);
}
});
}
function useFallback(callback) {
apiInstances = shuffleArray(FALLBACK_INSTANCES.slice()); // Copy and shuffle
currentInstanceIndex = 0;
callback();
}
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function performSearch(query) {
var resultsDiv = $("#search-results");
if (resultsDiv.length === 0) {
setContent('<div id="search-results">Searching...</div>');
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 =
'<table width="100%" border="1" cellpadding="2" cellspacing="0">';
html +=
'<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>';
$.each(tracks, function (i, t) {
var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title);
html += '<tr class="track-row">';
html +=
'<td align="center"><button onclick="window.playTrack(\'' +
t.id +
"')\">Play</button></td>";
html += "<td>" + safeTitle + "</td>";
html += "<td>" + safeArtist + "</td>";
html += "<td>" + safeAlbum + "</td>";
html += "</tr>";
});
html += "</table>";
resultsDiv.html(html);
},
function (err) {
resultsDiv.html("Error: " + err);
}
);
}
function renderTracks(tracks, title) {
var html = "<h3>" + title + "</h3>";
html += '<table width="100%" border="1" cellpadding="2" cellspacing="0">';
html +=
'<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>';
$.each(tracks, function (i, t) {
var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title);
html += '<tr class="track-row">';
html +=
'<td align="center"><button onclick="window.playTrack(\'' +
t.id +
"')\">Play</button></td>";
html += "<td>" + safeTitle + "</td>";
html += "<td>" + safeArtist + "</td>";
html += "<td>" + safeAlbum + "</td>";
html += "</tr>";
});
html += "</table>";
setContent(html);
}
function setContent(html) {
$("#main-content").html(html);
}
function apiRequest(endpoint, success, error) {
if (apiInstances.length === 0) {
error("No API instances available.");
return;
}
var currentBaseUrl = apiInstances[currentInstanceIndex];
var finalUrl = currentBaseUrl;
// Check for HTTP fallback
if (isHttpFallback) {
// If original was https, downgrade it
if (finalUrl.indexOf("https://") === 0) {
finalUrl = "http://" + finalUrl.substring(8);
}
}
try {
$.ajax({
url: finalUrl + endpoint,
method: "GET",
dataType: "json",
success: function (data) {
// Logic: If successful with HTTP fallback, maybe we should stick to it?
// For now, we just proceed.
success(data);
},
error: function (xhr, status, errorThrown) {
handleApiError(endpoint, success, error, status + " (" + errorThrown + ")");
}
});
} catch (e) {
handleApiError(endpoint, success, error, "Exception: " + e.message);
}
}
function handleApiError(endpoint, success, error, errorMsg) {
// 1. Try HTTP fallback for current instance if allowed
if (!isHttpFallback && window.location.protocol !== "https:") {
// Only if current instance is HTTPS
if (apiInstances[currentInstanceIndex].indexOf("https://") === 0) {
isHttpFallback = true;
apiRequest(endpoint, success, error);
return;
}
}
// 2. Move to next instance
isHttpFallback = false; // Reset for next instance
currentInstanceIndex++;
if (currentInstanceIndex < apiInstances.length) {
// Retry with next instance
apiRequest(endpoint, success, error);
} else {
// All instances failed
// We could try to reset index and wait, but for now we fail.
// Or maybe we should loop back to 0? But infinite loops are bad.
// Let's just fail after one full rotation.
currentInstanceIndex = 0; // Reset for next user interaction attempt
error("All API instances failed. Last error: " + errorMsg);
}
}
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) {
if (!text) return "";
return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
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;
}
});

View file

@ -1,81 +1,133 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<head>
<title>Monochrome Legacy</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="legacy.css">
<script>
// HTML5 Redirection Logic
// If browser supports Canvas and Audio, redirect to the HTML5 version.
// This targets Chrome 10+, Safari 3+, IE9+, Firefox 3.5+
(function () {
var hasCanvas = !!document.createElement("canvas").getContext;
var hasAudio = !!(window.Audio && new window.Audio().canPlayType);
// Prevent redirect loop if already there (check filename not needed if files differ, but safe)
if (hasCanvas && hasAudio) {
// Check if user manually opted out? (Optional, skipping for now)
if (window.location.href.indexOf("html5.html") === -1) {
window.location.href = "html5.html";
}
}
})();
</script>
<link rel="stylesheet" type="text/css" href="legacy.css" />
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="soundjs-0.5.2.min.js"></script>
<script type="text/javascript" src="flashplugin.js"></script>
<script type="text/javascript" src="legacy.js"></script>
</head>
<body>
<table width="100%" height="100%" border="0" cellpadding="0" cellspacing="0">
<!-- Header -->
<tr height="80">
</head>
<body>
<table
width="100%"
height="100%"
border="0"
cellpadding="0"
cellspacing="0"
>
<!-- Header -->
<tr height="80">
<td colspan="2" bgcolor="#000000" align="center">
<font color="#FFFFFF" size="6" face="Comic Sans MS, Arial"><b>Monochrome Music</b></font><br>
<font color="#cccccc" size="2">music</font>
<font color="#FFFFFF" size="6" face="Comic Sans MS, Arial"
><b>Monochrome Music</b></font
><br />
<font color="#cccccc" size="2">music</font>
</td>
</tr>
<!-- Marquee -->
<tr height="20">
<td colspan="2" class="marquee-container">
<marquee scrollamount="5" scrolldelay="100">Welcome to Monochrome Music Legacy Edition check out the latest hits new songs added daily under construction sign guestbook</marquee>
</td>
</tr>
</tr>
<!-- Main Body -->
<tr valign="top">
<!-- Marquee -->
<tr height="20">
<td colspan="2" class="marquee-container">
<marquee scrollamount="5" scrolldelay="100"
>Welcome to Monochrome Music Legacy Edition check out the latest
hits new songs added daily under construction sign
guestbook</marquee
>
</td>
</tr>
<!-- Main Body -->
<tr valign="top">
<!-- Sidebar -->
<td width="150" bgcolor="#dddddd" class="beveled-box">
<br>
<center><b>Menu</b></center>
<hr>
<ul style="list-style-type: square; padding-left: 20px;">
<li class="sidebar-link"><a href="#" id="btn-home">Home</a></li>
<!-- Search is now inline below -->
<li class="sidebar-link"><a href="/">Go to Modern Site</a></li>
</ul>
<br>
<!-- Search Form moved to main content -->
<br>
<center>
<img src="getie3.gif" alt="IE Logo" width="88" height="31"><br><br>
<img src="getnet3.gif" alt="Netscape Logo" width="88" height="31"><br><br>
<font size="1">Free and open software</font>
</center>
<br />
<center><b>Menu</b></center>
<hr />
<ul style="list-style-type: square; padding-left: 20px">
<li class="sidebar-link"><a href="#" id="btn-home">Home</a></li>
<li class="sidebar-link">
<a href="compatibility.html">Compatibility</a>
</li>
<!-- Search is now inline below -->
<li class="sidebar-link"><a href="/">Go to Modern Site</a></li>
</ul>
<br />
<!-- Search Form moved to main content -->
<br />
<center>
<img
src="getie3.gif"
alt="IE Logo"
width="88"
height="31"
/><br /><br />
<font size="1">Free and open software</font><br /><br />
<font size="1">made by binimum</font><br /><br />
</center>
</td>
<!-- Content -->
<td bgcolor="#ffffff">
<div style="padding: 10px;">
<!-- Now Playing / Player Control -->
<div class="controls" style="margin-bottom: 20px;">
<font face="Verdana" size="2">
<span id="now-playing-info">Status: Ready to play.</span>
</font>
<br><br>
<audio id="audio-player" controls preload="none" style="width: 300px; height: 30px;">
Your browser does not support the audio element.
</audio>
</div>
<!-- Moved Search Form -->
<div class="beveled-box" style="margin-bottom: 20px; text-align: center;">
<b>Search Music: </b>
<form id="search-form" onsubmit="return false;" style="display: inline;">
<input type="text" id="search-input" size="40">
<input type="submit" id="btn-search" value="Search">
</form>
</div>
<div id="main-content">
<center><h3>Loading...</h3></center>
</div>
<div style="padding: 10px">
<!-- Now Playing / Player Control -->
<div class="controls" style="margin-bottom: 20px">
<font face="Verdana" size="2">
<span id="now-playing-info">Status: Ready to play.</span>
</font>
<br /><br />
<audio
id="audio-player"
controls
preload="none"
style="width: 300px; height: 45px"
>
Your browser does not support the audio element.
</audio>
</div>
</td>
</tr>
</table>
</body>
<!-- Moved Search Form -->
<div
class="beveled-box"
style="margin-bottom: 20px; text-align: center"
>
<b>Search Music: </b>
<form
id="search-form"
onsubmit="return false;"
style="display: inline"
>
<input type="text" id="search-input" size="40" />
<input type="submit" id="btn-search" value="Search" />
</form>
</div>
<div id="main-content">
<center><h3>Loading...</h3></center>
</div>
</div>
</td>
</tr>
</table>
</body>
</html>

4
legacy/jquery-1.6.4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

32
legacy/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,9 +1,59 @@
// strictly ES5/Legacy JS
(function () {
var currentApiUrl = ""; // Will be set from instances.json
// jQuery 1.12.4 Legacy Support
$(document).ready(function () {
// CORS Support for IE8/9 (XDomainRequest)
// Required because IE8/9 do not support CORS via standard XMLHttpRequest
if (window.XDomainRequest) {
$.ajaxTransport(function(s) {
if (s.crossDomain && s.async) {
if (s.timeout) {
s.xdrTimeout = s.timeout;
delete s.timeout;
}
var xdr;
return {
send: function(_, complete) {
function callback(status, statusText, responses, responseHeaders) {
xdr.onload = xdr.onerror = xdr.ontimeout = $.noop;
xdr = undefined;
complete(status, statusText, responses, responseHeaders);
}
xdr = new XDomainRequest();
try {
xdr.open(s.type, s.url);
xdr.onload = function() {
callback(200, "OK", { text: xdr.responseText }, "Content-Type: " + xdr.contentType);
};
xdr.onerror = function() {
callback(404, "Not Found");
};
xdr.ontimeout = function() {
callback(0, "timeout");
};
xdr.timeout = s.xdrTimeout || Number.MAX_VALUE;
xdr.send((s.hasContent && s.data) || null);
} catch(e) {
// Protocol Mismatch generally throws here in IE
callback(500, "Protocol/Access Error", { text: e.message });
}
},
abort: function() {
if (xdr) {
xdr.onerror = $.noop;
xdr.abort();
}
}
};
}
});
}
// REMOVED: $.support.cors = true;
// We MUST NOT set this for IE9. If we do, jQuery tries to use standard XHR for cross-domain,
// which fails ("Access is denied"). Leaving it false forces jQuery to use our custom XDR transport.
var apiInstances = [];
var currentInstanceIndex = 0;
var isHttpFallback = false;
var FALLBACK_INSTANCES = [
"https://triton.squid.wtf",
"https://wolf.qqdl.site",
"https://maus.qqdl.site",
"https://vogel.qqdl.site",
@ -12,34 +62,321 @@
"https://tidal.kinoplus.online",
"https://tidal-api.binimum.org",
];
var audioPlayer;
var currentTrackInfo;
var audioPlayer = $("#audio-player")[0];
var currentTrackInfo = $("#now-playing-info");
window.onload = function () {
audioPlayer = document.getElementById("audio-player");
currentTrackInfo = document.getElementById("now-playing-info");
fetchInstances(function (url) {
currentApiUrl = url;
loadRecentTracks();
});
// Simple event delegation if we wanted, but explicit bindings are safer for old browsers
var btnHome = document.getElementById("btn-home");
if (btnHome) {
btnHome.onclick = function () {
// Initialize SoundJS
// Note: Class is FlashPlugin in 0.5.2, but SWF is FlashAudioPlugin.swf
createjs.FlashPlugin.swfPath = "./";
// Custom Architecture:
// We handle HTML5 Audio manually via playNativeFirst() for full control (UI, timeouts, hacks).
// SoundJS is reserved STRICTLY for Flash fallback on legacy browsers (IE, old Chrome).
// Therefore, we ONLY register the FlashPlugin.
createjs.Sound.registerPlugins([createjs.FlashPlugin]);
// Initial Load
// Run HTTPS probe first
checkHttpsSupport(function() {
fetchInstances(function () {
loadRecentTracks();
return false;
};
}
// Search button removed, using persistent form now
});
});
var searchForm = document.getElementById("search-form");
searchForm.onsubmit = function () {
var query = document.getElementById("search-input").value;
performSearch(query);
return false;
};
function checkHttpsSupport(callback) {
if (window.location.protocol === "http:") {
// If we are already on HTTP, we might want to check if HTTPS is possible?
// Or just assume if user loaded via HTTP, we might need HTTP for APIs too.
// But user might be on HTTP because they typed it, but API supports HTTPS.
// Let's Probe.
// However, if we are on HTTPS, mixed content blocking might prevent HTTP fallback checking?
// Actually, we want to know if Client supports HTTPS.
}
// Probe a known HTTPS endpoint (one of our instances)
// Use a known stable one, or just try the first instance later?
// Better to fail fast now.
var probeUrl = "https://tidal.kinoplus.online/";
console.log("Probing HTTPS support...");
var probeSuccess = false;
var probeFinished = false;
function finishProbe(success) {
if (probeFinished) return;
probeFinished = true;
if (success) {
console.log("HTTPS Probe Successful.");
isHttpFallback = false;
} else {
console.log("HTTPS Probe Failed. Defaulting to HTTP fallback.");
isHttpFallback = true;
}
callback();
}
var timeout = setTimeout(function() {
finishProbe(false);
}, 5000); // 3s timeout for HTTPS check
try {
$.ajax({
url: probeUrl,
dataType: "json",
timeout: 2500, // jQuery timeout
success: function() {
finishProbe(true);
},
error: function() {
finishProbe(false); // XHR Error or Timeout
}
});
} catch(e) {
finishProbe(false);
}
}
// 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
// Global Stop function to prevent overlap
function stopAllAudio() {
// 1. Stop SoundJS
if (typeof createjs !== "undefined" && createjs.Sound) {
createjs.Sound.stop();
}
// 2. Stop DOM Player
if (audioPlayer) {
try {
audioPlayer.pause();
audioPlayer.currentTime = 0;
// Don't clear src immediately as it might flash, just pause.
} catch(e) { }
}
}
window.playTrack = function (id, attemptFallback) {
var quality = attemptFallback ? "HIGH" : "LOSSLESS";
apiRequest(
"/track/?id=" + id + "&quality=" + quality,
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];
// Unified Playback Strategy:
// 1. Stop Everything
stopAllAudio();
// 2. Try Native DOM Player (Visible Interface)
// If this works, user gets controls. If it fails (IE), we fallback to SoundJS.
playNativeFirst(streamUrl, id, quality);
}
} catch (e) {
console.log("Manifest error: " + e);
}
} else {
handleError("Invalid track data");
}
},
function (err) {
handleError(err);
}
);
function playNativeFirst(url, id, quality, isRetry) {
var domPlayer = $("#audio-player")[0];
var playbackTimer = null;
// Quality Label
var qLabel = (quality === "LOSSLESS") ? " (FLAC)" : " (AAC)";
if (attemptFallback) qLabel = " (AAC)";
// Basic check for audio support
if (domPlayer && typeof domPlayer.play === 'function') {
// Explicitly check for Codec support
if (quality === "LOSSLESS") {
// FLAC check
var canPlay = "";
try {
canPlay = domPlayer.canPlayType("audio/flac");
} catch(e) {}
if (canPlay === "" || canPlay === "no") {
console.log("Browser reports no FLAC support. Fallback to AAC.");
if (!attemptFallback) {
window.playTrack(id, true);
return;
}
}
}
updateStatus("Starting Native Playback" + qLabel + ((isRetry) ? " (HTTP)..." : "..."));
// Helper to handle retry vs legacy fallback
function triggerRetryOrLegacy(msg) {
if (playbackTimer) {
clearTimeout(playbackTimer);
playbackTimer = null;
}
// Try HTTP fallback if SSL failed
if (!isRetry && url.indexOf("https://") === 0) {
console.log("HTTPS failed/timeout (" + msg + "), retrying with HTTP...");
var httpUrl = "http://" + url.substring(8);
playNativeFirst(httpUrl, id, quality, true);
return;
}
playLegacySoundJS(streamUrl, id, quality);
}
// Set error handler for THIS attempt
domPlayer.onerror = function() {
var errCode = domPlayer.error ? domPlayer.error.code : 0;
console.log("Native Error Code: " + errCode);
triggerRetryOrLegacy("onerror: " + errCode);
};
try {
domPlayer.src = url;
domPlayer.preload = "auto";
domPlayer.load(); // Force reload/buffering
var playPromise = domPlayer.play();
// Set a safety timeout for "forever pending" requests (common in Chrome 15 with SSL issues)
playbackTimer = setTimeout(function() {
console.log("Playback timeout - stalling detected.");
triggerRetryOrLegacy("timeout");
}, 5000); // 5 seconds to start playing
// If playback starts, clear timeout
domPlayer.onplaying = function() {
if (playbackTimer) {
clearTimeout(playbackTimer);
playbackTimer = null;
}
updateStatus("Now Playing..." + qLabel);
};
if (playPromise !== undefined) {
playPromise
.then(function() {
// Promise resolved doesn't always mean playing started (buffering)
// But usually it means intent is accepted.
// We keep timer running until 'onplaying' checks in?
// Actually promise resolve just means "accepted".
// Chrome 15 won't have promise.
// Modern browsers: resolve -> wait for data -> playing.
// If data hangs, promise resolved but playing never fires.
// So we keep timer.
})
.catch(function(e) {
console.log("Native Play Promise Rejected: " + e.name);
triggerRetryOrLegacy("promise rejection: " + e.name);
});
} else {
// Legacy browser (no promise)
// Wait for onplaying or timeout
}
} catch (e) {
console.log("Native Exception: " + e.message);
triggerRetryOrLegacy("exception: " + e.message);
}
} else {
// No native audio support (IE < 9)
playLegacySoundJS(streamUrl, id, quality);
}
}
function playLegacySoundJS(url, id, quality, isRetry) {
updateStatus("Activating Legacy Player (Flash)" + ((isRetry) ? " (HTTP)..." : "..."));
// SoundJS Logic
var soundJsUrl = url;
// Hint extension for SoundJS
if (soundJsUrl.indexOf(".mp3") === -1 && soundJsUrl.indexOf(".m4a") === -1) {
soundJsUrl += "#.m4a"; // Default to AAC hint
}
// If FLAC and we are here, SoundJS will likely fail, but we'll try or alert.
if (quality === "LOSSLESS") {
// SoundJS can't do FLAC. And if native failed, we are out of luck for FLAC.
// Try falling back to AAC quality for the whole track?
if (!attemptFallback) {
console.log("FLAC failed native, switching to HIGH quality fallback...");
window.playTrack(id, true);
return;
}
}
var soundId = "track_" + id + "_" + quality + (isRetry ? "_http" : "");
createjs.Sound.removeAllEventListeners("fileload");
var playSound = function() {
var instance = createjs.Sound.play(soundId);
if (!instance || instance.playState === createjs.Sound.PLAY_FAILED) {
handleLegacyError("Legacy Playback Failed");
} else {
updateStatus("Now Playing via Flash/Legacy...");
}
};
createjs.Sound.addEventListener("fileload", function(event) {
if (event.id === soundId) {
playSound();
}
});
try {
createjs.Sound.registerSound(soundJsUrl, soundId);
} catch(e) {
handleLegacyError("Legacy Setup Failed: " + e.message);
}
function handleLegacyError(msg) {
if (!isRetry && url.indexOf("https://") === 0) {
console.log("Legacy HTTPS failed ("+msg+"), retrying HTTP...");
var httpUrl = "http://" + url.substring(8);
playLegacySoundJS(httpUrl, id, quality, true);
return;
}
handleError(msg);
}
}
function updateStatus(msg) {
if (currentTrackInfo.length) {
currentTrackInfo.html(msg);
}
}
function handleError(msg) {
if (!attemptFallback) {
window.playTrack(id, true);
} else {
// alert("Playback Error: " + (msg || "Unknown"));
updateStatus("Error: " + msg);
}
}
};
function loadRecentTracks() {
@ -48,9 +385,9 @@
"/search/?s=a&limit=20",
function (data) {
if (data && data.data && data.data.items) {
renderTracks(data.data.items, "Recently Added / Popular");
renderTracks(data.data.items, "Recently Added / Popular");
} else {
setContent("No recent tracks found.");
setContent("No recent tracks found.");
}
},
function (err) {
@ -60,51 +397,54 @@
}
function fetchInstances(callback) {
var xhr = createXHR();
xhr.open("GET", "instances.json", true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
try {
var instances = JSON.parse(xhr.responseText);
if (instances && instances.length > 0) {
var randomUrl =
instances[Math.floor(Math.random() * instances.length)];
// Remove trailing slash if present
if (randomUrl.charAt(randomUrl.length - 1) === "/") {
randomUrl = randomUrl.substring(0, randomUrl.length - 1);
// using $.ajax directly to handle errors robustly
$.ajax({
url: "/instances.json",
dataType: "json",
success: function (instances) {
if (instances && instances.length > 0) {
apiInstances = shuffleArray(instances);
// Clean URLs
for (var i = 0; i < apiInstances.length; i++) {
if (apiInstances[i].charAt(apiInstances[i].length - 1) === "/") {
apiInstances[i] = apiInstances[i].substring(0, apiInstances[i].length - 1);
}
callback(randomUrl);
} else {
useFallback(callback);
}
} catch (e) {
useFallback(callback);
}
currentInstanceIndex = 0;
callback();
} else {
useFallback(callback);
}
},
error: function () {
useFallback(callback);
}
};
xhr.onerror = function () {
useFallback(callback);
};
xhr.send();
});
}
function useFallback(callback) {
var randomUrl =
FALLBACK_INSTANCES[Math.floor(Math.random() * FALLBACK_INSTANCES.length)];
callback(randomUrl);
apiInstances = shuffleArray(FALLBACK_INSTANCES.slice()); // Copy and shuffle
currentInstanceIndex = 0;
callback();
}
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function performSearch(query) {
var resultsDiv = document.getElementById("search-results");
if (!resultsDiv) {
var resultsDiv = $("#search-results");
if (resultsDiv.length === 0) {
setContent('<div id="search-results">Searching...</div>');
resultsDiv = document.getElementById("search-results");
resultsDiv = $("#search-results");
} else {
resultsDiv.innerHTML = "Searching...";
resultsDiv.html("Searching...");
}
apiRequest(
@ -112,17 +452,16 @@
function (data) {
var tracks = (data && data.data && data.data.items) ? data.data.items : [];
if (tracks.length === 0) {
resultsDiv.innerHTML = "No results found.";
resultsDiv.html("No results found.");
return;
}
// Manually render table string to avoid complex DOM manipulation
var html =
'<table width="100%" border="1" cellpadding="2" cellspacing="0">';
html +=
'<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>';
for (var i = 0; i < tracks.length; i++) {
var t = tracks[i];
$.each(tracks, function (i, t) {
var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title);
@ -136,13 +475,13 @@
html += "<td>" + safeArtist + "</td>";
html += "<td>" + safeAlbum + "</td>";
html += "</tr>";
}
});
html += "</table>";
resultsDiv.innerHTML = html;
resultsDiv.html(html);
},
function (err) {
resultsDiv.innerHTML = "Error: " + err;
resultsDiv.html("Error: " + err);
}
);
}
@ -153,8 +492,7 @@
html +=
'<tr bgcolor="#bbbbbb"><th>Play</th><th>Title</th><th>Artist</th><th>Album</th></tr>';
for (var i = 0; i < tracks.length; i++) {
var t = tracks[i];
$.each(tracks, function (i, t) {
var safeTitle = escapeHtml(t.title);
var safeArtist = escapeHtml(t.artist.name);
var safeAlbum = escapeHtml(t.album.title);
@ -168,99 +506,102 @@
html += "<td>" + safeArtist + "</td>";
html += "<td>" + safeAlbum + "</td>";
html += "</tr>";
}
});
html += "</table>";
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) {
var content = document.getElementById("main-content");
content.innerHTML = html;
$("#main-content").html(html);
}
function apiRequest(endpoint, success, error) {
var xhr = createXHR();
// Use fallback HTTP if needed logic
var finalUrl = currentApiUrl;
if (isHttpFallback && finalUrl.indexOf("https://") === 0) {
finalUrl = "http://" + finalUrl.substring(8);
if (apiInstances.length === 0) {
error("No API instances available.");
return;
}
var currentBaseUrl = apiInstances[currentInstanceIndex];
var finalUrl = currentBaseUrl;
xhr.open("GET", finalUrl + endpoint, true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
try {
var data = JSON.parse(xhr.responseText);
success(data);
} catch (e) {
error("JSON Parse Error");
}
} else {
// If failed and not yet fallback, try fallback
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");
// Check for HTTP fallback
if (isHttpFallback) {
// If original was https, downgrade it
if (finalUrl.indexOf("https://") === 0) {
finalUrl = "http://" + finalUrl.substring(8);
}
};
xhr.send();
}
try {
$.ajax({
url: finalUrl + endpoint,
method: "GET",
dataType: "json",
success: function (data) {
// Logic: If successful with HTTP fallback, maybe we should stick to it?
// For now, we just proceed.
success(data);
},
error: function (xhr, status, errorThrown) {
handleApiError(endpoint, success, error, status + " (" + errorThrown + ")");
}
});
} catch (e) {
handleApiError(endpoint, success, error, "Exception: " + e.message);
}
}
function handleApiError(endpoint, success, error, errorMsg) {
// 1. Try HTTP fallback for current instance if allowed
if (!isHttpFallback && window.location.protocol !== "https:") {
// Only if current instance is HTTPS
if (apiInstances[currentInstanceIndex].indexOf("https://") === 0) {
isHttpFallback = true;
apiRequest(endpoint, success, error);
return;
}
}
// 2. Move to next instance
isHttpFallback = false; // Reset for next instance
currentInstanceIndex++;
if (currentInstanceIndex < apiInstances.length) {
// Retry with next instance
apiRequest(endpoint, success, error);
} else {
// All instances failed
// We could try to reset index and wait, but for now we fail.
// Or maybe we should loop back to 0? But infinite loops are bad.
// Let's just fail after one full rotation.
currentInstanceIndex = 0; // Reset for next user interaction attempt
error("All API instances failed. Last error: " + errorMsg);
}
}
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) {
if (!text) return "";
return text
@ -271,70 +612,24 @@
.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) {
if (window.atob) {
return window.atob(str);
}
// Polyfill for IE
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;
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;
}
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;
}
}
})();
});

18
legacy/soundjs-0.5.2.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
legacy/swfobject.js Normal file

File diff suppressed because one or more lines are too long