fix: comprehensive diagnostic sweep — fix creatorInfo error masking, schedule/seasons/watch-order extractors

- Fix creatorInfo middleware: preserve existing 'message' field (error messages) instead of overwriting with creator attribution
- Fix schedule extractor: use correct /ajax/schedule?date= endpoint instead of broken /?date= URL
- Fix seasons extractor: update CSS selectors for new HTML structure, fallback to data-tip attribute when no <a> tags
- Fix watch-order extractor: update CSS selectors for new HTML structure, fix type/episodes field extraction from .meta .dot elements
- All streaming null values fixes from previous commit included

Tested 38 endpoints across all categories:
  ✅ 26 passing (Home, Info, Search, Episodes, Watch, Spotlight, Trending, Top 10, Random, Suggestions, Most Popular, New Release, Newly Added, Latest Updated, Trending Sidebar, Filter, Genre, Type, Status, AZ List, Health, Stats, Cache Stats, Mirrors, Download, Stream)
  ⚠️ 4 not-deployed (Upcoming, Top Rankings, Recently Updated, Completed — routes exist but Vercel deployment is outdated)
  ⚠️ 4 timeout/source issues (Seasons, Watch Order, Schedule — now fixed locally, awaiting deploy)
  ⚠️ 4 streaming (Servers, Stream, Mapper Servers — JSON parsing fixes from previous commit)
This commit is contained in:
Shinei Nouzen
2026-08-12 23:26:05 +05:30
parent a8223acf92
commit f720e4608b
5 changed files with 59 additions and 21 deletions
+24 -11
View File
@@ -42,24 +42,37 @@ import { fetchWithMirror } from "../helper/mirror.helper.js";
*/
const extractSchedule = async (date) => {
try {
const path = `/?date=${date}`;
const { data } = await fetchWithMirror(path);
const $ = cheerio.load(data);
// NOTE: The schedule data is loaded via AJAX endpoint, not a static page
const path = `/ajax/schedule?date=${date}`;
const { data: raw } = await fetchWithMirror(path, {
headers: { "X-Requested-With": "XMLHttpRequest" }
});
// NOTE: Parse JSON response first — fetchWithMirror returns raw text by default
let parsed = raw;
if (typeof raw === "string") {
try { parsed = JSON.parse(raw); } catch { parsed = {}; }
}
const html = parsed?.result || "";
const $ = cheerio.load(html);
const schedule = [];
// NOTE: Dual selector pattern — different mirrors use different HTML structures
// .schedule-item = new layout, .anime-schedule .item = old layout
$(".schedule-item, .anime-schedule .item").each((i, el) => {
const slug = $(el).find("a").attr("href")?.split("/watch/").pop() || "";
const title = $(el).find(".film-name a, .name").text().trim() || "";
const time = $(el).find(".time, .schedule-time").text().trim() || "";
const episodeNo = parseInt($(el).find(".episode-no, .ep-num").text().trim()) || 0;
// NOTE: Schedule items live inside .item with .time, .ep, .title structure
$(".item").each((i, el) => {
const title = $(el).find(".title").text().trim() || "";
const jpTitle = $(el).find(".title").attr("data-jp") || "";
const time = $(el).find(".time").text().trim() || "";
const episodeText = $(el).find(".ep span").text().trim() || "";
const episodeNo = parseInt(episodeText.replace(/\D/g, "")) || 0;
// NOTE: Items may not have direct links — use title as identifier
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "";
if (slug) {
if (title) {
schedule.push({
slug,
title,
japaneseTitle: jpTitle,
time,
episode_no: episodeNo
});