134 lines
4.1 KiB
JavaScript
134 lines
4.1 KiB
JavaScript
export function guideDisplayName(guide) {
|
|
if (guide.image_slot != null) return String(guide.image_slot);
|
|
if (guide.audio_slot != null) return String(guide.audio_slot);
|
|
return '—';
|
|
}
|
|
|
|
export function guideOverlayPosition(index) {
|
|
const value = Math.max(0, Math.round(Number(index) || 0));
|
|
return { normal: `${1 + value * 10}px`, compact: `${1 + value * 6}px` };
|
|
}
|
|
|
|
function nextH3GuideFrame(state) {
|
|
const total = Math.max(1, Math.round(Number(state?.timeline?.frame_count) || 1));
|
|
const occupied = new Set((state.guides || []).map((guide) => Number(guide.frame)));
|
|
for (let frame = 5; frame < total; frame += 17) {
|
|
if (!occupied.has(frame)) return frame;
|
|
}
|
|
return Math.min(total - 1, 5);
|
|
}
|
|
|
|
function newGuideFrame(state, snapMode) {
|
|
return snapMode === 'h3'
|
|
? nextH3GuideFrame(state)
|
|
: Math.max(0, Math.round(state.timeline.selected_frame || 0));
|
|
}
|
|
|
|
export function syncConnectedImageGuides(state, connectedSlots, makeId, snapMode = 'h3') {
|
|
const connected = new Set(connectedSlots);
|
|
const seen = new Set();
|
|
const nextGuides = [];
|
|
let changed = false;
|
|
|
|
for (const guide of state.guides) {
|
|
if (guide.image_slot == null) {
|
|
nextGuides.push(guide);
|
|
continue;
|
|
}
|
|
if (!connected.has(guide.image_slot) || seen.has(guide.image_slot)) {
|
|
changed = true;
|
|
continue;
|
|
}
|
|
seen.add(guide.image_slot);
|
|
nextGuides.push(guide);
|
|
}
|
|
|
|
for (const slot of connected) {
|
|
if (seen.has(slot)) continue;
|
|
const matchingAudio = nextGuides.find((guide) => guide.audio_slot === slot && guide.image_slot == null);
|
|
if (matchingAudio) {
|
|
matchingAudio.image_slot = slot;
|
|
seen.add(slot);
|
|
changed = true;
|
|
continue;
|
|
}
|
|
nextGuides.push({
|
|
id: makeId(slot),
|
|
enabled: true,
|
|
frame: newGuideFrame(state, snapMode),
|
|
image_slot: slot,
|
|
audio_slot: null,
|
|
});
|
|
changed = true;
|
|
}
|
|
|
|
if (nextGuides.length !== state.guides.length || nextGuides.some((guide, index) => guide !== state.guides[index])) {
|
|
state.guides = nextGuides;
|
|
changed = true;
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
|
|
export function syncConnectedAudioGuides(state, connectedSlots, makeId, snapMode = 'h3') {
|
|
const connected = new Set(connectedSlots);
|
|
const seen = new Set();
|
|
const nextGuides = [];
|
|
let changed = false;
|
|
|
|
for (const guide of state.guides) {
|
|
if (guide.audio_slot == null) {
|
|
nextGuides.push(guide);
|
|
continue;
|
|
}
|
|
if (!connected.has(guide.audio_slot) || seen.has(guide.audio_slot)) {
|
|
changed = true;
|
|
if (guide.image_slot != null) {
|
|
guide.audio_slot = null;
|
|
nextGuides.push(guide);
|
|
}
|
|
continue;
|
|
}
|
|
seen.add(guide.audio_slot);
|
|
nextGuides.push(guide);
|
|
}
|
|
|
|
for (const slot of connected) {
|
|
if (seen.has(slot)) continue;
|
|
const matchingImage = nextGuides.find((guide) => guide.image_slot === slot && guide.audio_slot == null);
|
|
if (matchingImage) {
|
|
matchingImage.audio_slot = slot;
|
|
seen.add(slot);
|
|
changed = true;
|
|
continue;
|
|
}
|
|
nextGuides.push({
|
|
id: makeId(slot),
|
|
enabled: true,
|
|
frame: newGuideFrame({ ...state, guides: nextGuides }, snapMode),
|
|
image_slot: null,
|
|
audio_slot: slot,
|
|
});
|
|
changed = true;
|
|
}
|
|
|
|
if (nextGuides.length !== state.guides.length || nextGuides.some((guide, index) => guide !== state.guides[index])) {
|
|
state.guides = nextGuides;
|
|
changed = true;
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
export function syncConnectedGuides(state, imageSlots, audioSlots, makeImageId, makeAudioId, snapMode = 'h3') {
|
|
const imageChanged = syncConnectedImageGuides(state, imageSlots, makeImageId, snapMode);
|
|
const audioChanged = syncConnectedAudioGuides(state, audioSlots, makeAudioId, snapMode);
|
|
return imageChanged || audioChanged;
|
|
}
|
|
|
|
export function isTrackedGuideInputName(name) {
|
|
const shortName = String(name || '').slice(String(name || '').lastIndexOf('.') + 1);
|
|
return shortName.startsWith('guide_image_') || shortName.startsWith('guide_audio_')
|
|
|| shortName === 'first_frame' || shortName === 'last_frame'
|
|
|| shortName === 'reference_media' || shortName === 'audio_reference';
|
|
}
|