release(v2.3.2): fix media preview URLs and tighten hover card layout
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,5 +1,18 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Changes 12/3/2025 (v2.3.2)
|
||||||
|
|
||||||
|
release(v2.3.2): fix media preview URLs and tighten hover card layout
|
||||||
|
|
||||||
|
- Reuse the working preview URL as a base when stepping between images/videos
|
||||||
|
so next/prev navigation keeps using the same inline/download endpoint
|
||||||
|
- Preserve video progress tracking and watched badges while fixing black-screen
|
||||||
|
playback issues across browsers
|
||||||
|
- Slightly shrink the file hover preview card (width/height, grid columns,
|
||||||
|
gaps, snippet/props heights) for a more compact, less intrusive peek
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Changes 12/3/2025 (v2.3.1)
|
## Changes 12/3/2025 (v2.3.1)
|
||||||
|
|
||||||
release(v2.3.1): polish file list actions & hover preview peak
|
release(v2.3.1): polish file list actions & hover preview peak
|
||||||
|
|||||||
@@ -393,17 +393,17 @@ function ensureHoverPreviewEl() {
|
|||||||
const propsEl = el.querySelector(".hover-preview-props");
|
const propsEl = el.querySelector(".hover-preview-props");
|
||||||
|
|
||||||
if (card) {
|
if (card) {
|
||||||
card.style.minWidth = "420px";
|
card.style.minWidth = "380px"; // was 420
|
||||||
card.style.maxWidth = "640px";
|
card.style.maxWidth = "600px"; // was 640
|
||||||
card.style.minHeight = "220px";
|
card.style.minHeight = "200px"; // was 220
|
||||||
card.style.padding = "10px 12px";
|
card.style.padding = "8px 10px"; // slightly tighter padding
|
||||||
card.style.overflow = "hidden";
|
card.style.overflow = "hidden";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grid) {
|
if (grid) {
|
||||||
grid.style.display = "grid";
|
grid.style.display = "grid";
|
||||||
grid.style.gridTemplateColumns = "220px minmax(260px, 1fr)";
|
grid.style.gridTemplateColumns = "200px minmax(240px, 1fr)"; // both columns ~9% smaller
|
||||||
grid.style.gap = "12px";
|
grid.style.gap = "10px";
|
||||||
grid.style.alignItems = "center";
|
grid.style.alignItems = "center";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,13 +426,14 @@ function ensureHoverPreviewEl() {
|
|||||||
thumb.style.display = "flex";
|
thumb.style.display = "flex";
|
||||||
thumb.style.alignItems = "center";
|
thumb.style.alignItems = "center";
|
||||||
thumb.style.justifyContent = "center";
|
thumb.style.justifyContent = "center";
|
||||||
thumb.style.minHeight = "140px";
|
thumb.style.minHeight = "120px"; // was 140
|
||||||
thumb.style.marginBottom = "6px";
|
thumb.style.marginBottom = "4px"; // slightly tighter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (snippet) {
|
if (snippet) {
|
||||||
snippet.style.marginTop = "4px";
|
snippet.style.marginTop = "4px";
|
||||||
snippet.style.maxHeight = "140px";
|
snippet.style.maxHeight = "120px";
|
||||||
snippet.style.overflow = "auto";
|
snippet.style.overflow = "auto";
|
||||||
snippet.style.fontSize = "0.78rem";
|
snippet.style.fontSize = "0.78rem";
|
||||||
snippet.style.whiteSpace = "pre-wrap";
|
snippet.style.whiteSpace = "pre-wrap";
|
||||||
@@ -464,9 +465,9 @@ function ensureHoverPreviewEl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (propsEl) {
|
if (propsEl) {
|
||||||
propsEl.style.fontSize = "0.78rem";
|
propsEl.style.fontSize = "0.76rem";
|
||||||
propsEl.style.lineHeight = "1.3";
|
propsEl.style.lineHeight = "1.3";
|
||||||
propsEl.style.maxHeight = "160px";
|
propsEl.style.maxHeight = "140px";
|
||||||
propsEl.style.overflow = "auto";
|
propsEl.style.overflow = "auto";
|
||||||
propsEl.style.paddingRight = "4px";
|
propsEl.style.paddingRight = "4px";
|
||||||
propsEl.style.wordBreak = "break-word";
|
propsEl.style.wordBreak = "break-word";
|
||||||
|
|||||||
@@ -503,6 +503,23 @@ export function previewFile(fileUrl, fileName) {
|
|||||||
const isVideo = VID_RE.test(lower);
|
const isVideo = VID_RE.test(lower);
|
||||||
const isAudio = AUD_RE.test(lower);
|
const isAudio = AUD_RE.test(lower);
|
||||||
|
|
||||||
|
// Base preview URL from the link we clicked
|
||||||
|
const baseUrl = fileUrl;
|
||||||
|
|
||||||
|
// Use the same preview endpoint, just swap the "file" param.
|
||||||
|
function siblingPreviewUrl(newName) {
|
||||||
|
try {
|
||||||
|
const u = new URL(baseUrl, window.location.origin);
|
||||||
|
u.searchParams.set('file', newName);
|
||||||
|
// cache-bust so we don’t get stale frames
|
||||||
|
u.searchParams.set('t', String(Date.now()));
|
||||||
|
return u.toString();
|
||||||
|
} catch {
|
||||||
|
// Fallback: go through generic download/inline endpoint
|
||||||
|
return buildPreviewUrl(folder, newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setTitle(overlay, name);
|
setTitle(overlay, name);
|
||||||
if (isSvg) {
|
if (isSvg) {
|
||||||
const downloadBtn = makeDownloadButton(folder, () => name);
|
const downloadBtn = makeDownloadButton(folder, () => name);
|
||||||
@@ -582,7 +599,7 @@ const navigate = (dir) => {
|
|||||||
img.dataset.scale = 1;
|
img.dataset.scale = 1;
|
||||||
img.dataset.rotate = 0;
|
img.dataset.rotate = 0;
|
||||||
img.style.transform = 'scale(1) rotate(0deg)';
|
img.style.transform = 'scale(1) rotate(0deg)';
|
||||||
img.src = buildPreviewUrl(folder, newFile);
|
img.src = siblingPreviewUrl(newFile); // <-- changed
|
||||||
};
|
};
|
||||||
|
|
||||||
if (images.length > 1) {
|
if (images.length > 1) {
|
||||||
@@ -624,12 +641,19 @@ const navigate = (dir) => {
|
|||||||
loadSavedMediaVolume(video);
|
loadSavedMediaVolume(video);
|
||||||
attachVolumePersistence(video);
|
attachVolumePersistence(video);
|
||||||
|
|
||||||
|
// Top-right action icons (Material icons, theme-aware)
|
||||||
const markBtnIcon = makeTopIcon('check_circle', t("mark_as_viewed") || "Mark as viewed");
|
const markBtnIcon = makeTopIcon('check_circle', t("mark_as_viewed") || "Mark as viewed");
|
||||||
const clearBtnIcon = makeTopIcon('restart_alt', t("clear_progress") || "Clear progress");
|
const clearBtnIcon = makeTopIcon('restart_alt', t("clear_progress") || "Clear progress");
|
||||||
|
|
||||||
// Track which file is currently active
|
// Track which file is currently active
|
||||||
let currentName = name;
|
let currentName = name;
|
||||||
|
|
||||||
|
// Use the URL we were passed in (old behavior) for the *first* video,
|
||||||
|
// fall back to API URL if for some reason it's empty.
|
||||||
|
const initialUrl = fileUrl && fileUrl.trim()
|
||||||
|
? fileUrl
|
||||||
|
: buildPreviewUrl(folder, name);
|
||||||
|
|
||||||
const downloadBtn = makeDownloadButton(folder, () => currentName);
|
const downloadBtn = makeDownloadButton(folder, () => currentName);
|
||||||
|
|
||||||
// Order: Download | Mark | Reset
|
// Order: Download | Mark | Reset
|
||||||
@@ -643,9 +667,16 @@ overlay.mediaList = videos;
|
|||||||
overlay.mediaIndex = Math.max(0, videos.findIndex(f => f.name === name));
|
overlay.mediaIndex = Math.max(0, videos.findIndex(f => f.name === name));
|
||||||
setNavVisibility(overlay, videos.length > 1, videos.length > 1);
|
setNavVisibility(overlay, videos.length > 1, videos.length > 1);
|
||||||
|
|
||||||
|
// Helper: set src for a given video name
|
||||||
const setVideoSrc = (nm) => {
|
const setVideoSrc = (nm) => {
|
||||||
currentName = nm;
|
currentName = nm;
|
||||||
video.src = buildPreviewUrl(folder, nm);
|
|
||||||
|
// For the current file, reuse the original working URL.
|
||||||
|
// For other files (next/prev), go through the API.
|
||||||
|
const url = (nm === name) ? initialUrl : buildPreviewUrl(folder, nm);
|
||||||
|
|
||||||
|
video.src = url;
|
||||||
|
video.src = siblingPreviewUrl(nm);
|
||||||
setTitle(overlay, nm);
|
setTitle(overlay, nm);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -790,7 +821,6 @@ setNavVisibility(overlay, videos.length > 1, videos.length > 1);
|
|||||||
if (!overlay.mediaList || overlay.mediaList.length < 2) return;
|
if (!overlay.mediaList || overlay.mediaList.length < 2) return;
|
||||||
overlay.mediaIndex = (overlay.mediaIndex + dir + overlay.mediaList.length) % overlay.mediaList.length;
|
overlay.mediaIndex = (overlay.mediaIndex + dir + overlay.mediaList.length) % overlay.mediaList.length;
|
||||||
const nm = overlay.mediaList[overlay.mediaIndex].name;
|
const nm = overlay.mediaList[overlay.mediaIndex].name;
|
||||||
currentName = nm; // keep download button in sync
|
|
||||||
setVideoSrc(nm);
|
setVideoSrc(nm);
|
||||||
renderStatus(null);
|
renderStatus(null);
|
||||||
};
|
};
|
||||||
@@ -810,6 +840,7 @@ setNavVisibility(overlay, videos.length > 1, videos.length > 1);
|
|||||||
overlay._onKey = onKey;
|
overlay._onKey = onKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Kick off first video using the original working URL
|
||||||
setVideoSrc(name);
|
setVideoSrc(name);
|
||||||
renderStatus(null);
|
renderStatus(null);
|
||||||
overlay.style.display = "flex";
|
overlay.style.display = "flex";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# === Update FileRise to v2.1.0 (safe rsync, no composer on demo) ===
|
# === Update FileRise to v2.3.2 (safe rsync, no composer on demo) ===
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
VER="v2.1.0"
|
VER="v2.3.2"
|
||||||
ASSET="FileRise-${VER}.zip" # matches GitHub release asset name
|
ASSET="FileRise-${VER}.zip" # matches GitHub release asset name
|
||||||
|
|
||||||
WEBROOT="/var/www"
|
WEBROOT="/var/www"
|
||||||
|
|||||||
Reference in New Issue
Block a user