add legacy stuff
This commit is contained in:
parent
c33ef02dca
commit
ab04031fcd
5 changed files with 483 additions and 0 deletions
BIN
legacy/getie3.gif
Normal file
BIN
legacy/getie3.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
legacy/getnet3.gif
Normal file
BIN
legacy/getnet3.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
81
legacy/index.html
Normal file
81
legacy/index.html
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||||
|
<html>
|
||||||
|
<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 type="text/javascript" src="legacy.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>
|
||||||
|
<!-- 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>
|
||||||
|
</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>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
98
legacy/legacy.css
Normal file
98
legacy/legacy.css
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
/* Retro 90s Styling */
|
||||||
|
body {
|
||||||
|
background-color: #c0c0c0;
|
||||||
|
font-family: "Times New Roman", Times, serif;
|
||||||
|
color: #000000;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-image: url("assets/bg_texture.gif"); /* Fallback if not found is just grey */
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #000000;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: #444444;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active {
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse; /* Not strictly 90s but makes it cleaner */
|
||||||
|
}
|
||||||
|
|
||||||
|
.beveled-box {
|
||||||
|
border-top: 2px solid #ffffff;
|
||||||
|
border-left: 2px solid #ffffff;
|
||||||
|
border-right: 2px solid #808080;
|
||||||
|
border-bottom: 2px solid #808080;
|
||||||
|
background-color: #c0c0c0;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inset-box {
|
||||||
|
border-top: 2px solid #808080;
|
||||||
|
border-left: 2px solid #808080;
|
||||||
|
border-right: 2px solid #ffffff;
|
||||||
|
border-bottom: 2px solid #ffffff;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.marquee-container {
|
||||||
|
background-color: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
padding: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-link {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.track-row td {
|
||||||
|
padding: 2px 5px;
|
||||||
|
border: 1px solid #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #a0a0a0;
|
||||||
|
border: 2px outset #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #c0c0c0;
|
||||||
|
border-top: 2px solid #ffffff;
|
||||||
|
border-left: 2px solid #ffffff;
|
||||||
|
border-right: 2px solid #000000;
|
||||||
|
border-bottom: 2px solid #000000;
|
||||||
|
padding: 2px 10px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
border-top: 2px solid #000000;
|
||||||
|
border-left: 2px solid #000000;
|
||||||
|
border-right: 2px solid #ffffff;
|
||||||
|
border-bottom: 2px solid #ffffff;
|
||||||
|
}
|
||||||
304
legacy/legacy.js
Normal file
304
legacy/legacy.js
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
// strictly ES5/Legacy JS
|
||||||
|
(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;
|
||||||
|
var currentTrackInfo;
|
||||||
|
|
||||||
|
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 () {
|
||||||
|
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 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) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
callback(randomUrl);
|
||||||
|
} else {
|
||||||
|
useFallback(callback);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
useFallback(callback);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
function performSearch(query) {
|
||||||
|
var resultsDiv = document.getElementById("search-results");
|
||||||
|
if (!resultsDiv) {
|
||||||
|
setContent('<div id="search-results">Searching...</div>');
|
||||||
|
resultsDiv = document.getElementById("search-results");
|
||||||
|
} else {
|
||||||
|
resultsDiv.innerHTML = "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.innerHTML = "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];
|
||||||
|
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.innerHTML = html;
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
resultsDiv.innerHTML = "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>';
|
||||||
|
|
||||||
|
for (var i = 0; i < tracks.length; i++) {
|
||||||
|
var t = tracks[i];
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
audioPlayer.src = manifest.urls[0];
|
||||||
|
audioPlayer.play();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(text) {
|
||||||
|
if (!text) return "";
|
||||||
|
return text
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
})();
|
||||||
Loading…
Reference in a new issue