diff --git a/src/sources/vidvault.js b/src/sources/vidvault.js index 11bf3ce..c3265b3 100644 --- a/src/sources/vidvault.js +++ b/src/sources/vidvault.js @@ -1,168 +1,178 @@ -import { formatBytes, USER_AGENT } from '../utils/helpers.js'; +// vidvault i see you change your api again over and over, dm me if you want me to remove your source and no longer add you const BASE_URL = 'https://vidvault.to'; -const API_BASE = `${BASE_URL}/api`; -const DL_PROXY_BASE = 'https://dl.gemlelispe.workers.dev'; -const SUB_PROXY_BASE = 'https://sub.k5s7sjozpn.workers.dev'; const HEADERS = { - Referer: `${BASE_URL}/`, - Origin: BASE_URL, - 'User-Agent': USER_AGENT, - Accept: 'application/json, text/plain, */*', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.9', + 'Referer': `${BASE_URL}/`, }; -let cookieJar = null; -let cookiePromise = null; +const PLAYBACK_HEADERS = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', + 'Referer': `${BASE_URL}/`, +}; -function ensureCookies() { - if (cookieJar !== null) return Promise.resolve(); - if (cookiePromise) return cookiePromise; - cookiePromise = (async () => { - try { - const res = await fetch(`${BASE_URL}/`, { - headers: { - 'User-Agent': USER_AGENT, - Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.9', - }, - signal: AbortSignal.timeout(10000), - }); - const setCookie = typeof res.headers.getSetCookie === 'function' - ? res.headers.getSetCookie() - : (res.headers.get('set-cookie') ? [res.headers.get('set-cookie')] : []); - cookieJar = setCookie.map(c => c.split(';')[0].trim()).filter(Boolean).join('; '); - } catch { - cookieJar = ''; - } - })(); - return cookiePromise; +function getDlEndpoint(type, id, s, e, quality) { + return s != null && e != null + ? `${BASE_URL}/download-link/${type}/${encodeURIComponent(id)}/${encodeURIComponent(s)}/${encodeURIComponent(e)}/${encodeURIComponent(quality)}` + : `${BASE_URL}/download-link/${type}/${encodeURIComponent(id)}/${encodeURIComponent(quality)}`; } -function withCookies(headers = {}) { - return cookieJar ? { ...headers, Cookie: cookieJar } : headers; +function getStartConversionEndpoint(type, id, s, e, quality) { + return s != null && e != null + ? `${BASE_URL}/start-conversion/${type}/${encodeURIComponent(id)}/${encodeURIComponent(s)}/${encodeURIComponent(e)}/${encodeURIComponent(quality)}` + : `${BASE_URL}/start-conversion/${type}/${encodeURIComponent(id)}/${encodeURIComponent(quality)}`; } -async function getToken() { - await ensureCookies(); - const res = await fetch(`${API_BASE}/get-token`, { - method: 'GET', - headers: withCookies(HEADERS), - signal: AbortSignal.timeout(10000), - }); - if (!res.ok) throw new Error(`Token fetch failed: ${res.status}`); - const data = await res.json(); - return data?.t; -} - -function getCaptionType(url) { - return String(url).toLowerCase().includes('.vtt') ? 'vtt' : 'srt'; -} - -async function fetchJson(url, options = {}) { +async function fetchDownloadUrl(type, id, s, e, quality) { try { - const res = await fetch(url, options); - if (!res.ok) return null; - return await res.json(); - } catch { - return null; - } -} - -async function resolveDirect(directPath, headers) { - const fullUrl = directPath.startsWith('http') ? directPath : `${BASE_URL}${directPath}`; - try { - const res = await fetch(fullUrl, { - method: 'HEAD', - redirect: 'manual', - headers: withCookies(headers), + const res = await fetch(getDlEndpoint(type, id, s, e, quality), { + headers: { ...HEADERS, Accept: 'application/json' }, + signal: AbortSignal.timeout(4000), }); - const loc = res.headers.get('location'); - if (loc) return loc; + if (!res.ok) return null; + const data = await res.json().catch(() => null); + if (data?.url) { + let clean = String(data.url).split('?')[0].split('#')[0]; + if (!clean.endsWith('.mkv') && !clean.endsWith('.mp4')) clean += '.mkv'; + return clean; + } } catch { } - return fullUrl; + return null; +} + +async function pollJob(jobId, maxWaitMs = 12000) { + const start = Date.now(); + while (Date.now() - start < maxWaitMs) { + try { + const res = await fetch(`${BASE_URL}/job/${jobId}?t=${Date.now()}`, { + headers: HEADERS, + signal: AbortSignal.timeout(3000), + }); + if (res.ok) { + const data = await res.json(); + if (data.status === 'done') return true; + if (data.status === 'error') return false; + } + } catch { } + await new Promise((r) => setTimeout(r, 600)); + } + return false; } export async function getStream(args) { const { id, s, e } = args || {}; + if (!id) return null; + const isTv = s != null && e != null; + const type = isTv ? 'tv' : 'movie'; + const targetUrl = isTv + ? `${BASE_URL}/tv/${id}/${s}/${e}` + : `${BASE_URL}/movie/${id}`; - const mediaPath = isTv - ? `${BASE_URL}/media/tv/${id}/${s}/${e}` - : `${BASE_URL}/media/movie/${id}`; + try { + const res = await fetch(targetUrl, { + headers: HEADERS, + signal: AbortSignal.timeout(args?.config?.timeout || 25000), + }); - await ensureCookies(); + if (!res.ok) return null; - const [mediaData, tokenData] = await Promise.all([ - fetchJson(mediaPath, { headers: withCookies(HEADERS) }).catch(() => null), - fetchJson(`${BASE_URL}/api/get-token`, { headers: withCookies(HEADERS) }).catch(() => null), - ]); + const html = await res.text(); + const allUrls = []; + const seen = new Set(); - const allUrls = []; - const seen = new Set(); + const itemRegex = /