feature, not a bug

This commit is contained in:
Tejas Panchal
2026-03-01 12:39:28 +05:30
commit a6184c63d4
91 changed files with 6797 additions and 0 deletions

2
src/configs/dataUrl.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
export const DEFAULT_HEADERS = {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
};

View File

@@ -0,0 +1,2 @@
export const PLAYER_SCRIPT_URL =
"https://megacloud.club/js/player/a/e1-player.min.js";

View File

@@ -0,0 +1,2 @@
export const PLAYER_SCRIPT_URL =
"https://rapid-cloud.co/js/player/prod/e6-player-v2.min.js";

View File

@@ -0,0 +1,20 @@
import extractVoiceActor from "../extractors/actors.extractor.js";
const getVoiceActor = async (req, res) => {
const id = req.params.id;
try {
const voiceActorData = await extractVoiceActor(id);
// Ensure the data is structured correctly
if (!voiceActorData || voiceActorData.results.data.length === 0) {
return res.status(404).json({ error: "No voice actor found." });
}
return res.json(voiceActorData); // Return the desired structure
} catch (e) {
console.error(e);
return res.status(500).json({ error: "An error occurred" });
}
};
export default getVoiceActor;

View File

@@ -0,0 +1,27 @@
import extractAnimeInfo from "../extractors/animeInfo.extractor.js";
import extractSeasons from "../extractors/seasons.extractor.js";
import { getCachedData, setCachedData } from "../helper/cache.helper.js";
export const getAnimeInfo = async (req, res) => {
const { id } = req.query;
// const cacheKey = `animeInfo_${id}`;
try {
// const cachedResponse = await getCachedData(cacheKey);
// if (cachedResponse && Object.keys(cachedResponse).length > 0) {
// return cachedResponse;
// }
const [seasons, data] = await Promise.all([
extractSeasons(id),
extractAnimeInfo(id),
]);
const responseData = { data: data, seasons: seasons };
// setCachedData(cacheKey, responseData).catch((err) => {
// console.error("Failed to set cache:", err);
// });
return responseData;
} catch (e) {
console.error(e);
return res.status(500).json({ error: "An error occurred" });
}
};

View File

@@ -0,0 +1,29 @@
import { extractor } from "../extractors/category.extractor.js";
import { getCachedData, setCachedData } from "../helper/cache.helper.js";
export const getCategory = async (req, res, routeType) => {
if (routeType === "genre/martial-arts") {
routeType = "genre/marial-arts";
}
const requestedPage = parseInt(req.query.page) || 1;
// const cacheKey = `${routeType.replace(/\//g, "_")}_page_${requestedPage}`;
try {
// const cachedResponse = await getCachedData(cacheKey);
// if (cachedResponse && Object.keys(cachedResponse).length > 0)
// return cachedResponse;
const { data, totalPages } = await extractor(routeType, requestedPage);
if (requestedPage > totalPages) {
const error = new Error("Requested page exceeds total available pages.");
error.status = 404;
throw error;
}
const responseData = { totalPages: totalPages, data: data };
// setCachedData(cacheKey, responseData).catch((err) => {
// console.error("Failed to set cache:", err);
// });
return responseData;
} catch (e) {
console.error(e);
return e;
}
};

View File

@@ -0,0 +1,20 @@
import extractCharacter from "../extractors/characters.extractor.js";
const getCharacter = async (req, res) => {
const id = req.params.id;
try {
const characterData = await extractCharacter(id);
// Ensure the data is structured correctly
if (!characterData || characterData.results.data.length === 0) {
return res.status(404).json({ error: "Character not found." });
}
return res.json(characterData); // Return the desired structure
} catch (e) {
console.error(e);
return res.status(500).json({ error: "An error occurred" });
}
};
export default getCharacter;

View File

@@ -0,0 +1,21 @@
import extractEpisodesList from "../extractors/episodeList.extractor.js";
import { getCachedData, setCachedData } from "../helper/cache.helper.js";
export const getEpisodes = async (req,res) => {
const { id } = req.params;
// const cacheKey = `episodes_${id}`;
try {
// const cachedResponse = await getCachedData(cacheKey);
// if (cachedResponse && Object.keys(cachedResponse).length > 0) {
// return cachedResponse;
// }
const data = await extractEpisodesList(encodeURIComponent(id));
// setCachedData(cacheKey, data).catch((err) => {
// console.error("Failed to set cache:", err);
// });
return data;
} catch (e) {
console.error("Error fetching episodes:", e);
return e;
}
};

View File

@@ -0,0 +1,66 @@
import extractFilterResults from "../extractors/filter.extractor.js";
export const filter = async (req) => {
try {
// Extract all possible query parameters
const {
type,
status,
rated,
score,
season,
language,
genres,
sort,
sy, // Start year
sm, // Start month
sd, // Start day
ey, // End year
em, // End month
ed, // End day
keyword,
page = 1
} = req.query;
// Convert page to number
const pageNum = parseInt(page);
// Create params object only with provided values
const params = {};
if (type) params.type = type;
if (status) params.status = status;
if (rated) params.rated = rated;
if (score) params.score = score;
if (season) params.season = season;
if (language) params.language = language;
if (genres) params.genres = genres;
if (sort) params.sort = sort;
if (sy) params.sy = sy;
if (sm) params.sm = sm;
if (sd) params.sd = sd;
if (ey) params.ey = ey;
if (em) params.em = em;
if (ed) params.ed = ed;
if (keyword) params.keyword = keyword;
if (pageNum > 1) params.page = pageNum;
// Log params for debugging
// console.log("Controller params:", params);
const [totalPage, data, currentPage, hasNextPage] = await extractFilterResults(params);
if (pageNum > totalPage) {
const error = new Error("Requested page exceeds total available pages.");
error.status = 404;
throw error;
}
return { data, totalPage, currentPage, hasNextPage };
} catch (e) {
console.error(e);
if (e.status === 404) {
throw e;
}
throw new Error("An error occurred while processing your request.");
}
};

View File

@@ -0,0 +1,68 @@
import getSpotlights from "../extractors/spotlight.extractor.js";
import getTrending from "../extractors/trending.extractor.js";
import extractPage from "../helper/extractPages.helper.js";
import extractTopTen from "../extractors/topten.extractor.js";
import { routeTypes } from "../routes/category.route.js";
import extractSchedule from "../extractors/schedule.extractor.js";
import { getCachedData, setCachedData } from "../helper/cache.helper.js";
const genres = routeTypes
.slice(0, 41)
.map((genre) => genre.replace("genre/", ""));
export const getHomeInfo = async (req,res) => {
// const cacheKey = "homeInfo";
try {
// const cachedResponse = await getCachedData(cacheKey);
// if (cachedResponse && Object.keys(cachedResponse).length > 0) {
// return cachedResponse;
// }
const [
spotlights,
trending,
topTen,
schedule,
topAiring,
mostPopular,
mostFavorite,
latestCompleted,
latestEpisode,
topUpcoming,
recentlyAdded,
] = await Promise.all([
getSpotlights(),
getTrending(),
extractTopTen(),
extractSchedule(new Date().toISOString().split("T")[0]),
extractPage(1, "top-airing"),
extractPage(1, "most-popular"),
extractPage(1, "most-favorite"),
extractPage(1, "completed"),
extractPage(1, "recently-updated"),
extractPage(1, "top-upcoming"),
extractPage(1, "recently-added"),
]);
const responseData = {
spotlights,
trending,
topTen,
today: { schedule },
topAiring: topAiring[0],
mostPopular: mostPopular[0],
mostFavorite: mostFavorite[0],
latestCompleted: latestCompleted[0],
latestEpisode: latestEpisode[0],
topUpcoming: topUpcoming[0],
recentlyAdded: recentlyAdded[0],
genres,
};
// setCachedData(cacheKey, responseData).catch((err) => {
// console.error("Failed to set cache:", err);
// });
return responseData;
} catch (fetchError) {
console.error("Error fetching fresh data:", fetchError);
return fetchError;
}
};

View File

@@ -0,0 +1,12 @@
import extractNextEpisodeSchedule from "../extractors/getNextEpisodeSchedule.extractor.js";
export const getNextEpisodeSchedule = async (req) => {
const { id } = req.params;
try {
const nextEpisodeSchedule = await extractNextEpisodeSchedule(id);
return { nextEpisodeSchedule: nextEpisodeSchedule };
} catch (e) {
console.error(e);
return e;
}
};

View File

@@ -0,0 +1,32 @@
import { getCachedData, setCachedData } from "../helper/cache.helper.js";
import extractPage from "../helper/extractPages.helper.js";
export const getProducer = async (req) => {
const { id } = req.params;
const routeType = `producer/${id}`;
const requestedPage = parseInt(req.query.page) || 1;
// const cacheKey = `${routeType.replace(/\//g, "_")}_page_${requestedPage}`;
try {
// const cachedResponse = await getCachedData(cacheKey);
// if (cachedResponse && Object.keys(cachedResponse).length > 0) {
// return cachedResponse;
// }
const [data, totalPages] = await extractPage(requestedPage, routeType);
if (requestedPage > totalPages) {
const error = new Error("Requested page exceeds total available pages.");
error.status = 404;
throw error;
}
const responseData = { totalPages: totalPages, data: data };
// setCachedData(cacheKey, responseData).catch((err) => {
// console.error("Failed to set cache:", err);
// });
return { data, totalPages };
} catch (e) {
console.error(e);
if (e.status === 404) {
throw e;
}
throw new Error("An error occurred while processing your request.");
}
};

View File

@@ -0,0 +1,12 @@
import extractQtip from "../extractors/qtip.extractor.js";
export const getQtip = async (req) => {
try {
const { id } = req.params;
const data = await extractQtip(id);
return data;
} catch (e) {
console.error(e);
return e;
}
};

View File

@@ -0,0 +1,11 @@
import extractRandom from "../extractors/random.extractor.js";
export const getRandom = async (req,res) => {
try {
const data = await extractRandom();
return data;
} catch (error) {
console.error("Error getting random anime:", error.message);
return e;
}
};

View File

@@ -0,0 +1,11 @@
import extractRandomId from "../extractors/randomId.extractor.js";
export const getRandomId = async (req,res) => {
try {
const data = await extractRandomId();
return data;
} catch (error) {
console.error("Error getting random anime ID:", error.message);
return e;
}
};

View File

@@ -0,0 +1,13 @@
import extractSchedule from "../extractors/schedule.extractor.js";
export const getSchedule = async (req) => {
const date = req.query.date;
const tzOffset = req.query.tzOffset || -330;
try {
const data = await extractSchedule(date, tzOffset);
return data;
} catch (e) {
console.error(e);
return e;
}
};

View File

@@ -0,0 +1,43 @@
import extractSearchResults from "../extractors/search.extractor.js";
import convertForeignLanguage from "../helper/foreignInput.helper.js";
export const search = async (req) => {
try {
let { keyword, type, status, rated, score, season, language, genres, sort, sy, sm, sd, ey, em, ed } = req.query;
let page = parseInt(req.query.page) || 1;
// Check if the search keyword is in a foreign language and if it can be converted
keyword = await convertForeignLanguage(keyword);
const [totalPage, data] = await extractSearchResults({
keyword: keyword,
type: type,
status: status,
rated: rated,
score: score,
season: season,
language: language,
genres: genres,
sort: sort,
page: page,
sy: sy,
sm: sm,
sd: sd,
ey: ey,
em: em,
ed: ed,
});
if (page > totalPage) {
const error = new Error("Requested page exceeds total available pages.");
error.status = 404;
throw error;
}
return { data, totalPage };
} catch (e) {
console.error(e);
if (e.status === 404) {
throw e;
}
throw new Error("An error occurred while processing your request.");
}
};

View File

@@ -0,0 +1,12 @@
import { extractServers } from "../extractors/streamInfo.extractor.js";
export const getServers = async (req) => {
try {
const { ep } = req.query;
const servers = await extractServers(ep);
return servers;
} catch (e) {
console.error(e);
return e;
}
};

View File

@@ -0,0 +1,17 @@
import { extractStreamingInfo } from "../extractors/streamInfo.extractor.js";
export const getStreamInfo = async (req, res, fallback = false) => {
try {
const input = req.query.id;
const server = req.query.server;
const type = req.query.type;
const match = input.match(/ep=(\d+)/);
if (!match) throw new Error("Invalid URL format");
const finalId = match[1];
const streamingInfo = await extractStreamingInfo(finalId, server, type, fallback);
return streamingInfo;
} catch (e) {
console.error(e);
return { error: e.message };
}
};

View File

@@ -0,0 +1,17 @@
import getSuggestion from "../extractors/suggestion.extractor.js";
import convertForeignLanguage from "../helper/foreignInput.helper.js";
export const getSuggestions = async (req) => {
let { keyword } = req.query;
// Check if the search keyword is in a foreign language and if it can be converted
keyword = await convertForeignLanguage(keyword);
try {
const data = await getSuggestion(encodeURIComponent(keyword));
return data;
} catch (e) {
console.error(e);
return e;
}
};

View File

@@ -0,0 +1,13 @@
import extractTopSearch from "../extractors/topsearch.extractor.js";
const getTopSearch = async () => {
try {
const data = await extractTopSearch();
return data;
} catch (e) {
console.error(e);
return e;
}
};
export default getTopSearch;

View File

@@ -0,0 +1,22 @@
import extractTopTen from "../extractors/topten.extractor.js";
import { getCachedData, setCachedData } from "../helper/cache.helper.js";
export const getTopTen = async (req,res) => {
// const cacheKey = "topTen";
try {
// const cachedResponse = await getCachedData(cacheKey);
// if (cachedResponse && Object.keys(cachedResponse).length > 0) {
// return cachedResponse;
// }
const topTen = await extractTopTen();
// await setCachedData(cacheKey, topTen).catch((err) => {
// console.error("Failed to set cache:", err);
// });
return topTen;
} catch (e) {
console.error(e);
return c
.status(500)
.json({ success: false, error: "Internal Server Error" });
}
};

View File

@@ -0,0 +1,16 @@
import extractVoiceActor from "../extractors/voiceactor.extractor.js";
export const getVoiceActors = async (req, res) => {
const requestedPage = parseInt(req.query.page) || 1;
const id = req.params.id;
try {
const { totalPages, charactersVoiceActors: data } = await extractVoiceActor(
id,
requestedPage
);
return { currentPage: requestedPage, totalPages, data };
} catch (e) {
console.error(e);
return e;
}
};

View File

@@ -0,0 +1,40 @@
import extractWatchlist from "../extractors/watchlist.extractor.js";
export const getWatchlist = async (req, res) => {
const { userId, page = 1 } = req.params;
try {
const { watchlist, totalPages } = await extractWatchlist(userId, page);
// Restructuring the response
return res.json({
success: true,
results: {
totalPages, // Include total pages in the response
data: watchlist.map(item => ({
id: item.id,
data_id: item.data_id,
poster: item.poster,
title: item.title,
japanese_title: item.japanese_title,
description: item.description,
tvInfo: {
showType: item.tvInfo.showType,
duration: item.tvInfo.duration,
sub: item.tvInfo.sub,
dub: item.tvInfo.dub,
// Include eps if it exists
...(item.tvInfo.eps && { eps: item.tvInfo.eps })
},
adultContent: item.adultContent,
}))
}
});
} catch (error) {
console.error("Error getting watchlist:", error.message);
if (!res.headersSent) {
return res.status(500).json({ error: "An error occurred while fetching the watchlist." });
}
}
};

View File

@@ -0,0 +1,91 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export async function extractVoiceActor(id) {
try {
const response = await axios.get(`https://${v1_base_url}/people/${id}`);
const $ = cheerio.load(response.data);
// Extract basic information
const name = $(".apw-detail .name").text().trim();
const japaneseName = $(".apw-detail .sub-name").text().trim();
// Extract profile image
const profile = $(".avatar-circle img").attr("src"); // Extracting the profile image URL
// Extract about information as a full bio description
const bioText = $("#bio .bio").text().trim();
const bioHtml = $("#bio .bio").html(); // Capture the raw HTML
const about = {
description: bioText, // Store the full bio as a single description
style: bioHtml, // Store the full HTML structure
};
// Extract voice acting roles
const roles = [];
$(".bac-list-wrap .bac-item").each((_, element) => {
const animeElement = $(element).find(".per-info.anime-info.ltr");
const characterElement = $(element).find(".per-info.rtl");
const role = {
anime: {
id: animeElement.find(".pi-name a").attr("href")?.split("/").pop(),
title: animeElement.find(".pi-name a").text().trim(),
poster:
animeElement.find(".pi-avatar img").attr("data-src") ||
animeElement.find(".pi-avatar img").attr("src"),
type: animeElement
.find(".pi-cast")
.text()
.trim()
.split(",")[0]
.trim(),
year: animeElement
.find(".pi-cast")
.text()
.trim()
.split(",")[1]
?.trim(),
},
character: {
id: characterElement
.find(".pi-name a")
.attr("href")
?.split("/")
.pop(),
name: characterElement.find(".pi-name a").text().trim(),
profile:
characterElement.find(".pi-avatar img").attr("data-src") ||
characterElement.find(".pi-avatar img").attr("src"),
role: characterElement.find(".pi-cast").text().trim(),
},
};
roles.push(role);
});
// Construct the final response
const voiceActorData = {
success: true,
results: {
data: [
{
id,
name,
profile,
japaneseName,
about,
roles,
},
],
},
};
return voiceActorData;
} catch (error) {
console.error("Error extracting voice actor data:", error);
throw new Error("Failed to extract voice actor information");
}
}
export default extractVoiceActor;

View File

@@ -0,0 +1,194 @@
import axios from "axios";
import * as cheerio from "cheerio";
import formatTitle from "../helper/formatTitle.helper.js";
import { v1_base_url } from "../utils/base_v1.js";
import extractRecommendedData from "./recommend.extractor.js";
import extractRelatedData from "./related.extractor.js";
import extractPopularData from "./popular.extractor.js";
async function extractAnimeInfo(id) {
try {
const [resp, characterData] = await Promise.all([
axios.get(`https://${v1_base_url}/${id}`),
axios.get(
`https://${v1_base_url}/ajax/character/list/${id.split("-").pop()}`
),
]);
const characterHtml = characterData.data?.html || "";
const $1 = cheerio.load(characterHtml);
const $ = cheerio.load(resp.data);
const data_id = id.split("-").pop();
const titleElement = $("#ani_detail .film-name");
const showType = $("#ani_detail .prebreadcrumb ol li")
.eq(1)
.find("a")
.text()
.trim();
const posterElement = $("#ani_detail .film-poster");
const tvInfoElement = $("#ani_detail .film-stats");
const tvInfo = {};
tvInfoElement.find(".tick-item, span.item").each((_, element) => {
const el = $(element);
const text = el.text().trim();
if (el.hasClass("tick-quality")) tvInfo.quality = text;
else if (el.hasClass("tick-sub")) tvInfo.sub = text;
else if (el.hasClass("tick-dub")) tvInfo.dub = text;
else if (el.hasClass("tick-eps")) tvInfo.eps = text;
else if (el.hasClass("tick-pg")) tvInfo.rating = text;
else if (el.is("span.item")) {
if (!tvInfo.showType) tvInfo.showType = text;
else if (!tvInfo.duration) tvInfo.duration = text;
}
});
const element = $(
"#ani_detail > .ani_detail-stage > .container > .anis-content > .anisc-info-wrap > .anisc-info > .item"
);
const overviewElement = $("#ani_detail .film-description .text");
const title = titleElement.text().trim();
const japanese_title = titleElement.attr("data-jname");
const synonyms = $('.item.item-title:has(.item-head:contains("Synonyms")) .name').text().trim();
const poster = posterElement.find("img").attr("src");
const syncDataScript = $("#syncData").html();
let anilistId = null;
let malId = null;
if (syncDataScript) {
try {
const syncData = JSON.parse(syncDataScript);
anilistId = syncData.anilist_id || null;
malId = syncData.mal_id || null;
} catch (error) {
console.error("Error parsing syncData:", error);
}
}
const animeInfo = {};
element.each((_, el) => {
const key = $(el).find(".item-head").text().trim().replace(":", "");
const value =
key === "Genres" || key === "Producers"
? $(el)
.find("a")
.map((_, a) => $(a).text().split(" ").join("-").trim())
.get()
: $(el).find(".name").text().split(" ").join("-").trim();
animeInfo[key] = value;
});
const trailers = [];
$('.block_area-promotions-list .screen-items .item').each((_, element) => {
const el = $(element);
const title = el.attr('data-title');
const url = el.attr('data-src');
if (url) {
const fullUrl = url.startsWith('//') ? `https:${url}` : url;
let videoId = null;
const match = fullUrl.match(/\/embed\/([^?&]+)/);
if (match && match[1]) {
videoId = match[1];
}
trailers.push({
title: title || null,
url: fullUrl,
thumbnail: videoId ? `https://img.youtube.com/vi/${videoId}/hqdefault.jpg` : null
});
}
});
animeInfo.trailers = trailers;
const season_id = formatTitle(title, data_id);
animeInfo["Overview"] = overviewElement.text().trim();
animeInfo["tvInfo"] = tvInfo;
let adultContent = false;
const tickRateText = $(".tick-rate", posterElement).text().trim();
if (tickRateText.includes("18+")) {
adultContent = true;
}
const [recommended_data, related_data, popular_data] = await Promise.all([
extractRecommendedData($),
extractRelatedData($),
extractPopularData($),
]);
let charactersVoiceActors = [];
if (characterHtml) {
charactersVoiceActors = $1(".bac-list-wrap .bac-item")
.map((index, el) => {
const character = {
id:
$1(el)
.find(".per-info.ltr .pi-avatar")
.attr("href")
?.split("/")[2] || "",
poster:
$1(el).find(".per-info.ltr .pi-avatar img").attr("data-src") ||
"",
name: $1(el).find(".per-info.ltr .pi-detail a").text(),
cast: $1(el).find(".per-info.ltr .pi-detail .pi-cast").text(),
};
let voiceActors = [];
const rtlVoiceActors = $1(el).find(".per-info.rtl");
const xxVoiceActors = $1(el).find(
".per-info.per-info-xx .pix-list .pi-avatar"
);
if (rtlVoiceActors.length > 0) {
voiceActors = rtlVoiceActors
.map((_, actorEl) => ({
id: $1(actorEl).find("a").attr("href")?.split("/").pop() || "",
poster: $1(actorEl).find("img").attr("data-src") || "",
name:
$1(actorEl).find(".pi-detail .pi-name a").text().trim() || "",
}))
.get();
} else if (xxVoiceActors.length > 0) {
voiceActors = xxVoiceActors
.map((_, actorEl) => ({
id: $1(actorEl).attr("href")?.split("/").pop() || "",
poster: $1(actorEl).find("img").attr("data-src") || "",
name: $1(actorEl).attr("title") || "",
}))
.get();
}
if (voiceActors.length === 0) {
voiceActors = $1(el)
.find(".per-info.per-info-xx .pix-list .pi-avatar")
.map((_, actorEl) => ({
id: $1(actorEl).attr("href")?.split("/")[2] || "",
poster: $1(actorEl).find("img").attr("data-src") || "",
name: $1(actorEl).attr("title") || "",
}))
.get();
}
return { character, voiceActors };
})
.get();
}
return {
adultContent,
data_id,
id: season_id,
anilistId,
malId,
title,
japanese_title,
synonyms,
poster,
showType,
animeInfo,
charactersVoiceActors,
recommended_data,
related_data,
popular_data,
};
} catch (e) {
console.error("Error extracting anime info:", e);
}
}
export default extractAnimeInfo;

View File

@@ -0,0 +1,14 @@
import extractPage from "../helper/extractPages.helper.js";
export async function extractor(path, page) {
try {
const [data, totalPages] = await extractPage(page, path);
return { data, totalPages };
} catch (error) {
console.error(
`Error extracting data for ${path} from page ${page}:`,
error.message
);
throw error;
}
}

View File

@@ -0,0 +1,91 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export async function extractCharacter(id) {
try {
const response = await axios.get(`https://${v1_base_url}//character/${id}`);
const $ = cheerio.load(response.data);
// Extract basic information
const name = $(".apw-detail .name").text().trim();
const japaneseName = $(".apw-detail .sub-name").text().trim();
// Extract profile image
const profile = $(".avatar-circle img").attr("src");
// Extract about information
const bioText = $("#bio .bio").text().trim();
const bioHtml = $("#bio .bio").html();
const about = {
description: bioText,
style: bioHtml,
};
// Extract voice actors
const voiceActors = [];
$("#voiactor .per-info").each((_, element) => {
const voiceActorElement = $(element);
const voiceActor = {
name: voiceActorElement.find(".pi-name a").text().trim(),
profile: voiceActorElement.find(".pi-avatar img").attr("src"),
language: voiceActorElement.find(".pi-cast").text().trim(),
id: voiceActorElement.find(".pi-name a").attr("href")?.split("/").pop(),
};
if (voiceActor.name && voiceActor.id) {
voiceActors.push(voiceActor);
}
});
// Extract animeography
const animeography = [];
$(".anif-block-ul li").each((_, el) => {
const item = $(el);
const anchor = item.find(".film-name a.dynamic-name");
const title = anchor.text().trim();
const japanese_title = anchor.attr("data-jname")?.trim();
const id = anchor.attr("href")?.split("/").pop();
const role = item.find(".fdi-item").first().text().trim();
const type = item.find(".fdi-item").last().text().trim();
const poster = item.find(".film-poster img").attr("src");
if (title && id) {
animeography.push({
title,
japanese_title,
id,
role: role.replace(" (Role)", ""),
type,
poster,
});
}
});
const characterData = {
success: true,
results: {
data: [
{
id,
name,
profile,
japaneseName,
about,
voiceActors,
animeography,
},
],
},
};
return characterData;
} catch (error) {
console.error("Error extracting character data:", error);
throw new Error("Failed to extract character information");
}
}
export default extractCharacter;

View File

@@ -0,0 +1,39 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
async function extractEpisodesList(id) {
try {
const showId = id.split("-").pop();
const response = await axios.get(
`https://${v1_base_url}/ajax/v2/episode/list/${showId}`,
{
headers: {
"X-Requested-With": "XMLHttpRequest",
Referer: `https://${v1_base_url}/watch/${id}`,
},
}
);
if (!response.data.html) return [];
const $ = cheerio.load(response.data.html);
const res = {
totalEpisodes: 0,
episodes: [],
};
res.totalEpisodes = Number($(".detail-infor-content .ss-list a").length);
$(".detail-infor-content .ss-list a").each((_, el) => {
res.episodes.push({
episode_no: Number($(el).attr("data-number")),
id: $(el)?.attr("href")?.split("/")?.pop() || null,
title: $(el)?.attr("title")?.trim() || null,
japanese_title: $(el).find(".ep-name").attr("data-jname"),
filler: $(el).hasClass("ssl-item-filler"),
});
});
return res;
} catch (error) {
console.error(error);
return [];
}
}
export default extractEpisodesList;

View File

@@ -0,0 +1,174 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { DEFAULT_HEADERS } from "../configs/header.config.js";
import { v1_base_url } from "../utils/base_v1.js";
import {
FILTER_LANGUAGE_MAP,
GENRE_MAP,
FILTER_TYPES,
FILTER_STATUS,
FILTER_RATED,
FILTER_SCORE,
FILTER_SEASON,
FILTER_SORT,
} from "../routes/filter.maping.js";
async function extractFilterResults(params = {}) {
try {
const normalizeParam = (param, mapping) => {
if (!param) return undefined;
if (typeof param === "string") {
const isAlreadyId = Object.values(mapping).includes(param);
if (isAlreadyId) {
return param;
}
const key = param.trim().toUpperCase();
return mapping.hasOwnProperty(key) ? mapping[key] : undefined;
}
return param;
};
const typeParam = normalizeParam(params.type, FILTER_TYPES);
const statusParam = normalizeParam(params.status, FILTER_STATUS);
const ratedParam = normalizeParam(params.rated, FILTER_RATED);
const scoreParam = normalizeParam(params.score, FILTER_SCORE);
const seasonParam = normalizeParam(params.season, FILTER_SEASON);
const sortParam = normalizeParam(params.sort, FILTER_SORT);
let languageParam = params.language;
if (languageParam != null) {
languageParam = String(languageParam).trim().toUpperCase();
languageParam = FILTER_LANGUAGE_MAP[languageParam] ?? (Object.values(FILTER_LANGUAGE_MAP).includes(languageParam) ? languageParam : undefined);
}
let genresParam = params.genres;
if (typeof genresParam === "string") {
genresParam = genresParam
.split(",")
.map((genre) => GENRE_MAP[genre.trim().toUpperCase()] || genre.trim())
.join(",");
}
const filteredParams = {
type: typeParam,
status: statusParam,
rated: ratedParam,
score: scoreParam,
season: seasonParam,
language: languageParam,
genres: genresParam,
sort: sortParam,
page: params.page || 1,
sy: params.sy || undefined,
sm: params.sm || undefined,
sd: params.sd || undefined,
ey: params.ey || undefined,
em: params.em || undefined,
ed: params.ed || undefined,
keyword: params.keyword || undefined,
};
Object.keys(filteredParams).forEach((key) => {
if (filteredParams[key] === undefined) {
delete filteredParams[key];
}
});
const queryParams = new URLSearchParams(filteredParams).toString();
let apiUrl = `https://${v1_base_url}/filter?${queryParams}`;
if (filteredParams.keyword) {
apiUrl = `https://${v1_base_url}/search?${queryParams}`;
}
const resp = await axios.get(apiUrl, {
headers: {
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"User-Agent": DEFAULT_HEADERS,
},
});
const $ = cheerio.load(resp.data);
const elements = ".flw-item";
const result = [];
$(elements).each((_, el) => {
const $el = $(el);
const href = $el.find(".film-poster-ahref").attr("href");
const data_id = Number($el.find(".film-poster-ahref").attr("data-id"));
result.push({
id: href ? href.slice(1) : null,
data_id: data_id ? `${data_id}` : null,
poster:
$el.find(".film-poster .film-poster-img").attr("data-src") ||
$el.find(".film-poster .film-poster-img").attr("src") ||
null,
title: $el.find(".film-name .dynamic-name").text().trim(),
japanese_title:
$el.find(".film-name .dynamic-name").attr("data-jname") || null,
tvInfo: {
showType:
$el.find(".fd-infor .fdi-item:first-child").text().trim() ||
"Unknown",
duration: $el.find(".fd-infor .fdi-duration").text().trim() || null,
sub:
Number(
$el
.find(".tick-sub")
.text()
.replace(/[^0-9]/g, "")
) || null,
dub:
Number(
$el
.find(".tick-dub")
.text()
.replace(/[^0-9]/g, "")
) || null,
eps:
Number(
$el
.find(".tick-eps")
.text()
.replace(/[^0-9]/g, "")
) || null,
},
adultContent: $el.find(".tick-rate").text().trim() || null,
});
});
const totalPage = Number(
$('.pre-pagination nav .pagination > .page-item a[title="Last"]')
?.attr("href")
?.split("=")
.pop() ||
$('.pre-pagination nav .pagination > .page-item a[title="Next"]')
?.attr("href")
?.split("=")
.pop() ||
$(".pre-pagination nav .pagination > .page-item.active a")
?.text()
?.trim() ||
1
);
return [
parseInt(totalPage, 10),
result.length > 0 ? result : [],
parseInt(params.page, 10) || 1,
parseInt(params.page, 10) < parseInt(totalPage, 10),
];
} catch (e) {
console.error("Error fetching data:", e);
throw e;
}
}
export { extractFilterResults as default };

View File

@@ -0,0 +1,16 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export default async function extractNextEpisodeSchedule(id) {
try {
const { data } = await axios.get(`https://${v1_base_url}/watch/${id}`);
const $ = cheerio.load(data);
const nextEpisodeSchedule = $(
".schedule-alert > .alert.small > span:last"
).attr("data-value");
return nextEpisodeSchedule;
} catch (error) {
console.error(error);
}
}

View File

@@ -0,0 +1,49 @@
export default async function extractPopularData($) {
const popularSection = $('#main-sidebar .block_area:has(.cat-heading:contains("Most Popular"))');
const popularElements = popularSection.find(".anif-block-ul .ulclear li");
return await Promise.all(
popularElements
.map(async (index, element) => {
const $el = $(element);
const id = $el.find(".film-detail .film-name a").attr("href")?.split("/").pop();
const data_id = $el.find(".film-poster").attr("data-id");
const title = $el.find(".film-detail .film-name a").text().trim();
const japanese_title = $el.find(".film-detail .film-name a").attr("data-jname")?.trim();
const poster = $el.find(".film-poster img").attr("data-src") || $el.find(".film-poster img").attr("src");
// Extract show type like "TV", "Movie", etc.
const showTypeText = $el.find(".tick").text().toLowerCase();
const showTypeMatch = ["TV", "ONA", "Movie", "OVA", "Special"].find(type =>
showTypeText.toLowerCase().includes(type.toLowerCase())
);
const tvInfo = {
showType: showTypeMatch || "Unknown"
};
// Extract tick items like sub, dub, eps
["sub", "dub", "eps"].forEach((type) => {
const value = $el.find(`.tick-item.tick-${type}`).text().trim();
if (value) {
tvInfo[type] = value;
}
});
// Adult content check
const tickRateText = $el.find(".film-poster > .tick-rate").text().trim();
const adultContent = tickRateText.includes("18+");
return {
data_id,
id,
title,
japanese_title,
poster,
tvInfo,
adultContent,
};
})
.get()
);
}

View File

@@ -0,0 +1,65 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export default async function extractQtip(id) {
try {
const { data } = await axios.get(
`https://${v1_base_url}/ajax/movie/qtip/${id}`,
{
headers: {
"x-requested-with": "XMLHttpRequest",
},
}
);
const $ = cheerio.load(data);
const title = $(".pre-qtip-title").text();
const rating = $(".pqd-li i.fas.fa-star").parent().text().trim();
const quality = $(".tick-item.tick-quality").text();
const subCount = $(".tick-item.tick-sub").text().trim();
const dubCount = $(".tick-item.tick-dub").text().trim();
const episodeCount = $(".tick-item.tick-eps").text().trim();
const type = $(".badge.badge-quality").text();
const description = $(".pre-qtip-description").text().trim();
const japaneseTitle = $(".pre-qtip-line:contains('Japanese:') .stick-text")
.text()
.trim();
const airedDate = $(".pre-qtip-line:contains('Aired:') .stick-text")
.text()
.trim();
const status = $(".pre-qtip-line:contains('Status:') .stick-text")
.text()
.trim();
const Synonyms = $(".pre-qtip-line:contains('Synonyms:') .stick-text")
.text()
.trim();
const genres = [];
$(".pre-qtip-line:contains('Genres:') a").each((i, elem) => {
genres.push($(elem).text().trim().split(" ").join("-"));
});
const watchLink = $(".pre-qtip-button a.btn.btn-play").attr("href");
const extractedData = {
title,
rating,
quality,
subCount,
dubCount,
episodeCount,
type,
description,
japaneseTitle,
Synonyms,
airedDate,
status,
genres,
watchLink,
};
return extractedData;
} catch (error) {
console.error("Error extracting data:", error);
return error;
}
}

View File

@@ -0,0 +1,18 @@
import axios from "axios";
import { v1_base_url } from "../utils/base_v1.js";
import extractAnimeInfo from "./animeInfo.extractor.js";
import { DEFAULT_HEADERS } from "../configs/header.config.js";
const axiosInstance = axios.create({ headers: DEFAULT_HEADERS });
export default async function extractRandom() {
try {
const resp = await axiosInstance.get(`https://${v1_base_url}/random`);
const redirectedUrl = resp.request.res.responseUrl;
const id = redirectedUrl.split("/").pop();
const animeInfo = await extractAnimeInfo(id);
return animeInfo;
} catch (error) {
console.error("Error extracting random anime info:", error);
}
}

View File

@@ -0,0 +1,16 @@
import axios from "axios";
import { v1_base_url } from "../utils/base_v1.js";
import { DEFAULT_HEADERS } from "../configs/header.config.js";
const axiosInstance = axios.create({ headers: DEFAULT_HEADERS });
export default async function extractRandomId() {
try {
const resp = await axiosInstance.get(`https://${v1_base_url}/random`);
const redirectedUrl = resp.request.res.responseUrl;
const id = redirectedUrl.split("/").pop();
return id;
} catch (error) {
console.error("Error extracting random anime info:", error);
}
}

View File

@@ -0,0 +1,65 @@
export default async function extractRecommendedData($) {
const recommendedElements = $(
"#main-content .block_area_category .tab-content .block_area-content .film_list-wrap .flw-item"
);
return await Promise.all(
recommendedElements
.map(async (index, element) => {
const id = $(element)
.find(".film-detail .film-name a")
.attr("href")
.split("/")
.pop();
const data_id = $(element).find(".film-poster a").attr("data-id");
const title = $(element)
.find(".film-detail .film-name a")
.text()
.trim();
const japanese_title = $(element)
.find(".film-detail .film-name a")
.attr("data-jname")
.trim();
const poster = $(element).find(".film-poster img").attr("data-src");
const $fdiItems = $(".film-detail .fd-infor .fdi-item", element);
const showType = $fdiItems
.filter((_, item) => {
const text = $(item).text().trim().toLowerCase();
return ["tv", "ona", "movie", "ova", "special"].some((type) =>
text.includes(type)
);
})
.first();
const tvInfo = {
showType: showType ? showType.text().trim() : "Unknown",
duration: $(".film-detail .fd-infor .fdi-duration", element)
.text()
.trim(),
};
["sub", "dub", "eps"].forEach((property) => {
const value = $(`.tick .tick-${property}`, element).text().trim();
if (value) {
tvInfo[property] = value;
}
});
let adultContent = false;
const tickRateText = $(".film-poster>.tick-rate", element)
.text()
.trim();
if (tickRateText.includes("18+")) {
adultContent = true;
}
return {
data_id,
id,
title,
japanese_title,
poster,
tvInfo,
adultContent,
};
})
.get()
);
}

View File

@@ -0,0 +1,51 @@
export default async function extractRelatedData($) {
const relatedSection = $('#main-sidebar .block_area:has(.cat-heading:contains("Related Anime"))');
const relatedElements = relatedSection.find(
".anif-block-ul .ulclear li"
);
return await Promise.all(
relatedElements
.map(async (index, element) => {
const $el = $(element);
const id = $el.find(".film-detail .film-name a").attr("href")?.split("/").pop();
const data_id = $el.find(".film-poster").attr("data-id");
const title = $el.find(".film-detail .film-name a").text().trim();
const japanese_title = $el.find(".film-detail .film-name a").attr("data-jname")?.trim();
const poster = $el.find(".film-poster img").attr("data-src") || $el.find(".film-poster img").attr("src");
// Extract show type like "TV", "Movie", etc.
const showTypeText = $el.find(".tick").text().toLowerCase();
const showTypeMatch = ["TV", "ONA", "Movie", "OVA", "Special"].find(type =>
showTypeText.toLowerCase().includes(type.toLowerCase())
);
const tvInfo = {
showType: showTypeMatch || "Unknown"
};
// Extract tick items like sub, dub, eps
["sub", "dub", "eps"].forEach((type) => {
const value = $el.find(`.tick-item.tick-${type}`).text().trim();
if (value) {
tvInfo[type] = value;
}
});
// Adult content check
const tickRateText = $el.find(".film-poster > .tick-rate").text().trim();
const adultContent = tickRateText.includes("18+");
return {
data_id,
id,
title,
japanese_title,
poster,
tvInfo,
adultContent,
};
})
.get()
);
}

View File

@@ -0,0 +1,51 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export default async function extractSchedule(date, tzOffset) {
try {
tzOffset = tzOffset ?? -330;
const resp = await axios.get(
`https://${v1_base_url}/ajax/schedule/list?tzOffset=${tzOffset}&date=${date}`
);
const $ = cheerio.load(resp.data.html);
const results = [];
$("li").each((i, element) => {
const id = $(element)
?.find("a")
.attr("href")
.split("?")[0]
.replace("/", "");
const data_id = id?.split("-").pop();
const title = $(element).find(".film-name").text().trim();
const japanese_title = $(element)
.find(".film-name")
.attr("data-jname")
?.trim();
const releaseDate = date;
const time = $(element).find(".time").text().trim();
const episode_no = $(element)
?.find(".btn-play")
.text()
.trim()
.split(" ")
.pop();
results.push({
id,
data_id,
title,
japanese_title,
releaseDate,
time,
episode_no,
});
});
return results;
} catch (error) {
console.log(error.message);
return [];
}
}

View File

@@ -0,0 +1,184 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { DEFAULT_HEADERS } from "../configs/header.config.js";
import { v1_base_url } from "../utils/base_v1.js";
import {
FILTER_LANGUAGE_MAP,
GENRE_MAP,
FILTER_TYPES,
FILTER_STATUS,
FILTER_RATED,
FILTER_SCORE,
FILTER_SEASON,
FILTER_SORT,
} from "../routes/filter.maping.js";
async function extractSearchResults(params = {}) {
try {
const normalizeParam = (param, mapping) => {
if (!param) return undefined;
if (typeof param === "string") {
const isAlreadyId = Object.values(mapping).includes(param);
if (isAlreadyId) {
return param;
}
const key = param.trim().toUpperCase();
return mapping.hasOwnProperty(key) ? mapping[key] : undefined;
}
return param;
};
const typeParam = normalizeParam(params.type, FILTER_TYPES);
const statusParam = normalizeParam(params.status, FILTER_STATUS);
const ratedParam = normalizeParam(params.rated, FILTER_RATED);
const scoreParam = normalizeParam(params.score, FILTER_SCORE);
const seasonParam = normalizeParam(params.season, FILTER_SEASON);
const sortParam = normalizeParam(params.sort, FILTER_SORT);
let languageParam = params.language;
if (languageParam != null) {
languageParam = String(languageParam).trim().toUpperCase();
languageParam = FILTER_LANGUAGE_MAP[languageParam] ?? (Object.values(FILTER_LANGUAGE_MAP).includes(languageParam) ? languageParam : undefined);
}
let genresParam = params.genres;
if (typeof genresParam === "string") {
genresParam = genresParam
.split(",")
.map((genre) => GENRE_MAP[genre.trim().toUpperCase()] || genre.trim())
.join(",");
}
const filteredParams = {
type: typeParam,
status: statusParam,
rated: ratedParam,
score: scoreParam,
season: seasonParam,
language: languageParam,
genres: genresParam,
sort: sortParam,
page: params.page || 1,
sy: params.sy || undefined,
sm: params.sm || undefined,
sd: params.sd || undefined,
ey: params.ey || undefined,
em: params.em || undefined,
ed: params.ed || undefined,
keyword: params.keyword || undefined,
};
Object.keys(filteredParams).forEach((key) => {
if (filteredParams[key] === undefined) {
delete filteredParams[key];
}
});
const queryParams = new URLSearchParams(filteredParams).toString();
const resp = await axios.get(`https://${v1_base_url}/search?${queryParams}`, {
headers: {
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"User-Agent": DEFAULT_HEADERS,
},
});
const $ = cheerio.load(resp.data);
const elements = "#main-content .film_list-wrap .flw-item";
const totalPage =
Number(
$('.pre-pagination nav .pagination > .page-item a[title="Last"]')
?.attr("href")
?.split("=")
.pop() ??
$('.pre-pagination nav .pagination > .page-item a[title="Next"]')
?.attr("href")
?.split("=")
.pop() ??
$(".pre-pagination nav .pagination > .page-item.active a")
?.text()
?.trim()
) || 1;
const result = [];
$(elements).each((_, el) => {
const id =
$(el)
.find(".film-detail .film-name .dynamic-name")
?.attr("href")
?.slice(1)
.split("?ref=search")[0] || null;
result.push({
id: id,
data_id: $(el)
.find(".film-poster .film-poster-ahref").attr("data-id"),
title: $(el)
.find(".film-detail .film-name .dynamic-name")
?.text()
?.trim(),
japanese_title:
$(el)
.find(".film-detail .film-name .dynamic-name")
?.attr("data-jname")
?.trim() || null,
poster:
$(el)
.find(".film-poster .film-poster-img")
?.attr("data-src")
?.trim() || null,
duration:
$(el)
.find(".film-detail .fd-infor .fdi-item.fdi-duration")
?.text()
?.trim(),
tvInfo: {
showType:
$(el)
.find(".film-detail .fd-infor .fdi-item:nth-of-type(1)")
.text()
.trim() || "Unknown",
rating: $(el).find(".film-poster .tick-rate")?.text()?.trim() || null,
sub:
Number(
$(el)
.find(".film-poster .tick-sub")
?.text()
?.trim()
.split(" ")
.pop()
) || null,
dub:
Number(
$(el)
.find(".film-poster .tick-dub")
?.text()
?.trim()
.split(" ")
.pop()
) || null,
eps:
Number(
$(el)
.find(".film-poster .tick-eps")
?.text()
?.trim()
.split(" ")
.pop()
) || null,
},
});
});
return [parseInt(totalPage, 10), result.length > 0 ? result : []];
} catch (e) {
console.error(e);
return e;
}
}
export default extractSearchResults;

View File

@@ -0,0 +1,30 @@
import axios from "axios";
import * as cheerio from "cheerio";
import formatTitle from "../helper/formatTitle.helper.js";
import { v1_base_url } from "../utils/base_v1.js";
async function extractSeasons(id) {
try {
const resp = await axios.get(`https://${v1_base_url}/watch/${id}`);
const $ = cheerio.load(resp.data);
const seasons = $(".anis-watch>.other-season>.inner>.os-list>a")
.map((index, element) => {
const data_number = index;
const data_id = parseInt($(element).attr("href").split("-").pop());
const season = $(element).find(".title").text().trim();
const title = $(element).attr("title").trim();
const id = href.replace(/^\/+/, "");
const season_poster = $(element)
.find(".season-poster")
.attr("style")
.match(/url\((.*?)\)/)[1];
return { id, data_number, data_id, season, title, season_poster };
})
.get();
return seasons;
} catch (e) {
console.log(e);
}
}
export default extractSeasons;

View File

@@ -0,0 +1,103 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
async function extractSpotlights() {
try {
const resp = await axios.get(`https://${v1_base_url}/home`);
const $ = cheerio.load(resp.data);
const slideElements = $(
"div.deslide-wrap > div.container > div#slider > div.swiper-wrapper > div.swiper-slide"
);
const promises = slideElements
.map(async (ind, ele) => {
const poster = $(ele)
.find(
"div.deslide-item > div.deslide-cover > div.deslide-cover-img > img.film-poster-img"
)
.attr("data-src");
const title = $(ele)
.find(
"div.deslide-item > div.deslide-item-content > div.desi-head-title"
)
.text()
.trim();
const japanese_title = $(ele)
.find(
"div.deslide-item > div.deslide-item-content > div.desi-head-title"
)
.attr("data-jname")
.trim();
const description = $(ele)
.find(
"div.deslide-item > div.deslide-item-content > div.desi-description"
)
.text()
.trim();
const id = $(ele)
.find(
".deslide-item > .deslide-item-content > .desi-buttons > a:eq(0)"
)
.attr("href")
.split("/")
.pop();
const data_id = $(ele)
.find(
".deslide-item > .deslide-item-content > .desi-buttons > a:eq(0)"
)
.attr("href")
.split("/")
.pop()
.split("-")
.pop();
const tvInfoMapping = {
0: "showType",
1: "duration",
2: "releaseDate",
3: "quality",
4: "episodeInfo",
};
const tvInfo = {};
await Promise.all(
$(ele)
.find("div.sc-detail > div.scd-item")
.map(async (index, element) => {
const key = tvInfoMapping[index];
let value = $(element).text().trim().replace(/\n/g, "");
const tickContainer = $(element).find(".tick");
if (tickContainer.length > 0) {
value = {
sub: tickContainer.find(".tick-sub").text().trim(),
dub: tickContainer.find(".tick-dub").text().trim(),
};
}
tvInfo[key] = value;
})
);
return {
id,
data_id,
poster,
title,
japanese_title,
description,
tvInfo,
};
})
.get();
const serverData = await Promise.all(promises);
return JSON.parse(JSON.stringify(serverData, null, 2));
} catch (error) {
console.error("Error fetching data:", error.message);
return error;
}
}
export default extractSpotlights;

View File

@@ -0,0 +1,68 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
// import decryptMegacloud from "../parsers/decryptors/megacloud.decryptor.js";
// import AniplayExtractor from "../parsers/aniplay.parser.js";
import { decryptSources_v1 } from "../parsers/decryptors/decrypt_v1.decryptor.js";
export async function extractServers(id) {
try {
const resp = await axios.get(
`https://${v1_base_url}/ajax/v2/episode/servers?episodeId=${id}`
);
const $ = cheerio.load(resp.data.html);
const serverData = [];
$(".server-item").each((index, element) => {
const data_id = $(element).attr("data-id");
const server_id = $(element).attr("data-server-id");
const type = $(element).attr("data-type");
const serverName = $(element).find("a").text().trim();
serverData.push({
type,
data_id,
server_id,
serverName,
});
});
return serverData;
} catch (error) {
console.log(error);
return [];
}
}
async function extractStreamingInfo(id, name, type, fallback) {
try {
const servers = await extractServers(id.split("?ep=").pop());
let requestedServer = servers.filter(
(server) =>
server.serverName.toLowerCase() === name.toLowerCase() &&
server.type.toLowerCase() === type.toLowerCase()
);
if (requestedServer.length === 0) {
requestedServer = servers.filter(
(server) =>
server.serverName.toLowerCase() === name.toLowerCase() &&
server.type.toLowerCase() === "raw"
);
}
if (requestedServer.length === 0) {
throw new Error(
`No matching server found for name: ${name}, type: ${type}`
);
}
const streamingLink = await decryptSources_v1(
id,
requestedServer[0].data_id,
name,
type,
fallback
);
return { streamingLink, servers };
} catch (error) {
console.error("An error occurred:", error);
return { streamingLink: [], servers: [] };
}
}
export { extractStreamingInfo };

View File

@@ -0,0 +1,19 @@
import axios from "axios";
import { v1_base_url } from "../utils/base_v1.js";
import { provider } from "../utils/provider.js";
export async function extractSubtitle(id) {
const resp = await axios.get(
`https://${v1_base_url}/ajax/v2/episode/sources/?id=${id}`
);
const source = await axios.get(
`${provider}/embed-2/ajax/e-1/getSources?id=${resp.data.link
.split("/")
.pop()
.replace(/\?k=\d?/g, "")}`
);
const subtitles = source.data.tracks;
const intro = source.data.intro;
const outro = source.data.outro;
return { subtitles, intro, outro };
}

View File

@@ -0,0 +1,50 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
async function getSuggestions(keyword) {
try {
const resp = await axios.get(
`https://${v1_base_url}/ajax/search/suggest?keyword=${keyword}`
);
const $ = cheerio.load(resp.data.html);
const results = [];
$(".nav-item")
.not(".nav-bottom")
.each((i, element) => {
const id = $(element).attr("href").split("?")[0].replace("/", "");
const data_id = id.split("-").pop();
const poster = $(element).find(".film-poster-img").attr("data-src");
const title = $(element).find(".film-name").text().trim();
const japanese_title = $(element).find(".film-name").attr("data-jname").trim();
const releaseDate = $(element)
.find(".film-infor span")
.first()
.text()
.trim();
const filmInforHtml = $(element).find(".film-infor").html();
const showTypeMatch = /<i class="dot"><\/i>([^<]+)<i class="dot"><\/i>/;
const showType = showTypeMatch.exec(filmInforHtml)?.[1]?.trim() || "";
const duration = $(element)
.find(".film-infor span")
.last()
.text()
.trim();
results.push({
id,
data_id,
poster,
title,
japanese_title,
releaseDate,
showType,
duration,
});
});
return results;
} catch (error) {
console.log(error.message);
}
}
export default getSuggestions;

View File

@@ -0,0 +1,21 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
async function extractTopSearch() {
try {
const { data } = await axios.get(`https://${v1_base_url}`);
const $ = cheerio.load(data);
const results = [];
$(".xhashtag a.item").each((_, element) => {
const title = $(element).text().trim();
const link = $(element).attr("href");
results.push({ title, link });
});
return results;
} catch (error) {
console.error("Error fetching data:", error.message);
}
}
export default extractTopSearch;

View File

@@ -0,0 +1,51 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
async function extractTopTen() {
try {
const resp = await axios.get(`https://${v1_base_url}/home`);
const $ = cheerio.load(resp.data);
const labels = ["today", "week", "month"];
const result = {};
labels.forEach((label, idx) => {
const data = $(
`#main-sidebar .block_area-realtime .block_area-content ul:eq(${idx})>li`
)
.map((index, element) => {
const number = $(".film-number>span", element).text().trim();
const title = $(".film-detail>.film-name>a", element).text().trim();
const poster = $(".film-poster>img", element).attr("data-src");
const japanese_title = $(".film-detail>.film-name>a", element)
.attr("data-jname")
.trim();
const data_id = $(".film-poster", element).attr("data-id");
const id = $(".film-detail>.film-name>a", element)
.attr("href")
.split("/")
.pop();
const tvInfo = ["sub", "dub", "eps"].reduce((info, property) => {
const value = $(`.tick .tick-${property}`, element).text().trim();
if (value) {
info[property] = value;
}
return info;
}, {});
return { id, data_id, number, title, japanese_title, poster, tvInfo };
})
.get();
result[label] = data;
});
return result;
} catch (error) {
console.error("Error fetching data:", error);
throw error;
}
}
export default extractTopTen;

View File

@@ -0,0 +1,35 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
async function fetchAnimeDetails(element) {
const data_id = element.attr("data-id");
const number = element.find(".number > span").text();
const poster = element.find("img").attr("data-src");
const title = element.find(".film-title").text().trim();
const japanese_title = element.find(".film-title").attr("data-jname").trim();
const id = element.find("a").attr("href").split("/").pop();
return { id, data_id, number, poster, title, japanese_title };
}
async function extractTrending() {
try {
const resp = await axios.get(`https://${v1_base_url}/home`);
const $ = cheerio.load(resp.data);
const trendingElements = $("#anime-trending #trending-home .swiper-slide");
const elementPromises = trendingElements
.map((index, element) => {
return fetchAnimeDetails($(element));
})
.get();
const trendingData = await Promise.all(elementPromises);
return JSON.parse(JSON.stringify(trendingData));
} catch (error) {
console.error("Error fetching data:", error.message);
return error;
}
}
export default extractTrending;

View File

@@ -0,0 +1,78 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export default async function extractVoiceActor(id, page) {
try {
const resp = await axios.get(
`https://${v1_base_url}/ajax/character/list/${id
.split("-")
.pop()}?page=${page}`
);
const $ = cheerio.load(resp.data.html);
let totalPages = 1;
const paginationList = $(".pre-pagination nav ul");
if (paginationList.length) {
const lastPageLink = paginationList.find("li").last().find("a");
const pageNumber =
lastPageLink.attr("data-url")?.match(/page=(\d+)/)?.[1] ||
lastPageLink.text().trim();
totalPages = parseInt(pageNumber) || totalPages;
}
const charactersVoiceActors = $(".bac-list-wrap .bac-item")
.map((index, el) => {
const character = {
id:
$(el)
.find(".per-info.ltr .pi-avatar")
.attr("href")
?.split("/")[2] || "",
poster:
$(el).find(".per-info.ltr .pi-avatar img").attr("data-src") || "",
name: $(el).find(".per-info.ltr .pi-detail a").text(),
cast: $(el).find(".per-info.ltr .pi-detail .pi-cast").text(),
};
let voiceActors = [];
const rtlVoiceActors = $(el).find(".per-info.rtl");
const xxVoiceActors = $(el).find(
".per-info.per-info-xx .pix-list .pi-avatar"
);
if (rtlVoiceActors.length > 0) {
voiceActors = rtlVoiceActors
.map((_, actorEl) => ({
id: $(actorEl).find("a").attr("href")?.split("/").pop() || "",
poster: $(actorEl).find("img").attr("data-src") || "",
name:
$(actorEl).find(".pi-detail .pi-name a").text().trim() || "",
}))
.get();
} else if (xxVoiceActors.length > 0) {
voiceActors = xxVoiceActors
.map((_, actorEl) => ({
id: $(actorEl).attr("href")?.split("/").pop() || "",
poster: $(actorEl).find("img").attr("data-src") || "",
name: $(actorEl).attr("title") || "",
}))
.get();
}
if (voiceActors.length === 0) {
voiceActors = $(el)
.find(".per-info.per-info-xx .pix-list .pi-avatar")
.map((_, actorEl) => ({
id: $(actorEl).attr("href")?.split("/")[2] || "",
poster: $(actorEl).find("img").attr("data-src") || "",
name: $(actorEl).attr("title") || "",
}))
.get();
}
return { character, voiceActors };
})
.get();
return { totalPages, charactersVoiceActors };
} catch (error) {
console.error("Error in extractVoiceActor:", error);
throw new Error("Could not extract voice actors");
}
}

View File

@@ -0,0 +1,63 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export default async function extractWatchlist(userId, page = 1) {
try {
const url = `https://${v1_base_url}/community/user/${userId}/watch-list?page=${page}`;
const { data } = await axios.get(url);
const $ = cheerio.load(data);
const watchlist = [];
const totalPages =
Number(
$('.pre-pagination nav .pagination > .page-item a[title="Last"]')
?.attr("href")
?.split("=")
.pop() ??
$('.pre-pagination nav .pagination > .page-item a[title="Next"]')
?.attr("href")
?.split("=")
.pop() ??
$(".pre-pagination nav .pagination > .page-item.active a")
?.text()
?.trim()
) || 1;
$(".flw-item").each((index, element) => {
const title = $(".film-name a", element).text().trim();
const poster = $(".film-poster img", element).attr("data-src");
const duration = $(".fdi-duration", element).text().trim();
const type = $(".fdi-item", element).first().text().trim();
const id = $(".film-poster a", element).attr("data-id");
const subCount = $(".tick-item.tick-sub", element).text().trim();
const dubCount = $(".tick-item.tick-dub", element).text().trim();
const link = $(".film-name a", element).attr("href");
const animeId = link.split("/").pop();
watchlist.push({
id: animeId,
title,
poster,
duration,
type,
subCount,
dubCount,
link: `https://${v1_base_url}${link}`,
showType: type,
tvInfo: {
showType: type,
duration: duration,
sub: subCount,
dub: dubCount,
},
});
});
return { watchlist, totalPages };
} catch (error) {
console.error("Error fetching watchlist:", error.message);
throw error;
}
}

View File

@@ -0,0 +1,34 @@
import axios from "axios";
import dotenv from "dotenv";
dotenv.config();
const CACHE_SERVER_URL = process.env.CACHE_URL || null;
export const getCachedData = async (key) => {
try {
if (!CACHE_SERVER_URL) {
console.log(CACHE_SERVER_URL);
return;
}
const response = await axios.get(`${CACHE_SERVER_URL}/${key}`);
return response.data;
} catch (error) {
if (error.response && error.response.status === 404) {
return null;
}
throw error;
}
};
export const setCachedData = async (key, value) => {
try {
if (!CACHE_SERVER_URL) {
return;
}
await axios.post(CACHE_SERVER_URL, { key, value });
} catch (error) {
console.error("Error setting cache data:", error);
throw error;
}
};

View File

@@ -0,0 +1,24 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { DEFAULT_HEADERS } from "../configs/header.config.js";
const axiosInstance = axios.create({ headers: DEFAULT_HEADERS });
async function countPages(url) {
try {
const { data } = await axiosInstance.get(url);
const $ = cheerio.load(data);
const lastPageHref = $(
".tab-content .pagination .page-item:last-child a"
).attr("href");
const lastPageNumber = lastPageHref
? parseInt(lastPageHref.split("=").pop())
: 1;
return lastPageNumber;
} catch (error) {
console.error("Error counting pages:", error.message);
throw error;
}
}
export default countPages;

View File

@@ -0,0 +1,92 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
import { DEFAULT_HEADERS } from "../configs/header.config.js";
const axiosInstance = axios.create({ headers: DEFAULT_HEADERS });
async function extractPage(page, params) {
try {
const resp = await axiosInstance.get(`https://${v1_base_url}/${params}?page=${page}`);
const $ = cheerio.load(resp.data);
const totalPages =
Number(
$('.pre-pagination nav .pagination > .page-item a[title="Last"]')
?.attr("href")
?.split("=")
.pop() ??
$('.pre-pagination nav .pagination > .page-item a[title="Next"]')
?.attr("href")
?.split("=")
.pop() ??
$(".pre-pagination nav .pagination > .page-item.active a")
?.text()
?.trim()
) || 1;
const contentSelector = params.includes("az-list")
? ".tab-content"
: "#main-content";
const data = await Promise.all(
$(`${contentSelector} .film_list-wrap .flw-item`).map(
async (index, element) => {
const $fdiItems = $(".film-detail .fd-infor .fdi-item", element);
const showType = $fdiItems
.filter((_, item) => {
const text = $(item).text().trim().toLowerCase();
return ["tv", "ona", "movie", "ova", "special", "music"].some((type) =>
text.includes(type)
);
})
.first();
const poster = $(".film-poster>img", element).attr("data-src");
const title = $(".film-detail .film-name", element).text();
const japanese_title = $(".film-detail>.film-name>a", element).attr(
"data-jname"
);
const description = $(".film-detail .description", element)
.text()
.trim();
const data_id = $(".film-poster>a", element).attr("data-id");
const id = $(".film-poster>a", element).attr("href").split("/").pop();
const tvInfo = {
showType: showType ? showType.text().trim() : "Unknown",
duration: $(".film-detail .fd-infor .fdi-duration", element)
.text()
.trim(),
};
let adultContent = false;
const tickRateText = $(".film-poster>.tick-rate", element)
.text()
.trim();
if (tickRateText.includes("18+")) {
adultContent = true;
}
["sub", "dub", "eps"].forEach((property) => {
const value = $(`.tick .tick-${property}`, element).text().trim();
if (value) {
tvInfo[property] = value;
}
});
return {
id,
data_id,
poster,
title,
japanese_title,
description,
tvInfo,
adultContent,
};
}
)
);
return [data, parseInt(totalPages, 10)];
} catch (error) {
console.error(`Error extracting data from page ${page}:`, error.message);
throw error;
}
}
export default extractPage;

View File

@@ -0,0 +1,8 @@
import axios from "axios";
async function fetchScript(url) {
const response = await axios.get(url);
return response.data;
}
export default fetchScript;

View File

@@ -0,0 +1,76 @@
import axios from "axios";
// import { getCachedData, setCachedData } from "./cache.helper";
async function getEnglishTitleFromAniList(userInput) {
// const cacheKey = `translation:${userInput}`;
try {
// Check cache
// const cachedValue = await getCachedData(cacheKey);
// if (cachedValue) {
// console.log(`Cache Hit ${userInput} -> ${cachedValue}`)
// }
const query = `
query ($search: String) {
Media (search: $search, type: ANIME) {
title {
romaji
english
}
}
}
`;
const response = await axios.post('https://graphql.anilist.co', {
query,
variables: { search: userInput }
}, {
headers: { 'Content-Type': 'application/json' },
timeout: 3000 // 3 seconds
});
const titles = response.data?.data?.Media?.title;
if (!titles) {
console.log(`AniList no match found for: ${userInput}`);
return userInput;
}
const result = titles.english || titles.romaji || userInput;
// await setCachedData(cacheKey, result);
return result;
} catch (error) {
console.error("AniList API Error:", error.response?.data || error.message);
throw error;
}
}
async function convertForeignLanguage(userInput) {
try {
if (!userInput) return '';
// If it's only Latin characters, return as-is
if (/^[a-zA-Z\s]+$/.test(userInput)) {
return userInput;
}
// Detect if it is Japanese, Chinese or Korean
const isForeign = /[\u3040-\u30ff\u3000-\u303f\u4e00-\u9faf\uac00-\ud7af]/.test(userInput);
if (isForeign) {
const translated = await getEnglishTitleFromAniList(userInput);
return translated;
}
return userInput;
} catch (error) {
console.error(`Error converting foreign input ${userInput}:`, error.message);
return userInput;
}
}
export default convertForeignLanguage;

View File

@@ -0,0 +1,9 @@
function formatTitle(title, data_id) {
let formattedTitle = title.replace(/[^\w\s]/g, "");
formattedTitle = formattedTitle.toLowerCase();
formattedTitle = formattedTitle.replace(/\s+/g, "-");
formattedTitle = `${formattedTitle}-${data_id}`;
return formattedTitle;
}
export default formatTitle;

View File

@@ -0,0 +1,34 @@
class ErrorLoadingException extends Error {
constructor(message) {
super(message);
this.name = "ErrorLoadingException";
}
}
function matchingKey(value, script) {
const regex = new RegExp(`,${value}=((?:0x)?([0-9a-fA-F]+))`);
const match = script.match(regex);
if (match) {
return match[2];
} else {
throw new ErrorLoadingException("Failed to match the key");
}
}
function getKeys(script) {
const regex =
/case\s*0x[0-9a-f]+:(?![^;]*=partKey)\s*\w+\s*=\s*(\w+)\s*,\s*\w+\s*=\s*(\w+);/g;
const matches = script.matchAll(regex);
return Array.from(matches, (match) => {
const matchKey1 = matchingKey(match[1], script);
const matchKey2 = matchingKey(match[2], script);
try {
return [parseInt(matchKey1, 16), parseInt(matchKey2, 16)];
} catch (e) {
return [];
}
}).filter((pair) => pair.length > 0);
}
export default getKeys;

View File

@@ -0,0 +1,71 @@
import axios from 'axios';
import * as cheerio from 'cheerio';
import { v1_base_url } from '../utils/base_v1.js';
export default async function extractToken(url) {
try {
const { data: html } = await axios.get(url, {
headers: {
Referer: `https://${v1_base_url}/`
}
});
const $ = cheerio.load(html);
const results = {};
// 1. Meta tag
const meta = $('meta[name="_gg_fb"]').attr('content');
if (meta) results.meta = meta;
// 2. Data attribute
const dpi = $('[data-dpi]').attr('data-dpi');
if (dpi) results.dataDpi = dpi;
// 3. Nonce from empty script
const nonceScript = $('script[nonce]').filter((i, el) => {
return $(el).text().includes('empty nonce script');
}).attr('nonce');
if (nonceScript) results.nonce = nonceScript;
// 4. JS string assignment: window.<key> = "value";
const stringAssignRegex = /window\.(\w+)\s*=\s*["']([\w-]+)["']/g;
const stringMatches = [...html.matchAll(stringAssignRegex)];
for (const [_, key, value] of stringMatches) {
results[`window.${key}`] = value;
}
// 5. JS object assignment: window.<key> = { ... };
const objectAssignRegex = /window\.(\w+)\s*=\s*(\{[\s\S]*?\});/g;
const matches = [...html.matchAll(objectAssignRegex)];
for (const [_, varName, rawObj] of matches) {
try {
const parsedObj = eval('(' + rawObj + ')');
if (parsedObj && typeof parsedObj === 'object') {
const stringValues = Object.values(parsedObj).filter(val => typeof val === 'string');
const concatenated = stringValues.join('');
if (concatenated.length >= 20) {
results[`window.${varName}`] = concatenated;
}
}
} catch (e) {
// Skip invalid object
}
}
// 6. HTML comment: <!-- _is_th:... -->
$('*').contents().each(function () {
if (this.type === 'comment') {
const match = this.data.trim().match(/^_is_th:([\w-]+)$/);
if (match) {
results.commentToken = match[1].trim();
}
}
});
const token = Object.values(results)[0];
return token || null;
} catch (err) {
console.error('Error:', err.message);
return null;
}
}

View File

@@ -0,0 +1,94 @@
import axios from "axios";
import { v3_base_url } from "../utils/base_v3.js";
const DEFAULT_BASE_URL = `https://${v3_base_url}`;
class AniplayExtractor {
constructor(baseUrl = DEFAULT_BASE_URL) {
this.baseUrl = baseUrl;
this.keys = null;
this.keysTs = 0;
}
isCacheValid() {
const now = Math.floor(Date.now() / 1000);
return this.keys && now - this.keysTs < 3600;
}
async fetchHtml(url) {
const { data } = await axios.get(url);
return data;
}
async fetchStaticJsUrl() {
const html = await this.fetchHtml(`${this.baseUrl}/anime/watch/1`);
const prefix = "/_next/static/chunks/app/(user)/(media)/";
const start = html.indexOf(prefix);
if (start === -1) throw new Error("Static chunk path not found in HTML.");
const slugStart = start + prefix.length;
const slugEnd = html.indexOf('"', slugStart);
const jsSlug = html.slice(slugStart, slugEnd);
return `${this.baseUrl}${prefix}${jsSlug}`;
}
async extractKeys() {
if (this.isCacheValid()) return this.keys;
const scriptUrl = await this.fetchStaticJsUrl();
const script = await this.fetchHtml(scriptUrl);
const regex =
/\(0,\w+\.createServerReference\)\("([a-f0-9]+)",\w+\.callServer,void 0,\w+\.findSourceMapURL,"(getSources|getEpisodes)"\)/g;
const matches = script.matchAll(regex);
const keysMap = { baseUrl: this.baseUrl };
for (const match of matches) {
const [, hash, fn] = match;
keysMap[fn] = hash;
}
if (!keysMap["getSources"] || !keysMap["getEpisodes"]) {
throw new Error("Could not extract all required keys.");
}
this.keys = keysMap;
this.keysTs = Math.floor(Date.now() / 1000);
return keysMap;
}
async getNextAction() {
const keys = await this.extractKeys();
return {
watch: keys["getSources"],
info: keys["getEpisodes"],
};
}
async fetchEpisode(animeId, ep, host = "hika", type = "sub") {
const nextAction = await this.getNextAction();
const url = `${this.baseUrl}/anime/watch/${animeId}?host=${host}&ep=${ep}&type=${type}`;
const payload = [
String(animeId),
host,
`${animeId}/${ep}`,
String(ep),
type,
];
try {
const res = await axios.post(url, payload, {
headers: {
"Next-Action": nextAction.watch,
},
});
const dataStr = res.data.split("1:")[1];
return JSON.parse(dataStr);
} catch (err) {
throw new Error(`Request failed: ${err.message}`);
}
}
}
export default AniplayExtractor;

View File

@@ -0,0 +1,844 @@
export const data = new Uint8ClampedArray([
246, 246, 246, 255, 226, 234, 236, 255, 113, 170, 187, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 0,
255, 255, 1, 61, 139, 163, 192, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 130, 180, 196, 254, 242, 243, 244, 254, 246, 246,
246, 254, 243, 244, 245, 254, 105, 165, 184, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140,
164, 255, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 132, 181,
196, 254, 243, 245, 245, 254, 188, 212, 220, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 139,
164, 255, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 139,
164, 254, 63, 142, 165, 254, 217, 230, 233, 254, 132, 181, 196, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 255, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 255, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 177, 206, 216, 254, 119, 174,
190, 255, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 164, 198,
210, 255, 119, 174, 190, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140,
164, 255, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140,
165, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140,
165, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140,
165, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140,
165, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140,
164, 254, 60, 140, 164, 254, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140,
164, 254, 60, 140, 165, 254, 60, 140, 164, 254, 60, 140, 164, 254, 60, 140,
164, 255, 163, 198, 210, 254, 119, 174, 190, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 255, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 255, 60, 139, 164, 254, 163, 198, 210, 254, 119, 174, 190, 254, 60, 139,
164, 254, 60, 140, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139,
164, 255, 60, 140, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140,
164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 139, 164, 254, 60, 140,
164, 255, 60, 139, 164, 254, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140,
164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140,
164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140,
164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 174,
190, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 131, 180,
195, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233,
239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255,
233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240,
255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239,
240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233,
239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255,
233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240,
255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239,
240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233, 239, 240, 255, 233,
239, 240, 255, 233, 239, 240, 255, 218, 230, 234, 255, 143, 187, 200, 255, 66,
143, 167, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60,
140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60,
140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60,
139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 173, 190, 255, 60,
139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 139, 185, 199, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 223, 233, 236,
255, 136, 183, 197, 255, 69, 145, 168, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 140, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164,
255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 184, 199, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 242, 243, 244, 255, 219, 231, 235, 255, 217, 229, 233, 255,
217, 229, 233, 255, 217, 229, 233, 255, 217, 229, 233, 255, 217, 229, 233,
255, 217, 229, 233, 255, 217, 229, 233, 255, 217, 229, 233, 255, 217, 229,
233, 255, 217, 229, 233, 255, 217, 229, 233, 255, 217, 229, 233, 255, 217,
229, 233, 255, 217, 229, 233, 255, 97, 160, 180, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 139, 185, 199, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 173, 190,
255, 60, 140, 164, 255, 60, 140, 165, 255, 60, 140, 164, 255, 139, 185, 199,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119,
174, 190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139,
185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164,
183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198,
210, 255, 119, 174, 190, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139,
164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164,
255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 140, 164, 255, 60, 140, 164,
255, 60, 139, 164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 163, 198, 210, 255, 119, 173, 190, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 140, 164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 140, 164, 255, 60, 139, 164,
255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 184, 199, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 139, 185, 199, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 173, 190,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 185, 199,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119,
174, 190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139,
185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 241, 243, 244, 255, 227, 235, 238, 255, 243, 245, 245, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
230, 237, 239, 255, 239, 242, 243, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 233, 239, 241, 255, 235, 239, 241,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 239, 242, 243, 255, 230, 236, 239, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164,
183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198,
210, 255, 119, 174, 190, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139,
164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 216, 230, 233, 255, 94, 160, 179, 255, 66, 143, 166, 255, 99, 161, 182,
255, 221, 232, 236, 255, 246, 246, 246, 255, 245, 245, 245, 255, 127, 178,
194, 255, 68, 144, 168, 255, 79, 150, 173, 255, 187, 213, 220, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 154, 193, 205, 255, 73, 147, 170, 255, 72, 146, 169,
255, 156, 194, 206, 255, 246, 246, 246, 255, 246, 246, 246, 255, 208, 223,
229, 255, 85, 154, 176, 255, 65, 143, 166, 255, 112, 169, 187, 255, 236, 240,
242, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 163, 198, 210,
255, 119, 174, 190, 255, 60, 140, 164, 255, 60, 140, 165, 255, 60, 140, 164,
255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
137, 184, 197, 255, 60, 140, 165, 255, 60, 140, 164, 255, 60, 140, 164, 255,
88, 156, 177, 255, 210, 226, 230, 255, 133, 181, 196, 255, 60, 140, 164, 255,
60, 140, 165, 255, 60, 140, 164, 255, 85, 154, 175, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 239,
242, 243, 255, 64, 143, 166, 255, 60, 140, 165, 255, 60, 140, 164, 255, 60,
140, 164, 255, 146, 189, 202, 255, 203, 221, 227, 255, 70, 145, 168, 255, 60,
140, 164, 255, 60, 140, 165, 255, 60, 140, 164, 255, 165, 200, 210, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 140, 164,
255, 60, 140, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 173, 190,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 185, 199,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 137, 183, 198, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 67,
144, 167, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 86, 154, 175, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 237, 241, 242, 255, 64, 142, 166,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164,
255, 64, 141, 166, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 164, 200, 211, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 102, 163, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 139, 184, 199, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 218, 230, 234, 255, 83, 153, 174, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 67, 144, 167, 255, 174, 206, 215,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 153, 193, 205, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 101, 163, 182, 255,
226, 235, 238, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102,
164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163,
198, 210, 255, 119, 174, 190, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60,
139, 164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 213, 227, 231, 255, 85, 154, 175, 255, 60, 140,
164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140,
164, 255, 64, 142, 165, 255, 178, 208, 216, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 242, 243, 244, 255, 148, 189, 203, 255, 60, 139, 164,
255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 140, 164, 255, 97, 160, 180, 255, 231, 238, 240, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119,
173, 190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139,
185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 244, 245, 245, 255, 112, 169, 187, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 67, 143,
167, 255, 229, 236, 239, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 200, 220, 226, 255, 61, 141, 165, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 140, 186, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119, 174, 190,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 185, 199,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 235, 240, 242, 255,
133, 181, 196, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255,
86, 155, 176, 255, 221, 232, 236, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 203,
221, 227, 255, 70, 145, 168, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 150, 191, 204, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 140,
164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 139, 185, 199, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 165, 199, 210, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255,
115, 171, 188, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 245, 245, 245, 255, 83, 153, 174, 255, 60,
140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 61,
141, 165, 255, 192, 215, 222, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140,
164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 140, 164, 255, 60, 140,
165, 255, 60, 140, 164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 131, 181, 196, 255, 60, 140, 165, 255, 60, 140, 164, 255,
60, 140, 164, 255, 67, 143, 168, 255, 140, 185, 200, 255, 83, 153, 174, 255,
60, 140, 164, 255, 60, 140, 165, 255, 60, 140, 164, 255, 79, 151, 173, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 231, 238, 240, 255, 60, 140, 164, 255, 60, 140, 165, 255, 60,
140, 164, 255, 60, 140, 164, 255, 89, 156, 177, 255, 124, 176, 192, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 140, 165, 255, 60, 140, 164, 255, 158,
195, 207, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164,
183, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 163, 198,
210, 255, 119, 173, 190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 181, 208, 217, 255, 68, 144, 167, 255, 60, 139, 164, 255, 64, 141, 166,
255, 174, 205, 214, 255, 245, 246, 246, 255, 209, 224, 229, 255, 81, 151, 173,
255, 60, 139, 164, 255, 60, 139, 164, 255, 129, 179, 194, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
245, 246, 246, 255, 104, 165, 184, 255, 60, 139, 164, 255, 60, 139, 164, 255,
96, 160, 180, 255, 231, 237, 239, 255, 242, 244, 244, 255, 140, 185, 200, 255,
60, 139, 164, 255, 60, 139, 164, 255, 68, 144, 168, 255, 205, 222, 228, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 163, 183, 255, 60, 139,
164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119, 174,
190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 185,
199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 192, 215, 222, 255, 155, 194, 206, 255, 194, 216, 223, 255, 245, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 220, 231, 235, 255, 160,
197, 208, 255, 177, 207, 215, 255, 238, 242, 242, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 227, 236, 237, 255, 169, 202, 212, 255, 169, 202, 212, 255,
226, 234, 237, 255, 246, 246, 246, 255, 246, 246, 246, 255, 242, 244, 244,
255, 183, 210, 219, 255, 155, 194, 206, 255, 205, 222, 228, 255, 245, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198, 210,
255, 119, 174, 190, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164,
255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
102, 164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255,
163, 198, 210, 255, 119, 173, 190, 255, 60, 139, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 139, 164, 255, 139, 184, 199, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255,
60, 139, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 140, 164, 255,
60, 140, 164, 255, 60, 139, 164, 255, 139, 185, 199, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 215, 229, 233, 255, 222, 233, 236,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 223, 233, 236, 255, 213, 227, 232, 255, 245, 245, 245, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139,
164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 140,
164, 255, 60, 140, 165, 255, 60, 140, 164, 255, 139, 185, 199, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 242, 244, 244, 255, 111, 169, 186, 255, 60, 140, 165, 255, 64, 142,
166, 255, 132, 181, 196, 255, 216, 229, 233, 255, 246, 246, 246, 255, 246,
246, 246, 255, 222, 233, 236, 255, 164, 199, 210, 255, 97, 161, 180, 255, 73,
147, 170, 255, 106, 166, 184, 255, 178, 207, 216, 255, 235, 239, 242, 255,
246, 246, 246, 255, 241, 243, 244, 255, 201, 221, 226, 255, 117, 172, 189,
255, 61, 141, 165, 255, 61, 140, 164, 255, 138, 185, 198, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 140, 164, 255, 60, 140, 164,
255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 173, 190, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 185, 199, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 196, 217, 224, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 74, 147, 171, 255, 132, 181, 195, 255, 150, 191, 204,
255, 77, 149, 172, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 95, 160, 180, 255, 158, 196, 207,
255, 120, 173, 191, 255, 61, 140, 165, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 63, 141, 165, 255, 230, 237, 239, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 102, 163, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 163, 198, 210, 255, 119, 174, 190, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 202, 221, 226,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 67, 144, 167, 255, 236, 241, 242, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183,
255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198, 210,
255, 119, 174, 190, 255, 60, 140, 164, 255, 60, 140, 165, 255, 60, 140, 164,
255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 136, 183,
198, 255, 64, 142, 166, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 140,
165, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 140,
165, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 140, 165, 255, 60, 140,
164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 140, 165, 255, 60, 140,
164, 255, 60, 140, 164, 255, 60, 140, 165, 255, 71, 145, 168, 255, 153, 192,
205, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 140,
164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 173,
190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 185,
199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 206,
224, 229, 255, 118, 172, 190, 255, 64, 141, 165, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 95,
160, 180, 255, 143, 187, 200, 255, 87, 155, 176, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 63,
141, 165, 255, 134, 181, 196, 255, 225, 235, 237, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 102, 163, 183, 255, 60, 139, 164, 255,
60, 139, 164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255,
60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139, 184, 199, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 212, 227, 231, 255, 129, 179, 194, 255, 89, 157, 177,
255, 85, 154, 175, 255, 111, 169, 187, 255, 183, 210, 219, 255, 246, 246, 246,
255, 246, 246, 246, 255, 243, 245, 245, 255, 172, 203, 213, 255, 106, 165,
184, 255, 83, 153, 174, 255, 93, 159, 179, 255, 142, 187, 201, 255, 221, 231,
235, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 163, 198, 210, 255, 119, 174, 190, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 139, 185, 199, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 244, 245, 246,
255, 244, 245, 245, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 243, 244, 245, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60, 139, 164,
255, 60, 139, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119, 174, 190,
255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 139, 185, 199,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 164, 183, 255, 60,
140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 163, 198, 210, 255, 119,
174, 190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 139,
185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 102, 163,
183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 163, 198,
210, 255, 119, 174, 190, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139,
164, 255, 139, 185, 199, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246,
246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246,
246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255,
246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246, 255, 246, 246, 246,
255, 102, 164, 183, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164,
255, 163, 198, 210, 255, 129, 180, 195, 255, 60, 140, 164, 255, 60, 140, 165,
255, 60, 140, 164, 255, 93, 158, 178, 255, 158, 196, 207, 255, 159, 197, 207,
255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197,
207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159,
197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255,
159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207,
255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197,
207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159,
197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255,
159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207,
255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197,
207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159,
197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255,
159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207,
255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197,
207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 159, 197, 207, 255, 156,
194, 207, 255, 69, 144, 168, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60,
140, 164, 255, 169, 202, 212, 255, 176, 206, 215, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 203, 221, 227, 255, 234, 239, 240, 255, 84,
153, 175, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 107, 167, 185, 255, 241, 243, 244, 255, 246,
246, 246, 255, 203, 221, 227, 255, 85, 154, 176, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60,
140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60,
140, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60,
139, 164, 255, 60, 139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60,
139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60,
139, 164, 255, 60, 140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 140, 164, 255, 60, 139, 164, 255, 60, 139, 164, 255, 60,
140, 164, 255, 60, 139, 164, 255, 92, 157, 179, 255, 222, 232, 236, 255, 246,
246, 246, 255,
]);

View File

@@ -0,0 +1,22 @@
// this is kept as backup in case megacloud's architecture rollback to it's previous architecture
// import decryptMegacloud from "./megacloud.decryptor.js";
// export async function decryptAllServers(data) {
// const promises = data.map(async (server) => {
// try {
// if (
// server.type === "sub" ||
// server.type === "dub" ||
// server.type === "raw"
// ) {
// return await decryptMegacloud(server.id, server.name, server.type);
// }
// } catch (error) {
// console.error(`Error decrypting server ${server.id}:`, error);
// return null;
// }
// });
// return Promise.all(promises);
// }

View File

@@ -0,0 +1,152 @@
import axios from "axios";
import CryptoJS from "crypto-js";
import * as cheerio from "cheerio";
import { v1_base_url } from "../../utils/base_v1.js";
import { v4_base_url } from "../../utils/base_v4.js";
import { fallback_1, fallback_2 } from "../../utils/fallback.js";
function fetch_key(data) {
let key = null;
const xyMatch = data.match(/window\._xy_ws\s*=\s*["']([^"']+)["']/);
if (xyMatch) {
key = xyMatch[1];
}
if (!key) {
const lkMatch = data.match(/window\._lk_db\s*=\s*\{([^}]+)\}/);
if (lkMatch) {
key = [...lkMatch[1].matchAll(/:\s*["']([^"']+)["']/g)]
.map((v) => v[1])
.join("");
}
}
if (!key) {
const nonceMatch = data.match(/nonce\s*=\s*["']([^"']+)["']/);
if (nonceMatch) {
key = nonceMatch[1];
}
}
if (!key) {
const dpiMatch = data.match(/data-dpi\s*=\s*["']([^"']+)["']/);
if (dpiMatch) {
key = dpiMatch[1];
}
}
if (!key) {
const metaMatch = data.match(
/<meta[^>]*name\s*=\s*["']_gg_fb["'][^>]*content\s*=\s*["']([^"']+)["']/i,
);
if (metaMatch) {
key = metaMatch[1];
}
}
if (!key) {
const isThMatch = data.match(/_is_th\s*:\s*([A-Za-z0-9]+)/);
if (isThMatch) {
key = isThMatch[1];
}
}
return key;
}
export async function decryptSources_v1(epID, id, name, type, fallback) {
try {
let decryptedSources = null;
let iframeURL = null;
if (fallback) {
const fallback_server = ["hd-1", "hd-3"].includes(name.toLowerCase())
? fallback_1
: fallback_2;
iframeURL = `https://${fallback_server}/stream/s-2/${epID}/${type}`;
const { data } = await axios.get(
`https://${fallback_server}/stream/s-2/${epID}/${type}`,
{
headers: {
Referer: `https://${fallback_server}/`,
},
},
);
const $ = cheerio.load(data);
const dataId = $("#megaplay-player").attr("data-id");
const { data: decryptedData } = await axios.get(
`https://${fallback_server}/stream/getSources?id=${dataId}`,
{
headers: {
"X-Requested-With": "XMLHttpRequest",
},
},
);
decryptedSources = decryptedData;
} else {
const { data: sourcesData } = await axios.get(
`https://${v1_base_url}/ajax/v2/episode/sources?id=${id}`,
);
const ajaxLink = sourcesData?.link;
if (!ajaxLink) throw new Error("Missing link in sourcesData");
console.log(ajaxLink);
const sourceIdMatch = /\/([^/?]+)\?/.exec(ajaxLink);
const sourceId = sourceIdMatch?.[1];
if (!sourceId) throw new Error("Unable to extract sourceId from link");
const new_url = `https://megacloud.blog/embed-2/v3/e-1/${sourceId}?k=1`;
const { data: stream_data } = await axios.post(
"https://megacloud.zenime.site/get-sources",
{
embedUrl: new_url,
},
{
headers: {
"Content-Type": "application/json",
},
},
);
decryptedSources = stream_data;
// const baseUrlMatch = ajaxLink.match(
// /^(https?:\/\/[^\/]+(?:\/[^\/]+){3})/,
// );
// if (!baseUrlMatch) throw new Error("Could not extract base URL");
// const baseUrl = baseUrlMatch[1];
// iframeURL = `${baseUrl}/${sourceId}?k=1&autoPlay=0&oa=0&asi=1`;
// const { data: rawSourceData } = await axios.get(
// `${baseUrl}/getSources?id=${sourceId}`,
// );
// decryptedSources = rawSourceData;
}
return {
id,
type,
link: {
file: fallback
? (decryptedSources?.sources?.file ?? "")
: (decryptedSources?.sources?.[0].file ?? ""),
type: "hls",
},
tracks: decryptedSources.tracks ?? [],
intro: decryptedSources.intro ?? null,
outro: decryptedSources.outro ?? null,
iframe: iframeURL,
server: name,
};
} catch (error) {
console.error(
`Error during decryptSources_v1(${id}, epID=${epID}, server=${name}):`,
error.message,
);
return null;
}
}

View File

@@ -0,0 +1,68 @@
// this is kept as backup in case megacloud's architecture rollback to it's previous architecture
// import axios from "axios";
// import CryptoJS from "crypto-js";
// import { v2_base_url } from "../../utils/base_v2.js";
// import fetchScript from "../../helper/fetchScript.helper.js";
// import getKeys from "../../helper/getKey.helper.js";
// import { PLAYER_SCRIPT_URL } from "../../configs/player_v2.config.js";
// async function decryptSources_v2(id, name, type) {
// try {
// const [{ data: sourcesData }, decryptKey_v2] = await Promise.all([
// axios.get(`https://${v2_base_url}/ajax/episode/sources?id=${id}`),
// getKeys(await fetchScript(PLAYER_SCRIPT_URL)),
// ]);
// const ajaxResp = sourcesData.link;
// const [hostname] = /^(https?:\/\/(?:www\.)?[^\/\?]+)/.exec(ajaxResp) || [];
// const [_, sourceId] = /\/([^\/\?]+)\?/.exec(ajaxResp) || [];
// const { data: source } = await axios.get(
// `${hostname}/ajax/embed-6-v2/getSources?id=${sourceId}`
// );
// if (source.encrypted === true) {
// const sourcesArray = source.sources.split("");
// let extractedKey = "";
// let currentIndex = 0;
// for (const index of decryptKey_v2) {
// const start = index[0] + currentIndex;
// const end = start + index[1];
// for (let i = start; i < end; i++) {
// extractedKey += sourcesArray[i];
// sourcesArray[i] = "";
// }
// currentIndex += index[1];
// }
// const decrypted = CryptoJS.AES.decrypt(
// sourcesArray.join(""),
// extractedKey
// ).toString(CryptoJS.enc.Utf8);
// const decryptedSources = JSON.parse(decrypted);
// source.sources = null;
// source.sources = {
// file: decryptedSources[0].file,
// type: "hls",
// };
// }
// if (source.hasOwnProperty("server")) {
// delete source.server;
// }
// return {
// id: id,
// type: type,
// link: source.sources,
// tracks: source.tracks,
// intro: source.intro,
// outro: source.outro,
// server: name,
// };
// } catch (error) {
// console.error("Error during decryption:", error);
// }
// }
// export { decryptSources_v2 };

View File

@@ -0,0 +1,811 @@
//inspired from https://github.com/drblgn/rabbit_wasm
import util from "util";
import pixels from "image-pixels";
import cryptoJs from "crypto-js";
import axios from "axios";
const user_agent =
"Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0";
import { webcrypto } from "crypto";
const crypto = webcrypto;
import { dataURL } from "../../configs/dataUrl.js";
// import { v1_base_url } from "../../utils/base_v1.js";
import { v4_base_url } from "../../utils/base_v4.js";
let wasm;
let arr = new Array(128).fill(void 0);
const dateNow = Date.now();
let content;
let referrer = "";
function isDetached(buffer) {
if (buffer.byteLength === 0) {
const formatted = util.format(buffer);
return formatted.includes("detached");
}
return false;
}
const meta = {
content: content,
};
const image_data = {
height: 50,
width: 65,
data: new Uint8ClampedArray(),
};
const canvas = {
baseUrl: "",
width: 0,
height: 0,
style: {
style: {
display: "inline",
},
},
context2d: {},
};
const fake_window = {
localStorage: {
setItem: function (item, value) {
fake_window.localStorage[item] = value;
},
},
navigator: {
webdriver: false,
userAgent: user_agent,
},
length: 0,
document: {
cookie: "",
},
origin: "",
location: {
href: "",
origin: "",
},
performance: {
timeOrigin: dateNow,
},
xrax: "",
c: false,
G: "",
z: function (a) {
return [
(4278190080 & a) >> 24,
(16711680 & a) >> 16,
(65280 & a) >> 8,
255 & a,
];
},
crypto: crypto,
msCrypto: crypto,
browser_version: 1676800512,
};
const nodeList = {
image: {
src: "",
height: 50,
width: 65,
complete: true,
},
context2d: {},
length: 1,
};
function get(index) {
return arr[index];
}
arr.push(void 0, null, true, false);
let size = 0;
let memoryBuff;
function getMemBuff() {
return (memoryBuff =
null !== memoryBuff && 0 !== memoryBuff.byteLength
? memoryBuff
: new Uint8Array(wasm.memory.buffer));
}
const encoder = new TextEncoder();
const encode = function (text, array) {
return encoder.encodeInto(text, array);
};
function parse(text, func, func2) {
if (void 0 === func2) {
var encoded = encoder.encode(text);
const parsedIndex = func(encoded.length, 1) >>> 0;
return (
getMemBuff()
.subarray(parsedIndex, parsedIndex + encoded.length)
.set(encoded),
(size = encoded.length),
parsedIndex
);
}
let len = text.length;
let parsedLen = func(len, 1) >>> 0;
var new_arr = getMemBuff();
let i = 0;
for (; i < len; i++) {
var char = text.charCodeAt(i);
if (127 < char) {
break;
}
new_arr[parsedLen + i] = char;
}
return (
i !== len &&
(0 !== i && (text = text.slice(i)),
(parsedLen = func2(parsedLen, len, (len = i + 3 * text.length), 1) >>> 0),
(encoded = getMemBuff().subarray(parsedLen + i, parsedLen + len)),
(i += encode(text, encoded).written),
(parsedLen = func2(parsedLen, len, i, 1) >>> 0)),
(size = i),
parsedLen
);
}
let dataView;
function isNull(test) {
return null == test;
}
function getDataView() {
return (dataView =
dataView === null ||
isDetached(dataView.buffer) ||
dataView.buffer !== wasm.memory.buffer
? new DataView(wasm.memory.buffer)
: dataView);
}
let pointer = arr.length;
function shift(QP) {
QP < 132 || ((arr[QP] = pointer), (pointer = QP));
}
function shiftGet(QP) {
var Qn = get(QP);
return shift(QP), Qn;
}
const decoder = new TextDecoder("utf-8", {
fatal: true,
ignoreBOM: true,
});
function decodeSub(index, offset) {
return (
(index >>>= 0), decoder.decode(getMemBuff().subarray(index, index + offset))
);
}
function addToStack(item) {
pointer === arr.length && arr.push(arr.length + 1);
var Qn = pointer;
return (pointer = arr[Qn]), (arr[Qn] = item), Qn;
}
function args(QP, Qn, QT, func) {
const Qx = {
a: QP,
b: Qn,
cnt: 1,
dtor: QT,
};
return (
(QP = (...Qw) => {
Qx.cnt++;
try {
return func(Qx.a, Qx.b, ...Qw);
} finally {
0 == --Qx.cnt &&
(wasm.__wbindgen_export_2.get(Qx.dtor)(Qx.a, Qx.b), (Qx.a = 0));
}
}),
((QP.original = Qx), QP)
);
}
function export3(QP, Qn) {
return shiftGet(wasm.__wbindgen_export_3(QP, Qn));
}
function export4(Qy, QO, QX) {
wasm.__wbindgen_export_4(Qy, QO, addToStack(QX));
}
function export5(QP, Qn) {
wasm.__wbindgen_export_5(QP, Qn);
}
function applyToWindow(func, args) {
try {
return func.apply(fake_window, args);
} catch (error) {
wasm.__wbindgen_export_6(addToStack(error));
}
}
function Qj(QP, Qn) {
return (
(Qn = Qn(+QP.length, 1) >>> 0),
(getMemBuff().set(QP, Qn), (size = QP.length), Qn)
);
}
async function QN(QP, Qn) {
let QT, Qt;
return "function" == typeof Response && QP instanceof Response
? ((QT = await QP.arrayBuffer()),
(Qt = await WebAssembly.instantiate(QT, Qn)),
Object.assign(Qt, { bytes: QT }))
: (Qt = await WebAssembly.instantiate(QP, Qn)) instanceof
WebAssembly.Instance
? {
instance: Qt,
module: QP,
}
: Qt;
}
function initWasm() {
const wasmObj = {
wbg: {
__wbindgen_is_function: function (index) {
return typeof get(index) == "function";
},
__wbindgen_is_string: function (index) {
return typeof get(index) == "string";
},
__wbindgen_is_object: function (index) {
let object = get(index);
return typeof object == "object" && object !== null;
},
__wbindgen_number_get: function (offset, index) {
let number = get(index);
getDataView().setFloat64(offset + 8, isNull(number) ? 0 : number, true);
getDataView().setInt32(offset, isNull(number) ? 0 : 1, true);
},
__wbindgen_string_get: function (offset, index) {
let str = get(index);
let val = parse(
str,
wasm.__wbindgen_export_0,
wasm.__wbindgen_export_1
);
getDataView().setInt32(offset + 4, size, true);
getDataView().setInt32(offset, val, true);
},
__wbindgen_object_drop_ref: function (index) {
shiftGet(index);
},
__wbindgen_cb_drop: function (index) {
let org = shiftGet(index).original;
return 1 == org.cnt-- && !(org.a = 0);
},
__wbindgen_string_new: function (index, offset) {
return addToStack(decodeSub(index, offset));
},
__wbindgen_is_null: function (index) {
return null === get(index);
},
__wbindgen_is_undefined: function (index) {
return void 0 === get(index);
},
__wbindgen_boolean_get: function (index) {
let bool = get(index);
return "boolean" == typeof bool ? (bool ? 1 : 0) : 2;
},
__wbg_instanceof_CanvasRenderingContext2d_4ec30ddd3f29f8f9: function () {
return true;
},
__wbg_subarray_adc418253d76e2f1: function (index, num1, num2) {
return addToStack(get(index).subarray(num1 >>> 0, num2 >>> 0));
},
__wbg_randomFillSync_5c9c955aa56b6049: function () {},
__wbg_getRandomValues_3aa56aa6edec874c: function () {
return applyToWindow(function (index1, index2) {
get(index1).getRandomValues(get(index2));
}, arguments);
},
__wbg_msCrypto_eb05e62b530a1508: function (index) {
return addToStack(get(index).msCrypto);
},
__wbg_toString_6eb7c1f755c00453: function (index) {
let fakestr = "[object Storage]";
return addToStack(fakestr);
},
__wbg_toString_139023ab33acec36: function (index) {
return addToStack(get(index).toString());
},
__wbg_require_cca90b1a94a0255b: function () {
return applyToWindow(function () {
return addToStack(module.require);
}, arguments);
},
__wbg_crypto_1d1f22824a6a080c: function (index) {
return addToStack(get(index).crypto);
},
__wbg_process_4a72847cc503995b: function (index) {
return addToStack(get(index).process);
},
__wbg_versions_f686565e586dd935: function (index) {
return addToStack(get(index).versions);
},
__wbg_node_104a2ff8d6ea03a2: function (index) {
return addToStack(get(index).node);
},
__wbg_localStorage_3d538af21ea07fcc: function () {
return applyToWindow(function (index) {
let data = fake_window.localStorage;
if (isNull(data)) {
return 0;
} else {
return addToStack(data);
}
}, arguments);
},
__wbg_setfillStyle_59f426135f52910f: function () {},
__wbg_setshadowBlur_229c56539d02f401: function () {},
__wbg_setshadowColor_340d5290cdc4ae9d: function () {},
__wbg_setfont_16d6e31e06a420a5: function () {},
__wbg_settextBaseline_c3266d3bd4a6695c: function () {},
__wbg_drawImage_cb13768a1bdc04bd: function () {},
__wbg_getImageData_66269d289f37d3c7: function () {
return applyToWindow(function () {
return addToStack(image_data);
}, arguments);
},
__wbg_rect_2fa1df87ef638738: function () {},
__wbg_fillRect_4dd28e628381d240: function () {},
__wbg_fillText_07e5da9e41652f20: function () {},
__wbg_setProperty_5144ddce66bbde41: function () {},
__wbg_createElement_03cf347ddad1c8c0: function () {
return applyToWindow(function (index, decodeIndex, decodeIndexOffset) {
return addToStack(canvas);
}, arguments);
},
__wbg_querySelector_118a0639aa1f51cd: function () {
return applyToWindow(function (index, decodeIndex, decodeOffset) {
return addToStack(meta);
}, arguments);
},
__wbg_querySelectorAll_50c79cd4f7573825: function () {
return applyToWindow(function () {
return addToStack(nodeList);
}, arguments);
},
__wbg_getAttribute_706ae88bd37410fa: function (
offset,
index,
decodeIndex,
decodeOffset
) {
let attr = meta.content;
let todo = isNull(attr)
? 0
: parse(attr, wasm.__wbindgen_export_0, wasm.__wbindgen_export_1);
getDataView().setInt32(offset + 4, size, true);
getDataView().setInt32(offset, todo, true);
},
__wbg_target_6795373f170fd786: function (index) {
let target = get(index).target;
return isNull(target) ? 0 : addToStack(target);
},
__wbg_addEventListener_f984e99465a6a7f4: function () {},
__wbg_instanceof_HtmlCanvasElement_1e81f71f630e46bc: function () {
return true;
},
__wbg_setwidth_233645b297bb3318: function (index, set) {
get(index).width = set >>> 0;
},
__wbg_setheight_fcb491cf54e3527c: function (index, set) {
get(index).height = set >>> 0;
},
__wbg_getContext_dfc91ab0837db1d1: function () {
return applyToWindow(function (index) {
return addToStack(get(index).context2d);
}, arguments);
},
__wbg_toDataURL_97b108dd1a4b7454: function () {
return applyToWindow(function (offset, index) {
let _dataUrl = parse(
dataURL,
wasm.__wbindgen_export_0,
wasm.__wbindgen_export_1
);
getDataView().setInt32(offset + 4, size, true);
getDataView().setInt32(offset, _dataUrl, true);
}, arguments);
},
__wbg_instanceof_HtmlDocument_1100f8a983ca79f9: function () {
return true;
},
__wbg_style_ca229e3326b3c3fb: function (index) {
addToStack(get(index).style);
},
__wbg_instanceof_HtmlImageElement_9c82d4e3651a8533: function () {
return true;
},
__wbg_src_87a0e38af6229364: function (offset, index) {
let _src = parse(
get(index).src,
wasm.__wbindgen_export_0,
wasm.__wbindgen_export_1
);
getDataView().setInt32(offset + 4, size, true);
getDataView().setInt32(offset, _src, true);
},
__wbg_width_e1a38bdd483e1283: function (index) {
return get(index).width;
},
__wbg_height_e4cc2294187313c9: function (index) {
return get(index).height;
},
__wbg_complete_1162c2697406af11: function (index) {
return get(index).complete;
},
__wbg_data_d34dc554f90b8652: function (offset, index) {
var _data = Qj(get(index).data, wasm.__wbindgen_export_0);
getDataView().setInt32(offset + 4, size, true);
getDataView().setInt32(offset, _data, true);
},
__wbg_origin_305402044aa148ce: function () {
return applyToWindow(function (offset, index) {
let _origin = parse(
get(index).origin,
wasm.__wbindgen_export_0,
wasm.__wbindgen_export_1
);
getDataView().setInt32(offset + 4, size, true);
getDataView().setInt32(offset, _origin, true);
}, arguments);
},
__wbg_length_8a9352f7b7360c37: function (index) {
return get(index).length;
},
__wbg_get_c30ae0782d86747f: function (index) {
let _image = get(index).image;
return isNull(_image) ? 0 : addToStack(_image);
},
__wbg_timeOrigin_f462952854d802ec: function (index) {
return get(index).timeOrigin;
},
__wbg_instanceof_Window_cee7a886d55e7df5: function () {
return true;
},
__wbg_document_eb7fd66bde3ee213: function (index) {
let _document = get(index).document;
return isNull(_document) ? 0 : addToStack(_document);
},
__wbg_location_b17760ac7977a47a: function (index) {
return addToStack(get(index).location);
},
__wbg_performance_4ca1873776fdb3d2: function (index) {
let _performance = get(index).performance;
return isNull(_performance) ? 0 : addToStack(_performance);
},
__wbg_origin_e1f8acdeb3a39a2b: function (offset, index) {
let _origin = parse(
get(index).origin,
wasm.__wbindgen_export_0,
wasm.__wbindgen_export_1
);
getDataView().setInt32(offset + 4, size, true);
getDataView().setInt32(offset, _origin, true);
},
__wbg_get_8986951b1ee310e0: function (index, decode1, decode2) {
let data = get(index)[decodeSub(decode1, decode2)];
return isNull(data) ? 0 : addToStack(data);
},
__wbg_setTimeout_6ed7182ebad5d297: function () {
return applyToWindow(function () {
return 7;
}, arguments);
},
__wbg_self_05040bd9523805b9: function () {
return applyToWindow(function () {
return addToStack(fake_window);
}, arguments);
},
__wbg_window_adc720039f2cb14f: function () {
return applyToWindow(function () {
return addToStack(fake_window);
}, arguments);
},
__wbg_globalThis_622105db80c1457d: function () {
return applyToWindow(function () {
return addToStack(fake_window);
}, arguments);
},
__wbg_global_f56b013ed9bcf359: function () {
return applyToWindow(function () {
return addToStack(fake_window);
}, arguments);
},
__wbg_newnoargs_cfecb3965268594c: function (index, offset) {
return addToStack(new Function(decodeSub(index, offset)));
},
__wbindgen_object_clone_ref: function (index) {
return addToStack(get(index));
},
__wbg_eval_c824e170787ad184: function () {
return applyToWindow(function (index, offset) {
let fake_str = "fake_" + decodeSub(index, offset);
let ev = eval(fake_str);
return addToStack(ev);
}, arguments);
},
__wbg_call_3f093dd26d5569f8: function () {
return applyToWindow(function (index, index2) {
return addToStack(get(index).call(get(index2)));
}, arguments);
},
__wbg_call_67f2111acd2dfdb6: function () {
return applyToWindow(function (index, index2, index3) {
return addToStack(get(index).call(get(index2), get(index3)));
}, arguments);
},
__wbg_set_961700853a212a39: function () {
return applyToWindow(function (index, index2, index3) {
return Reflect.set(get(index), get(index2), get(index3));
}, arguments);
},
__wbg_buffer_b914fb8b50ebbc3e: function (index) {
return addToStack(get(index).buffer);
},
__wbg_newwithbyteoffsetandlength_0de9ee56e9f6ee6e: function (
index,
val,
val2
) {
return addToStack(new Uint8Array(get(index), val >>> 0, val2 >>> 0));
},
__wbg_newwithlength_0d03cef43b68a530: function (length) {
return addToStack(new Uint8Array(length >>> 0));
},
__wbg_new_b1f2d6842d615181: function (index) {
return addToStack(new Uint8Array(get(index)));
},
__wbg_buffer_67e624f5a0ab2319: function (index) {
return addToStack(get(index).buffer);
},
__wbg_length_21c4b0ae73cba59d: function (index) {
return get(index).length;
},
__wbg_set_7d988c98e6ced92d: function (index, index2, val) {
get(index).set(get(index2), val >>> 0);
},
__wbindgen_debug_string: function () {},
__wbindgen_throw: function (index, offset) {
throw new Error(decodeSub(index, offset));
},
__wbindgen_memory: function () {
return addToStack(wasm.memory);
},
__wbindgen_closure_wrapper117: function (Qn, QT) {
return addToStack(args(Qn, QT, 2, export3));
},
__wbindgen_closure_wrapper119: function (Qn, QT) {
return addToStack(args(Qn, QT, 2, export4));
},
__wbindgen_closure_wrapper121: function (Qn, QT) {
return addToStack(args(Qn, QT, 2, export5));
},
__wbindgen_closure_wrapper123: function (Qn, QT) {
let test = addToStack(args(Qn, QT, 9, export4));
return test;
},
},
};
return wasmObj;
}
function assignWasm(resp) {
wasm = resp.exports;
(dataView = null), (memoryBuff = null), wasm;
}
function QZ(QP) {
let Qn;
return (
(Qn = initWasm()),
QP instanceof WebAssembly.Module || (QP = new WebAssembly.Module(QP)),
assignWasm(new WebAssembly.Instance(QP, Qn))
);
}
async function loadWasm(url) {
let mod, buffer;
return (
(mod = initWasm()),
({
instance: url,
module: mod,
bytes: buffer,
} = ((url = fetch(url)), void 0, await QN(await url, mod))),
assignWasm(url),
buffer
);
}
const grootLoader = {
groot: function () {
wasm.groot();
},
};
let wasmLoader = Object.assign(loadWasm, { initSync: QZ }, grootLoader);
const V = async (url) => {
let Q0 = await wasmLoader(url);
fake_window.bytes = Q0;
try {
wasmLoader.groot();
} catch (error) {
console.error("error: ", error);
}
fake_window.jwt_plugin(Q0);
return fake_window.navigate();
};
const getMeta = async (url) => {
let resp = await fetch(url, {
headers: {
UserAgent: user_agent,
Referrer: referrer,
},
});
let txt = await resp.text();
let regx = /name="j_crt" content="[A-Za-z0-9]*/g;
let match = txt.match(regx)[0];
let content = match.slice(match.lastIndexOf('"') + 1);
meta.content = content + "==";
};
const i = (a, P) => {
try {
for (let Q0 = 0; Q0 < a.length; Q0++) {
a[Q0] = a[Q0] ^ P[Q0 % P.length];
}
} catch (Q1) {
return null;
}
};
const M = (a, P) => {
try {
var Q0 = cryptoJs.AES.decrypt(a, P);
return JSON.parse(Q0.toString(cryptoJs.enc.Utf8));
} catch (Q1) {
var Q0 = cryptoJs.AES.decrypt(a, P);
}
return [];
};
function z(a) {
return [
(a & 4278190080) >> 24,
(a & 16711680) >> 16,
(a & 65280) >> 8,
a & 255,
];
}
const decryptSource = async (embed_url) => {
referrer = embed_url.includes("mega")
? `https://${v4_base_url}`
: new URL(embed_url).origin;
// let regx = /([A-Z])\w+/;
let xrax = embed_url.split("/").pop().split("?").shift();
// regx = /https:\/\/[a-zA-Z0-9.]*/;
// let base_url = embed_url.match(regx)[0];
const base_url = new URL(embed_url).origin;
nodeList.image.src = base_url + "/images/image.png?v=0.0.9";
let data = new Uint8ClampedArray((await pixels(nodeList.image.src)).data);
image_data.data = data;
let test = embed_url.split("/");
let browser_version = 1676800512;
canvas.baseUrl = base_url;
fake_window.origin = base_url;
fake_window.location.origin = base_url;
fake_window.location.href = embed_url;
fake_window.xrax = xrax;
fake_window.G = xrax;
await getMeta(embed_url);
let Q5 = await V(base_url + "/images/loading.png?v=0.0.9");
let getSourcesUrl = "";
if (base_url.includes("mega")) {
getSourcesUrl =
base_url +
"/" +
test[3] +
"/ajax/" +
test[4] +
"/getSources?id=" +
fake_window.pid +
"&v=" +
fake_window.localStorage.kversion +
"&h=" +
fake_window.localStorage.kid +
"&b=" +
browser_version;
} else {
getSourcesUrl =
base_url +
"/ajax/" +
test[3] +
// "/" +
// test[4] +
"/getSources?id=" +
fake_window.pid +
"&v=" +
fake_window.localStorage.kversion +
"&h=" +
fake_window.localStorage.kid +
"&b=" +
browser_version;
}
let { data: resp } = await axios.get(getSourcesUrl, {
headers: {
"User-Agent": user_agent,
Referrer: embed_url + "&autoPlay=1&oa=0&asi=1",
"Accept-Language": "en,bn;q=0.9,en-US;q=0.8",
"sec-ch-ua":
'"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
"sec-ch-ua-mobile": "?1",
"sec-ch-ua-platform": '"Android"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Site": "same-origin",
"X-Requested-With": "XMLHttpRequest",
"Sec-Fetch-Mode": "cors",
},
});
let Q3 = fake_window.localStorage.kversion;
let Q1 = z(Q3);
Q5 = new Uint8Array(Q5);
let Q8 = resp.t != 0 ? (i(Q5, Q1), Q5) : ((Q8 = resp.k), i(Q8, Q1), Q8);
let str = btoa(String.fromCharCode.apply(null, new Uint8Array(Q8)));
var decryptedSource = M(resp.sources, str);
resp.sources = decryptedSource;
return resp;
};
export default async function decryptMegacloud(id, name, type) {
try {
const { data: sourcesData } = await axios.get(
// `https://${v1_base_url}/ajax/v2/episode/sources?id=${id}`
`https://${v4_base_url}/ajax/episode/sources?id=${id}`
);
const source = await decryptSource(sourcesData.link);
return {
id: id,
type: type,
link: source.sources[0],
tracks: source.tracks,
intro: source.intro,
outro: source.outro,
server: name,
iframe: sourcesData.link,
};
} catch (error) {
console.error("Error during decryption:", error);
}
}

View File

@@ -0,0 +1,29 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v1_base_url } from "../utils/base_v1.js";
export async function fetchServerData_v1(id) {
try {
const { data } = await axios.get(
`https://${v1_base_url}/ajax/v2/episode/servers?episodeId=${id}`
);
const $ = cheerio.load(data.html);
const serverData = $("div.ps_-block > div.ps__-list > div.server-item")
.filter((_, ele) => {
const name = $(ele).find("a.btn").text();
return name === "HD-1" || name === "HD-2";
})
.map((_, ele) => ({
name: $(ele).find("a.btn").text(),
id: $(ele).attr("data-id"),
type: $(ele).attr("data-type"),
}))
.get();
return serverData;
} catch (error) {
console.error("Error fetching server data:", error);
return [];
}
}

View File

@@ -0,0 +1,29 @@
import axios from "axios";
import * as cheerio from "cheerio";
import { v2_base_url } from "../utils/base_v2.js";
export async function fetchServerData_v2(id) {
try {
const { data } = await axios.get(
`https://${v2_base_url}/ajax/episode/servers?episodeId=${id}`
);
const $ = cheerio.load(data.html);
const serverData = $("div.ps_-block > div.ps__-list > div.server-item")
.filter((_, ele) => {
const name = $(ele).find("a.btn").text().trim();
return name === "Vidcloud";
})
.map((_, ele) => ({
name: $(ele).find("a.btn").text().trim(),
id: $(ele).attr("data-id"),
type: $(ele).attr("data-type"),
}))
.get();
return serverData;
} catch (error) {
console.error("Error fetching server data:", error);
return [];
}
}

89
src/routes/apiRoutes.js Normal file
View File

@@ -0,0 +1,89 @@
import * as homeInfoController from "../controllers/homeInfo.controller.js";
import * as categoryController from "../controllers/category.controller.js";
import * as topTenController from "../controllers/topten.controller.js";
import * as animeInfoController from "../controllers/animeInfo.controller.js";
import * as streamController from "../controllers/streamInfo.controller.js";
import * as searchController from "../controllers/search.controller.js";
import * as episodeListController from "../controllers/episodeList.controller.js";
import * as suggestionsController from "../controllers/suggestion.controller.js";
import * as scheduleController from "../controllers/schedule.controller.js";
import * as serversController from "../controllers/servers.controller.js";
import * as randomController from "../controllers/random.controller.js";
import * as qtipController from "../controllers/qtip.controller.js";
import * as randomIdController from "../controllers/randomId.controller.js";
import * as producerController from "../controllers/producer.controller.js";
import * as characterListController from "../controllers/voiceactor.controller.js";
import * as nextEpisodeScheduleController from "../controllers/nextEpisodeSchedule.controller.js";
import { routeTypes } from "./category.route.js";
import { getWatchlist } from "../controllers/watchlist.controller.js";
import getVoiceActors from "../controllers/actors.controller.js";
import getCharacter from "../controllers/characters.controller.js";
import * as filterController from "../controllers/filter.controller.js";
import getTopSearch from "../controllers/topsearch.controller.js";
export const createApiRoutes = (app, jsonResponse, jsonError) => {
const createRoute = (path, controllerMethod) => {
app.get(path, async (req, res) => {
try {
const data = await controllerMethod(req, res);
if (!res.headersSent) {
return jsonResponse(res, data);
}
} catch (err) {
console.error(`Error in route ${path}:`, err);
if (!res.headersSent) {
return jsonError(res, err.message || "Internal server error");
}
}
});
};
["/api", "/api/"].forEach((route) => {
app.get(route, async (req, res) => {
try {
const data = await homeInfoController.getHomeInfo(req, res);
if (!res.headersSent) {
return jsonResponse(res, data);
}
} catch (err) {
console.error("Error in home route:", err);
if (!res.headersSent) {
return jsonError(res, err.message || "Internal server error");
}
}
});
});
routeTypes.forEach((routeType) =>
createRoute(`/api/${routeType}`, (req, res) =>
categoryController.getCategory(req, res, routeType)
)
);
createRoute("/api/top-ten", topTenController.getTopTen);
createRoute("/api/info", animeInfoController.getAnimeInfo);
createRoute("/api/episodes/:id", episodeListController.getEpisodes);
createRoute("/api/servers/:id", serversController.getServers);
createRoute("/api/stream", (req, res) => streamController.getStreamInfo(req, res, false));
createRoute("/api/stream/fallback", (req, res) => streamController.getStreamInfo(req, res, true));
createRoute("/api/search", searchController.search);
createRoute("/api/filter", filterController.filter);
createRoute("/api/search/suggest", suggestionsController.getSuggestions);
createRoute("/api/schedule", scheduleController.getSchedule);
createRoute(
"/api/schedule/:id",
nextEpisodeScheduleController.getNextEpisodeSchedule
);
createRoute("/api/random", randomController.getRandom);
createRoute("/api/random/id", randomIdController.getRandomId);
createRoute("/api/qtip/:id", qtipController.getQtip);
createRoute("/api/producer/:id", producerController.getProducer);
createRoute(
"/api/character/list/:id",
characterListController.getVoiceActors
);
createRoute("/api/watchlist/:userId{/:page}", getWatchlist);
createRoute("/api/actors/:id", getVoiceActors);
createRoute("/api/character/:id", getCharacter);
createRoute("/api/top-search", getTopSearch);
};

View File

@@ -0,0 +1,87 @@
export const routeTypes = [
"genre/action",
"genre/adventure",
"genre/cars",
"genre/comedy",
"genre/dementia",
"genre/demons",
"genre/drama",
"genre/ecchi",
"genre/fantasy",
"genre/game",
"genre/harem",
"genre/historical",
"genre/horror",
"genre/isekai",
"genre/josei",
"genre/kids",
"genre/magic",
"genre/martial-arts",
"genre/mecha",
"genre/military",
"genre/music",
"genre/mystery",
"genre/parody",
"genre/police",
"genre/psychological",
"genre/romance",
"genre/samurai",
"genre/school",
"genre/sci-fi",
"genre/seinen",
"genre/shoujo",
"genre/shoujo-ai",
"genre/shounen",
"genre/shounen-ai",
"genre/slice-of-life",
"genre/space",
"genre/sports",
"genre/super-power",
"genre/supernatural",
"genre/thriller",
"genre/vampire",
"top-airing",
"most-popular",
"most-favorite",
"completed",
"recently-updated",
"recently-added",
"top-upcoming",
"subbed-anime",
"dubbed-anime",
"movie",
"special",
"ova",
"ona",
"tv",
"music",
"az-list",
"az-list/other",
"az-list/0-9",
"az-list/a",
"az-list/b",
"az-list/c",
"az-list/d",
"az-list/e",
"az-list/f",
"az-list/g",
"az-list/h",
"az-list/i",
"az-list/j",
"az-list/k",
"az-list/l",
"az-list/m",
"az-list/n",
"az-list/o",
"az-list/p",
"az-list/q",
"az-list/r",
"az-list/s",
"az-list/t",
"az-list/u",
"az-list/v",
"az-list/w",
"az-list/x",
"az-list/y",
"az-list/z",
];

129
src/routes/filter.maping.js Normal file
View File

@@ -0,0 +1,129 @@
const FILTER_LANGUAGE_MAP = {
ALL: '',
SUB: '1',
DUB: '2',
SUB_DUB: '3'
};
const GENRE_MAP = {
ACTION: '1',
ADVENTURE: '2',
CARS: '3',
COMEDY: '4',
DEMENTIA: '5',
DEMONS: '6',
DRAMA: '8',
ECCHI: '9',
FANTASY: '10',
GAME: '11',
HAREM: '35',
HISTORICAL: '13',
HORROR: '14',
ISEKAI: '44',
JOSEI: '43',
KIDS: '15',
MAGIC: '16',
MARTIAL_ARTS: '17',
MECHA: '18',
MILITARY: '38',
MUSIC: '19',
MYSTERY: '7',
PARODY: '20',
POLICE: '39',
PSYCHOLOGICAL: '40',
ROMANCE: '22',
SAMURAI: '21',
SCHOOL: '23',
SCI_FI: '24',
SEINEN: '42',
SHOUJO: '25',
SHOUJO_AI: '26',
SHOUNEN: '27',
SHOUNEN_AI: '28',
SLICE_OF_LIFE: '36',
SPACE: '29',
SPORTS: '30',
SUPER_POWER: '31',
SUPERNATURAL: '37',
THRILLER: '41',
VAMPIRE: '32'
};
const FILTER_TYPES = {
ALL: '',
MOVIE: '1',
TV: '2',
OVA: '3',
ONA: '4',
SPECIAL: '5',
MUSIC: '6'
};
const FILTER_STATUS = {
ALL: '',
FINISHED: '1',
CURRENTLY_AIRING: '2',
NOT_YET_AIRED: '3'
};
const FILTER_RATED = {
ALL: '',
G: '1',
PG: '2',
PG_13: '3',
R: '4',
R_PLUS: '5',
RX: '6'
};
const FILTER_SCORE = {
ALL: '',
APPALLING: '1',
HORRIBLE: '2',
VERY_BAD: '3',
BAD: '4',
AVERAGE: '5',
FINE: '6',
GOOD: '7',
VERY_GOOD: '8',
GREAT: '9',
MASTERPIECE: '10'
};
const FILTER_SEASON = {
ALL: '',
SPRING: '1',
SUMMER: '2',
FALL: '3',
WINTER: '4'
};
const FILTER_LANGUAGE = {
ALL: '',
SUB: '1',
DUB: '2',
SUB_DUB: '3'
};
const FILTER_SORT = {
DEFAULT: 'default',
RECENTLY_ADDED: 'recently_added',
RECENTLY_UPDATED: 'recently_updated',
SCORE: 'score',
NAME_AZ: 'name_az',
RELEASED_DATE: 'released_date',
MOST_WATCHED: 'most_watched'
};
export {
FILTER_LANGUAGE_MAP,
GENRE_MAP,
FILTER_TYPES,
FILTER_STATUS,
FILTER_RATED,
FILTER_SCORE,
FILTER_SEASON,
FILTER_LANGUAGE,
FILTER_SORT
};

1
src/utils/base_v1.js Normal file
View File

@@ -0,0 +1 @@
export const v1_base_url = "hianime.do";

1
src/utils/base_v2.js Normal file
View File

@@ -0,0 +1 @@
export const v2_base_url = "kaido.to";

1
src/utils/base_v3.js Normal file
View File

@@ -0,0 +1 @@
export const v3_base_url = "aniplay.lol";

1
src/utils/base_v4.js Normal file
View File

@@ -0,0 +1 @@
export const v4_base_url = "9animetv.to";

2
src/utils/fallback.js Normal file
View File

@@ -0,0 +1,2 @@
export const fallback_1="megaplay.buzz"
export const fallback_2="vidwish.live"

1
src/utils/provider.js Normal file
View File

@@ -0,0 +1 @@
export const provider = "https://megacloud.club";