push changes
This commit is contained in:
parent
699e2e4e3c
commit
89f070696f
6 changed files with 264 additions and 60 deletions
BIN
legacy/FlashAudioPlugin.swf
Normal file
BIN
legacy/FlashAudioPlugin.swf
Normal file
Binary file not shown.
20
legacy/flashplugin.js
Normal file
20
legacy/flashplugin.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -5,6 +5,9 @@
|
||||||
<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="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>
|
<script type="text/javascript" src="legacy.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -44,7 +47,8 @@
|
||||||
<img src="getie3.gif" alt="IE Logo" width="88" height="31"><br><br>
|
<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>
|
<img src="getnet3.gif" alt="Netscape Logo" width="88" height="31"><br><br>
|
||||||
<font size="1">Free and open software</font><br><br>
|
<font size="1">Free and open software</font><br><br>
|
||||||
<font size="1">made by binimum</font>
|
<font size="1">made by binimum</font><br><br>
|
||||||
|
<font size="1">all browsers that support <a href="https://caniuse.com/aac">aac audio</a> (may work in unsupported browsers with adobe flash) or <a href="https://caniuse.com/flac">flac audio</a> should work</font>
|
||||||
</center>
|
</center>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|
|
||||||
262
legacy/legacy.js
262
legacy/legacy.js
|
|
@ -1,9 +1,9 @@
|
||||||
// jQuery 1.12.4 Legacy Support
|
// jQuery 1.12.4 Legacy Support
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
var currentApiUrl = ""; // Will be set from instances.json
|
var apiInstances = [];
|
||||||
|
var currentInstanceIndex = 0;
|
||||||
var isHttpFallback = false;
|
var isHttpFallback = false;
|
||||||
var FALLBACK_INSTANCES = [
|
var FALLBACK_INSTANCES = [
|
||||||
"https://triton.squid.wtf",
|
|
||||||
"https://wolf.qqdl.site",
|
"https://wolf.qqdl.site",
|
||||||
"https://maus.qqdl.site",
|
"https://maus.qqdl.site",
|
||||||
"https://vogel.qqdl.site",
|
"https://vogel.qqdl.site",
|
||||||
|
|
@ -15,9 +15,15 @@ $(document).ready(function () {
|
||||||
var audioPlayer = $("#audio-player")[0];
|
var audioPlayer = $("#audio-player")[0];
|
||||||
var currentTrackInfo = $("#now-playing-info");
|
var currentTrackInfo = $("#now-playing-info");
|
||||||
|
|
||||||
|
// Initialize SoundJS
|
||||||
|
// Note: Class is FlashPlugin in 0.5.2, but SWF is FlashAudioPlugin.swf
|
||||||
|
createjs.FlashPlugin.swfPath = "./";
|
||||||
|
// Prioritize HTMLAudio -> WebAudio -> Flash
|
||||||
|
// HTMLAudio is better for streaming music (avoids XHR/CORS issues of WebAudio)
|
||||||
|
createjs.Sound.registerPlugins([createjs.HTMLAudioPlugin, createjs.WebAudioPlugin, createjs.FlashPlugin]);
|
||||||
|
|
||||||
// Initial Load
|
// Initial Load
|
||||||
fetchInstances(function (url) {
|
fetchInstances(function () {
|
||||||
currentApiUrl = url;
|
|
||||||
loadRecentTracks();
|
loadRecentTracks();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -35,55 +41,164 @@ $(document).ready(function () {
|
||||||
|
|
||||||
// Global functions exposed for inline onclicks
|
// Global functions exposed for inline onclicks
|
||||||
// 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) {
|
window.playTrack = function (id, attemptFallback) {
|
||||||
var quality = attemptFallback ? "HIGH" : "LOSSLESS";
|
var quality = attemptFallback ? "HIGH" : "LOSSLESS";
|
||||||
apiRequest(
|
apiRequest(
|
||||||
"/track/?id=" + id + "&quality=" + quality,
|
"/track/?id=" + id + "&quality=" + quality,
|
||||||
function (data) {
|
function (data) {
|
||||||
var success = false;
|
|
||||||
if (data && data.data && data.data.manifest) {
|
if (data && data.data && data.data.manifest) {
|
||||||
try {
|
try {
|
||||||
var manifestStr = base64Decode(data.data.manifest);
|
var manifestStr = base64Decode(data.data.manifest);
|
||||||
var manifest = JSON.parse(manifestStr);
|
var manifest = JSON.parse(manifestStr);
|
||||||
if (manifest.urls && manifest.urls.length > 0) {
|
if (manifest.urls && manifest.urls.length > 0) {
|
||||||
var streamUrl = manifest.urls[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) {
|
// Unified Playback Strategy:
|
||||||
var qualityLabel = attemptFallback ? " (AAC)" : " (FLAC)";
|
// 1. Stop Everything
|
||||||
currentTrackInfo.html("Now Playing..." + qualityLabel);
|
stopAllAudio();
|
||||||
}
|
|
||||||
success = true;
|
// 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) {
|
} catch (e) {
|
||||||
// Fall through to fallback
|
console.log("Manifest error: " + e);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
if (!attemptFallback) {
|
|
||||||
// Try fallback to HIGH (AAC)
|
|
||||||
window.playTrack(id, true);
|
|
||||||
} else {
|
} else {
|
||||||
alert("No stream URLs found or invalid manifest.");
|
handleError("Invalid track data");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
function (err) {
|
function (err) {
|
||||||
if (!attemptFallback) {
|
handleError(err);
|
||||||
// Try fallback to HIGH (AAC) on request error too
|
|
||||||
window.playTrack(id, true);
|
|
||||||
} else {
|
|
||||||
alert("Error playing track: " + err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function playNativeFirst(url, id, quality) {
|
||||||
|
var domPlayer = $("#audio-player")[0];
|
||||||
|
|
||||||
|
// Quality Label
|
||||||
|
var qLabel = (quality === "LOSSLESS") ? " (FLAC)" : " (AAC)";
|
||||||
|
if (attemptFallback) qLabel = " (AAC)";
|
||||||
|
|
||||||
|
// Basic check for audio support
|
||||||
|
if (domPlayer && typeof domPlayer.play === 'function') {
|
||||||
|
updateStatus("Starting Native Playback" + qLabel + "...");
|
||||||
|
|
||||||
|
// Set error handler for THIS attempt
|
||||||
|
domPlayer.onerror = function() {
|
||||||
|
var errCode = domPlayer.error ? domPlayer.error.code : 0;
|
||||||
|
console.log("Native Error Code: " + errCode);
|
||||||
|
// Fallback to legacy
|
||||||
|
playLegacySoundJS(url, id, quality);
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
domPlayer.src = url;
|
||||||
|
var playPromise = domPlayer.play();
|
||||||
|
|
||||||
|
if (playPromise !== undefined) {
|
||||||
|
playPromise
|
||||||
|
.then(function() {
|
||||||
|
updateStatus("Now Playing..." + qLabel);
|
||||||
|
})
|
||||||
|
.catch(function(e) {
|
||||||
|
console.log("Native Play Promise Rejected: " + e.name);
|
||||||
|
// Auto-play policy or format issue?
|
||||||
|
// Try SounJS as fallback
|
||||||
|
playLegacySoundJS(url, id, quality);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Legacy browser (no promise), assume success unless onError fires
|
||||||
|
updateStatus("Now Playing..." + qLabel);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Native Exception: " + e.message);
|
||||||
|
playLegacySoundJS(url, id, quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// No native audio support (IE < 9)
|
||||||
|
playLegacySoundJS(url, id, quality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function playLegacySoundJS(url, id, quality) {
|
||||||
|
updateStatus("Activating Legacy Player (Flash)...");
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
createjs.Sound.removeAllEventListeners("fileload");
|
||||||
|
|
||||||
|
var playSound = function() {
|
||||||
|
var instance = createjs.Sound.play(soundId);
|
||||||
|
if (!instance || instance.playState === createjs.Sound.PLAY_FAILED) {
|
||||||
|
handleError("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) {
|
||||||
|
handleError("Legacy Setup Failed: " + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
function loadRecentTracks() {
|
||||||
|
|
@ -106,16 +221,19 @@ $(document).ready(function () {
|
||||||
function fetchInstances(callback) {
|
function fetchInstances(callback) {
|
||||||
// using $.ajax directly to handle errors robustly
|
// using $.ajax directly to handle errors robustly
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "instances.json",
|
url: "/instances.json",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (instances) {
|
success: function (instances) {
|
||||||
if (instances && instances.length > 0) {
|
if (instances && instances.length > 0) {
|
||||||
var randomUrl =
|
apiInstances = shuffleArray(instances);
|
||||||
instances[Math.floor(Math.random() * instances.length)];
|
// Clean URLs
|
||||||
if (randomUrl.charAt(randomUrl.length - 1) === "/") {
|
for (var i = 0; i < apiInstances.length; i++) {
|
||||||
randomUrl = randomUrl.substring(0, randomUrl.length - 1);
|
if (apiInstances[i].charAt(apiInstances[i].length - 1) === "/") {
|
||||||
|
apiInstances[i] = apiInstances[i].substring(0, apiInstances[i].length - 1);
|
||||||
}
|
}
|
||||||
callback(randomUrl);
|
}
|
||||||
|
currentInstanceIndex = 0;
|
||||||
|
callback();
|
||||||
} else {
|
} else {
|
||||||
useFallback(callback);
|
useFallback(callback);
|
||||||
}
|
}
|
||||||
|
|
@ -127,9 +245,19 @@ $(document).ready(function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function useFallback(callback) {
|
function useFallback(callback) {
|
||||||
var randomUrl =
|
apiInstances = shuffleArray(FALLBACK_INSTANCES.slice()); // Copy and shuffle
|
||||||
FALLBACK_INSTANCES[Math.floor(Math.random() * FALLBACK_INSTANCES.length)];
|
currentInstanceIndex = 0;
|
||||||
callback(randomUrl);
|
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) {
|
function performSearch(query) {
|
||||||
|
|
@ -211,10 +339,21 @@ $(document).ready(function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function apiRequest(endpoint, success, error) {
|
function apiRequest(endpoint, success, error) {
|
||||||
var finalUrl = currentApiUrl;
|
if (apiInstances.length === 0) {
|
||||||
if (isHttpFallback && finalUrl.indexOf("https://") === 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);
|
finalUrl = "http://" + finalUrl.substring(8);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
@ -222,26 +361,45 @@ $(document).ready(function () {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
|
// Logic: If successful with HTTP fallback, maybe we should stick to it?
|
||||||
|
// For now, we just proceed.
|
||||||
success(data);
|
success(data);
|
||||||
},
|
},
|
||||||
error: function (xhr, status, errorThrown) {
|
error: function (xhr, status, errorThrown) {
|
||||||
if (!isHttpFallback && window.location.protocol !== "https:") {
|
handleApiError(endpoint, success, error, status + " (" + errorThrown + ")");
|
||||||
isHttpFallback = true;
|
|
||||||
// Retry with fallback logic (recursive call will pick up isHttpFallback)
|
|
||||||
apiRequest(endpoint, success, error);
|
|
||||||
} else {
|
|
||||||
error("Request Failed: " + status + " (" + errorThrown + ")");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} 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:") {
|
if (!isHttpFallback && window.location.protocol !== "https:") {
|
||||||
|
// Only if current instance is HTTPS
|
||||||
|
if (apiInstances[currentInstanceIndex].indexOf("https://") === 0) {
|
||||||
isHttpFallback = true;
|
isHttpFallback = true;
|
||||||
apiRequest(endpoint, success, error);
|
apiRequest(endpoint, success, error);
|
||||||
} else {
|
return;
|
||||||
error("Exception: " + e.message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
function playWithEmbed(url) {
|
||||||
|
|
|
||||||
18
legacy/soundjs-0.5.2.min.js
vendored
Normal file
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
4
legacy/swfobject.js
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue