diff --git a/api/v1/src/release.ts b/api/v1/src/release.ts
index c509abe..a3cd174 100644
--- a/api/v1/src/release.ts
+++ b/api/v1/src/release.ts
@@ -1,14 +1,16 @@
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";
+// In-memory cache
+const cache = new Map(); // ключ — releaseId, значение — { code, release }
+
const baseHeaders = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Accept": "application/json",
};
-// Функция для расчёта рейтинга из rates_scores_stats
+// Расчёт взвешенного рейтинга Shikimori
function calculateWeightedScore(stats) {
if (!stats?.length) return null;
-
let total = 0;
let count = 0;
@@ -22,52 +24,44 @@ function calculateWeightedScore(stats) {
return count ? (total / count).toFixed(2) : null;
}
-// Получаем данные Shikimori
-async function getShikimoriData(search, year) {
- if (!search) {
- return { weightedScore: "N/A", characters: [] };
- }
+// Получение данных Shikimori по названию и году
+async function getShikimoriData(titles, year) {
+ for (const title of titles) {
+ const animeUrl = `https://shikimori.one/api/animes?search=${encodeURIComponent(title)}&limit=1${year ? `&year=${year}` : ""}`;
- const animeUrl = `https://shikimori.one/api/animes?search=${encodeURIComponent(search)}&limit=1${year ? `&year=${year}` : ""}`;
+ try {
+ const animeRes = await fetch(animeUrl, { headers: baseHeaders });
+ const animeData = await animeRes.json();
+ const anime = animeData?.[0];
+ if (!anime || !anime.id) continue;
- try {
- const animeRes = await fetch(animeUrl, { headers: baseHeaders });
- const animeData = await animeRes.json();
- const anime = animeData?.[0];
+ const statsUrl = `https://shikimori.one/api/animes/${anime.id}`;
+ const statsRes = await fetch(statsUrl, { headers: baseHeaders });
+ const statsData = await statsRes.json();
+ const weightedScore = calculateWeightedScore(statsData.rates_scores_stats) || "N/A";
- if (!anime || !anime.id) {
- return { weightedScore: "N/A", characters: [] };
+ const rolesUrl = `https://shikimori.one/api/animes/${anime.id}/roles`;
+ const rolesRes = await fetch(rolesUrl, { headers: baseHeaders });
+ const roles = await rolesRes.json();
+
+ const mainCharacters = roles
+ .filter((c) => c.roles.includes("Main"))
+ .slice(0, 5)
+ .map((c) => ({
+ name: c.character.russian,
+ url: `https://shikimori.one${c.character.url}`,
+ }));
+
+ return { weightedScore, characters: mainCharacters };
+ } catch {
+ continue;
}
-
- // Получаем рейтинг из rates_scores_stats
- const statsUrl = `https://shikimori.one/api/animes/${anime.id}`;
- const statsRes = await fetch(statsUrl, { headers: baseHeaders });
- const statsData = await statsRes.json();
- const weightedScore = calculateWeightedScore(statsData.rates_scores_stats) || "N/A";
-
- // Получаем главных персонажей
- const rolesUrl = `https://shikimori.one/api/animes/${anime.id}/roles`;
- const rolesRes = await fetch(rolesUrl, { headers: baseHeaders });
- const roles = await rolesRes.json();
-
- const mainCharacters = roles
- .filter((c) => c.roles.includes("Main"))
- .slice(0, 5)
- .map((c) => ({
- name: c.character.russian,
- url: `https://shikimori.one${c.character.url}`,
- }));
-
- return {
- weightedScore,
- characters: mainCharacters,
- };
- } catch {
- return { weightedScore: "N/A", characters: [] };
}
+
+ return { weightedScore: "N/A", characters: [] };
}
-// Получаем рейтинг MyAnimeList через Jikan
+// Получение рейтинга с MyAnimeList
async function getMALScore(title) {
const url = `https://api.jikan.moe/v4/anime?q=${encodeURIComponent(title)}&limit=1`;
@@ -75,19 +69,20 @@ async function getMALScore(title) {
const response = await fetch(url);
const data = await response.json();
const anime = data?.data?.[0];
-
- if (!anime || !anime.score) {
- return "N/A";
- }
-
+ if (!anime || !anime.score) return "N/A";
return `${anime.score}★`;
} catch {
return "N/A";
}
}
-// Основная функция получения релиза и формирования примечания
+// Основная функция обработки релиза
async function getReleaseFromAnixart(releaseId, token = "") {
+ // Проверка кэша
+ if (cache.has(releaseId)) {
+ return cache.get(releaseId);
+ }
+
const url = `https://api.anixart.tv/release/${releaseId}${token ? `?token=${token}` : ""}`;
try {
@@ -96,46 +91,54 @@ async function getReleaseFromAnixart(releaseId, token = "") {
const release = data?.release;
if (!release) {
- return { code: 2, release: null };
+ const result = { code: 2, release: null };
+ cache.set(releaseId, result);
+ return result;
}
- const title = release.title_original || release.title_ru || "";
+ const title_original = release.title_original || "";
+ const title_ru = release.title_ru || "";
const year = release.year || "";
try {
- const shikiData = await getShikimoriData(title, year);
+ const shikiData = await getShikimoriData([title_original, title_ru], year);
const shikiScore = shikiData.weightedScore !== "N/A" ? `Рейтинг Shikimori: ${shikiData.weightedScore}★` : "";
- const malScoreRaw = await getMALScore(title);
+ const malScoreRaw = await getMALScore(title_original || title_ru);
const malScore = malScoreRaw !== "N/A" ? `Рейтинг MyAnimeList: ${malScoreRaw}` : "";
const characters = shikiData.characters.length
? `Главные персонажи: ` + shikiData.characters.map(c => `${c.name}`).join(", ")
: "";
- // Собираем рейтинг и персонажей, фильтруя пустые строки
const ratingParts = [shikiScore, malScore].filter(Boolean).join("
");
- const charsPart = characters ? characters : "";
-
- // Примечание от Anixart (без лишних br если пустое)
const originalNote = release.note?.trim();
-
let finalNote = "";
+
if (ratingParts) finalNote += ratingParts;
- if (charsPart) finalNote += (finalNote ? "
" : "") + charsPart;
+ if (characters) finalNote += (finalNote ? "
" : "") + characters;
if (originalNote) finalNote += (finalNote ? "
" : "") + `Примечание от Anixart:
${originalNote}`;
release.note = finalNote || null;
-
} catch {
release.note = null;
}
- return { code: 0, release };
+ // Принудительно разблокируем
+ release.is_ru_blocked = false;
+ release.is_tpp_disabled = false;
+ release.is_view_blocked = false;
+ release.is_play_disabled = false;
+
+ const result = { code: 0, release };
+ cache.set(releaseId, result);
+ return result;
} catch {
- return { code: 2, release: null };
+ const result = { code: 2, release: null };
+ cache.set(releaseId, result);
+ return result;
}
}
-// HTTP сервер
+// HTTP-сервер
serve(async (req) => {
const url = new URL(req.url);
const path = url.pathname;