From b69b4ab5e43356b072469cedb09c0512785350e7 Mon Sep 17 00:00:00 2001 From: aka paul <50n50@noreply.localhost> Date: Sat, 6 Dec 2025 22:38:02 +0000 Subject: [PATCH] Update hianime/hianime.js --- hianime/hianime.js | 291 ++++++++++++++++++++++++++++++--------------- 1 file changed, 195 insertions(+), 96 deletions(-) diff --git a/hianime/hianime.js b/hianime/hianime.js index 7a22871..d93e674 100644 --- a/hianime/hianime.js +++ b/hianime/hianime.js @@ -1,115 +1,214 @@ async function searchResults(keyword) { + const results = []; + try { - const encodedKeyword = encodeURIComponent(keyword); - const responseText = await fetchv2(`https://bshar1865-hianime2.vercel.app/api/v2/hianime/search?q=${encodedKeyword}`); - const data = await responseText.json(); + const response = await fetchv2("https://hianime.to/search?keyword=" + encodeURIComponent(keyword)); + const html = await response.text(); - console.log("Search results:", data); + const blocks = html.split('
').slice(1); - const transformedResults = data.data.animes.map(anime => ({ - title: anime.name, - image: anime.poster, - href: `https://hianime.to/watch/${anime.id}` - })); - - console.log("Transformed results:", transformedResults); - return JSON.stringify(transformedResults); - } catch (error) { - console.log('Fetch error:', error); - return JSON.stringify([{ title: 'Error', image: '', href: '' }]); + for (const block of blocks) { + const href = block.match(/[\s\S]*?
\s*([\s\S]*?)\s*<\/div>/); + const dateMatch = html.match(/Released:\s*<\/strong>\s*([^<\n]+)/); + + const description = descMatch ? descMatch[1].trim() : "N/A"; + const airdate = dateMatch ? dateMatch[1].trim() : "N/A"; - const transformedResults = [{ - description: animeInfo.description || 'No description available', - aliases: `Duration: ${animeInfo.stats?.duration || 'Unknown'}`, - airdate: `Aired: ${moreInfo?.aired || 'Unknown'}` - }]; - - console.log("Transformed results:", transformedResults); - return JSON.stringify(transformedResults); - } catch (error) { - console.log('Details error:', error); return JSON.stringify([{ - description: 'Error loading description', - aliases: 'Duration: Unknown', - airdate: 'Aired: Unknown' + description: description, + aliases: "N/A", + airdate: airdate }]); - } -} -async function extractEpisodes(url) { - try { - const match = url.match(/https:\/\/hianime\.to\/watch\/(.+)$/); - const encodedID = match[1]; - const response = await fetchv2(`https://bshar1865-hianime2.vercel.app/api/v2/hianime/anime/${encodedID}/episodes`); - const data = await response.json(); - - const transformedResults = data.data.episodes.map(episode => ({ - href: episode.episodeId, - number: episode.number - })); - - console.log("Transformed results:" + transformedResults); - return JSON.stringify(transformedResults); - } catch (error) { - console.log('Fetch error:', error); + } catch (err) { + return JSON.stringify([{ + description: "Error", + aliases: "Error", + airdate: "Error" + }]); } } -async function extractStreamUrl(id) { - try { - const subRes = await fetchv2(`https://animeapiiiii.vercel.app/api/stream?id=${id}&server=hd-1&type=sub`); - const subJson = await subRes.json(); - - const streamSub = subJson.results.streamingLink.link.file; - const englishSubtitles = (subJson.results.streamingLink.tracks || []).find( - track => track.kind === "captions" && track.label.toLowerCase().includes("english") - )?.file || ""; - - let streamDub = null; - try { - const dubRes = await fetchv2(`https://animeapiiiii.vercel.app/api/stream?id=${id}&server=hd-1&type=dub`); - const dubJson = await dubRes.json(); - streamDub = dubJson.results?.streamingLink?.link?.file || null; - } catch (e) { - streamDub = null; - } - - const streams = []; - - if (streamDub) { - streams.push("DUB", streamDub); - } - - if (streamSub) { - streams.push("SUB", streamSub); - } - - const final = { - streams, - subtitles: englishSubtitles - }; - - console.log("RETURN: " + JSON.stringify(final)); - return JSON.stringify(final); - - } catch (error) { - console.log("Error in extractStreamUrl:", error); - return JSON.stringify({ - streams: [], - subtitles: "" - }); +async function extractEpisodes(url) { + const results = []; + try { + let watchUrl = url; + if (!/\/watch\//.test(watchUrl)) { + watchUrl = watchUrl.replace(/\/([^\/]+)$/, '/watch/$1'); } + + const watchResp = await fetchv2("https://hianime.to" + watchUrl); + const watchHtml = await watchResp.text(); + const idMatch = watchHtml.match(/]+id="wrapper"[^>]+data-id="(\d+)"[^>]*>/); + if (!idMatch) throw new Error("movie_id not found"); + const movieId = idMatch[1]; + + const epListResp = await fetchv2(`https://hianime.to/ajax/v2/episode/list/${movieId}`); + const epListJson = await epListResp.json(); + const epHtml = epListJson.html; + + const epRegex = /]+class="ssl-item\s+ep-item"[^>]+data-number="(\d+)"[^>]+data-id="(\d+)"[^>]*>/g; + let match; + while ((match = epRegex.exec(epHtml)) !== null) { + results.push({ + href: match[2], + number: parseInt(match[1], 10) + }); + } + + return JSON.stringify(results); + } catch (err) { + console.error(err); + return JSON.stringify([{ id: "Error", href: "Error", number: "Error", title: "Error" }]); + } } +async function extractStreamUrl(ID) { + try { + const serversResp = await fetchv2(`https://hianime.to/ajax/v2/episode/servers?episodeId=${ID}`); + const serversJson = await serversResp.json(); + const serversHtml = serversJson.html; + + const subServerMatch = serversHtml.match(/
{ + try { + const sourcesResp = await fetchv2(`https://hianime.to/ajax/v2/episode/sources?id=${serverId}`); + const sourcesJson = await sourcesResp.json(); + const iframeUrl = sourcesJson.link; + + if (!iframeUrl) return null; + + const iframeResp = await fetchv2(iframeUrl, headers); + const iframeHtml = await iframeResp.text(); + + const videoTagMatch = iframeHtml.match(/data-id="([^"]+)"/); + if (!videoTagMatch) return null; + const fileId = videoTagMatch[1]; + + const nonceMatch = iframeHtml.match(/\b[a-zA-Z0-9]{48}\b/) || + iframeHtml.match(/\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b.*?\b([a-zA-Z0-9]{16})\b/); + if (!nonceMatch) return null; + + const nonce = nonceMatch.length === 4 ? + nonceMatch[1] + nonceMatch[2] + nonceMatch[3] : + nonceMatch[0]; + + const urlParts = iframeUrl.split('/'); + const protocol = iframeUrl.startsWith('https') ? 'https:' : 'http:'; + const hostname = urlParts[2]; + const defaultDomain = `${protocol}//${hostname}/`; + + const getSourcesUrl = `${defaultDomain}embed-2/v3/e-1/getSources?id=${fileId}&_k=${nonce}`; + const getSourcesResp = await fetchv2(getSourcesUrl, headers); + const getSourcesJson = await getSourcesResp.json(); + + const videoUrl = getSourcesJson.sources?.[0]?.file || ""; + if (!videoUrl) return null; + + const streamHeaders = { + "Referer": defaultDomain, + "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36" + }; + + return { + title: title, + streamUrl: videoUrl, + headers: streamHeaders, + sourcesData: getSourcesJson + }; + } catch (e) { + console.log(`${title} failed:`, e); + return null; + } + }; + + const serverPromises = []; + if (subServerId) serverPromises.push(processServer(subServerId, "SUB")); + if (dubServerId) serverPromises.push(processServer(dubServerId, "DUB")); + + const results = await Promise.all(serverPromises); + const streams = results.filter(r => r !== null); + + if (streams.length === 0) { + return "https://error.org/"; + } + + const englishTrack = streams[0].sourcesData.tracks?.find(t => t.kind === "captions" && t.label === "English"); + const subtitle = englishTrack ? englishTrack.file : ""; + + const finalStreams = streams.map(s => ({ + title: s.title, + streamUrl: s.streamUrl, + headers: s.headers + })); + + return JSON.stringify({ + streams: finalStreams, + subtitle: subtitle + }); + } catch (err) { + console.error(err); + return "https://error.org/"; + } +} + +function decodeHtmlEntities(text) { + if (!text) { + return ""; + } + return text + .replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec)) + .replace(/&#x([0-9a-fA-F]+);/g, (match, hex) => String.fromCharCode(parseInt(hex, 16))) + .replace(/"/g, "\"") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/ /g, " "); +} + + + +