This commit is contained in:
+56
-31
@@ -26,7 +26,11 @@ function _wrapImage(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _safeJsonParse(s, fallback) {
|
function _safeJsonParse(s, fallback) {
|
||||||
try { return JSON.parse(s); } catch (_) { return fallback; }
|
try {
|
||||||
|
return JSON.parse(s);
|
||||||
|
} catch (_) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function scoreTitle(title, keyword) {
|
function scoreTitle(title, keyword) {
|
||||||
@@ -68,6 +72,7 @@ function _dubbingRank(name) {
|
|||||||
function _pack(obj) {
|
function _pack(obj) {
|
||||||
return "yummy:" + encodeURIComponent(JSON.stringify(obj || {}));
|
return "yummy:" + encodeURIComponent(JSON.stringify(obj || {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function _unpack(href) {
|
function _unpack(href) {
|
||||||
const s = String(href || "");
|
const s = String(href || "");
|
||||||
if (!s.startsWith("yummy:")) return null;
|
if (!s.startsWith("yummy:")) return null;
|
||||||
@@ -168,11 +173,15 @@ async function extractEpisodes(animeIdOrUrl) {
|
|||||||
|
|
||||||
const vids = Array.isArray(json?.response) ? json.response : [];
|
const vids = Array.isArray(json?.response) ? json.response : [];
|
||||||
|
|
||||||
// Keep only Kodik entries (we parse kodik)
|
// Keep only Kodik entries (we parse Kodik)
|
||||||
const kodikVids = vids.filter(v => {
|
const kodikVids = vids.filter(v => {
|
||||||
const iframe = String(v?.iframe_url || "");
|
const iframe = String(v?.iframe_url || "");
|
||||||
const player = String(v?.data?.player || "");
|
const player = String(v?.data?.player || "").toLowerCase();
|
||||||
return iframe.includes("kodik.info") || player.toLowerCase().includes("kodik");
|
return (
|
||||||
|
iframe.includes("kodik.info") ||
|
||||||
|
iframe.includes("kodikplayer.com") ||
|
||||||
|
player.includes("kodik")
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Group by episode number
|
// Group by episode number
|
||||||
@@ -202,7 +211,6 @@ async function extractEpisodes(animeIdOrUrl) {
|
|||||||
? { start: v.skips.ending.time, stop: v.skips.ending.time + v.skips.ending.length }
|
? { start: v.skips.ending.time, stop: v.skips.ending.time + v.skips.ending.length }
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
// raw timecode format (time + length)
|
|
||||||
const skips =
|
const skips =
|
||||||
(v?.skips?.opening && Number.isFinite(v.skips.opening.time) && Number.isFinite(v.skips.opening.length)) ||
|
(v?.skips?.opening && Number.isFinite(v.skips.opening.time) && Number.isFinite(v.skips.opening.length)) ||
|
||||||
(v?.skips?.ending && Number.isFinite(v.skips.ending.time) && Number.isFinite(v.skips.ending.length))
|
(v?.skips?.ending && Number.isFinite(v.skips.ending.time) && Number.isFinite(v.skips.ending.length))
|
||||||
@@ -230,12 +238,9 @@ async function extractEpisodes(animeIdOrUrl) {
|
|||||||
|
|
||||||
const ep = byNum.get(num);
|
const ep = byNum.get(num);
|
||||||
|
|
||||||
// Save first available skips/duration
|
|
||||||
if (!ep.opening && opening) ep.opening = opening;
|
if (!ep.opening && opening) ep.opening = opening;
|
||||||
if (!ep.ending && ending) ep.ending = ending;
|
if (!ep.ending && ending) ep.ending = ending;
|
||||||
if (!ep.duration && duration) ep.duration = duration;
|
if (!ep.duration && duration) ep.duration = duration;
|
||||||
|
|
||||||
// keep first raw skips object if present
|
|
||||||
if (!ep.skips && skips) ep.skips = skips;
|
if (!ep.skips && skips) ep.skips = skips;
|
||||||
|
|
||||||
ep.options.push({
|
ep.options.push({
|
||||||
@@ -250,7 +255,6 @@ async function extractEpisodes(animeIdOrUrl) {
|
|||||||
const out = Array.from(byNum.values())
|
const out = Array.from(byNum.values())
|
||||||
.sort((a, b) => a.num - b.num)
|
.sort((a, b) => a.num - b.num)
|
||||||
.map(ep => {
|
.map(ep => {
|
||||||
// sort voiceovers
|
|
||||||
ep.options.sort((x, y) => _dubbingRank(x.dubbing) - _dubbingRank(y.dubbing));
|
ep.options.sort((x, y) => _dubbingRank(x.dubbing) - _dubbingRank(y.dubbing));
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -265,21 +269,19 @@ async function extractEpisodes(animeIdOrUrl) {
|
|||||||
title: `Episode ${ep.num}`
|
title: `Episode ${ep.num}`
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use skips from the first (sorted) voiceover option
|
|
||||||
const primary = ep.options[0];
|
const primary = ep.options[0];
|
||||||
if (primary?.opening) item.opening = primary.opening;
|
if (primary?.opening) item.opening = primary.opening;
|
||||||
if (primary?.ending) item.ending = primary.ending;
|
if (primary?.ending) item.ending = primary.ending;
|
||||||
|
|
||||||
// raw timecodes (time + length)
|
|
||||||
if (ep.skips) item.skips = ep.skips;
|
if (ep.skips) item.skips = ep.skips;
|
||||||
|
|
||||||
if (ep.duration) item.duration = ep.duration;
|
if (ep.duration) item.duration = ep.duration;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
|
||||||
return JSON.stringify(out);
|
return JSON.stringify(out);
|
||||||
} catch (_) {
|
} catch (err) {
|
||||||
|
console.log("extractEpisodes error:", err?.message || err);
|
||||||
return JSON.stringify([]);
|
return JSON.stringify([]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,7 +303,12 @@ async function extractStreamUrl(href) {
|
|||||||
|
|
||||||
for (const opt of options) {
|
for (const opt of options) {
|
||||||
const iframeUrl = _absUrl(opt?.iframe_url);
|
const iframeUrl = _absUrl(opt?.iframe_url);
|
||||||
if (!iframeUrl || !iframeUrl.includes("kodik.info")) continue;
|
if (
|
||||||
|
!iframeUrl ||
|
||||||
|
(!iframeUrl.includes("kodik.info") && !iframeUrl.includes("kodikplayer.com"))
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const qualitiesJson = await kodikParser(iframeUrl);
|
const qualitiesJson = await kodikParser(iframeUrl);
|
||||||
const qualities = _safeJsonParse(qualitiesJson, {});
|
const qualities = _safeJsonParse(qualitiesJson, {});
|
||||||
@@ -327,7 +334,7 @@ async function extractStreamUrl(href) {
|
|||||||
streamUrl: finalUrl,
|
streamUrl: finalUrl,
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": _ua(),
|
"User-Agent": _ua(),
|
||||||
"Referer": "https://kodik.info/"
|
"Referer": IMAGE_REFERER
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -336,7 +343,8 @@ async function extractStreamUrl(href) {
|
|||||||
streams,
|
streams,
|
||||||
subtitle: "https://none.com"
|
subtitle: "https://none.com"
|
||||||
});
|
});
|
||||||
} catch (_) {
|
} catch (err) {
|
||||||
|
console.log("extractStreamUrl error:", err?.message || err);
|
||||||
return JSON.stringify({ streams: [], subtitle: "https://none.com" });
|
return JSON.stringify({ streams: [], subtitle: "https://none.com" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,6 +356,7 @@ async function kodikParser(url) {
|
|||||||
"Referer": IMAGE_REFERER,
|
"Referer": IMAGE_REFERER,
|
||||||
"User-Agent": _ua()
|
"User-Agent": _ua()
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetchv2(url, headers);
|
const response = await fetchv2(url, headers);
|
||||||
const htmlText = await response.text();
|
const htmlText = await response.text();
|
||||||
|
|
||||||
@@ -362,23 +371,28 @@ async function kodikParser(url) {
|
|||||||
const videoInfo_id = videoInfoIdMatch ? videoInfoIdMatch[1] : "";
|
const videoInfo_id = videoInfoIdMatch ? videoInfoIdMatch[1] : "";
|
||||||
|
|
||||||
const finalData =
|
const finalData =
|
||||||
`d=${urlParams.d}` +
|
`d=${urlParams.d || ""}` +
|
||||||
`&d_sign=${urlParams.d_sign}` +
|
`&d_sign=${urlParams.d_sign || ""}` +
|
||||||
`&pd=${urlParams.pd}` +
|
`&pd=${urlParams.pd || ""}` +
|
||||||
`&pd_sign=${urlParams.pd_sign}` +
|
`&pd_sign=${urlParams.pd_sign || ""}` +
|
||||||
`&ref=${urlParams.ref}` +
|
`&ref=${urlParams.ref || ""}` +
|
||||||
`&ref_sign=${urlParams.ref_sign}` +
|
`&ref_sign=${urlParams.ref_sign || ""}` +
|
||||||
`&bad_user=false&cdn_is_working=false` +
|
`&bad_user=false&cdn_is_working=true` +
|
||||||
`&type=${videoInfo_type}&hash=${videoInfo_hash}&id=${videoInfo_id}&info=%7B%7D`;
|
`&type=${videoInfo_type}&hash=${videoInfo_hash}&id=${videoInfo_id}&info=%7B%7D`;
|
||||||
|
|
||||||
const headers2 = {
|
const headers2 = {
|
||||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
"Referer": "https://kodik.info",
|
"Referer": IMAGE_REFERER,
|
||||||
"User-Agent": _ua(),
|
"User-Agent": _ua(),
|
||||||
"X-Requested-With": "XMLHttpRequest"
|
"X-Requested-With": "XMLHttpRequest"
|
||||||
};
|
};
|
||||||
|
|
||||||
const apiResponse = await fetchv2("https://kodik.info/ftor", headers2, "POST", finalData);
|
const apiResponse = await fetchv2(
|
||||||
|
"https://kodikplayer.com/ftor",
|
||||||
|
headers2,
|
||||||
|
"POST",
|
||||||
|
finalData
|
||||||
|
);
|
||||||
const apiJson = await apiResponse.json();
|
const apiJson = await apiResponse.json();
|
||||||
|
|
||||||
const qualities = {};
|
const qualities = {};
|
||||||
@@ -396,7 +410,8 @@ async function kodikParser(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return JSON.stringify(qualities, null, 2);
|
return JSON.stringify(qualities, null, 2);
|
||||||
} catch (_) {
|
} catch (err) {
|
||||||
|
console.log("kodikParser error:", err?.message || err);
|
||||||
return JSON.stringify({ error: "kodik_parse_failed" });
|
return JSON.stringify({ error: "kodik_parse_failed" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,7 +421,6 @@ function decode(input) {
|
|||||||
const map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
const map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
let out = "", b = 0, c = 0;
|
let out = "", b = 0, c = 0;
|
||||||
|
|
||||||
// ROT +18 letters
|
|
||||||
const r = [];
|
const r = [];
|
||||||
for (let i = 0; i < input.length; i++) {
|
for (let i = 0; i < input.length; i++) {
|
||||||
const ch = input[i];
|
const ch = input[i];
|
||||||
@@ -415,7 +429,9 @@ function decode(input) {
|
|||||||
const max = ch <= "Z" ? 90 : 122;
|
const max = ch <= "Z" ? 90 : 122;
|
||||||
const sh = cc + 18;
|
const sh = cc + 18;
|
||||||
r.push(String.fromCharCode(sh <= max ? sh : sh - 26));
|
r.push(String.fromCharCode(sh <= max ? sh : sh - 26));
|
||||||
} else r.push(ch);
|
} else {
|
||||||
|
r.push(ch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const rot = r.join("");
|
const rot = r.join("");
|
||||||
@@ -446,6 +462,15 @@ function _defaultExport() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try { globalThis.default = _defaultExport; } catch (_) {}
|
try {
|
||||||
try { this.default = _defaultExport; } catch (_) {}
|
globalThis.default = _defaultExport;
|
||||||
try { globalThis.module = globalThis.module || {}; globalThis.module.exports = { default: _defaultExport }; } catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.default = _defaultExport;
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
globalThis.module = globalThis.module || {};
|
||||||
|
globalThis.module.exports = { default: _defaultExport };
|
||||||
|
} catch (_) {}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
"name": "emp0ry",
|
"name": "emp0ry",
|
||||||
"icon": "https://avatars.githubusercontent.com/u/64217088"
|
"icon": "https://avatars.githubusercontent.com/u/64217088"
|
||||||
},
|
},
|
||||||
"version": "1.0.2",
|
"version": "1.0.3",
|
||||||
"language": "Russian",
|
"language": "Russian",
|
||||||
"streamType": "HLS",
|
"streamType": "HLS",
|
||||||
"quality": "1080p",
|
"quality": "1080p",
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"type": "anime",
|
"type": "anime",
|
||||||
"downloadSupport": false,
|
"downloadSupport": false,
|
||||||
"supportsMojuru": true,
|
"supportsMojuru": true,
|
||||||
|
"supportsDartotsu": true,
|
||||||
"supportsSora": true,
|
"supportsSora": true,
|
||||||
"supportsLuna": true
|
"supportsLuna": true
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user