From 90e3ae6152d280b197e4fec96cefbf32cb862c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=BC=E3=83=BC=E3=83=AC?= Date: Wed, 11 Jun 2025 17:40:25 +0500 Subject: [PATCH] Update release.ts --- api/v1/src/release.ts | 125 +++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 61 deletions(-) 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;