UI Değişiklikleri
This commit is contained in:
152
server/server.js
152
server/server.js
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user