fix(MediaManager, DeviceDetailOverlay): improve file existence checks and handle missing files in swap lists
This commit is contained in:
parent
39c72386fa
commit
4c07f8c4a1
|
|
@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
|
|||
import { X, ChevronLeft, ChevronRight, Printer, HardDrive, Network, Box, FolderOpen, MoreVertical, Play, Pause, SkipForward, SkipBack, RotateCcw } from 'lucide-react';
|
||||
import { motion, AnimatePresence } from 'motion/react';
|
||||
import { toast } from 'sonner';
|
||||
import { getFileContents, joinPath } from '../webdav';
|
||||
import { fileExists, getFileContents, joinPath } from '../webdav';
|
||||
import MediaBrowser from './MediaBrowser';
|
||||
import MediaSet from './MediaSet';
|
||||
|
||||
|
|
@ -122,38 +122,26 @@ export default function DeviceDetailOverlay({
|
|||
}
|
||||
};
|
||||
|
||||
// Detect if URL is part of a media set (e.g., disk1.d64, disk2.d64)
|
||||
const detectMediaSet = () => {
|
||||
if (!deviceData.url) return null;
|
||||
|
||||
const match = deviceData.url.match(/^(.+?)(\d+)(\.[^.]+)$/);
|
||||
if (!match) return null;
|
||||
|
||||
const [, prefix, num, ext] = match;
|
||||
const currentNum = parseInt(num);
|
||||
|
||||
// Generate potential media set
|
||||
const mediaSet = [];
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
mediaSet.push(`${prefix}${i}${ext}`);
|
||||
}
|
||||
|
||||
return {
|
||||
prefix,
|
||||
extension: ext,
|
||||
currentIndex: currentNum - 1,
|
||||
files: mediaSet
|
||||
};
|
||||
};
|
||||
|
||||
// Prefer an explicit .lst-derived mediaSet stored in config; fall back to pattern detection.
|
||||
const mediaSetFiles: string[] | null = (() => {
|
||||
const [mediaSetFiles, setMediaSetFiles] = useState<string[] | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (Array.isArray(deviceData.media_set) && deviceData.media_set.length > 0) {
|
||||
return deviceData.media_set as string[];
|
||||
setMediaSetFiles(deviceData.media_set as string[]);
|
||||
return;
|
||||
}
|
||||
const detected = detectMediaSet();
|
||||
return detected ? detected.files : null;
|
||||
})();
|
||||
if (!deviceData.url) { setMediaSetFiles(null); return; }
|
||||
const match = (deviceData.url as string).match(/^(.+?)(\d+)(\.[^.]+)$/);
|
||||
if (!match) { setMediaSetFiles(null); return; }
|
||||
const [, prefix, , ext] = match;
|
||||
const candidates: string[] = [];
|
||||
for (let i = 1; i <= 10; i++) candidates.push(`${prefix}${i}${ext}`);
|
||||
let cancelled = false;
|
||||
Promise.all(candidates.map(f => fileExists(f).catch(() => false))).then(flags => {
|
||||
if (!cancelled) setMediaSetFiles(candidates.filter((_, i) => flags[i]));
|
||||
});
|
||||
return () => { cancelled = true; };
|
||||
}, [deviceData.url, deviceData.media_set]);
|
||||
|
||||
const switchMedia = (file: string) => {
|
||||
const path = getDevicePath();
|
||||
|
|
@ -166,11 +154,17 @@ export default function DeviceDetailOverlay({
|
|||
try {
|
||||
const text = await (await getFileContents(selectedPath)).text();
|
||||
const dir = selectedPath.split('/').slice(0, -1).join('/') || '/';
|
||||
const files = text.split('\n')
|
||||
const candidates = text.split('\n')
|
||||
.map(l => l.trim())
|
||||
.filter(l => l.length > 0 && !l.startsWith('#'))
|
||||
.map(l => l.startsWith('/') ? l : joinPath(dir, l));
|
||||
if (files.length === 0) { toast.error('Swap list is empty'); return; }
|
||||
if (candidates.length === 0) { toast.error('Swap list is empty'); return; }
|
||||
const existsArr = await Promise.all(candidates.map(f => fileExists(f).catch(() => false)));
|
||||
const files = candidates.filter((_, i) => existsArr[i]);
|
||||
if (files.length === 0) { toast.error('No files in swap list exist on device'); return; }
|
||||
if (files.length < candidates.length) {
|
||||
toast.warning(`${candidates.length - files.length} missing file(s) skipped from swap list`);
|
||||
}
|
||||
const newConfig = JSON.parse(JSON.stringify(config));
|
||||
let dev = newConfig;
|
||||
for (const k of devicePath) dev = dev[k];
|
||||
|
|
|
|||
|
|
@ -760,14 +760,23 @@ export default function MediaManager({ initialPath = '/', rootPath, title, confi
|
|||
try {
|
||||
const text = await (await getFileContents(mountEntry.path)).text();
|
||||
const dir = splitPath(mountEntry.path).parent;
|
||||
const files = text.split('\n')
|
||||
const candidates = text.split('\n')
|
||||
.map(l => l.trim())
|
||||
.filter(l => l.length > 0 && !l.startsWith('#'))
|
||||
.map(l => l.startsWith('/') ? l : joinPath(dir, l));
|
||||
if (files.length === 0) {
|
||||
if (candidates.length === 0) {
|
||||
toast.error(`${mountEntry.name}: swap list is empty`);
|
||||
return;
|
||||
}
|
||||
const exists = await Promise.all(candidates.map(f => fileExists(f).catch(() => false)));
|
||||
const files = candidates.filter((_, i) => exists[i]);
|
||||
if (files.length === 0) {
|
||||
toast.error(`${mountEntry.name}: no files in swap list exist on device`);
|
||||
return;
|
||||
}
|
||||
if (files.length < candidates.length) {
|
||||
toast.warning(`${candidates.length - files.length} missing file(s) skipped from swap list`);
|
||||
}
|
||||
dev.url = files[0];
|
||||
dev.media_set = files;
|
||||
} catch (e: any) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user