Compare commits
No commits in common. "ece99f8e48bccc04ff7d6c97ffdd07f0da819823" and "d2952c3ac07f307a5fcb7c07649e2feb7b779451" have entirely different histories.
ece99f8e48
...
d2952c3ac0
9
app.py
9
app.py
@ -542,13 +542,8 @@ def list_directory_contents(directory, subpath):
|
|||||||
music_exts = ('.mp3',)
|
music_exts = ('.mp3',)
|
||||||
image_exts = ('.jpg', '.jpeg', '.png', '.gif', '.bmp')
|
image_exts = ('.jpg', '.jpeg', '.png', '.gif', '.bmp')
|
||||||
|
|
||||||
blocked_filenames = [
|
blocked_filenames = ['Thumbs.db', '*.mrk']
|
||||||
'Thumbs.db',
|
|
||||||
'*.mrk',
|
|
||||||
'*.arw', '*.cr2', '*.lrf'
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with os.scandir(directory) as it:
|
with os.scandir(directory) as it:
|
||||||
# Sorting by name if required.
|
# Sorting by name if required.
|
||||||
|
|||||||
29
auth.py
29
auth.py
@ -171,23 +171,16 @@ def require_secret(f):
|
|||||||
if 'device_id' not in session:
|
if 'device_id' not in session:
|
||||||
session['device_id'] = os.urandom(32).hex()
|
session['device_id'] = os.urandom(32).hex()
|
||||||
|
|
||||||
# For token links, immediately open the single folder they grant access to.
|
# AUTO-JUMP FOR TOKENS - Disabled for now to debug
|
||||||
if (
|
# try:
|
||||||
args_token
|
# if args_token and is_valid_token(args_token):
|
||||||
and request.method == 'GET'
|
# token_item = decode_token(args_token)
|
||||||
and request.endpoint == 'index'
|
# target_foldername = token_item['folders'][0]['foldername']
|
||||||
and is_valid_token(args_token)
|
# # Mark session as modified to ensure it's saved before redirect
|
||||||
):
|
# session.modified = True
|
||||||
try:
|
# return redirect(f"/path/{target_foldername}")
|
||||||
token_item = decode_token(args_token)
|
# except Exception as e:
|
||||||
folders = token_item.get('folders', [])
|
# print(f"Error during auto-jump: {e}")
|
||||||
if len(folders) == 1:
|
|
||||||
target_foldername = folders[0].get('foldername')
|
|
||||||
if target_foldername:
|
|
||||||
session.modified = True # ensure session persists before redirect
|
|
||||||
return redirect(f"/path/{target_foldername}")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error during token auto-open: {e}")
|
|
||||||
|
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
@ -479,4 +472,4 @@ if __name__ == '__main__':
|
|||||||
print("Token:", token)
|
print("Token:", token)
|
||||||
|
|
||||||
result = decode_token(token)
|
result = decode_token(token)
|
||||||
print("Decoded payload:", result)
|
print("Decoded payload:", result)
|
||||||
@ -3,44 +3,6 @@ let currentMusicFiles = []; // Array of objects with at least { path, index }
|
|||||||
let currentMusicIndex = -1; // Index of the current music file
|
let currentMusicIndex = -1; // Index of the current music file
|
||||||
let currentTrackPath = "";
|
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
|
// Cache common DOM elements
|
||||||
const mainContainer = document.querySelector('main');
|
const mainContainer = document.querySelector('main');
|
||||||
const searchContainer = document.querySelector('search');
|
const searchContainer = document.querySelector('search');
|
||||||
@ -99,20 +61,17 @@ function renderContent(data) {
|
|||||||
});
|
});
|
||||||
document.getElementById('breadcrumbs').innerHTML = breadcrumbHTML;
|
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)
|
// Check for image-only directory (no subdirectories, at least one file, all images)
|
||||||
const isImageOnly = data.directories.length === 0
|
const isImageOnly = data.directories.length === 0
|
||||||
&& imageFiles.length > 0
|
&& data.files.length > 0
|
||||||
&& nonImageFiles.length === 0;
|
&& data.files.every(file => file.file_type === 'image');
|
||||||
|
|
||||||
let contentHTML = '';
|
let contentHTML = '';
|
||||||
|
|
||||||
if (isImageOnly) {
|
if (isImageOnly) {
|
||||||
// Display thumbnails grid
|
// Display thumbnails grid
|
||||||
contentHTML += '<div class="images-grid">';
|
contentHTML += '<div class="images-grid">';
|
||||||
imageFiles.forEach(file => {
|
data.files.forEach(file => {
|
||||||
const thumbUrl = `${file.path}?thumbnail=true`;
|
const thumbUrl = `${file.path}?thumbnail=true`;
|
||||||
contentHTML += `
|
contentHTML += `
|
||||||
<div class="image-item">
|
<div class="image-item">
|
||||||
@ -122,8 +81,6 @@ function renderContent(data) {
|
|||||||
data-file-type="${file.file_type}">
|
data-file-type="${file.file_type}">
|
||||||
<img
|
<img
|
||||||
src="/media/${thumbUrl}"
|
src="/media/${thumbUrl}"
|
||||||
data-thumb-url="/media/${thumbUrl}"
|
|
||||||
data-full-url="/media/${file.path}"
|
|
||||||
class="thumbnail"
|
class="thumbnail"
|
||||||
onload="this.closest('.image-item').classList.add('loaded')"
|
onload="this.closest('.image-item').classList.add('loaded')"
|
||||||
/>
|
/>
|
||||||
@ -181,9 +138,9 @@ function renderContent(data) {
|
|||||||
|
|
||||||
// Render files (including music and non-image files)
|
// Render files (including music and non-image files)
|
||||||
currentMusicFiles = [];
|
currentMusicFiles = [];
|
||||||
if (nonImageFiles.length > 0) {
|
if (data.files.length > 0) {
|
||||||
contentHTML += '<ul>';
|
contentHTML += '<ul>';
|
||||||
nonImageFiles.forEach((file, idx) => {
|
data.files.forEach((file, idx) => {
|
||||||
let symbol = '📄';
|
let symbol = '📄';
|
||||||
if (file.file_type === 'music') {
|
if (file.file_type === 'music') {
|
||||||
symbol = '🔊';
|
symbol = '🔊';
|
||||||
@ -201,32 +158,6 @@ function renderContent(data) {
|
|||||||
});
|
});
|
||||||
contentHTML += '</ul>';
|
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
|
// Insert generated content
|
||||||
@ -243,7 +174,7 @@ function renderContent(data) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Attach event listeners for file items (including images)
|
// Attach event listeners for file items (including images)
|
||||||
if (isImageOnly || imageFiles.length > 0) {
|
if (isImageOnly) {
|
||||||
document.querySelectorAll('.image-item').forEach(item => {
|
document.querySelectorAll('.image-item').forEach(item => {
|
||||||
item.addEventListener('click', function(e) {
|
item.addEventListener('click', function(e) {
|
||||||
if (!e.target.closest('a')) {
|
if (!e.target.closest('a')) {
|
||||||
@ -264,8 +195,9 @@ function renderContent(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update gallery images for lightbox or similar
|
// Update gallery images for lightbox or similar
|
||||||
currentGalleryImages = imageFiles.map(f => f.path);
|
currentGalleryImages = data.files
|
||||||
ensureFirstFivePreviews();
|
.filter(f => f.file_type === 'image')
|
||||||
|
.map(f => f.path);
|
||||||
|
|
||||||
attachEventListeners();
|
attachEventListeners();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user