diff --git a/streamingunity/streamingunity.js b/streamingunity/streamingunity.js index a18d302..3a203a8 100644 --- a/streamingunity/streamingunity.js +++ b/streamingunity/streamingunity.js @@ -1,230 +1,241 @@ +async function getLandingWebsiteHref() { + var response = await fetch("https://previtera.vercel.app/"); + var href = await response.text(); + return href; +} + async function searchResults(keyword) { - const response = await soraFetch( - `https://streamingcommunityz.kitchen/it/archive?search=${keyword}` - ); - const html = await response.text(); + const landingUrl = await getLandingWebsiteHref() - const regex = /]*id="app"[^>]*data-page="([^"]*)"/; - const match = regex.exec(html); - - if (!match || !match[1]) { - return JSON.stringify([]); - } - - const dataPage = match[1].replaceAll(`"`, `"`); - const pageData = JSON.parse(dataPage); - const titles = pageData.props?.titles || []; - - const results = - titles - .map((item) => { - const posterImage = item.images?.find((img) => img.type === "poster"); - return { - title: - item.name?.replaceAll("amp;", "").replaceAll("'", "'") || "", - image: posterImage?.filename - ? `https://cdn.streamingcommunityz.kitchen/images/${posterImage.filename}` - : "", - href: `https://streamingcommunityz.kitchen/it/titles/${item.id}-${item.slug}`, - }; - }) - .filter((item) => item.image) || []; - - return JSON.stringify(results); -} - -async function extractDetails(url) { - const response = await soraFetch(`${url}/season-1`); - const html = await response.text(); - - const regex = /]*id="app"[^>]*data-page="([^"]*)"/; - const match = regex.exec(html); - - if (!match || !match[1]) { - return JSON.stringify([]); - } - - const dataPage = match[1].replaceAll(`"`, `"`); - const pageData = JSON.parse(dataPage); - const titleData = pageData.props?.title; - - if (!titleData) { - return JSON.stringify([]); - } - - return JSON.stringify([ - { - description: - titleData.plot?.replaceAll("amp;", "").replaceAll("'", "'") || - "N/A", - aliases: - titleData.original_name - ?.replaceAll("amp;", "") - .replaceAll("'", "'") || "N/A", - airdate: titleData.release_date || "N/A", - }, - ]); -} - -async function extractEpisodes(url) { - try { - const episodes = []; - const baseUrl = url.replace(/\/season-\d+$/, ""); - - const response = await soraFetch(`${baseUrl}/season-1`); + const response = await soraFetch( + `https://${landingUrl}/it/archive?search=${keyword}` + ); const html = await response.text(); + const regex = /]*id="app"[^>]*data-page="([^"]*)"/; const match = regex.exec(html); - if (!match?.[1]) return JSON.stringify([]); + if (!match || !match[1]) { + return JSON.stringify([]); + } - const pageData = JSON.parse(match[1].replaceAll(`"`, `"`)); + const dataPage = match[1].replaceAll(`"`, `"`); + const pageData = JSON.parse(dataPage); + const titles = pageData.props?.titles || []; + + const results = + titles + .map((item) => { + const posterImage = item.images?.find((img) => img.type === "poster"); + return { + title: item.name?.replaceAll("amp;", "").replaceAll("'", "'") || "", + image: posterImage?.filename ? + `https://cdn.${landingUrl}/images/${posterImage.filename}` : + "", + href: `https://${landingUrl}/it/titles/${item.id}-${item.slug}`, + }; + }) + .filter((item) => item.image) || []; + + return JSON.stringify(results); +} + +async function extractDetails(url) { + const baseUrl = await getLandingWebsiteHref() + + const response = await soraFetch(`${url}/season-1`); + const html = await response.text(); + + const regex = /]*id="app"[^>]*data-page="([^"]*)"/; + const match = regex.exec(html); + + if (!match || !match[1]) { + return JSON.stringify([]); + } + + const dataPage = match[1].replaceAll(`"`, `"`); + const pageData = JSON.parse(dataPage); const titleData = pageData.props?.title; - if (!titleData) return JSON.stringify([]); - const titleId = titleData.id; - const totalSeasons = titleData.seasons_count || 1; + if (!titleData) { + return JSON.stringify([]); + } - let hasEpisodes = false; + return JSON.stringify([{ + description: titleData.plot?.replaceAll("amp;", "").replaceAll("'", "'") || + "N/A", + aliases: titleData.original_name + ?.replaceAll("amp;", "") + .replaceAll("'", "'") || "N/A", + airdate: titleData.release_date || "N/A", + }, ]); +} - for (let season = 1; season <= totalSeasons; season++) { - try { - const seasonResponse = await soraFetch(`${baseUrl}/season-${season}`); - const seasonHtml = await seasonResponse.text(); - const seasonMatch = regex.exec(seasonHtml); +async function extractEpisodes(url) { + try { + const landingUrl = await getLandingWebsiteHref() - if (seasonMatch?.[1]) { - const seasonData = JSON.parse( - seasonMatch[1].replaceAll(`"`, `"`) - ); - const seasonEpisodes = seasonData.props?.loadedSeason?.episodes || []; + const episodes = []; + const baseUrl = url.replace(/\/season-\d+$/, ""); - if (seasonEpisodes.length > 0) { - hasEpisodes = true; - seasonEpisodes.forEach((episode) => { - episodes.push({ - href: `https://streamingcommunityz.kitchen/it/iframe/${titleId}?episode_id=${episode.id}`, - number: episode.number || episodes.length + 1, - }); - }); - } + const response = await soraFetch(`${baseUrl}/season-1`); + const html = await response.text(); + const regex = /]*id="app"[^>]*data-page="([^"]*)"/; + const match = regex.exec(html); + + if (!match?.[1]) return JSON.stringify([]); + + const pageData = JSON.parse(match[1].replaceAll(`"`, `"`)); + const titleData = pageData.props?.title; + if (!titleData) return JSON.stringify([]); + + const titleId = titleData.id; + const totalSeasons = titleData.seasons_count || 1; + + let hasEpisodes = false; + + for (let season = 1; season <= totalSeasons; season++) { + try { + const seasonResponse = await soraFetch(`${baseUrl}/season-${season}`); + const seasonHtml = await seasonResponse.text(); + const seasonMatch = regex.exec(seasonHtml); + + if (seasonMatch?.[1]) { + const seasonData = JSON.parse( + seasonMatch[1].replaceAll(`"`, `"`) + ); + const seasonEpisodes = seasonData.props?.loadedSeason?.episodes || []; + + if (seasonEpisodes.length > 0) { + hasEpisodes = true; + seasonEpisodes.forEach((episode) => { + episodes.push({ + href: `https://${landingUrl}/it/iframe/${titleId}?episode_id=${episode.id}`, + number: episode.number || episodes.length + 1, + }); + }); + } + } + } catch (error) { + console.log(`Error fetching season ${season}:`, error); + } } - } catch (error) { - console.log(`Error fetching season ${season}:`, error); - } - } - if (!hasEpisodes) { - episodes.push({ - href: `https://streamingcommunityz.kitchen/it/iframe/${titleId}`, - number: 1, - }); - } + if (!hasEpisodes) { + episodes.push({ + href: `https://${landingUrl}/it/iframe/${titleId}`, + number: 1, + }); + } - return JSON.stringify(episodes); - } catch (error) { - console.log("Error extracting episodes:", error); - return JSON.stringify([]); - } + return JSON.stringify(episodes); + } catch (error) { + console.log("Error extracting episodes:", error); + return JSON.stringify([]); + } } async function extractStreamUrl(url) { - try { - let modifiedUrl = url; - if (!url.includes("/it/iframe") && !url.includes("/en/iframe")) { - modifiedUrl = url.replace("/iframe", "/it/iframe"); - } - const response1 = await soraFetch(modifiedUrl); - const html1 = await response1.text(); + try { + let modifiedUrl = url; + if (!url.includes("/it/iframe") && !url.includes("/en/iframe")) { + modifiedUrl = url.replace("/iframe", "/it/iframe"); + } + const response1 = await soraFetch(modifiedUrl); + const html1 = await response1.text(); - const iframeMatch = html1.match(/]*src="([^"]*)"/); - if (!iframeMatch) { - console.log("No iframe found in the HTML."); - return null; - } + const iframeMatch = html1.match(/]*src="([^"]*)"/); + if (!iframeMatch) { + console.log("No iframe found in the HTML."); + return null; + } - const embedUrl = iframeMatch[1].replace(/amp;/g, ""); - console.log("Embed URL:", embedUrl); + const embedUrl = iframeMatch[1].replace(/amp;/g, ""); + console.log("Embed URL:", embedUrl); - const response2 = await soraFetch(embedUrl); - const html2 = await response2.text(); + const response2 = await soraFetch(embedUrl); + const html2 = await response2.text(); - let finalUrl = null; + let finalUrl = null; - if (html2.includes("window.masterPlaylist")) { - const urlMatch = html2.match(/url:\s*['"]([^'"]+)['"]/); - const tokenMatch = html2.match(/['"]?token['"]?\s*:\s*['"]([^'"]+)['"]/); - const expiresMatch = html2.match( - /['"]?expires['"]?\s*:\s*['"]([^'"]+)['"]/ - ); + if (html2.includes("window.masterPlaylist")) { + const urlMatch = html2.match(/url:\s*['"]([^'"]+)['"]/); + const tokenMatch = html2.match(/['"]?token['"]?\s*:\s*['"]([^'"]+)['"]/); + const expiresMatch = html2.match( + /['"]?expires['"]?\s*:\s*['"]([^'"]+)['"]/ + ); - if (urlMatch && tokenMatch && expiresMatch) { - const baseUrl = urlMatch[1]; - const token = tokenMatch[1]; - const expires = expiresMatch[1]; + if (urlMatch && tokenMatch && expiresMatch) { + const baseUrl = urlMatch[1]; + const token = tokenMatch[1]; + const expires = expiresMatch[1]; - if (baseUrl.includes("?b=1")) { - finalUrl = `${baseUrl}&token=${token}&expires=${expires}&h=1`; + if (baseUrl.includes("?b=1")) { + finalUrl = `${baseUrl}&token=${token}&expires=${expires}&h=1`; + } else { + finalUrl = `${baseUrl}?token=${token}&expires=${expires}&h=1`; + } + } + } + + if (!finalUrl) { + const m3u8Match = html2.match(/(https?:\/\/[^'"\s]+\.m3u8[^'"\s]*)/); + if (m3u8Match) { + finalUrl = m3u8Match[1]; + } + } + + if (!finalUrl) { + const scriptMatches = html2.match(/]*>(.*?)<\/script>/gs); + if (scriptMatches) { + for (const script of scriptMatches) { + const streamMatch = script.match( + /['"]?(https?:\/\/[^'"\s]+(?:\.m3u8|playlist)[^'"\s]*)/ + ); + if (streamMatch) { + finalUrl = streamMatch[1]; + break; + } + } + } + } + + if (!finalUrl) { + const videoMatch = html2.match( + /(?:src|source|url)['"]?\s*[:=]\s*['"]?(https?:\/\/[^'"\s]+(?:\.mp4|\.m3u8|\.mpd)[^'"\s]*)/ + ); + if (videoMatch) { + finalUrl = videoMatch[2] || videoMatch[1]; + } + } + + if (finalUrl) { + console.log("Final URL found:", finalUrl); + return finalUrl; } else { - finalUrl = `${baseUrl}?token=${token}&expires=${expires}&h=1`; + console.log( + "No stream URL found. HTML content:", + html2.substring(0, 1000) + ); + return null; } - } + } catch (error) { + console.log("Fetch error:", error); + return null; } - - if (!finalUrl) { - const m3u8Match = html2.match(/(https?:\/\/[^'"\s]+\.m3u8[^'"\s]*)/); - if (m3u8Match) { - finalUrl = m3u8Match[1]; - } - } - - if (!finalUrl) { - const scriptMatches = html2.match(/]*>(.*?)<\/script>/gs); - if (scriptMatches) { - for (const script of scriptMatches) { - const streamMatch = script.match( - /['"]?(https?:\/\/[^'"\s]+(?:\.m3u8|playlist)[^'"\s]*)/ - ); - if (streamMatch) { - finalUrl = streamMatch[1]; - break; - } - } - } - } - - if (!finalUrl) { - const videoMatch = html2.match( - /(?:src|source|url)['"]?\s*[:=]\s*['"]?(https?:\/\/[^'"\s]+(?:\.mp4|\.m3u8|\.mpd)[^'"\s]*)/ - ); - if (videoMatch) { - finalUrl = videoMatch[2] || videoMatch[1]; - } - } - - if (finalUrl) { - console.log("Final URL found:", finalUrl); - return finalUrl; - } else { - console.log( - "No stream URL found. HTML content:", - html2.substring(0, 1000) - ); - return null; - } - } catch (error) { - console.log("Fetch error:", error); - return null; - } } -async function soraFetch(url, options = { headers: {}, method: 'GET', body: null }) { +async function soraFetch(url, options = { + headers: {}, + method: 'GET', + body: null +}) { try { return await fetchv2(url, options.headers ?? {}, options.method ?? 'GET', options.body ?? null); - } catch(e) { + } catch (e) { try { return await fetch(url, options); - } catch(error) { + } catch (error) { return null; } }