fix: store original base64 rawPipeId in deepTranslate + use decoded id in getWatchSources

This commit is contained in:
Sʜɪɴᴇɪ Nᴏᴜᴢᴇɴ
2026-06-25 04:10:34 +05:30
parent f7b3e32cb7
commit 90b0999d7d
+18 -13
View File
@@ -116,15 +116,20 @@ const translateId = (encodedId) => {
// ---- FEATURE: Recursively decode all base64 IDs in a nested object ---- // ---- FEATURE: Recursively decode all base64 IDs in a nested object ----
/** /**
* Walks a JSON structure and decodes any base64 "id" fields. * Walks a JSON structure and decodes any base64 "id" fields.
* Handles nested objects and arrays of objects. * Saves the original base64 value in a `rawPipeId` field on episode objects
* so the pipe sources endpoint can be called directly from the client.
* *
* @param {object|Array} obj - The object or array to process * @param {object|Array} obj - The object or process
* @returns {object|Array} The same object with decoded IDs (mutated in place) * @returns {object|Array} The same object with decoded IDs (mutated in place)
*/ */
const deepTranslate = (obj) => { const deepTranslate = (obj) => {
if (obj && typeof obj === "object") { if (obj && typeof obj === "object") {
for (const key of Object.keys(obj)) { for (const key of Object.keys(obj)) {
if (key === "id" && typeof obj[key] === "string") { if (key === "id" && typeof obj[key] === "string") {
// NOTE: Save original base64 before decoding (needed for pipe sources call)
if (obj.number !== undefined) {
obj.rawPipeId = obj[key];
}
obj[key] = translateId(obj[key]); obj[key] = translateId(obj[key]);
} else if (typeof obj[key] === "object") { } else if (typeof obj[key] === "object") {
deepTranslate(obj[key]); deepTranslate(obj[key]);
@@ -173,11 +178,9 @@ const injectSourceSlugs = (data, anilistId) => {
for (const ep of epList) { for (const ep of epList) {
if (ep.id && ep.number) { if (ep.id && ep.number) {
const origId = ep.id; // NOTE: rawPipeId is already set by deepTranslate — preserve original base64
// NOTE: Preserve the raw pipe ID so getWatchSources can resolve it later // Take only the prefix before ":" for the slug
ep.rawPipeId = origId; const prefix = ep.id.includes(":") ? ep.id.split(":")[0] : ep.id;
// NOTE: Take only the prefix before ":" for the slug
const prefix = origId.includes(":") ? origId.split(":")[0] : origId;
ep.id = `watch/${provName}/${anilistId}/${category}/${prefix}-${ep.number}`; ep.id = `watch/${provName}/${anilistId}/${category}/${prefix}-${ep.number}`;
} }
} }
@@ -306,16 +309,18 @@ const getWatchSources = async (provider, anilistId, category, slug) => {
const episodes = provData.episodes?.[category] || []; const episodes = provData.episodes?.[category] || [];
let targetId = null; let targetId = null;
// NOTE: Match slug against the tail of the episode ID (e.g. "animedao-1") // NOTE: fetchRawEpisodes returns raw pipe IDs (e.g. "animedao:cowboy-bebop:1")
// Build the slug from the prefix and episode number to match against the URL slug
for (const ep of episodes) { for (const ep of episodes) {
if (ep.id) { const origId = ep.id || "";
const epSlug = ep.id.split("/").pop(); const prefix = origId.includes(":") ? origId.split(":")[0] : origId;
if (epSlug === slug && ep.rawPipeId) { const generated = `${prefix}-${ep.number}`;
targetId = ep.rawPipeId;
if (generated === slug) {
targetId = ep.id; // getSources expects decoded ID, it will base64url-encode
break; break;
} }
} }
}
if (!targetId) throw new Error(`Episode slug '${slug}' not found for provider ${provider}`); if (!targetId) throw new Error(`Episode slug '${slug}' not found for provider ${provider}`);
return getSources(targetId, provider, anilistId, category); return getSources(targetId, provider, anilistId, category);