feat(anime): turkanime bölüm listesi çekme özelliği ekle
Turkanime anime URL'lerini destekleyerek bölüm listelerini çekme özelliği eklendi. Kullanıcılar turkanime.tv anime sayfa URL'lerini girerek bölüm linklerini alabilirler. - Yeni TURKANIME_DEBUG çevre değişkeni eklendi - /api/turkanime/episodes API uç noktası eklendi - İstemci tarafında URL normalizasyonu ve işlemesi eklendi - HTML'den bölüm linklerini çıkarma mantığı eklendi
This commit is contained in:
118
server/server.js
118
server/server.js
@@ -91,6 +91,7 @@ const YT_ALLOWED_RESOLUTIONS = new Set([
|
||||
]);
|
||||
const YT_EXTRACTOR_ARGS =
|
||||
process.env.YT_DLP_EXTRACTOR_ARGS || null;
|
||||
const TURKANIME_DEBUG = String(process.env.TURKANIME_DEBUG || "").toLowerCase() === "1";
|
||||
let resolvedYtDlpBinary = null;
|
||||
const TMDB_API_KEY = process.env.TMDB_API_KEY;
|
||||
const TMDB_BASE_URL = "https://api.themoviedb.org/3";
|
||||
@@ -728,6 +729,52 @@ function normalizeYoutubeWatchUrl(value) {
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeTurkanimeUrl(value) {
|
||||
if (!value || typeof value !== "string") return null;
|
||||
try {
|
||||
const urlObj = new URL(value.trim());
|
||||
if (urlObj.protocol !== "https:") return null;
|
||||
const host = urlObj.hostname.toLowerCase();
|
||||
if (!host.endsWith("turkanime.tv")) return null;
|
||||
if (!urlObj.pathname.startsWith("/anime/")) return null;
|
||||
urlObj.hash = "";
|
||||
return urlObj.toString();
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function extractTurkanimeEpisodeLinks(html) {
|
||||
if (!html) return [];
|
||||
const listMatch = html.match(
|
||||
/<ul[^>]*class=["'][^"']*list[^"']*menum[^"']*["'][^>]*>([\s\S]*?)<\/ul>/i
|
||||
);
|
||||
if (!listMatch) return [];
|
||||
const listHtml = listMatch[1];
|
||||
const hrefs = [];
|
||||
const hrefRegex = /href=["']([^"']+)["']/gi;
|
||||
let match;
|
||||
while ((match = hrefRegex.exec(listHtml))) {
|
||||
hrefs.push(match[1]);
|
||||
}
|
||||
const links = hrefs
|
||||
.filter((href) => href.includes("/video/"))
|
||||
.map((href) => {
|
||||
if (href.startsWith("//")) return `https:${href}`;
|
||||
if (href.startsWith("/")) return `https://www.turkanime.tv${href}`;
|
||||
return href;
|
||||
})
|
||||
.filter((href) => {
|
||||
try {
|
||||
const urlObj = new URL(href);
|
||||
return urlObj.hostname.toLowerCase().endsWith("turkanime.tv");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return Array.from(new Set(links));
|
||||
}
|
||||
|
||||
function startYoutubeDownload(url) {
|
||||
const normalized = normalizeYoutubeWatchUrl(url);
|
||||
if (!normalized) return null;
|
||||
@@ -6234,6 +6281,77 @@ app.post("/api/youtube/download", requireAuth, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/api/turkanime/episodes", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const rawUrl = req.body?.url;
|
||||
const normalized = normalizeTurkanimeUrl(rawUrl);
|
||||
if (!normalized) {
|
||||
return res.status(400).json({
|
||||
ok: false,
|
||||
error: "Geçerli bir turkanime.tv anime URL'si gerekli."
|
||||
});
|
||||
}
|
||||
if (TURKANIME_DEBUG) {
|
||||
console.log("🧪 Turkanime fetch başlıyor:", normalized);
|
||||
}
|
||||
const resp = await fetch(normalized, {
|
||||
headers: {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
|
||||
Accept: "text/html"
|
||||
}
|
||||
});
|
||||
if (!resp.ok) {
|
||||
if (TURKANIME_DEBUG) {
|
||||
console.warn("🧪 Turkanime HTTP hata:", resp.status, resp.statusText);
|
||||
}
|
||||
return res.status(502).json({
|
||||
ok: false,
|
||||
error: `Turkanime sayfası alınamadı (HTTP ${resp.status}).`
|
||||
});
|
||||
}
|
||||
const html = await resp.text();
|
||||
if (TURKANIME_DEBUG) {
|
||||
console.log("🧪 Turkanime HTML uzunluğu:", html.length);
|
||||
}
|
||||
const links = extractTurkanimeEpisodeLinks(html);
|
||||
if (!links.length) {
|
||||
if (TURKANIME_DEBUG) {
|
||||
const hasBolumler = html.includes("bolumler");
|
||||
const hasList = /class=["'][^"']*list[^"']*menum/i.test(html);
|
||||
const bolumIndex = html.indexOf("bolumler");
|
||||
const snippetStart = bolumIndex > 200 ? bolumIndex - 200 : 0;
|
||||
const snippet =
|
||||
bolumIndex >= 0
|
||||
? html.slice(snippetStart, bolumIndex + 400)
|
||||
: html.slice(0, 400);
|
||||
console.warn("🧪 Turkanime bölüm listesi bulunamadı.", {
|
||||
hasBolumler,
|
||||
hasList,
|
||||
bolumIndex,
|
||||
snippet
|
||||
});
|
||||
}
|
||||
return res.status(404).json({
|
||||
ok: false,
|
||||
error: "Bölüm listesi bulunamadı."
|
||||
});
|
||||
}
|
||||
if (TURKANIME_DEBUG) {
|
||||
console.log("🧪 Turkanime bölüm link sayısı:", links.length);
|
||||
}
|
||||
res.json({ ok: true, links });
|
||||
} catch (err) {
|
||||
if (TURKANIME_DEBUG) {
|
||||
console.error("🧪 Turkanime hata:", err?.message || err);
|
||||
}
|
||||
res.status(500).json({
|
||||
ok: false,
|
||||
error: err?.message || "Turkanime verisi alınamadı."
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// --- 🎫 YouTube cookies yönetimi ---
|
||||
app.get("/api/youtube/cookies", requireAuth, (req, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user