From 42e16cb8f867be29403ddf4dc7835674f2789e2c Mon Sep 17 00:00:00 2001 From: uimaxbai <61615730+uimaxbai@users.noreply.github.com> Date: Wed, 31 Dec 2025 13:36:01 +0000 Subject: [PATCH] add html5 version of site to appease certain browsers --- legacy/html5.html | 122 +++++++++ legacy/html5.js | 627 ++++++++++++++++++++++++++++++++++++++++++++++ legacy/index.html | 192 +++++++++----- legacy/legacy.js | 51 ++++ 4 files changed, 924 insertions(+), 68 deletions(-) create mode 100644 legacy/html5.html create mode 100644 legacy/html5.js diff --git a/legacy/html5.html b/legacy/html5.html new file mode 100644 index 0000000..dfbd92b --- /dev/null +++ b/legacy/html5.html @@ -0,0 +1,122 @@ + + + + Monochrome Legacy (HTML5) + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Monochrome Music
+ music +
+ Welcome to Monochrome Music Legacy Edition check out the latest + hits new songs added daily under construction sign + guestbook +
+
+
Menu
+
+ +
+ +
+
+ IE Logo

+ Netscape Logo

+ Free and open software

+ made by binimum

+ all browsers that support + aac audio (may work in + unsupported browsers with adobe flash) or + flac audio should + work +
+
+
+ +
+ + Status: Ready to play. + +

+ +
+ + +
+ Search Music: +
+ + +
+
+ +
+

Loading...

+
+
+
+ + diff --git a/legacy/html5.js b/legacy/html5.js new file mode 100644 index 0000000..beb665c --- /dev/null +++ b/legacy/html5.js @@ -0,0 +1,627 @@ +// 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(); + } + } + }; + } + }); + } + // Enable CORS logic in jQuery generally (if supported by this jQuery version) + if ($.support) { + $.support.cors = true; + } + + 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) + 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() { + 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('
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 += + ''; + + $.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 += ""; + html += ""; + html += ""; + html += ""; + }); + html += "
PlayTitleArtistAlbum
" + safeTitle + "" + safeArtist + "" + safeAlbum + "
"; + + resultsDiv.html(html); + }, + function (err) { + resultsDiv.html("Error: " + err); + } + ); + } + + function renderTracks(tracks, title) { + var html = "

" + title + "

"; + html += ''; + html += + ''; + + $.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 += ""; + html += ""; + html += ""; + html += ""; + }); + html += "
PlayTitleArtistAlbum
" + safeTitle + "" + safeArtist + "" + safeAlbum + "
"; + + 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 = $('
'); + 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; + } +}); diff --git a/legacy/index.html b/legacy/index.html index 788f402..89a453a 100644 --- a/legacy/index.html +++ b/legacy/index.html @@ -1,87 +1,143 @@ - + - + Monochrome Legacy - - + + + + - - - - - - + + +
+ + - - - - - - + - - + + + + + + + - -
- Monochrome Music
- music + Monochrome Music
+ music
- Welcome to Monochrome Music Legacy Edition check out the latest hits new songs added daily under construction sign guestbook -
+ Welcome to Monochrome Music Legacy Edition check out the latest + hits new songs added daily under construction sign + guestbook +
-
-
Menu
-
- -
- -
-
- IE Logo

- Netscape Logo

- Free and open software

- made by binimum

- all browsers that support aac audio (may work in unsupported browsers with adobe flash) or flac audio should work -
+
+
Menu
+
+ +
+ +
+
+ IE Logo

+ Netscape Logo

+ Free and open software

+ made by binimum

+ all browsers that support + aac audio (may work in + unsupported browsers with adobe flash) or + flac audio should + work +
-
- -
- - Status: Ready to play. - -

- -
- - -
- Search Music: -
- - -
-
- -
-

Loading...

-
+
+ +
+ + Status: Ready to play. + +

+
-
- + +
+ Search Music: +
+ + +
+
+ +
+

Loading...

+
+ + + + + diff --git a/legacy/legacy.js b/legacy/legacy.js index 2fd2da5..8f1b5fc 100644 --- a/legacy/legacy.js +++ b/legacy/legacy.js @@ -1,5 +1,56 @@ // 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(); + } + } + }; + } + }); + } + // Enable CORS logic in jQuery generally (if supported by this jQuery version) + if ($.support) { + $.support.cors = true; + } + var apiInstances = []; var currentInstanceIndex = 0; var isHttpFallback = false;