feat(DeviceDetailOverlay): improve media set detection logic and optimize state management
This commit is contained in:
parent
de303e9327
commit
5c28a69055
|
|
@ -125,33 +125,40 @@ export default function DeviceDetailOverlay({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prefer an explicit .lst-derived mediaSet stored in config; fall back to pattern detection.
|
|
||||||
const [mediaSetFiles, setMediaSetFiles] = useState<MediaSetEntry[] | null>(null);
|
const [mediaSetFiles, setMediaSetFiles] = useState<MediaSetEntry[] | null>(null);
|
||||||
const prevDeviceNumberRef = useRef(device.number);
|
const detectTokenRef = useRef(0);
|
||||||
|
|
||||||
|
// Cancel any in-flight detection and reset when navigating to a different device.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const deviceChanged = prevDeviceNumberRef.current !== device.number;
|
++detectTokenRef.current;
|
||||||
prevDeviceNumberRef.current = device.number;
|
setMediaSetFiles(null);
|
||||||
|
}, [device.number]);
|
||||||
|
|
||||||
|
// Sync config-backed media_set to display state whenever it is set explicitly
|
||||||
|
// (e.g. after a playlist is mounted).
|
||||||
|
useEffect(() => {
|
||||||
if (Array.isArray(deviceData.media_set) && deviceData.media_set.length > 1) {
|
if (Array.isArray(deviceData.media_set) && deviceData.media_set.length > 1) {
|
||||||
setMediaSetFiles(deviceData.media_set as MediaSetEntry[]);
|
setMediaSetFiles(deviceData.media_set as MediaSetEntry[]);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// Don't run pattern detection when switching devices — only when the URL
|
}, [deviceData.media_set]);
|
||||||
// is actively being changed within the same device.
|
|
||||||
if (deviceChanged || !deviceData.url) { setMediaSetFiles(null); return; }
|
// Pattern-detect sibling numbered files for the given URL. Called only when
|
||||||
const match = (deviceData.url as string).match(/^(.+?)(\d+)(\.[^.]+)$/);
|
// the user actively sets a URL — never on overlay load or device switch.
|
||||||
if (!match) { setMediaSetFiles(null); return; }
|
const detectMediaSet = async (url: string) => {
|
||||||
|
const token = ++detectTokenRef.current;
|
||||||
|
setMediaSetFiles(null);
|
||||||
|
const match = url.match(/^(.+?)(\d+)(\.[^.]+)$/);
|
||||||
|
if (!match) return;
|
||||||
const [, prefix, , ext] = match;
|
const [, prefix, , ext] = match;
|
||||||
const candidates: string[] = [];
|
const candidates: string[] = [];
|
||||||
for (let i = 1; i <= 10; i++) candidates.push(`${prefix}${i}${ext}`);
|
for (let i = 1; i <= 10; i++) candidates.push(`${prefix}${i}${ext}`);
|
||||||
let cancelled = false;
|
const flags = await Promise.all(
|
||||||
Promise.all(candidates.map(f => stat(f).then(r => r !== null).catch(() => false))).then(flags => {
|
candidates.map(f => stat(f).then(r => r !== null).catch(() => false))
|
||||||
|
);
|
||||||
|
if (detectTokenRef.current !== token) return;
|
||||||
const found = candidates.filter((_, i) => flags[i]);
|
const found = candidates.filter((_, i) => flags[i]);
|
||||||
if (!cancelled) setMediaSetFiles(found.length > 1 ? found : null);
|
setMediaSetFiles(found.length > 1 ? found : null);
|
||||||
});
|
};
|
||||||
return () => { cancelled = true; };
|
|
||||||
}, [device.number, deviceData.url, deviceData.media_set]);
|
|
||||||
|
|
||||||
const switchMedia = (file: string) => {
|
const switchMedia = (file: string) => {
|
||||||
const path = getDevicePath();
|
const path = getDevicePath();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user