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:
parent
21d6a65643
commit
be050b0057
@ -131,6 +131,7 @@
|
|||||||
.file-duration, .file-quality {
|
.file-duration, .file-quality {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
min-width: 80px; /* Ensure consistent column width */
|
||||||
}
|
}
|
||||||
|
|
||||||
.problematic-label {
|
.problematic-label {
|
||||||
|
|||||||
@ -70,7 +70,7 @@ function displayFiles(files) {
|
|||||||
|
|
||||||
// Use actual duration from file metadata
|
// Use actual duration from file metadata
|
||||||
const duration = file.duration || '00:00';
|
const duration = file.duration || '00:00';
|
||||||
const quality = 'unknown'; // Placeholder for quality
|
const quality = file.quality || 'unknown';
|
||||||
|
|
||||||
// Add label for problematic files
|
// Add label for problematic files
|
||||||
const problemLabel = file.isProblematic ? '<span class="problematic-label">⚠️</span> ' : '';
|
const problemLabel = file.isProblematic ? '<span class="problematic-label">⚠️</span> ' : '';
|
||||||
|
|||||||
@ -35,14 +35,15 @@ async function scanDirectory(directoryPath) {
|
|||||||
const subDirFiles = await scanDirectory(filePath);
|
const subDirFiles = await scanDirectory(filePath);
|
||||||
mediaFiles.push(...subDirFiles);
|
mediaFiles.push(...subDirFiles);
|
||||||
} else if (isMediaFile(filePath)) {
|
} else if (isMediaFile(filePath)) {
|
||||||
// Extract duration for media files
|
// Extract duration and quality for media files
|
||||||
let fileData = {
|
let fileData = {
|
||||||
path: filePath,
|
path: filePath,
|
||||||
name: file,
|
name: file,
|
||||||
size: stat.size,
|
size: stat.size,
|
||||||
modified: stat.mtime,
|
modified: stat.mtime,
|
||||||
duration: '00:00',
|
duration: '00:00',
|
||||||
isProblematic: false
|
isProblematic: false,
|
||||||
|
quality: 'unknown'
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -53,6 +54,13 @@ async function scanDirectory(directoryPath) {
|
|||||||
console.warn(`Failed to extract duration for ${filePath}:`, error.message);
|
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);
|
mediaFiles.push(fileData);
|
||||||
}
|
}
|
||||||
} catch (fileError) {
|
} 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)
|
* Extract file metadata (duration and quality)
|
||||||
* @param {string} filePath - Path to the media file
|
* @param {string} filePath - Path to the media file
|
||||||
* @returns {Promise<Object>} - File metadata
|
* @returns {Promise<Object>} - File metadata
|
||||||
*/
|
*/
|
||||||
async function extractFileMetadata(filePath) {
|
async function extractFileMetadata(filePath) {
|
||||||
// Extract duration using ffmpeg
|
// Extract duration and quality using ffmpeg
|
||||||
let duration = '00:00';
|
let duration = '00:00';
|
||||||
|
let quality = 'unknown';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
duration = await extractFileDuration(filePath);
|
duration = await extractFileDuration(filePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(`Failed to extract duration for ${filePath}:`, error.message);
|
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 {
|
return {
|
||||||
duration: duration,
|
duration: duration,
|
||||||
quality: 'unknown'
|
quality: quality
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,5 +222,6 @@ module.exports = {
|
|||||||
scanDirectory,
|
scanDirectory,
|
||||||
extractFileMetadata,
|
extractFileMetadata,
|
||||||
isMediaFile,
|
isMediaFile,
|
||||||
extractFileDuration
|
extractFileDuration,
|
||||||
};
|
extractVideoQuality
|
||||||
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user