Sİdebar'da music kategorisi oluşturuldu
This commit is contained in:
116
server/server.js
116
server/server.js
@@ -764,9 +764,10 @@ async function finalizeYoutubeJob(job, exitCode) {
|
||||
mediaInfo,
|
||||
infoJson
|
||||
);
|
||||
const payload = updateYoutubeThumbnail(job, metadataPayload) || metadataPayload;
|
||||
const mediaType = payload?.type || "video";
|
||||
const categories = payload?.categories || null;
|
||||
const payloadWithThumb =
|
||||
updateYoutubeThumbnail(job, metadataPayload) || metadataPayload;
|
||||
const mediaType = payloadWithThumb?.type || "video";
|
||||
const categories = payloadWithThumb?.categories || null;
|
||||
upsertInfoFile(job.savePath, {
|
||||
infoHash: job.id,
|
||||
name: job.title,
|
||||
@@ -5125,8 +5126,13 @@ app.get("/api/files", requireAuth, (req, res) => {
|
||||
const seriesEpisodeInfo = relWithinRoot
|
||||
? info.seriesEpisodes?.[relWithinRoot] || null
|
||||
: null;
|
||||
const mediaCategory =
|
||||
fileMeta?.type || (relWithinRoot ? info.type : null) || null;
|
||||
let mediaCategory = fileMeta?.type || null;
|
||||
if (!mediaCategory) {
|
||||
const canInheritFromInfo = !relWithinRoot || isVideo;
|
||||
if (canInheritFromInfo && info.type) {
|
||||
mediaCategory = info.type;
|
||||
}
|
||||
}
|
||||
const isPrimaryVideo =
|
||||
!!info.primaryVideoPath && info.primaryVideoPath === relWithinRoot;
|
||||
const displayName = entry.name;
|
||||
@@ -6078,6 +6084,89 @@ app.get("/api/tvshows", requireAuth, (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
function collectMusicEntries() {
|
||||
const entries = [];
|
||||
const dirEntries = fs
|
||||
.readdirSync(DOWNLOAD_DIR, { withFileTypes: true })
|
||||
.filter((dirent) => dirent.isDirectory());
|
||||
|
||||
for (const dirent of dirEntries) {
|
||||
const folder = sanitizeRelative(dirent.name);
|
||||
if (!folder) continue;
|
||||
// Klasörün tamamı çöpe taşınmışsa atla
|
||||
if (isPathTrashed(folder, "", true)) continue;
|
||||
const info = readInfoForRoot(folder) || {};
|
||||
const files = info.files || {};
|
||||
const fileKeys = Object.keys(files);
|
||||
if (!fileKeys.length) continue;
|
||||
|
||||
let targetPath = info.primaryVideoPath;
|
||||
if (targetPath && files[targetPath]?.type !== "music") {
|
||||
targetPath = null;
|
||||
}
|
||||
if (!targetPath) {
|
||||
targetPath =
|
||||
fileKeys.find((key) => files[key]?.type === "music") || fileKeys[0];
|
||||
}
|
||||
if (!targetPath) continue;
|
||||
const fileMeta = files[targetPath];
|
||||
// Hedef dosya çöpteyse atla
|
||||
if (isPathTrashed(folder, targetPath, false)) continue;
|
||||
const mediaType = fileMeta?.type || info.type || null;
|
||||
if (mediaType !== "music") continue;
|
||||
|
||||
const metadataPath = path.join(YT_DATA_ROOT, folder, "metadata.json");
|
||||
let metadata = null;
|
||||
if (fs.existsSync(metadataPath)) {
|
||||
try {
|
||||
metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
|
||||
} catch (err) {
|
||||
console.warn(`⚠️ YT metadata okunamadı (${metadataPath}): ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const keysArray = fileKeys;
|
||||
const fileIndex = Math.max(keysArray.indexOf(targetPath), 0);
|
||||
const infoHash = info.infoHash || folder;
|
||||
const title =
|
||||
info.name || metadata?.title || path.basename(targetPath) || folder;
|
||||
const thumbnail =
|
||||
metadata?.thumbnail ||
|
||||
(metadata ? `/yt-data/${folder}/thumbnail.jpg` : null);
|
||||
|
||||
entries.push({
|
||||
id: `${folder}:${targetPath}`,
|
||||
folder,
|
||||
infoHash,
|
||||
fileIndex,
|
||||
filePath: targetPath,
|
||||
title,
|
||||
added: info.added || info.createdAt || null,
|
||||
size: fileMeta?.size || 0,
|
||||
url:
|
||||
metadata?.url ||
|
||||
fileMeta?.youtube?.url ||
|
||||
fileMeta?.youtube?.videoId
|
||||
? `https://www.youtube.com/watch?v=${fileMeta.youtube.videoId}`
|
||||
: null,
|
||||
thumbnail,
|
||||
categories: metadata?.categories || fileMeta?.categories || null
|
||||
});
|
||||
}
|
||||
entries.sort((a, b) => (b.added || 0) - (a.added || 0));
|
||||
return entries;
|
||||
}
|
||||
|
||||
app.get("/api/music", requireAuth, (req, res) => {
|
||||
try {
|
||||
const entries = collectMusicEntries();
|
||||
res.json(entries);
|
||||
} catch (err) {
|
||||
console.error("🎵 Music API error:", err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
async function rebuildTvMetadata({ clearCache = false } = {}) {
|
||||
if (!TVDB_API_KEY) {
|
||||
throw new Error("TVDB API erişimi için gerekli anahtar tanımlı değil.");
|
||||
@@ -6330,6 +6419,23 @@ app.get("/stream/:hash", requireAuth, (req, res) => {
|
||||
return streamLocalFile(absPath, range, res);
|
||||
}
|
||||
|
||||
const info = readInfoForRoot(req.params.hash);
|
||||
if (info && info.files) {
|
||||
const fileKeys = Object.keys(info.files);
|
||||
if (fileKeys.length) {
|
||||
const idx = Number(req.query.index) || 0;
|
||||
const targetKey = fileKeys[idx] || fileKeys[0];
|
||||
const absPath = path.join(
|
||||
DOWNLOAD_DIR,
|
||||
req.params.hash,
|
||||
targetKey.replace(/\\/g, "/")
|
||||
);
|
||||
if (fs.existsSync(absPath)) {
|
||||
return streamLocalFile(absPath, range, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(404).end();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user