improve image preview
This commit is contained in:
parent
a0ec67f22a
commit
ece99f8e48
7
app.py
7
app.py
@ -542,7 +542,12 @@ def list_directory_contents(directory, subpath):
|
||||
music_exts = ('.mp3',)
|
||||
image_exts = ('.jpg', '.jpeg', '.png', '.gif', '.bmp')
|
||||
|
||||
blocked_filenames = ['Thumbs.db', '*.mrk']
|
||||
blocked_filenames = [
|
||||
'Thumbs.db',
|
||||
'*.mrk',
|
||||
'*.arw', '*.cr2', '*.lrf'
|
||||
]
|
||||
|
||||
|
||||
try:
|
||||
with os.scandir(directory) as it:
|
||||
|
||||
@ -3,6 +3,44 @@ let currentMusicFiles = []; // Array of objects with at least { path, index }
|
||||
let currentMusicIndex = -1; // Index of the current music file
|
||||
let currentTrackPath = "";
|
||||
|
||||
// Check thumb availability in parallel; sequentially generate missing ones to avoid concurrent creation.
|
||||
function ensureFirstFivePreviews() {
|
||||
const images = Array.from(document.querySelectorAll('.images-grid img')).slice(0, 5);
|
||||
if (!images.length) return;
|
||||
|
||||
const checks = images.map(img => {
|
||||
const thumbUrl = img.dataset.thumbUrl || img.src;
|
||||
const fullUrl = img.dataset.fullUrl;
|
||||
return fetch(thumbUrl, { method: 'GET', cache: 'no-store' })
|
||||
.then(res => ({
|
||||
img,
|
||||
thumbUrl,
|
||||
fullUrl,
|
||||
hasThumb: res.ok && res.status !== 204
|
||||
}))
|
||||
.catch(() => ({ img, thumbUrl, fullUrl, hasThumb: false }));
|
||||
});
|
||||
|
||||
Promise.all(checks).then(results => {
|
||||
const missing = results.filter(r => !r.hasThumb && r.fullUrl);
|
||||
if (!missing.length) return;
|
||||
generateThumbsSequentially(missing);
|
||||
});
|
||||
}
|
||||
|
||||
async function generateThumbsSequentially(entries) {
|
||||
for (const { img, thumbUrl, fullUrl } of entries) {
|
||||
try {
|
||||
await fetch(fullUrl, { method: 'GET', cache: 'no-store' });
|
||||
const cacheBust = `_=${Date.now()}`;
|
||||
const separator = thumbUrl.includes('?') ? '&' : '?';
|
||||
img.src = `${thumbUrl}${separator}${cacheBust}`;
|
||||
} catch (e) {
|
||||
// ignore; best effort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache common DOM elements
|
||||
const mainContainer = document.querySelector('main');
|
||||
const searchContainer = document.querySelector('search');
|
||||
@ -61,17 +99,20 @@ function renderContent(data) {
|
||||
});
|
||||
document.getElementById('breadcrumbs').innerHTML = breadcrumbHTML;
|
||||
|
||||
const imageFiles = data.files.filter(file => file.file_type === 'image');
|
||||
const nonImageFiles = data.files.filter(file => file.file_type !== 'image');
|
||||
|
||||
// Check for image-only directory (no subdirectories, at least one file, all images)
|
||||
const isImageOnly = data.directories.length === 0
|
||||
&& data.files.length > 0
|
||||
&& data.files.every(file => file.file_type === 'image');
|
||||
&& imageFiles.length > 0
|
||||
&& nonImageFiles.length === 0;
|
||||
|
||||
let contentHTML = '';
|
||||
|
||||
if (isImageOnly) {
|
||||
// Display thumbnails grid
|
||||
contentHTML += '<div class="images-grid">';
|
||||
data.files.forEach(file => {
|
||||
imageFiles.forEach(file => {
|
||||
const thumbUrl = `${file.path}?thumbnail=true`;
|
||||
contentHTML += `
|
||||
<div class="image-item">
|
||||
@ -81,6 +122,8 @@ function renderContent(data) {
|
||||
data-file-type="${file.file_type}">
|
||||
<img
|
||||
src="/media/${thumbUrl}"
|
||||
data-thumb-url="/media/${thumbUrl}"
|
||||
data-full-url="/media/${file.path}"
|
||||
class="thumbnail"
|
||||
onload="this.closest('.image-item').classList.add('loaded')"
|
||||
/>
|
||||
@ -138,9 +181,9 @@ function renderContent(data) {
|
||||
|
||||
// Render files (including music and non-image files)
|
||||
currentMusicFiles = [];
|
||||
if (data.files.length > 0) {
|
||||
if (nonImageFiles.length > 0) {
|
||||
contentHTML += '<ul>';
|
||||
data.files.forEach((file, idx) => {
|
||||
nonImageFiles.forEach((file, idx) => {
|
||||
let symbol = '📄';
|
||||
if (file.file_type === 'music') {
|
||||
symbol = '🔊';
|
||||
@ -158,6 +201,32 @@ function renderContent(data) {
|
||||
});
|
||||
contentHTML += '</ul>';
|
||||
}
|
||||
|
||||
// Show images in preview grid after the file list
|
||||
if (imageFiles.length > 0) {
|
||||
contentHTML += '<div class="images-grid">';
|
||||
imageFiles.forEach(file => {
|
||||
const thumbUrl = `${file.path}?thumbnail=true`;
|
||||
contentHTML += `
|
||||
<div class="image-item">
|
||||
|
||||
<a href="#" class="play-file image-link"
|
||||
data-url="${file.path}"
|
||||
data-file-type="${file.file_type}">
|
||||
<img
|
||||
src="/media/${thumbUrl}"
|
||||
data-thumb-url="/media/${thumbUrl}"
|
||||
data-full-url="/media/${file.path}"
|
||||
class="thumbnail"
|
||||
onload="this.closest('.image-item').classList.add('loaded')"
|
||||
/>
|
||||
</a>
|
||||
<span class="file-name">${file.name}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
contentHTML += '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// Insert generated content
|
||||
@ -174,7 +243,7 @@ function renderContent(data) {
|
||||
});
|
||||
|
||||
// Attach event listeners for file items (including images)
|
||||
if (isImageOnly) {
|
||||
if (isImageOnly || imageFiles.length > 0) {
|
||||
document.querySelectorAll('.image-item').forEach(item => {
|
||||
item.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('a')) {
|
||||
@ -195,9 +264,8 @@ function renderContent(data) {
|
||||
}
|
||||
|
||||
// Update gallery images for lightbox or similar
|
||||
currentGalleryImages = data.files
|
||||
.filter(f => f.file_type === 'image')
|
||||
.map(f => f.path);
|
||||
currentGalleryImages = imageFiles.map(f => f.path);
|
||||
ensureFirstFivePreviews();
|
||||
|
||||
attachEventListeners();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user