Added quality column feature. Files now display quality information like 1080p30fps or 720p60fps. Enhanced error handling for problematic files with visual labeling and quality extraction.

This commit is contained in:
Jarian Cottingham 2026-02-18 21:32:35 -06:00
parent ac2248d7ed
commit 65988a942e
3 changed files with 100 additions and 7 deletions

View File

@ -131,6 +131,7 @@
.file-duration, .file-quality {
margin: 0 10px;
color: #666;
min-width: 80px; /* Ensure consistent column width */
}
.problematic-label {

View File

@ -70,7 +70,7 @@ function displayFiles(files) {
// Use actual duration from file metadata
const duration = file.duration || '00:00';
const quality = 'unknown'; // Placeholder for quality
const quality = file.quality || 'unknown';
// Add label for problematic files
const problemLabel = file.isProblematic ? '<span class="problematic-label">⚠️</span> ' : '';

View File

@ -35,14 +35,15 @@ async function scanDirectory(directoryPath) {
const subDirFiles = await scanDirectory(filePath);
mediaFiles.push(...subDirFiles);
} else if (isMediaFile(filePath)) {
// Extract duration for media files
// Extract duration and quality for media files
let fileData = {
path: filePath,
name: file,
size: stat.size,
modified: stat.mtime,
duration: '00:00',
isProblematic: false
isProblematic: false,
quality: 'unknown'
};
try {
@ -53,6 +54,13 @@ async function scanDirectory(directoryPath) {
console.warn(`Failed to extract duration for ${filePath}:`, error.message);
}
try {
const quality = await extractVideoQuality(filePath);
fileData.quality = quality;
} catch (error) {
console.warn(`Failed to extract quality for ${filePath}:`, error.message);
}
mediaFiles.push(fileData);
}
} catch (fileError) {
@ -107,23 +115,106 @@ async function extractFileDuration(filePath) {
});
}
/**
* Extract video quality information using ffmpeg
* @param {string} filePath - Path to the media file
* @returns {Promise<string>} - Quality information (e.g., "1080p30fps")
*/
async function extractVideoQuality(filePath) {
return new Promise((resolve, reject) => {
ffmpeg.ffprobe(filePath, (err, metadata) => {
if (err) {
console.warn(`ffprobe error for quality extraction ${filePath}:`, err.message);
resolve('unknown');
return;
}
try {
// Find the video stream
const videoStream = metadata.streams.find(stream => stream.codec_type === 'video');
if (!videoStream) {
resolve('unknown');
return;
}
// Get resolution
const width = videoStream.width || 0;
const height = videoStream.height || 0;
// Determine quality based on height
let quality = 'unknown';
if (height >= 2160) {
quality = '4K';
} else if (height >= 1440) {
quality = '1440p';
} else if (height >= 1080) {
quality = '1080p';
} else if (height >= 720) {
quality = '720p';
} else if (height >= 480) {
quality = '480p';
} else {
quality = 'unknown';
}
// Get frame rate
let fps = '';
if (videoStream.r_frame_rate) {
// Parse frame rate like "30/1" or "25/1"
const fpsParts = videoStream.r_frame_rate.split('/');
if (fpsParts.length === 2) {
const fpsValue = Math.round(parseInt(fpsParts[0]) / parseInt(fpsParts[1]));
fps = `${fpsValue}fps`;
} else {
const fpsValue = Math.round(parseFloat(videoStream.r_frame_rate));
fps = `${fpsValue}fps`;
}
}
// Format the quality string
if (quality !== 'unknown' && fps) {
resolve(`${quality}${fps}`);
} else if (quality !== 'unknown') {
resolve(quality);
} else if (fps) {
resolve(fps);
} else {
resolve('unknown');
}
} catch (error) {
console.warn(`Error extracting quality for ${filePath}:`, error.message);
resolve('unknown');
}
});
});
}
/**
* Extract file metadata (duration and quality)
* @param {string} filePath - Path to the media file
* @returns {Promise<Object>} - File metadata
*/
async function extractFileMetadata(filePath) {
// Extract duration using ffmpeg
// Extract duration and quality using ffmpeg
let duration = '00:00';
let quality = 'unknown';
try {
duration = await extractFileDuration(filePath);
} catch (error) {
console.warn(`Failed to extract duration for ${filePath}:`, error.message);
}
try {
quality = await extractVideoQuality(filePath);
} catch (error) {
console.warn(`Failed to extract quality for ${filePath}:`, error.message);
}
return {
duration: duration,
quality: 'unknown'
quality: quality
};
}
@ -131,5 +222,6 @@ module.exports = {
scanDirectory,
extractFileMetadata,
isMediaFile,
extractFileDuration
};
extractFileDuration,
extractVideoQuality
};