fix: add cookie-aware session establishment for stream AJAX endpoints

Root cause: upstream /ajax/server and /ajax/server/list endpoints require
session cookies set by visiting the watch page. fetchWithMirror() didn't
persist cookies between requests, causing upstream to return 500.

- Extract cookies from set-cookie headers when fetching watch/home page
- Pass cookies with AJAX requests for stream info and server list
- Accept optional slug query param in /api/stream for targeted session
- Both extractors now use cookie-aware axios for session establishment
This commit is contained in:
Shinei Nouzen
2026-08-14 06:59:17 +05:30
parent 320bf0915b
commit 75199d4dcd
3 changed files with 82 additions and 14 deletions
+75 -7
View File
@@ -16,10 +16,11 @@
* ======= • ======= • ======= • ======= • =======• =======
*/
import axios from "axios";
import * as cheerio from "cheerio";
import { headers } from "../configs/header.config.js";
import { BASE_URL } from "../configs/dataUrl.js";
import { fetchWithMirror } from "../helper/mirror.helper.js";
import { fetchWithMirror, getWorkingMirror } from "../helper/mirror.helper.js";
import { normalizeServerName } from "./streamResolver.extractor.js";
// ══════════════════════════════════════════════════════════════
@@ -43,14 +44,48 @@ import { normalizeServerName } from "./streamResolver.extractor.js";
*/
const extractStreamInfo = async (linkId, watchSlug = null) => {
try {
// NOTE: Establish session by visiting watch page first (required for AJAX endpoints)
// NOTE: Establish session with cookies — AJAX endpoints require session cookies
const mirror = await getWorkingMirror();
let cookieHeader = "";
if (watchSlug) {
await fetchWithMirror(`/watch/${watchSlug}`);
try {
const sessionRes = await axios.get(`${mirror}/watch/${watchSlug}`, {
headers,
timeout: 10000,
maxRedirects: 5,
});
const setCookies = sessionRes.headers["set-cookie"];
if (Array.isArray(setCookies)) {
cookieHeader = setCookies.map(c => c.split(";")[0]).join("; ");
}
} catch { /* session establishment is best-effort */ }
}
// NOTE: Fallback — if no slug provided, try fetching any page to get session cookies
if (!cookieHeader) {
try {
const fallbackRes = await axios.get(`${mirror}/home`, {
headers,
timeout: 10000,
maxRedirects: 5,
});
const setCookies = fallbackRes.headers["set-cookie"];
if (Array.isArray(setCookies)) {
cookieHeader = setCookies.map(c => c.split(";")[0]).join("; ");
}
} catch { /* fallback is best-effort */ }
}
const path = `/ajax/server?get=${linkId}`;
const requestHeaders = {
...headers,
"X-Requested-With": "XMLHttpRequest",
...(cookieHeader ? { "Cookie": cookieHeader } : {}),
};
const { data: raw } = await fetchWithMirror(path, {
headers: { "X-Requested-With": "XMLHttpRequest" }
headers: requestHeaders
});
// NOTE: Handle both string JSON and parsed object responses
@@ -116,14 +151,47 @@ const extractStreamInfo = async (linkId, watchSlug = null) => {
*/
const extractServerList = async (episodeIds, watchSlug = null) => {
try {
// NOTE: Establish session by visiting watch page first (required for AJAX endpoints)
// NOTE: Establish session with cookies — AJAX endpoints require session cookies
const mirror = await getWorkingMirror();
let cookieHeader = "";
if (watchSlug) {
await fetchWithMirror(`/watch/${watchSlug}`);
try {
const sessionRes = await axios.get(`${mirror}/watch/${watchSlug}`, {
headers,
timeout: 10000,
maxRedirects: 5,
});
const setCookies = sessionRes.headers["set-cookie"];
if (Array.isArray(setCookies)) {
cookieHeader = setCookies.map(c => c.split(";")[0]).join("; ");
}
} catch { /* session establishment is best-effort */ }
}
if (!cookieHeader) {
try {
const fallbackRes = await axios.get(`${mirror}/home`, {
headers,
timeout: 10000,
maxRedirects: 5,
});
const setCookies = fallbackRes.headers["set-cookie"];
if (Array.isArray(setCookies)) {
cookieHeader = setCookies.map(c => c.split(";")[0]).join("; ");
}
} catch { /* fallback is best-effort */ }
}
const path = `/ajax/server/list?servers=${episodeIds}`;
const requestHeaders = {
...headers,
"X-Requested-With": "XMLHttpRequest",
...(cookieHeader ? { "Cookie": cookieHeader } : {}),
};
const { data: raw } = await fetchWithMirror(path, {
headers: { "X-Requested-With": "XMLHttpRequest" }
headers: requestHeaders
});
// NOTE: Parse JSON response first — fetchWithMirror returns raw text by default