UI Değişiklikleri

This commit is contained in:
2025-10-28 18:56:07 +03:00
parent f5cfa05188
commit 0930edfa0f
3 changed files with 151 additions and 27 deletions

View File

@@ -57,6 +57,8 @@ const TVDB_USER_TOKEN = "mock_api_key"
const TVDB_BASE_URL = "https://api4.thetvdb.com/v4";
const TVDB_IMAGE_BASE =
process.env.TVDB_IMAGE_BASE || "https://artworks.thetvdb.com";
const FANART_TV_API_KEY = process.env.FANART_TV_API_KEY || null;
const FANART_TV_BASE_URL = "https://webservice.fanart.tv/v3";
const FFPROBE_PATH = process.env.FFPROBE_PATH || "ffprobe";
const FFPROBE_MAX_BUFFER =
Number(process.env.FFPROBE_MAX_BUFFER) > 0
@@ -107,6 +109,40 @@ async function downloadTvdbImage(imagePath, targetPath) {
}
}
async function fetchFanartTvImages(thetvdbId) {
if (!FANART_TV_API_KEY || !thetvdbId) return null;
const url = `${FANART_TV_BASE_URL}/tv/${thetvdbId}?api_key=${FANART_TV_API_KEY}`;
try {
const resp = await fetch(url);
if (!resp.ok) {
console.warn(`⚠️ Fanart.tv isteği başarısız (${url}): ${resp.status}`);
return null;
}
const data = await resp.json();
console.log("🖼️ Fanart.tv backdrop araması:", { thetvdbId, hasShowbackground: Boolean(data.showbackground) });
return data;
} catch (err) {
console.warn(`⚠️ Fanart.tv isteği hatası (${url}): ${err.message}`);
return null;
}
}
async function downloadFanartTvImage(imageUrl, targetPath) {
if (!imageUrl) return false;
try {
const resp = await fetch(imageUrl);
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
ensureDirForFile(targetPath);
const arr = await resp.arrayBuffer();
fs.writeFileSync(targetPath, Buffer.from(arr));
return true;
} catch (err) {
console.warn(`⚠️ Fanart.tv görsel indirilemedi (${imageUrl}): ${err.message}`);
return false;
}
}
function titleCase(value) {
if (!value) return "";
return value
@@ -218,6 +254,64 @@ function normalizeTvdbSeason(raw) {
};
}
function toDimension(value) {
const num = Number(value);
return Number.isFinite(num) ? num : null;
}
function artworkKind(value) {
return String(value || "").toLowerCase();
}
function isBackgroundArtwork(entry) {
const candidates = [
entry?.type,
entry?.artworkType,
entry?.artworkTypeSlug,
entry?.type2,
entry?.name,
entry?.artwork
];
return candidates
.map(artworkKind)
.some((kind) =>
kind.includes("background") ||
kind.includes("fanart") ||
kind.includes("landscape") ||
kind === "1"
);
}
function selectBackgroundArtwork(entries) {
if (!Array.isArray(entries) || !entries.length) return null;
const candidates = entries.filter(isBackgroundArtwork);
if (!candidates.length) return null;
const normalized = candidates.map((entry) => {
const width = toDimension(entry.width);
const height = toDimension(entry.height);
const area = width && height ? width * height : null;
return { entry, width, height, area };
});
const landscape = normalized
.filter((item) => item.width && item.height && item.width >= item.height)
.sort((a, b) => (b.area || 0) - (a.area || 0));
if (landscape.length) return landscape[0].entry;
normalized.sort((a, b) => (b.area || 0) - (a.area || 0));
return normalized[0].entry;
}
async function fetchTvdbArtworks(seriesId, typeSlug) {
if (!seriesId || !typeSlug) return [];
const resp = await tvdbFetch(`/series/${seriesId}/artworks/${typeSlug}`);
if (!resp) return [];
if (Array.isArray(resp.data)) return resp.data;
if (Array.isArray(resp.artworks)) return resp.artworks;
return [];
}
function infoFilePath(savePath) {
return path.join(savePath, INFO_FILENAME);
}
@@ -1546,20 +1640,36 @@ async function ensureSeriesData(
return type.includes("poster") || type === "series" || type === "2";
}) || artworksRaw[0];
const backdropArtwork = artworksRaw.find((a) => {
const type = String(
a?.type ||
a?.artworkType ||
a?.type2 ||
a?.name ||
a?.artwork
).toLowerCase();
return (
type.includes("fanart") ||
type.includes("background") ||
type === "1"
);
});
// Fanart.tv'den backdrop al
let backdropImage = null;
const fanartData = await fetchFanartTvImages(seriesData.id);
if (fanartData?.showbackground && Array.isArray(fanartData.showbackground) && fanartData.showbackground.length > 0) {
// İlk showbackground resmini al
const firstBackdrop = fanartData.showbackground[0];
backdropImage = firstBackdrop.url;
}
// Eğer Fanart.tv'de backdrop yoksa, TVDB'i fallback olarak kullan
if (!backdropImage) {
let backdropArtwork = selectBackgroundArtwork(artworksRaw);
if (!backdropArtwork) {
const backgroundArtworks = await fetchTvdbArtworks(seriesData.id, "background");
backdropArtwork = selectBackgroundArtwork(backgroundArtworks);
}
if (!backdropArtwork) {
const fanartArtworks = await fetchTvdbArtworks(seriesData.id, "fanart");
backdropArtwork = selectBackgroundArtwork(fanartArtworks);
}
if (backdropArtwork) {
backdropImage = backdropArtwork?.image ||
backdropArtwork?.file ||
backdropArtwork?.fileName ||
backdropArtwork?.thumbnail ||
backdropArtwork?.url ||
null;
}
}
const posterImage =
posterArtwork?.image ||
@@ -1568,13 +1678,6 @@ async function ensureSeriesData(
posterArtwork?.thumbnail ||
posterArtwork?.url ||
null;
const backdropImage =
backdropArtwork?.image ||
backdropArtwork?.file ||
backdropArtwork?.fileName ||
backdropArtwork?.thumbnail ||
backdropArtwork?.url ||
null;
const posterPath = path.join(showDir, "poster.jpg");
const backdropPath = path.join(showDir, "backdrop.jpg");
@@ -1583,7 +1686,12 @@ async function ensureSeriesData(
await downloadTvdbImage(posterImage, posterPath);
}
if (backdropImage && !fs.existsSync(backdropPath)) {
await downloadTvdbImage(backdropImage, backdropPath);
// Eğer backdropImage Fanart.tv'den geldiyse, onun indirme fonksiyonunu kullan
if (fanartData?.showbackground && backdropImage.startsWith('http')) {
await downloadFanartTvImage(backdropImage, backdropPath);
} else {
await downloadTvdbImage(backdropImage, backdropPath);
}
}
const seasonPaths = seasonAssetPaths(rootFolder, seriesInfo.season);