Files
MyTube/backend/src/services/metadataService.ts

84 lines
2.5 KiB
TypeScript

import { exec } from 'child_process';
import { eq } from 'drizzle-orm';
import fs from 'fs-extra';
import path from 'path';
import { VIDEOS_DIR } from '../config/paths';
import { db } from '../db';
import { videos } from '../db/schema';
export const getVideoDuration = async (filePath: string): Promise<number | null> => {
try {
const duration = await new Promise<string>((resolve, reject) => {
exec(`ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${filePath}"`, (error, stdout, _stderr) => {
if (error) {
reject(error);
} else {
resolve(stdout.trim());
}
});
});
if (duration) {
const durationSec = parseFloat(duration);
if (!isNaN(durationSec)) {
return Math.round(durationSec);
}
}
return null;
} catch (error) {
console.error(`Error getting duration for ${filePath}:`, error);
return null;
}
};
export const backfillDurations = async () => {
console.log('Starting duration backfill...');
try {
const allVideos = await db.select().from(videos).all();
console.log(`Found ${allVideos.length} videos to check for duration.`);
let updatedCount = 0;
for (const video of allVideos) {
if (video.duration) {
continue;
}
let videoPath = video.videoPath;
if (!videoPath) continue;
let fsPath = '';
if (videoPath.startsWith('/videos/')) {
const relativePath = videoPath.replace('/videos/', '');
fsPath = path.join(VIDEOS_DIR, relativePath);
} else {
continue;
}
if (!fs.existsSync(fsPath)) {
// console.warn(`File not found: ${fsPath}`); // Reduce noise
continue;
}
const duration = await getVideoDuration(fsPath);
if (duration !== null) {
await db.update(videos)
.set({ duration: duration.toString() })
.where(eq(videos.id, video.id));
console.log(`Updated duration for ${video.title}: ${duration}s`);
updatedCount++;
}
}
if (updatedCount > 0) {
console.log(`Duration backfill finished. Updated ${updatedCount} videos.`);
} else {
console.log('Duration backfill finished. No videos needed update.');
}
} catch (error) {
console.error("Error during duration backfill:", error);
}
};