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/"; } }