update
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
function calculateSimilarity(title, keyword) {
|
||||
const titleLower = title.toLowerCase();
|
||||
const keywordLower = keyword.toLowerCase();
|
||||
|
||||
if (titleLower === keywordLower) return 1000;
|
||||
|
||||
if (titleLower.startsWith(keywordLower)) return 800;
|
||||
|
||||
if (titleLower.includes(keywordLower)) return 600;
|
||||
|
||||
let matches = 0;
|
||||
for (let i = 0; i < Math.min(titleLower.length, keywordLower.length); i++) {
|
||||
if (titleLower[i] === keywordLower[i]) matches++;
|
||||
else break;
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
async function searchResults(keyword) {
|
||||
const results = [];
|
||||
try {
|
||||
const response = await fetchv2("https://triton.squid.wtf/search/?s=" + encodeURIComponent(keyword));
|
||||
const data = await response.json();
|
||||
|
||||
const items = data.data?.items || data.items || [];
|
||||
if (Array.isArray(items)) {
|
||||
for (const item of items) {
|
||||
|
||||
let imageUrl = "";
|
||||
if (item.album && item.album.cover) {
|
||||
const cover = item.album.cover.replace(/-/g, '/');
|
||||
imageUrl = `https://resources.tidal.com/images/${cover}/1280x1280.jpg`;
|
||||
}
|
||||
|
||||
const qualityDisplay = getQualityDisplay(item.audioQuality);
|
||||
const title = `${item.title || "Unknown Title"} • ${qualityDisplay}`;
|
||||
const href = `https://hund.qqdl.site/track/?id=${item.id}&quality=${item.audioQuality}`;
|
||||
|
||||
results.push({
|
||||
title: title,
|
||||
image: imageUrl,
|
||||
href: href,
|
||||
baseTitle: item.title || "Unknown Title",
|
||||
similarity: calculateSimilarity(item.title || "Unknown Title", keyword)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
results.sort((a, b) => b.similarity - a.similarity);
|
||||
|
||||
results.forEach(r => {
|
||||
delete r.baseTitle;
|
||||
delete r.similarity;
|
||||
});
|
||||
|
||||
return JSON.stringify(results);
|
||||
} catch (err) {
|
||||
console.error("Search error:", err);
|
||||
return JSON.stringify([{
|
||||
title: "Error",
|
||||
image: "Error",
|
||||
href: "Error"
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
function getQualityDisplay(quality) {
|
||||
const qualityMap = {
|
||||
"LOSSLESS": "Hi-Res",
|
||||
"HIRES_LOSSLESS": "Hi-Res Lossless",
|
||||
"HIGH": "High",
|
||||
"LOW": "Low",
|
||||
"DOLBY_ATMOS": "Dolby Atmos"
|
||||
};
|
||||
return qualityMap[quality] || quality || "Unknown";
|
||||
}
|
||||
|
||||
async function extractDetails(url) {
|
||||
return JSON.stringify([{
|
||||
description: "",
|
||||
aliases: "",
|
||||
airdate: ""
|
||||
}]);
|
||||
}
|
||||
|
||||
async function extractEpisodes(url) {
|
||||
const results = [];
|
||||
try {
|
||||
results.push({
|
||||
href: url,
|
||||
number: 1
|
||||
});
|
||||
return JSON.stringify(results);
|
||||
} catch (err) {
|
||||
return JSON.stringify([{
|
||||
href: "Error",
|
||||
number: "Error"
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
function decodeBase64(str) {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
let result = '';
|
||||
let i = 0;
|
||||
|
||||
str = str.replace(/=+$/, '');
|
||||
|
||||
while (i < str.length) {
|
||||
const a = chars.indexOf(str.charAt(i++));
|
||||
const b = chars.indexOf(str.charAt(i++));
|
||||
const c = i < str.length ? chars.indexOf(str.charAt(i++)) : 0;
|
||||
const d = i < str.length ? chars.indexOf(str.charAt(i++)) : 0;
|
||||
|
||||
const bitmap = (a << 18) | (b << 12) | (c << 6) | d;
|
||||
|
||||
result += String.fromCharCode((bitmap >> 16) & 255);
|
||||
if (c != 64) result += String.fromCharCode((bitmap >> 8) & 255);
|
||||
if (d != 64) result += String.fromCharCode(bitmap & 255);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function extractStreamUrl(url) {
|
||||
try {
|
||||
const response = await fetchv2(url);
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.data) {
|
||||
console.error("No data field in response");
|
||||
return "https://error.org/";
|
||||
}
|
||||
|
||||
if (!data.data.manifest) {
|
||||
console.error("No manifest field in response");
|
||||
return "https://error.org/";
|
||||
}
|
||||
|
||||
try {
|
||||
const manifestString = data.data.manifest.trim();
|
||||
|
||||
let decodedManifest = decodeBase64(manifestString);
|
||||
|
||||
decodedManifest = decodedManifest.replace(/\0/g, '').trim();
|
||||
|
||||
const manifestJson = JSON.parse(decodedManifest);
|
||||
|
||||
if (manifestJson.urls && manifestJson.urls.length > 0) {
|
||||
return manifestJson.urls[0];
|
||||
} else {
|
||||
console.error("No URLs found in manifest");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to decode/parse manifest:", err.message, err.stack);
|
||||
}
|
||||
|
||||
return "https://error.org/";
|
||||
} catch (err) {
|
||||
console.error("Extract stream URL error:", err.message, err.stack);
|
||||
return "https://error.org/";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"sourceName": "Tidal",
|
||||
"iconUrl": "https://images.icon-icons.com/2429/PNG/512/tidal_logo_icon_147227.png",
|
||||
"author": {
|
||||
"name": "50/50",
|
||||
"icon": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ3122kQwublLkZ6rf1fEpUP79BxZOFmH9BSA&s"
|
||||
},
|
||||
"version": "1.0.1",
|
||||
"language": "Music",
|
||||
"streamType": "mp4",
|
||||
"quality": "Lossless",
|
||||
"baseUrl": "https://tidal.com/",
|
||||
"searchBaseUrl": "https://tidal.com/",
|
||||
"scriptUrl": "https://git.luna-app.eu/50n50/sources/raw/branch/main/tidal/tidal.js",
|
||||
"asyncJS": true,
|
||||
"softsub": true,
|
||||
"type": "anime/movies/shows",
|
||||
"downloadSupport": false,
|
||||
"supportsSora": true,
|
||||
"supportsLuna": true,
|
||||
"supportsTsumi": true,
|
||||
"supportsHiyoku": true
|
||||
}
|
||||
Reference in New Issue
Block a user