lyrics-transcriber 0.66.0__py3-none-any.whl → 0.69.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lyrics_transcriber/core/config.py +1 -1
- lyrics_transcriber/core/controller.py +22 -0
- lyrics_transcriber/correction/anchor_sequence.py +16 -3
- lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md +210 -0
- lyrics_transcriber/frontend/package.json +1 -1
- lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +4 -2
- lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +257 -134
- lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +35 -237
- lyrics_transcriber/frontend/src/components/ReferenceView.tsx +27 -3
- lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +688 -0
- lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +29 -18
- lyrics_transcriber/frontend/src/hooks/useManualSync.ts +198 -30
- lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -1
- lyrics_transcriber/frontend/web_assets/assets/{index-BMWgZ3MR.js → index-izP9z1oB.js} +985 -327
- lyrics_transcriber/frontend/web_assets/assets/index-izP9z1oB.js.map +1 -0
- lyrics_transcriber/frontend/web_assets/index.html +1 -1
- lyrics_transcriber/lyrics/base_lyrics_provider.py +1 -1
- lyrics_transcriber/output/ass/config.py +37 -0
- lyrics_transcriber/output/ass/lyrics_line.py +1 -1
- lyrics_transcriber/output/generator.py +21 -5
- lyrics_transcriber/output/subtitles.py +2 -1
- {lyrics_transcriber-0.66.0.dist-info → lyrics_transcriber-0.69.0.dist-info}/METADATA +1 -1
- {lyrics_transcriber-0.66.0.dist-info → lyrics_transcriber-0.69.0.dist-info}/RECORD +26 -24
- lyrics_transcriber/frontend/web_assets/assets/index-BMWgZ3MR.js.map +0 -1
- {lyrics_transcriber-0.66.0.dist-info → lyrics_transcriber-0.69.0.dist-info}/LICENSE +0 -0
- {lyrics_transcriber-0.66.0.dist-info → lyrics_transcriber-0.69.0.dist-info}/WHEEL +0 -0
- {lyrics_transcriber-0.66.0.dist-info → lyrics_transcriber-0.69.0.dist-info}/entry_points.txt +0 -0
@@ -33824,9 +33824,31 @@ function ReferenceView({
|
|
33824
33824
|
const copyToClipboard = (text) => {
|
33825
33825
|
navigator.clipboard.writeText(text);
|
33826
33826
|
};
|
33827
|
+
const copyAllReferenceText = () => {
|
33828
|
+
const allText = currentSourceSegments.map((segment) => segment.words.map((w) => w.text).join(" ")).join("\n");
|
33829
|
+
copyToClipboard(allText);
|
33830
|
+
};
|
33827
33831
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Paper, { sx: { p: 0.8, position: "relative" }, children: [
|
33828
33832
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 0.5 }, children: [
|
33829
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
33833
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
33834
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "h6", sx: { fontSize: "0.9rem", mb: 0 }, children: "Reference Lyrics" }),
|
33835
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
33836
|
+
IconButton,
|
33837
|
+
{
|
33838
|
+
size: "small",
|
33839
|
+
onClick: copyAllReferenceText,
|
33840
|
+
sx: {
|
33841
|
+
padding: "2px",
|
33842
|
+
height: "20px",
|
33843
|
+
width: "20px",
|
33844
|
+
minHeight: "20px",
|
33845
|
+
minWidth: "20px"
|
33846
|
+
},
|
33847
|
+
title: "Copy all reference lyrics",
|
33848
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ContentCopyIcon, { sx: { fontSize: "1rem" } })
|
33849
|
+
}
|
33850
|
+
)
|
33851
|
+
] }),
|
33830
33852
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
33831
33853
|
SourceSelector,
|
33832
33854
|
{
|
@@ -34357,7 +34379,7 @@ const StopIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
|
34357
34379
|
d: "M6 6h12v12H6z"
|
34358
34380
|
}), "Stop");
|
34359
34381
|
const TAP_THRESHOLD_MS = 200;
|
34360
|
-
const DEFAULT_WORD_DURATION =
|
34382
|
+
const DEFAULT_WORD_DURATION = 0.5;
|
34361
34383
|
const OVERLAP_BUFFER = 0.01;
|
34362
34384
|
function useManualSync({
|
34363
34385
|
editedSegment,
|
@@ -34366,12 +34388,14 @@ function useManualSync({
|
|
34366
34388
|
updateSegment: updateSegment2
|
34367
34389
|
}) {
|
34368
34390
|
const [isManualSyncing, setIsManualSyncing] = reactExports.useState(false);
|
34391
|
+
const [isPaused, setIsPaused] = reactExports.useState(false);
|
34369
34392
|
const [syncWordIndex, setSyncWordIndex] = reactExports.useState(-1);
|
34370
34393
|
const currentTimeRef = reactExports.useRef(currentTime);
|
34371
34394
|
const [isSpacebarPressed, setIsSpacebarPressed] = reactExports.useState(false);
|
34372
34395
|
const wordStartTimeRef = reactExports.useRef(null);
|
34373
34396
|
const wordsRef = reactExports.useRef([]);
|
34374
34397
|
const spacebarPressTimeRef = reactExports.useRef(null);
|
34398
|
+
const needsSegmentUpdateRef = reactExports.useRef(false);
|
34375
34399
|
reactExports.useEffect(() => {
|
34376
34400
|
currentTimeRef.current = currentTime;
|
34377
34401
|
}, [currentTime]);
|
@@ -34380,13 +34404,58 @@ function useManualSync({
|
|
34380
34404
|
wordsRef.current = [...editedSegment.words];
|
34381
34405
|
}
|
34382
34406
|
}, [editedSegment]);
|
34407
|
+
reactExports.useEffect(() => {
|
34408
|
+
if (needsSegmentUpdateRef.current) {
|
34409
|
+
needsSegmentUpdateRef.current = false;
|
34410
|
+
updateSegment2(wordsRef.current);
|
34411
|
+
}
|
34412
|
+
}, [updateSegment2, syncWordIndex]);
|
34383
34413
|
const cleanupManualSync = reactExports.useCallback(() => {
|
34384
34414
|
setIsManualSyncing(false);
|
34415
|
+
setIsPaused(false);
|
34385
34416
|
setSyncWordIndex(-1);
|
34386
34417
|
setIsSpacebarPressed(false);
|
34387
34418
|
wordStartTimeRef.current = null;
|
34388
34419
|
spacebarPressTimeRef.current = null;
|
34420
|
+
needsSegmentUpdateRef.current = false;
|
34421
|
+
if (window.toggleAudioPlayback && window.isAudioPlaying) {
|
34422
|
+
window.toggleAudioPlayback();
|
34423
|
+
}
|
34389
34424
|
}, []);
|
34425
|
+
const pauseManualSync = reactExports.useCallback(() => {
|
34426
|
+
if (isManualSyncing && !isPaused) {
|
34427
|
+
console.log("useManualSync - Pausing manual sync");
|
34428
|
+
setIsPaused(true);
|
34429
|
+
if (window.toggleAudioPlayback && window.isAudioPlaying) {
|
34430
|
+
window.toggleAudioPlayback();
|
34431
|
+
}
|
34432
|
+
}
|
34433
|
+
}, [isManualSyncing, isPaused]);
|
34434
|
+
const resumeManualSync = reactExports.useCallback(() => {
|
34435
|
+
var _a;
|
34436
|
+
if (isManualSyncing && isPaused) {
|
34437
|
+
console.log("useManualSync - Resuming manual sync");
|
34438
|
+
setIsPaused(false);
|
34439
|
+
if (editedSegment) {
|
34440
|
+
const firstUnsyncedIndex = editedSegment.words.findIndex(
|
34441
|
+
(word) => word.start_time === null || word.end_time === null
|
34442
|
+
);
|
34443
|
+
if (firstUnsyncedIndex !== -1 && firstUnsyncedIndex !== syncWordIndex) {
|
34444
|
+
console.log("useManualSync - Resuming from first unsynced word", {
|
34445
|
+
previousIndex: syncWordIndex,
|
34446
|
+
newIndex: firstUnsyncedIndex,
|
34447
|
+
wordText: (_a = editedSegment.words[firstUnsyncedIndex]) == null ? void 0 : _a.text
|
34448
|
+
});
|
34449
|
+
setSyncWordIndex(firstUnsyncedIndex);
|
34450
|
+
} else {
|
34451
|
+
console.log("useManualSync - Resuming from current position", { syncWordIndex });
|
34452
|
+
}
|
34453
|
+
}
|
34454
|
+
if (onPlaySegment && currentTimeRef.current !== void 0) {
|
34455
|
+
onPlaySegment(currentTimeRef.current);
|
34456
|
+
}
|
34457
|
+
}
|
34458
|
+
}, [isManualSyncing, isPaused, onPlaySegment, editedSegment, syncWordIndex]);
|
34390
34459
|
const handleKeyDown = reactExports.useCallback((e) => {
|
34391
34460
|
if (e.code !== "Space") return;
|
34392
34461
|
console.log("useManualSync - Spacebar pressed down", {
|
@@ -34397,25 +34466,71 @@ function useManualSync({
|
|
34397
34466
|
});
|
34398
34467
|
e.preventDefault();
|
34399
34468
|
e.stopPropagation();
|
34400
|
-
if (isManualSyncing && editedSegment && !isSpacebarPressed) {
|
34401
|
-
const currentWord = syncWordIndex < editedSegment.words.length ? editedSegment.words[syncWordIndex] : null;
|
34402
|
-
console.log("useManualSync - Recording word start time", {
|
34403
|
-
wordIndex: syncWordIndex,
|
34404
|
-
wordText: currentWord == null ? void 0 : currentWord.text,
|
34405
|
-
time: currentTimeRef.current
|
34406
|
-
});
|
34469
|
+
if (isManualSyncing && editedSegment && !isSpacebarPressed && !isPaused) {
|
34407
34470
|
setIsSpacebarPressed(true);
|
34408
34471
|
wordStartTimeRef.current = currentTimeRef.current;
|
34409
34472
|
spacebarPressTimeRef.current = Date.now();
|
34410
34473
|
if (syncWordIndex < editedSegment.words.length) {
|
34411
34474
|
const newWords = [...wordsRef.current];
|
34412
|
-
const
|
34413
|
-
|
34475
|
+
const currentWord = newWords[syncWordIndex];
|
34476
|
+
const currentStartTime = currentTimeRef.current;
|
34477
|
+
currentWord.start_time = currentStartTime;
|
34478
|
+
if (syncWordIndex > 0) {
|
34479
|
+
const previousWord = newWords[syncWordIndex - 1];
|
34480
|
+
if (previousWord.start_time !== null) {
|
34481
|
+
const timeSincePreviousStart = currentStartTime - previousWord.start_time;
|
34482
|
+
const needsAdjustment = previousWord.end_time === null || previousWord.end_time !== null && previousWord.end_time > currentStartTime;
|
34483
|
+
if (needsAdjustment) {
|
34484
|
+
if (timeSincePreviousStart > 1) {
|
34485
|
+
previousWord.end_time = previousWord.start_time + 0.5;
|
34486
|
+
console.log("useManualSync - Gap detected, setting previous word end time to +500ms", {
|
34487
|
+
previousWordIndex: syncWordIndex - 1,
|
34488
|
+
previousWordText: previousWord.text,
|
34489
|
+
previousStartTime: previousWord.start_time,
|
34490
|
+
previousEndTime: previousWord.end_time,
|
34491
|
+
gap: timeSincePreviousStart.toFixed(2) + "s",
|
34492
|
+
reason: "gap > 1s"
|
34493
|
+
});
|
34494
|
+
} else {
|
34495
|
+
previousWord.end_time = currentStartTime - 5e-3;
|
34496
|
+
console.log("useManualSync - Setting previous word end time to current start - 5ms", {
|
34497
|
+
previousWordIndex: syncWordIndex - 1,
|
34498
|
+
previousWordText: previousWord.text,
|
34499
|
+
previousEndTime: previousWord.end_time,
|
34500
|
+
currentStartTime,
|
34501
|
+
gap: timeSincePreviousStart.toFixed(2) + "s",
|
34502
|
+
reason: "normal flow"
|
34503
|
+
});
|
34504
|
+
}
|
34505
|
+
} else {
|
34506
|
+
console.log("useManualSync - Preserving previous word timing (manually set)", {
|
34507
|
+
previousWordIndex: syncWordIndex - 1,
|
34508
|
+
previousWordText: previousWord.text,
|
34509
|
+
previousStartTime: previousWord.start_time,
|
34510
|
+
previousEndTime: previousWord.end_time,
|
34511
|
+
preservedDuration: previousWord.end_time !== null ? (previousWord.end_time - previousWord.start_time).toFixed(2) + "s" : "N/A",
|
34512
|
+
reason: "already timed correctly"
|
34513
|
+
});
|
34514
|
+
}
|
34515
|
+
}
|
34516
|
+
}
|
34517
|
+
console.log("useManualSync - Recording word start time", {
|
34518
|
+
wordIndex: syncWordIndex,
|
34519
|
+
wordText: currentWord == null ? void 0 : currentWord.text,
|
34520
|
+
time: currentStartTime
|
34521
|
+
});
|
34414
34522
|
wordsRef.current = newWords;
|
34415
|
-
|
34523
|
+
needsSegmentUpdateRef.current = true;
|
34416
34524
|
}
|
34417
34525
|
} else if (!isManualSyncing && editedSegment && onPlaySegment) {
|
34418
|
-
console.log("useManualSync - Handling segment playback"
|
34526
|
+
console.log("useManualSync - Handling segment playback", {
|
34527
|
+
editedSegmentId: editedSegment.id,
|
34528
|
+
isGlobalReplacement: editedSegment.id === "global-replacement"
|
34529
|
+
});
|
34530
|
+
if (editedSegment.id === "global-replacement") {
|
34531
|
+
console.log("useManualSync - Ignoring playback for global replacement - please use Manual Sync");
|
34532
|
+
return;
|
34533
|
+
}
|
34419
34534
|
const startTime = editedSegment.start_time ?? 0;
|
34420
34535
|
const endTime = editedSegment.end_time ?? 0;
|
34421
34536
|
if (currentTimeRef.current >= startTime && currentTimeRef.current <= endTime) {
|
@@ -34426,7 +34541,7 @@ function useManualSync({
|
|
34426
34541
|
onPlaySegment(startTime);
|
34427
34542
|
}
|
34428
34543
|
}
|
34429
|
-
}, [isManualSyncing, editedSegment, syncWordIndex, onPlaySegment,
|
34544
|
+
}, [isManualSyncing, editedSegment, syncWordIndex, onPlaySegment, isSpacebarPressed, isPaused]);
|
34430
34545
|
const handleKeyUp = reactExports.useCallback((e) => {
|
34431
34546
|
if (e.code !== "Space") return;
|
34432
34547
|
console.log("useManualSync - Spacebar released", {
|
@@ -34438,7 +34553,7 @@ function useManualSync({
|
|
34438
34553
|
});
|
34439
34554
|
e.preventDefault();
|
34440
34555
|
e.stopPropagation();
|
34441
|
-
if (isManualSyncing && editedSegment && isSpacebarPressed) {
|
34556
|
+
if (isManualSyncing && editedSegment && isSpacebarPressed && !isPaused) {
|
34442
34557
|
const currentWord = syncWordIndex < editedSegment.words.length ? editedSegment.words[syncWordIndex] : null;
|
34443
34558
|
const pressDuration = spacebarPressTimeRef.current ? Date.now() - spacebarPressTimeRef.current : 0;
|
34444
34559
|
const isTap = pressDuration < TAP_THRESHOLD_MS;
|
@@ -34449,6 +34564,7 @@ function useManualSync({
|
|
34449
34564
|
endTime: currentTimeRef.current,
|
34450
34565
|
pressDuration: `${pressDuration}ms`,
|
34451
34566
|
isTap,
|
34567
|
+
tapThreshold: TAP_THRESHOLD_MS,
|
34452
34568
|
duration: currentWord ? (currentTimeRef.current - (wordStartTimeRef.current || 0)).toFixed(2) + "s" : "N/A"
|
34453
34569
|
});
|
34454
34570
|
setIsSpacebarPressed(false);
|
@@ -34459,11 +34575,19 @@ function useManualSync({
|
|
34459
34575
|
const defaultEndTime = (wordStartTimeRef.current || currentTimeRef.current) + DEFAULT_WORD_DURATION;
|
34460
34576
|
currentWord2.end_time = defaultEndTime;
|
34461
34577
|
console.log("useManualSync - Tap detected, setting default duration", {
|
34578
|
+
wordText: currentWord2.text,
|
34579
|
+
startTime: wordStartTimeRef.current,
|
34462
34580
|
defaultEndTime,
|
34463
34581
|
duration: DEFAULT_WORD_DURATION
|
34464
34582
|
});
|
34465
34583
|
} else {
|
34466
34584
|
currentWord2.end_time = currentTimeRef.current;
|
34585
|
+
console.log("useManualSync - Hold detected, using actual timing", {
|
34586
|
+
wordText: currentWord2.text,
|
34587
|
+
startTime: wordStartTimeRef.current,
|
34588
|
+
endTime: currentTimeRef.current,
|
34589
|
+
actualDuration: (currentTimeRef.current - (wordStartTimeRef.current || 0)).toFixed(2) + "s"
|
34590
|
+
});
|
34467
34591
|
}
|
34468
34592
|
wordsRef.current = newWords;
|
34469
34593
|
if (syncWordIndex === editedSegment.words.length - 1) {
|
@@ -34480,10 +34604,10 @@ function useManualSync({
|
|
34480
34604
|
});
|
34481
34605
|
setSyncWordIndex(syncWordIndex + 1);
|
34482
34606
|
}
|
34483
|
-
|
34607
|
+
needsSegmentUpdateRef.current = true;
|
34484
34608
|
}
|
34485
34609
|
}
|
34486
|
-
}, [isManualSyncing, editedSegment, syncWordIndex,
|
34610
|
+
}, [isManualSyncing, editedSegment, syncWordIndex, isSpacebarPressed, isPaused]);
|
34487
34611
|
reactExports.useEffect(() => {
|
34488
34612
|
if (isManualSyncing && editedSegment && syncWordIndex > 0) {
|
34489
34613
|
const newWords = [...wordsRef.current];
|
@@ -34499,10 +34623,10 @@ function useManualSync({
|
|
34499
34623
|
});
|
34500
34624
|
prevWord.end_time = currentWord.start_time - OVERLAP_BUFFER;
|
34501
34625
|
wordsRef.current = newWords;
|
34502
|
-
|
34626
|
+
needsSegmentUpdateRef.current = true;
|
34503
34627
|
}
|
34504
34628
|
}
|
34505
|
-
}, [syncWordIndex, isManualSyncing, editedSegment
|
34629
|
+
}, [syncWordIndex, isManualSyncing, editedSegment]);
|
34506
34630
|
const handleSpacebar = reactExports.useCallback((e) => {
|
34507
34631
|
if (e.type === "keydown") {
|
34508
34632
|
handleKeyDown(e);
|
@@ -34511,33 +34635,62 @@ function useManualSync({
|
|
34511
34635
|
}
|
34512
34636
|
}, [handleKeyDown, handleKeyUp]);
|
34513
34637
|
const startManualSync = reactExports.useCallback(() => {
|
34638
|
+
var _a;
|
34514
34639
|
if (isManualSyncing) {
|
34515
34640
|
cleanupManualSync();
|
34516
34641
|
return;
|
34517
34642
|
}
|
34518
34643
|
if (!editedSegment || !onPlaySegment) return;
|
34519
34644
|
wordsRef.current = [...editedSegment.words];
|
34645
|
+
const firstUnsyncedIndex = editedSegment.words.findIndex(
|
34646
|
+
(word) => word.start_time === null || word.end_time === null
|
34647
|
+
);
|
34648
|
+
const startIndex = firstUnsyncedIndex !== -1 ? firstUnsyncedIndex : 0;
|
34649
|
+
console.log("useManualSync - Starting manual sync", {
|
34650
|
+
totalWords: editedSegment.words.length,
|
34651
|
+
startingFromIndex: startIndex,
|
34652
|
+
startingWord: (_a = editedSegment.words[startIndex]) == null ? void 0 : _a.text
|
34653
|
+
});
|
34520
34654
|
setIsManualSyncing(true);
|
34521
|
-
setSyncWordIndex(
|
34655
|
+
setSyncWordIndex(startIndex);
|
34522
34656
|
setIsSpacebarPressed(false);
|
34523
34657
|
wordStartTimeRef.current = null;
|
34524
34658
|
spacebarPressTimeRef.current = null;
|
34659
|
+
needsSegmentUpdateRef.current = false;
|
34525
34660
|
onPlaySegment((editedSegment.start_time ?? 0) - 3);
|
34526
34661
|
}, [isManualSyncing, editedSegment, onPlaySegment, cleanupManualSync]);
|
34527
34662
|
reactExports.useEffect(() => {
|
34528
|
-
|
34529
|
-
if (
|
34530
|
-
|
34531
|
-
|
34532
|
-
console.log("Stopping playback: current time exceeded end time");
|
34533
|
-
(_a = window.toggleAudioPlayback) == null ? void 0 : _a.call(window);
|
34534
|
-
cleanupManualSync();
|
34663
|
+
if (!editedSegment || !isManualSyncing) return;
|
34664
|
+
if (editedSegment.id === "global-replacement") {
|
34665
|
+
console.log("useManualSync - Skipping auto-stop for global replacement segment");
|
34666
|
+
return;
|
34535
34667
|
}
|
34536
|
-
|
34668
|
+
const checkAutoStop = () => {
|
34669
|
+
var _a;
|
34670
|
+
const endTime = editedSegment.end_time ?? 0;
|
34671
|
+
if (window.isAudioPlaying && currentTimeRef.current > endTime) {
|
34672
|
+
console.log("useManualSync - Auto-stopping: current time exceeded end time", {
|
34673
|
+
currentTime: currentTimeRef.current,
|
34674
|
+
endTime,
|
34675
|
+
segmentId: editedSegment.id
|
34676
|
+
});
|
34677
|
+
(_a = window.toggleAudioPlayback) == null ? void 0 : _a.call(window);
|
34678
|
+
cleanupManualSync();
|
34679
|
+
}
|
34680
|
+
};
|
34681
|
+
checkAutoStop();
|
34682
|
+
const intervalId = setInterval(checkAutoStop, 100);
|
34683
|
+
return () => {
|
34684
|
+
clearInterval(intervalId);
|
34685
|
+
};
|
34686
|
+
}, [isManualSyncing, editedSegment, cleanupManualSync]);
|
34537
34687
|
return {
|
34538
34688
|
isManualSyncing,
|
34689
|
+
isPaused,
|
34539
34690
|
syncWordIndex,
|
34540
34691
|
startManualSync,
|
34692
|
+
pauseManualSync,
|
34693
|
+
resumeManualSync,
|
34541
34694
|
cleanupManualSync,
|
34542
34695
|
handleSpacebar,
|
34543
34696
|
isSpacebarPressed
|
@@ -34566,6 +34719,9 @@ const AutorenewIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path"
|
|
34566
34719
|
const PauseCircleOutlineIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
34567
34720
|
d: "M9 16h2V8H9zm3-14C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8m1-4h2V8h-2z"
|
34568
34721
|
}), "PauseCircleOutline");
|
34722
|
+
const PlayArrowIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
34723
|
+
d: "M8 5v14l11-7z"
|
34724
|
+
}), "PlayArrow");
|
34569
34725
|
const CenterFocusStrongIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
34570
34726
|
d: "M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4m-7 7H3v4c0 1.1.9 2 2 2h4v-2H5zM5 5h4V3H5c-1.1 0-2 .9-2 2v4h2zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2m0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2z"
|
34571
34727
|
}), "CenterFocusStrong");
|
@@ -34668,7 +34824,7 @@ const TimelineCursor = styled(Box)(({ theme: theme2 }) => ({
|
|
34668
34824
|
zIndex: 1
|
34669
34825
|
// Ensure it's above other elements
|
34670
34826
|
}));
|
34671
|
-
function TimelineEditor({ words, startTime, endTime, onWordUpdate, currentTime = 0, onPlaySegment, showPlaybackIndicator = true }) {
|
34827
|
+
function TimelineEditor({ words, startTime, endTime, onWordUpdate, onUnsyncWord, currentTime = 0, onPlaySegment, showPlaybackIndicator = true }) {
|
34672
34828
|
const containerRef = reactExports.useRef(null);
|
34673
34829
|
const [dragState, setDragState] = reactExports.useState(null);
|
34674
34830
|
const MIN_DURATION = 0.1;
|
@@ -34694,21 +34850,14 @@ function TimelineEditor({ words, startTime, endTime, onWordUpdate, currentTime =
|
|
34694
34850
|
const marks = [];
|
34695
34851
|
const startSecond = Math.floor(startTime);
|
34696
34852
|
const endSecond = Math.ceil(endTime);
|
34697
|
-
for (let time = startSecond; time <= endSecond; time
|
34853
|
+
for (let time = startSecond; time <= endSecond; time++) {
|
34698
34854
|
if (time >= startTime && time <= endTime) {
|
34699
34855
|
const position2 = timeToPosition(time);
|
34700
|
-
const isFullSecond = Math.abs(time - Math.round(time)) < 1e-3;
|
34701
34856
|
marks.push(
|
34702
34857
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { children: [
|
34703
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
34704
|
-
|
34705
|
-
|
34706
|
-
className: isFullSecond ? "" : "subsecond",
|
34707
|
-
sx: { left: `${position2}%` }
|
34708
|
-
}
|
34709
|
-
),
|
34710
|
-
isFullSecond && /* @__PURE__ */ jsxRuntimeExports.jsxs(TimelineLabel, { sx: { left: `${position2}%` }, children: [
|
34711
|
-
Math.round(time),
|
34858
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TimelineMark, { sx: { left: `${position2}%` } }),
|
34859
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(TimelineLabel, { sx: { left: `${position2}%` }, children: [
|
34860
|
+
time,
|
34712
34861
|
"s"
|
34713
34862
|
] })
|
34714
34863
|
] }, time)
|
@@ -34788,6 +34937,19 @@ function TimelineEditor({ words, startTime, endTime, onWordUpdate, currentTime =
|
|
34788
34937
|
const handleMouseUp = () => {
|
34789
34938
|
setDragState(null);
|
34790
34939
|
};
|
34940
|
+
const handleContextMenu = (e, wordIndex) => {
|
34941
|
+
e.preventDefault();
|
34942
|
+
e.stopPropagation();
|
34943
|
+
const word = words[wordIndex];
|
34944
|
+
if (word.start_time === null || word.end_time === null) return;
|
34945
|
+
if (onUnsyncWord) {
|
34946
|
+
console.log("TimelineEditor - Right-click unsync word", {
|
34947
|
+
wordIndex,
|
34948
|
+
wordText: word.text
|
34949
|
+
});
|
34950
|
+
onUnsyncWord(wordIndex);
|
34951
|
+
}
|
34952
|
+
};
|
34791
34953
|
const isWordHighlighted = (word) => {
|
34792
34954
|
if (!currentTime || word.start_time === null || word.end_time === null) return false;
|
34793
34955
|
return currentTime >= word.start_time && currentTime <= word.end_time;
|
@@ -34842,6 +35004,7 @@ function TimelineEditor({ words, startTime, endTime, onWordUpdate, currentTime =
|
|
34842
35004
|
e.stopPropagation();
|
34843
35005
|
handleMouseDown(e, index, "move");
|
34844
35006
|
},
|
35007
|
+
onContextMenu: (e) => handleContextMenu(e, index),
|
34845
35008
|
children: [
|
34846
35009
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
34847
35010
|
ResizeHandle,
|
@@ -34873,6 +35036,125 @@ function TimelineEditor({ words, startTime, endTime, onWordUpdate, currentTime =
|
|
34873
35036
|
}
|
34874
35037
|
);
|
34875
35038
|
}
|
35039
|
+
const TimelineControls = reactExports.memo(({
|
35040
|
+
isGlobal,
|
35041
|
+
visibleStartTime,
|
35042
|
+
visibleEndTime,
|
35043
|
+
startTime,
|
35044
|
+
endTime,
|
35045
|
+
zoomLevel,
|
35046
|
+
autoScrollEnabled,
|
35047
|
+
currentTime,
|
35048
|
+
isManualSyncing,
|
35049
|
+
isReplaceAllMode,
|
35050
|
+
isPaused,
|
35051
|
+
onScrollLeft,
|
35052
|
+
onZoomOut,
|
35053
|
+
onZoomIn,
|
35054
|
+
onScrollRight,
|
35055
|
+
onToggleAutoScroll,
|
35056
|
+
onJumpToCurrentTime,
|
35057
|
+
onStartManualSync,
|
35058
|
+
onPauseResume,
|
35059
|
+
onStopAudio
|
35060
|
+
}) => {
|
35061
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", children: [
|
35062
|
+
isGlobal && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
35063
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Scroll Left", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35064
|
+
IconButton,
|
35065
|
+
{
|
35066
|
+
onClick: onScrollLeft,
|
35067
|
+
disabled: visibleStartTime <= startTime,
|
35068
|
+
size: "small",
|
35069
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowBack, {})
|
35070
|
+
}
|
35071
|
+
) }),
|
35072
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Zoom Out (Show More Time)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35073
|
+
IconButton,
|
35074
|
+
{
|
35075
|
+
onClick: onZoomOut,
|
35076
|
+
disabled: zoomLevel >= endTime - startTime || isReplaceAllMode && isManualSyncing && !isPaused,
|
35077
|
+
size: "small",
|
35078
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomOutIcon, {})
|
35079
|
+
}
|
35080
|
+
) }),
|
35081
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Zoom In (Show Less Time)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35082
|
+
IconButton,
|
35083
|
+
{
|
35084
|
+
onClick: onZoomIn,
|
35085
|
+
disabled: zoomLevel <= 2 || isReplaceAllMode && isManualSyncing && !isPaused,
|
35086
|
+
size: "small",
|
35087
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomInIcon, {})
|
35088
|
+
}
|
35089
|
+
) }),
|
35090
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Scroll Right", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35091
|
+
IconButton,
|
35092
|
+
{
|
35093
|
+
onClick: onScrollRight,
|
35094
|
+
disabled: visibleEndTime >= endTime,
|
35095
|
+
size: "small",
|
35096
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowForwardIcon, {})
|
35097
|
+
}
|
35098
|
+
) }),
|
35099
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
35100
|
+
Tooltip,
|
35101
|
+
{
|
35102
|
+
title: autoScrollEnabled ? "Disable Auto-Page Turn During Playback" : "Enable Auto-Page Turn During Playback",
|
35103
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35104
|
+
IconButton,
|
35105
|
+
{
|
35106
|
+
onClick: onToggleAutoScroll,
|
35107
|
+
color: autoScrollEnabled ? "primary" : "default",
|
35108
|
+
size: "small",
|
35109
|
+
children: autoScrollEnabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(AutorenewIcon, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(PauseCircleOutlineIcon, {})
|
35110
|
+
}
|
35111
|
+
)
|
35112
|
+
}
|
35113
|
+
),
|
35114
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Jump to Current Playback Position", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35115
|
+
IconButton,
|
35116
|
+
{
|
35117
|
+
onClick: onJumpToCurrentTime,
|
35118
|
+
disabled: !currentTime,
|
35119
|
+
size: "small",
|
35120
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(CenterFocusStrongIcon, {})
|
35121
|
+
}
|
35122
|
+
) })
|
35123
|
+
] }),
|
35124
|
+
isReplaceAllMode && onStopAudio && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35125
|
+
Button,
|
35126
|
+
{
|
35127
|
+
variant: "outlined",
|
35128
|
+
onClick: onStopAudio,
|
35129
|
+
startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(StopIcon, {}),
|
35130
|
+
color: "error",
|
35131
|
+
size: "small",
|
35132
|
+
children: "Stop Audio"
|
35133
|
+
}
|
35134
|
+
),
|
35135
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
35136
|
+
Button,
|
35137
|
+
{
|
35138
|
+
variant: isManualSyncing ? "outlined" : "contained",
|
35139
|
+
onClick: onStartManualSync,
|
35140
|
+
startIcon: isManualSyncing ? /* @__PURE__ */ jsxRuntimeExports.jsx(CancelIcon, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(PlayCircleOutlineIcon, {}),
|
35141
|
+
color: isManualSyncing ? "error" : "primary",
|
35142
|
+
children: isManualSyncing ? "Cancel Sync" : "Manual Sync"
|
35143
|
+
}
|
35144
|
+
),
|
35145
|
+
isManualSyncing && isReplaceAllMode && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35146
|
+
Button,
|
35147
|
+
{
|
35148
|
+
variant: "outlined",
|
35149
|
+
onClick: onPauseResume,
|
35150
|
+
startIcon: isPaused ? /* @__PURE__ */ jsxRuntimeExports.jsx(PlayArrowIcon, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(PauseCircleOutlineIcon, {}),
|
35151
|
+
color: isPaused ? "success" : "warning",
|
35152
|
+
size: "small",
|
35153
|
+
children: isPaused ? "Resume" : "Pause"
|
35154
|
+
}
|
35155
|
+
)
|
35156
|
+
] });
|
35157
|
+
});
|
34876
35158
|
function EditTimelineSection({
|
34877
35159
|
words,
|
34878
35160
|
startTime,
|
@@ -34886,16 +35168,32 @@ function EditTimelineSection({
|
|
34886
35168
|
syncWordIndex,
|
34887
35169
|
isSpacebarPressed,
|
34888
35170
|
onWordUpdate,
|
35171
|
+
onUnsyncWord,
|
34889
35172
|
onPlaySegment,
|
35173
|
+
onStopAudio,
|
34890
35174
|
startManualSync,
|
34891
|
-
|
35175
|
+
pauseManualSync,
|
35176
|
+
resumeManualSync,
|
35177
|
+
isPaused = false,
|
35178
|
+
isGlobal = false,
|
35179
|
+
defaultZoomLevel = 10,
|
35180
|
+
isReplaceAllMode = false
|
34892
35181
|
}) {
|
34893
|
-
|
34894
|
-
const [zoomLevel, setZoomLevel] = reactExports.useState(10);
|
35182
|
+
const [zoomLevel, setZoomLevel] = reactExports.useState(defaultZoomLevel);
|
34895
35183
|
const [visibleStartTime, setVisibleStartTime] = reactExports.useState(startTime);
|
34896
35184
|
const [visibleEndTime, setVisibleEndTime] = reactExports.useState(Math.min(startTime + zoomLevel, endTime));
|
34897
35185
|
const [autoScrollEnabled, setAutoScrollEnabled] = reactExports.useState(true);
|
34898
35186
|
const timelineRef = reactExports.useRef(null);
|
35187
|
+
const effectiveTimeRange = reactExports.useMemo(() => ({
|
35188
|
+
start: isGlobal ? visibleStartTime : startTime,
|
35189
|
+
end: isGlobal ? visibleEndTime : endTime
|
35190
|
+
}), [isGlobal, visibleStartTime, visibleEndTime, startTime, endTime]);
|
35191
|
+
reactExports.useEffect(() => {
|
35192
|
+
if (isManualSyncing && !isPaused) {
|
35193
|
+
console.log("EditTimelineSection - Auto-enabling auto-scroll for manual sync");
|
35194
|
+
setAutoScrollEnabled(true);
|
35195
|
+
}
|
35196
|
+
}, [isManualSyncing, isPaused]);
|
34899
35197
|
reactExports.useEffect(() => {
|
34900
35198
|
if (isGlobal) {
|
34901
35199
|
setVisibleStartTime(startTime);
|
@@ -34905,8 +35203,13 @@ function EditTimelineSection({
|
|
34905
35203
|
setVisibleEndTime(endTime);
|
34906
35204
|
}
|
34907
35205
|
}, [startTime, endTime, zoomLevel, isGlobal]);
|
35206
|
+
const lastScrollUpdateRef = reactExports.useRef(0);
|
35207
|
+
const SCROLL_THROTTLE_MS = 100;
|
34908
35208
|
reactExports.useEffect(() => {
|
34909
35209
|
if (!isGlobal || !currentTime || !autoScrollEnabled) return;
|
35210
|
+
const now = Date.now();
|
35211
|
+
if (now - lastScrollUpdateRef.current < SCROLL_THROTTLE_MS) return;
|
35212
|
+
lastScrollUpdateRef.current = now;
|
34910
35213
|
if (currentTime < visibleStartTime) {
|
34911
35214
|
const newStart = Math.max(startTime, currentTime);
|
34912
35215
|
const newEnd = Math.min(endTime, newStart + zoomLevel);
|
@@ -34935,9 +35238,21 @@ function EditTimelineSection({
|
|
34935
35238
|
setVisibleEndTime(endTime);
|
34936
35239
|
}
|
34937
35240
|
}, [zoomLevel, startTime, endTime, isGlobal, visibleStartTime]);
|
34938
|
-
const
|
35241
|
+
const handleZoomIn = reactExports.useCallback(() => {
|
35242
|
+
if (isReplaceAllMode && isManualSyncing && !isPaused) return;
|
35243
|
+
if (zoomLevel > 2) {
|
35244
|
+
setZoomLevel(zoomLevel - 2);
|
35245
|
+
}
|
35246
|
+
}, [isReplaceAllMode, isManualSyncing, isPaused, zoomLevel]);
|
35247
|
+
const handleZoomOut = reactExports.useCallback(() => {
|
35248
|
+
if (isReplaceAllMode && isManualSyncing && !isPaused) return;
|
35249
|
+
if (zoomLevel < endTime - startTime) {
|
35250
|
+
setZoomLevel(zoomLevel + 2);
|
35251
|
+
}
|
35252
|
+
}, [isReplaceAllMode, isManualSyncing, isPaused, zoomLevel, endTime, startTime]);
|
35253
|
+
const toggleAutoScroll = reactExports.useCallback(() => {
|
34939
35254
|
setAutoScrollEnabled(!autoScrollEnabled);
|
34940
|
-
};
|
35255
|
+
}, [autoScrollEnabled]);
|
34941
35256
|
const jumpToCurrentTime = reactExports.useCallback(() => {
|
34942
35257
|
if (!isGlobal || !currentTime) return;
|
34943
35258
|
const halfZoom = zoomLevel / 2;
|
@@ -34949,34 +35264,6 @@ function EditTimelineSection({
|
|
34949
35264
|
setVisibleStartTime(newStart);
|
34950
35265
|
setVisibleEndTime(newEnd);
|
34951
35266
|
}, [currentTime, zoomLevel, startTime, endTime, isGlobal]);
|
34952
|
-
reactExports.useEffect(() => {
|
34953
|
-
const handleKeyDown = (e) => {
|
34954
|
-
if (isGlobal) {
|
34955
|
-
if (e.altKey && e.key === "a") {
|
34956
|
-
e.preventDefault();
|
34957
|
-
toggleAutoScroll();
|
34958
|
-
}
|
34959
|
-
if (e.altKey && e.key === "j") {
|
34960
|
-
e.preventDefault();
|
34961
|
-
jumpToCurrentTime();
|
34962
|
-
}
|
34963
|
-
}
|
34964
|
-
};
|
34965
|
-
window.addEventListener("keydown", handleKeyDown);
|
34966
|
-
return () => {
|
34967
|
-
window.removeEventListener("keydown", handleKeyDown);
|
34968
|
-
};
|
34969
|
-
}, [isGlobal, toggleAutoScroll, jumpToCurrentTime]);
|
34970
|
-
const handleZoomIn = () => {
|
34971
|
-
if (zoomLevel > 2) {
|
34972
|
-
setZoomLevel(zoomLevel - 2);
|
34973
|
-
}
|
34974
|
-
};
|
34975
|
-
const handleZoomOut = () => {
|
34976
|
-
if (zoomLevel < endTime - startTime) {
|
34977
|
-
setZoomLevel(zoomLevel + 2);
|
34978
|
-
}
|
34979
|
-
};
|
34980
35267
|
const handleScroll = reactExports.useCallback((event) => {
|
34981
35268
|
if (isGlobal && event.deltaX !== 0) {
|
34982
35269
|
event.preventDefault();
|
@@ -34996,7 +35283,7 @@ function EditTimelineSection({
|
|
34996
35283
|
setVisibleEndTime(newEnd);
|
34997
35284
|
}
|
34998
35285
|
}, [isGlobal, visibleStartTime, visibleEndTime, startTime, endTime, zoomLevel]);
|
34999
|
-
const handleScrollLeft = () => {
|
35286
|
+
const handleScrollLeft = reactExports.useCallback(() => {
|
35000
35287
|
if (!isGlobal) return;
|
35001
35288
|
setAutoScrollEnabled(false);
|
35002
35289
|
const scrollAmount = zoomLevel * 0.25;
|
@@ -35004,8 +35291,8 @@ function EditTimelineSection({
|
|
35004
35291
|
const newEnd = newStart + zoomLevel;
|
35005
35292
|
setVisibleStartTime(newStart);
|
35006
35293
|
setVisibleEndTime(newEnd);
|
35007
|
-
};
|
35008
|
-
const handleScrollRight = () => {
|
35294
|
+
}, [isGlobal, zoomLevel, startTime, visibleStartTime]);
|
35295
|
+
const handleScrollRight = reactExports.useCallback(() => {
|
35009
35296
|
if (!isGlobal) return;
|
35010
35297
|
setAutoScrollEnabled(false);
|
35011
35298
|
const scrollAmount = zoomLevel * 0.25;
|
@@ -35019,9 +35306,25 @@ function EditTimelineSection({
|
|
35019
35306
|
setVisibleEndTime(newEnd);
|
35020
35307
|
}
|
35021
35308
|
setVisibleStartTime(newStart);
|
35022
|
-
};
|
35023
|
-
const
|
35024
|
-
|
35309
|
+
}, [isGlobal, zoomLevel, endTime, visibleEndTime, startTime]);
|
35310
|
+
const handlePauseResume = reactExports.useCallback(() => {
|
35311
|
+
if (isPaused && resumeManualSync) {
|
35312
|
+
resumeManualSync();
|
35313
|
+
} else if (!isPaused && pauseManualSync) {
|
35314
|
+
pauseManualSync();
|
35315
|
+
}
|
35316
|
+
}, [isPaused, resumeManualSync, pauseManualSync]);
|
35317
|
+
const currentWordInfo = reactExports.useMemo(() => {
|
35318
|
+
var _a;
|
35319
|
+
if (!isManualSyncing || syncWordIndex < 0 || syncWordIndex >= words.length) {
|
35320
|
+
return null;
|
35321
|
+
}
|
35322
|
+
return {
|
35323
|
+
index: syncWordIndex + 1,
|
35324
|
+
total: words.length,
|
35325
|
+
text: ((_a = words[syncWordIndex]) == null ? void 0 : _a.text) || ""
|
35326
|
+
};
|
35327
|
+
}, [isManualSyncing, syncWordIndex, words]);
|
35025
35328
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
35026
35329
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
35027
35330
|
Box,
|
@@ -35033,11 +35336,12 @@ function EditTimelineSection({
|
|
35033
35336
|
TimelineEditor,
|
35034
35337
|
{
|
35035
35338
|
words,
|
35036
|
-
startTime:
|
35037
|
-
endTime:
|
35339
|
+
startTime: effectiveTimeRange.start,
|
35340
|
+
endTime: effectiveTimeRange.end,
|
35038
35341
|
onWordUpdate,
|
35039
35342
|
currentTime,
|
35040
|
-
onPlaySegment
|
35343
|
+
onPlaySegment,
|
35344
|
+
onUnsyncWord
|
35041
35345
|
}
|
35042
35346
|
)
|
35043
35347
|
}
|
@@ -35054,88 +35358,40 @@ function EditTimelineSection({
|
|
35054
35358
|
" - ",
|
35055
35359
|
(currentEndTime == null ? void 0 : currentEndTime.toFixed(2)) ?? "N/A"
|
35056
35360
|
] }),
|
35057
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
35058
|
-
isGlobal && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
35059
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Scroll Left", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35060
|
-
IconButton,
|
35061
|
-
{
|
35062
|
-
onClick: handleScrollLeft,
|
35063
|
-
disabled: visibleStartTime <= startTime,
|
35064
|
-
size: "small",
|
35065
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowBack, {})
|
35066
|
-
}
|
35067
|
-
) }),
|
35068
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Zoom Out (Show More Time)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35069
|
-
IconButton,
|
35070
|
-
{
|
35071
|
-
onClick: handleZoomOut,
|
35072
|
-
disabled: zoomLevel >= endTime - startTime,
|
35073
|
-
size: "small",
|
35074
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomOutIcon, {})
|
35075
|
-
}
|
35076
|
-
) }),
|
35077
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Zoom In (Show Less Time)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35078
|
-
IconButton,
|
35079
|
-
{
|
35080
|
-
onClick: handleZoomIn,
|
35081
|
-
disabled: zoomLevel <= 2,
|
35082
|
-
size: "small",
|
35083
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomInIcon, {})
|
35084
|
-
}
|
35085
|
-
) }),
|
35086
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Scroll Right", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35087
|
-
IconButton,
|
35088
|
-
{
|
35089
|
-
onClick: handleScrollRight,
|
35090
|
-
disabled: visibleEndTime >= endTime,
|
35091
|
-
size: "small",
|
35092
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowForwardIcon, {})
|
35093
|
-
}
|
35094
|
-
) }),
|
35095
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
35096
|
-
Tooltip,
|
35097
|
-
{
|
35098
|
-
title: autoScrollEnabled ? "Disable Auto-Page Turn During Playback (Alt+A)" : "Enable Auto-Page Turn During Playback (Alt+A)",
|
35099
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35100
|
-
IconButton,
|
35101
|
-
{
|
35102
|
-
onClick: toggleAutoScroll,
|
35103
|
-
color: autoScrollEnabled ? "primary" : "default",
|
35104
|
-
size: "small",
|
35105
|
-
children: autoScrollEnabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(AutorenewIcon, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(PauseCircleOutlineIcon, {})
|
35106
|
-
}
|
35107
|
-
)
|
35108
|
-
}
|
35109
|
-
),
|
35110
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Jump to Current Playback Position (Alt+J)", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
35111
|
-
IconButton,
|
35112
|
-
{
|
35113
|
-
onClick: jumpToCurrentTime,
|
35114
|
-
disabled: !currentTime,
|
35115
|
-
size: "small",
|
35116
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(CenterFocusStrongIcon, {})
|
35117
|
-
}
|
35118
|
-
) })
|
35119
|
-
] }),
|
35361
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 2 }, children: [
|
35120
35362
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
35121
|
-
|
35363
|
+
TimelineControls,
|
35122
35364
|
{
|
35123
|
-
|
35124
|
-
|
35125
|
-
|
35126
|
-
|
35127
|
-
|
35128
|
-
|
35365
|
+
isGlobal,
|
35366
|
+
visibleStartTime,
|
35367
|
+
visibleEndTime,
|
35368
|
+
startTime,
|
35369
|
+
endTime,
|
35370
|
+
zoomLevel,
|
35371
|
+
autoScrollEnabled,
|
35372
|
+
currentTime,
|
35373
|
+
isManualSyncing,
|
35374
|
+
isReplaceAllMode,
|
35375
|
+
isPaused,
|
35376
|
+
onScrollLeft: handleScrollLeft,
|
35377
|
+
onZoomOut: handleZoomOut,
|
35378
|
+
onZoomIn: handleZoomIn,
|
35379
|
+
onScrollRight: handleScrollRight,
|
35380
|
+
onToggleAutoScroll: toggleAutoScroll,
|
35381
|
+
onJumpToCurrentTime: jumpToCurrentTime,
|
35382
|
+
onStartManualSync: startManualSync,
|
35383
|
+
onPauseResume: handlePauseResume,
|
35384
|
+
onStopAudio
|
35129
35385
|
}
|
35130
35386
|
),
|
35131
|
-
|
35387
|
+
currentWordInfo && /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { children: [
|
35132
35388
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(Typography, { variant: "body2", children: [
|
35133
35389
|
"Word ",
|
35134
|
-
|
35390
|
+
currentWordInfo.index,
|
35135
35391
|
" of ",
|
35136
|
-
|
35392
|
+
currentWordInfo.total,
|
35137
35393
|
": ",
|
35138
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children:
|
35394
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: currentWordInfo.text })
|
35139
35395
|
] }),
|
35140
35396
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "caption", color: "text.secondary", children: isSpacebarPressed ? "Holding spacebar... Release when word ends" : "Press spacebar when word starts (tap for short words, hold for long words)" })
|
35141
35397
|
] })
|
@@ -36317,6 +36573,9 @@ function PreviewVideoSection({
|
|
36317
36573
|
const CloudUpload = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
36318
36574
|
d: "M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96M14 13v4h-4v-4H7l5-5 5 5z"
|
36319
36575
|
}), "CloudUpload");
|
36576
|
+
const ContentPasteIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
36577
|
+
d: "M19 2h-4.18C14.4.84 13.3 0 12 0S9.6.84 9.18 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2m-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1m7 18H5V4h2v3h10V4h2z"
|
36578
|
+
}), "ContentPaste");
|
36320
36579
|
const EditIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
36321
36580
|
d: "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75z"
|
36322
36581
|
}), "Edit");
|
@@ -36335,9 +36594,6 @@ const OndemandVideo = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path"
|
|
36335
36594
|
const PauseIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
36336
36595
|
d: "M6 19h4V5H6zm8-14v14h4V5z"
|
36337
36596
|
}), "Pause");
|
36338
|
-
const PlayArrowIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
36339
|
-
d: "M8 5v14l11-7z"
|
36340
|
-
}), "PlayArrow");
|
36341
36597
|
const RedoIcon = createSvgIcon(/* @__PURE__ */ jsxRuntimeExports.jsx("path", {
|
36342
36598
|
d: "M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.65 0-8.58 3.03-9.96 7.22L3.9 16c1.05-3.19 4.05-5.5 7.6-5.5 1.95 0 3.73.72 5.12 1.88L13 16h9V7z"
|
36343
36599
|
}), "Redo");
|
@@ -36621,6 +36877,545 @@ function ReviewChangesModal({
|
|
36621
36877
|
}
|
36622
36878
|
);
|
36623
36879
|
}
|
36880
|
+
function ReplaceAllLyricsModal({
|
36881
|
+
open,
|
36882
|
+
onClose,
|
36883
|
+
onSave,
|
36884
|
+
onPlaySegment,
|
36885
|
+
currentTime = 0,
|
36886
|
+
setModalSpacebarHandler
|
36887
|
+
}) {
|
36888
|
+
const [inputText, setInputText] = reactExports.useState("");
|
36889
|
+
const [isReplaced, setIsReplaced] = reactExports.useState(false);
|
36890
|
+
const [globalSegment, setGlobalSegment] = reactExports.useState(null);
|
36891
|
+
const [originalSegments, setOriginalSegments] = reactExports.useState([]);
|
36892
|
+
const [currentSegments, setCurrentSegments] = reactExports.useState([]);
|
36893
|
+
const getAudioDuration = reactExports.useCallback(() => {
|
36894
|
+
if (window.getAudioDuration) {
|
36895
|
+
const duration2 = window.getAudioDuration();
|
36896
|
+
return duration2 > 0 ? duration2 : 600;
|
36897
|
+
}
|
36898
|
+
return 600;
|
36899
|
+
}, []);
|
36900
|
+
const parseInfo = reactExports.useMemo(() => {
|
36901
|
+
if (!inputText.trim()) return { lines: 0, words: 0 };
|
36902
|
+
const lines = inputText.trim().split("\n").filter((line2) => line2.trim().length > 0);
|
36903
|
+
const totalWords = lines.reduce((count, line2) => {
|
36904
|
+
return count + line2.trim().split(/\s+/).length;
|
36905
|
+
}, 0);
|
36906
|
+
return { lines: lines.length, words: totalWords };
|
36907
|
+
}, [inputText]);
|
36908
|
+
const processLyrics = reactExports.useCallback(() => {
|
36909
|
+
if (!inputText.trim()) return;
|
36910
|
+
const lines = inputText.trim().split("\n").filter((line2) => line2.trim().length > 0);
|
36911
|
+
const newSegments = [];
|
36912
|
+
const allWords = [];
|
36913
|
+
lines.forEach((line2) => {
|
36914
|
+
const words = line2.trim().split(/\s+/).filter((word) => word.length > 0);
|
36915
|
+
const segmentWords = [];
|
36916
|
+
words.forEach((wordText) => {
|
36917
|
+
const word = {
|
36918
|
+
id: nanoid(),
|
36919
|
+
text: wordText,
|
36920
|
+
start_time: null,
|
36921
|
+
end_time: null,
|
36922
|
+
confidence: 1,
|
36923
|
+
created_during_correction: true
|
36924
|
+
};
|
36925
|
+
segmentWords.push(word);
|
36926
|
+
allWords.push(word);
|
36927
|
+
});
|
36928
|
+
const segment = {
|
36929
|
+
id: nanoid(),
|
36930
|
+
text: line2.trim(),
|
36931
|
+
words: segmentWords,
|
36932
|
+
start_time: null,
|
36933
|
+
end_time: null
|
36934
|
+
};
|
36935
|
+
newSegments.push(segment);
|
36936
|
+
});
|
36937
|
+
const audioDuration = getAudioDuration();
|
36938
|
+
const endTime = Math.max(audioDuration, 3600);
|
36939
|
+
console.log("ReplaceAllLyricsModal - Creating global segment", {
|
36940
|
+
audioDuration,
|
36941
|
+
endTime,
|
36942
|
+
wordCount: allWords.length
|
36943
|
+
});
|
36944
|
+
const globalSegment2 = {
|
36945
|
+
id: "global-replacement",
|
36946
|
+
text: allWords.map((w) => w.text).join(" "),
|
36947
|
+
words: allWords,
|
36948
|
+
start_time: 0,
|
36949
|
+
end_time: endTime
|
36950
|
+
};
|
36951
|
+
setCurrentSegments(newSegments);
|
36952
|
+
setOriginalSegments(JSON.parse(JSON.stringify(newSegments)));
|
36953
|
+
setGlobalSegment(globalSegment2);
|
36954
|
+
setIsReplaced(true);
|
36955
|
+
}, [inputText, getAudioDuration]);
|
36956
|
+
const handlePasteFromClipboard = reactExports.useCallback(async () => {
|
36957
|
+
try {
|
36958
|
+
const text = await navigator.clipboard.readText();
|
36959
|
+
setInputText(text);
|
36960
|
+
} catch (error) {
|
36961
|
+
console.error("Failed to read from clipboard:", error);
|
36962
|
+
alert("Failed to read from clipboard. Please paste manually.");
|
36963
|
+
}
|
36964
|
+
}, []);
|
36965
|
+
const updateSegment2 = reactExports.useCallback((newWords) => {
|
36966
|
+
if (!globalSegment) return;
|
36967
|
+
const validStartTimes = newWords.map((w) => w.start_time).filter((t) => t !== null);
|
36968
|
+
const validEndTimes = newWords.map((w) => w.end_time).filter((t) => t !== null);
|
36969
|
+
const segmentStartTime = validStartTimes.length > 0 ? Math.min(...validStartTimes) : null;
|
36970
|
+
const segmentEndTime = validEndTimes.length > 0 ? Math.max(...validEndTimes) : null;
|
36971
|
+
const updatedGlobalSegment = {
|
36972
|
+
...globalSegment,
|
36973
|
+
words: newWords,
|
36974
|
+
text: newWords.map((w) => w.text).join(" "),
|
36975
|
+
start_time: segmentStartTime,
|
36976
|
+
end_time: segmentEndTime
|
36977
|
+
};
|
36978
|
+
setGlobalSegment(updatedGlobalSegment);
|
36979
|
+
const updatedSegments = currentSegments.map((segment) => {
|
36980
|
+
const segmentWordsWithTiming = segment.words.map((segmentWord) => {
|
36981
|
+
const globalWord = newWords.find((w) => w.id === segmentWord.id);
|
36982
|
+
return globalWord || segmentWord;
|
36983
|
+
});
|
36984
|
+
const wordsWithTiming = segmentWordsWithTiming.filter(
|
36985
|
+
(w) => w.start_time !== null && w.end_time !== null
|
36986
|
+
);
|
36987
|
+
if (wordsWithTiming.length === segmentWordsWithTiming.length && wordsWithTiming.length > 0) {
|
36988
|
+
const segmentStart = Math.min(...wordsWithTiming.map((w) => w.start_time));
|
36989
|
+
const segmentEnd = Math.max(...wordsWithTiming.map((w) => w.end_time));
|
36990
|
+
return {
|
36991
|
+
...segment,
|
36992
|
+
words: segmentWordsWithTiming,
|
36993
|
+
start_time: segmentStart,
|
36994
|
+
end_time: segmentEnd
|
36995
|
+
};
|
36996
|
+
} else {
|
36997
|
+
return {
|
36998
|
+
...segment,
|
36999
|
+
words: segmentWordsWithTiming
|
37000
|
+
};
|
37001
|
+
}
|
37002
|
+
});
|
37003
|
+
setCurrentSegments(updatedSegments);
|
37004
|
+
}, [globalSegment, currentSegments]);
|
37005
|
+
const {
|
37006
|
+
isManualSyncing,
|
37007
|
+
isPaused,
|
37008
|
+
syncWordIndex,
|
37009
|
+
startManualSync,
|
37010
|
+
pauseManualSync,
|
37011
|
+
resumeManualSync,
|
37012
|
+
cleanupManualSync,
|
37013
|
+
handleSpacebar,
|
37014
|
+
isSpacebarPressed
|
37015
|
+
} = useManualSync({
|
37016
|
+
editedSegment: globalSegment,
|
37017
|
+
currentTime,
|
37018
|
+
onPlaySegment,
|
37019
|
+
updateSegment: updateSegment2
|
37020
|
+
});
|
37021
|
+
const handleWordUpdate = reactExports.useCallback((wordIndex, updates) => {
|
37022
|
+
var _a;
|
37023
|
+
if (!globalSegment) return;
|
37024
|
+
if (isManualSyncing && !isPaused) {
|
37025
|
+
console.log("ReplaceAllLyricsModal - Ignoring word update during active manual sync");
|
37026
|
+
return;
|
37027
|
+
}
|
37028
|
+
console.log("ReplaceAllLyricsModal - Manual word update", {
|
37029
|
+
wordIndex,
|
37030
|
+
wordText: (_a = globalSegment.words[wordIndex]) == null ? void 0 : _a.text,
|
37031
|
+
updates,
|
37032
|
+
isManualSyncing,
|
37033
|
+
isPaused
|
37034
|
+
});
|
37035
|
+
const newWords = [...globalSegment.words];
|
37036
|
+
newWords[wordIndex] = {
|
37037
|
+
...newWords[wordIndex],
|
37038
|
+
...updates
|
37039
|
+
};
|
37040
|
+
updateSegment2(newWords);
|
37041
|
+
}, [globalSegment, updateSegment2, isManualSyncing, isPaused]);
|
37042
|
+
const handleUnsyncWord = reactExports.useCallback((wordIndex) => {
|
37043
|
+
var _a;
|
37044
|
+
if (!globalSegment) return;
|
37045
|
+
console.log("ReplaceAllLyricsModal - Un-syncing word", {
|
37046
|
+
wordIndex,
|
37047
|
+
wordText: (_a = globalSegment.words[wordIndex]) == null ? void 0 : _a.text
|
37048
|
+
});
|
37049
|
+
const newWords = [...globalSegment.words];
|
37050
|
+
newWords[wordIndex] = {
|
37051
|
+
...newWords[wordIndex],
|
37052
|
+
start_time: null,
|
37053
|
+
end_time: null
|
37054
|
+
};
|
37055
|
+
updateSegment2(newWords);
|
37056
|
+
}, [globalSegment, updateSegment2]);
|
37057
|
+
const handleClose = reactExports.useCallback(() => {
|
37058
|
+
cleanupManualSync();
|
37059
|
+
setInputText("");
|
37060
|
+
setIsReplaced(false);
|
37061
|
+
setGlobalSegment(null);
|
37062
|
+
setOriginalSegments([]);
|
37063
|
+
setCurrentSegments([]);
|
37064
|
+
onClose();
|
37065
|
+
}, [onClose, cleanupManualSync]);
|
37066
|
+
const handleSave = reactExports.useCallback(() => {
|
37067
|
+
if (!globalSegment || !currentSegments.length) return;
|
37068
|
+
const finalSegments = [];
|
37069
|
+
let wordIndex = 0;
|
37070
|
+
currentSegments.forEach((segment) => {
|
37071
|
+
const originalWordCount = segment.words.length;
|
37072
|
+
const segmentWords = globalSegment.words.slice(wordIndex, wordIndex + originalWordCount);
|
37073
|
+
wordIndex += originalWordCount;
|
37074
|
+
if (segmentWords.length > 0) {
|
37075
|
+
const validStartTimes = segmentWords.map((w) => w.start_time).filter((t) => t !== null);
|
37076
|
+
const validEndTimes = segmentWords.map((w) => w.end_time).filter((t) => t !== null);
|
37077
|
+
const segmentStartTime = validStartTimes.length > 0 ? Math.min(...validStartTimes) : null;
|
37078
|
+
const segmentEndTime = validEndTimes.length > 0 ? Math.max(...validEndTimes) : null;
|
37079
|
+
finalSegments.push({
|
37080
|
+
...segment,
|
37081
|
+
words: segmentWords,
|
37082
|
+
text: segmentWords.map((w) => w.text).join(" "),
|
37083
|
+
start_time: segmentStartTime,
|
37084
|
+
end_time: segmentEndTime
|
37085
|
+
});
|
37086
|
+
}
|
37087
|
+
});
|
37088
|
+
console.log("ReplaceAllLyricsModal - Saving new segments:", {
|
37089
|
+
originalSegmentCount: currentSegments.length,
|
37090
|
+
finalSegmentCount: finalSegments.length,
|
37091
|
+
totalWords: finalSegments.reduce((count, seg) => count + seg.words.length, 0)
|
37092
|
+
});
|
37093
|
+
onSave(finalSegments);
|
37094
|
+
handleClose();
|
37095
|
+
}, [globalSegment, currentSegments, onSave, handleClose]);
|
37096
|
+
const handleReset = reactExports.useCallback(() => {
|
37097
|
+
if (!originalSegments.length) return;
|
37098
|
+
console.log("ReplaceAllLyricsModal - Resetting to original state");
|
37099
|
+
const resetWords = originalSegments.flatMap(
|
37100
|
+
(segment) => segment.words.map((word) => ({
|
37101
|
+
...word,
|
37102
|
+
start_time: null,
|
37103
|
+
end_time: null
|
37104
|
+
}))
|
37105
|
+
);
|
37106
|
+
const audioDuration = getAudioDuration();
|
37107
|
+
const resetGlobalSegment = {
|
37108
|
+
id: "global-replacement",
|
37109
|
+
text: resetWords.map((w) => w.text).join(" "),
|
37110
|
+
words: resetWords,
|
37111
|
+
start_time: 0,
|
37112
|
+
end_time: Math.max(audioDuration, 3600)
|
37113
|
+
// At least 1 hour to prevent auto-stop
|
37114
|
+
};
|
37115
|
+
const resetCurrentSegments = originalSegments.map((segment) => ({
|
37116
|
+
...segment,
|
37117
|
+
words: segment.words.map((word) => ({
|
37118
|
+
...word,
|
37119
|
+
start_time: null,
|
37120
|
+
end_time: null
|
37121
|
+
})),
|
37122
|
+
start_time: null,
|
37123
|
+
end_time: null
|
37124
|
+
}));
|
37125
|
+
setGlobalSegment(resetGlobalSegment);
|
37126
|
+
setCurrentSegments(resetCurrentSegments);
|
37127
|
+
}, [originalSegments, getAudioDuration]);
|
37128
|
+
const spacebarHandlerRef = reactExports.useRef(handleSpacebar);
|
37129
|
+
spacebarHandlerRef.current = handleSpacebar;
|
37130
|
+
reactExports.useEffect(() => {
|
37131
|
+
if (open && isReplaced) {
|
37132
|
+
console.log("ReplaceAllLyricsModal - Setting up spacebar handler");
|
37133
|
+
const handleKeyEvent = (e) => {
|
37134
|
+
if (e.code === "Space") {
|
37135
|
+
console.log("ReplaceAllLyricsModal - Spacebar captured in modal");
|
37136
|
+
e.preventDefault();
|
37137
|
+
e.stopPropagation();
|
37138
|
+
spacebarHandlerRef.current(e);
|
37139
|
+
}
|
37140
|
+
};
|
37141
|
+
setModalSpacebarHandler(() => handleKeyEvent);
|
37142
|
+
return () => {
|
37143
|
+
if (!open) {
|
37144
|
+
console.log("ReplaceAllLyricsModal - Clearing spacebar handler");
|
37145
|
+
setModalSpacebarHandler(void 0);
|
37146
|
+
}
|
37147
|
+
};
|
37148
|
+
} else if (open) {
|
37149
|
+
setModalSpacebarHandler(void 0);
|
37150
|
+
}
|
37151
|
+
}, [open, isReplaced, setModalSpacebarHandler]);
|
37152
|
+
const timeRange = reactExports.useMemo(() => {
|
37153
|
+
const audioDuration = getAudioDuration();
|
37154
|
+
return { start: 0, end: audioDuration };
|
37155
|
+
}, [getAudioDuration]);
|
37156
|
+
const segmentProgressProps = reactExports.useMemo(() => ({
|
37157
|
+
currentSegments,
|
37158
|
+
globalSegment,
|
37159
|
+
syncWordIndex
|
37160
|
+
}), [currentSegments, globalSegment, syncWordIndex]);
|
37161
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
37162
|
+
Dialog,
|
37163
|
+
{
|
37164
|
+
open,
|
37165
|
+
onClose: handleClose,
|
37166
|
+
maxWidth: false,
|
37167
|
+
fullWidth: true,
|
37168
|
+
onKeyDown: (e) => {
|
37169
|
+
if (e.key === "Enter" && !e.shiftKey && isReplaced) {
|
37170
|
+
e.preventDefault();
|
37171
|
+
handleSave();
|
37172
|
+
}
|
37173
|
+
},
|
37174
|
+
PaperProps: {
|
37175
|
+
sx: {
|
37176
|
+
height: "90vh",
|
37177
|
+
margin: "5vh 2vh",
|
37178
|
+
maxWidth: "calc(100vw - 4vh)",
|
37179
|
+
width: "calc(100vw - 4vh)"
|
37180
|
+
}
|
37181
|
+
},
|
37182
|
+
children: [
|
37183
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(DialogTitle, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
37184
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { flex: 1 }, children: "Replace All Lyrics" }),
|
37185
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconButton, { onClick: handleClose, sx: { ml: "auto" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, {}) })
|
37186
|
+
] }),
|
37187
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
37188
|
+
DialogContent,
|
37189
|
+
{
|
37190
|
+
dividers: true,
|
37191
|
+
sx: {
|
37192
|
+
display: "flex",
|
37193
|
+
flexDirection: "column",
|
37194
|
+
flexGrow: 1,
|
37195
|
+
overflow: "hidden"
|
37196
|
+
},
|
37197
|
+
children: !isReplaced ? (
|
37198
|
+
// Step 1: Input new lyrics
|
37199
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 2, height: "100%" }, children: [
|
37200
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "h6", gutterBottom: true, children: "Paste your new lyrics below:" }),
|
37201
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", color: "text.secondary", gutterBottom: true, children: "Each line will become a separate segment. Words will be separated by spaces." }),
|
37202
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", gap: 2, mb: 2 }, children: [
|
37203
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
37204
|
+
Button,
|
37205
|
+
{
|
37206
|
+
variant: "outlined",
|
37207
|
+
onClick: handlePasteFromClipboard,
|
37208
|
+
startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(ContentPasteIcon, {}),
|
37209
|
+
size: "small",
|
37210
|
+
children: "Paste from Clipboard"
|
37211
|
+
}
|
37212
|
+
),
|
37213
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Typography, { variant: "body2", sx: {
|
37214
|
+
alignSelf: "center",
|
37215
|
+
color: "text.secondary",
|
37216
|
+
fontWeight: "medium"
|
37217
|
+
}, children: [
|
37218
|
+
parseInfo.lines,
|
37219
|
+
" lines, ",
|
37220
|
+
parseInfo.words,
|
37221
|
+
" words"
|
37222
|
+
] })
|
37223
|
+
] }),
|
37224
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
37225
|
+
TextField,
|
37226
|
+
{
|
37227
|
+
multiline: true,
|
37228
|
+
rows: 15,
|
37229
|
+
value: inputText,
|
37230
|
+
onChange: (e) => setInputText(e.target.value),
|
37231
|
+
placeholder: "Paste your lyrics here...\nEach line will become a segment\nWords will be separated by spaces",
|
37232
|
+
sx: {
|
37233
|
+
flexGrow: 1,
|
37234
|
+
"& .MuiInputBase-root": {
|
37235
|
+
height: "100%",
|
37236
|
+
alignItems: "flex-start"
|
37237
|
+
}
|
37238
|
+
}
|
37239
|
+
}
|
37240
|
+
),
|
37241
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { display: "flex", justifyContent: "flex-end", gap: 2 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
37242
|
+
Button,
|
37243
|
+
{
|
37244
|
+
variant: "contained",
|
37245
|
+
onClick: processLyrics,
|
37246
|
+
disabled: !inputText.trim(),
|
37247
|
+
startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(AutoFixHighIcon, {}),
|
37248
|
+
children: "Replace All Lyrics"
|
37249
|
+
}
|
37250
|
+
) })
|
37251
|
+
] })
|
37252
|
+
) : (
|
37253
|
+
// Step 2: Manual sync interface
|
37254
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", flexDirection: "column", height: "100%", gap: 2 }, children: [
|
37255
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Paper, { sx: { p: 2, bgcolor: "background.paper" }, children: [
|
37256
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "h6", gutterBottom: true, children: "Lyrics Replaced Successfully" }),
|
37257
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Typography, { variant: "body2", color: "text.secondary", children: [
|
37258
|
+
"Created ",
|
37259
|
+
currentSegments.length,
|
37260
|
+
" segments with ",
|
37261
|
+
globalSegment == null ? void 0 : globalSegment.words.length,
|
37262
|
+
" words total. Use Manual Sync to set timing for all words."
|
37263
|
+
] })
|
37264
|
+
] }),
|
37265
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Divider, {}),
|
37266
|
+
globalSegment && /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", gap: 2, flexGrow: 1, minHeight: 0 }, children: [
|
37267
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { flex: 2, display: "flex", flexDirection: "column", minHeight: 0 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
37268
|
+
EditTimelineSection,
|
37269
|
+
{
|
37270
|
+
words: globalSegment.words,
|
37271
|
+
startTime: timeRange.start,
|
37272
|
+
endTime: timeRange.end,
|
37273
|
+
originalStartTime: 0,
|
37274
|
+
originalEndTime: getAudioDuration(),
|
37275
|
+
currentStartTime: globalSegment.start_time,
|
37276
|
+
currentEndTime: globalSegment.end_time,
|
37277
|
+
currentTime,
|
37278
|
+
isManualSyncing,
|
37279
|
+
syncWordIndex,
|
37280
|
+
isSpacebarPressed,
|
37281
|
+
onWordUpdate: handleWordUpdate,
|
37282
|
+
onUnsyncWord: handleUnsyncWord,
|
37283
|
+
onPlaySegment,
|
37284
|
+
onStopAudio: () => {
|
37285
|
+
if (window.toggleAudioPlayback && window.isAudioPlaying) {
|
37286
|
+
window.toggleAudioPlayback();
|
37287
|
+
}
|
37288
|
+
},
|
37289
|
+
startManualSync,
|
37290
|
+
pauseManualSync,
|
37291
|
+
resumeManualSync,
|
37292
|
+
isPaused,
|
37293
|
+
isGlobal: true,
|
37294
|
+
defaultZoomLevel: 10,
|
37295
|
+
isReplaceAllMode: true
|
37296
|
+
}
|
37297
|
+
) }),
|
37298
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
37299
|
+
SegmentProgressPanel,
|
37300
|
+
{
|
37301
|
+
currentSegments: segmentProgressProps.currentSegments,
|
37302
|
+
globalSegment: segmentProgressProps.globalSegment,
|
37303
|
+
syncWordIndex: segmentProgressProps.syncWordIndex
|
37304
|
+
}
|
37305
|
+
)
|
37306
|
+
] })
|
37307
|
+
] })
|
37308
|
+
)
|
37309
|
+
}
|
37310
|
+
),
|
37311
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(DialogActions, { children: isReplaced && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
37312
|
+
EditActionBar,
|
37313
|
+
{
|
37314
|
+
onReset: handleReset,
|
37315
|
+
onClose: handleClose,
|
37316
|
+
onSave: handleSave,
|
37317
|
+
editedSegment: globalSegment,
|
37318
|
+
isGlobal: true
|
37319
|
+
}
|
37320
|
+
) })
|
37321
|
+
]
|
37322
|
+
}
|
37323
|
+
);
|
37324
|
+
}
|
37325
|
+
const SegmentProgressItem = reactExports.memo(({
|
37326
|
+
segment,
|
37327
|
+
index,
|
37328
|
+
isActive
|
37329
|
+
}) => {
|
37330
|
+
const wordsWithTiming = segment.words.filter(
|
37331
|
+
(w) => w.start_time !== null && w.end_time !== null
|
37332
|
+
).length;
|
37333
|
+
const totalWords = segment.words.length;
|
37334
|
+
const isComplete = wordsWithTiming === totalWords;
|
37335
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
37336
|
+
Paper,
|
37337
|
+
{
|
37338
|
+
ref: isActive ? (el) => {
|
37339
|
+
if (el) {
|
37340
|
+
el.scrollIntoView({
|
37341
|
+
behavior: "smooth",
|
37342
|
+
block: "center"
|
37343
|
+
});
|
37344
|
+
}
|
37345
|
+
} : void 0,
|
37346
|
+
sx: {
|
37347
|
+
p: 1,
|
37348
|
+
mb: 1,
|
37349
|
+
bgcolor: isActive ? "primary.light" : isComplete ? "success.light" : "background.paper",
|
37350
|
+
border: isActive ? 2 : 1,
|
37351
|
+
borderColor: isActive ? "primary.main" : "divider"
|
37352
|
+
},
|
37353
|
+
children: [
|
37354
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
37355
|
+
Typography,
|
37356
|
+
{
|
37357
|
+
variant: "body2",
|
37358
|
+
sx: {
|
37359
|
+
fontWeight: isActive ? "bold" : "normal",
|
37360
|
+
mb: 0.5
|
37361
|
+
},
|
37362
|
+
children: [
|
37363
|
+
"Segment ",
|
37364
|
+
index + 1,
|
37365
|
+
": ",
|
37366
|
+
segment.text.slice(0, 50),
|
37367
|
+
segment.text.length > 50 ? "..." : ""
|
37368
|
+
]
|
37369
|
+
}
|
37370
|
+
),
|
37371
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(Typography, { variant: "caption", color: "text.secondary", children: [
|
37372
|
+
wordsWithTiming,
|
37373
|
+
"/",
|
37374
|
+
totalWords,
|
37375
|
+
" words synced",
|
37376
|
+
isComplete && segment.start_time !== null && segment.end_time !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
37377
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
|
37378
|
+
segment.start_time.toFixed(2),
|
37379
|
+
"s - ",
|
37380
|
+
segment.end_time.toFixed(2),
|
37381
|
+
"s"
|
37382
|
+
] })
|
37383
|
+
] })
|
37384
|
+
]
|
37385
|
+
},
|
37386
|
+
segment.id
|
37387
|
+
);
|
37388
|
+
});
|
37389
|
+
const SegmentProgressPanel = reactExports.memo(({
|
37390
|
+
currentSegments,
|
37391
|
+
globalSegment,
|
37392
|
+
syncWordIndex
|
37393
|
+
}) => {
|
37394
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }, children: [
|
37395
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "h6", gutterBottom: true, children: "Segment Progress" }),
|
37396
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: {
|
37397
|
+
overflow: "auto",
|
37398
|
+
flexGrow: 1,
|
37399
|
+
border: 1,
|
37400
|
+
borderColor: "divider",
|
37401
|
+
borderRadius: 1,
|
37402
|
+
p: 1
|
37403
|
+
}, children: currentSegments.map((segment, index) => {
|
37404
|
+
const isActive = Boolean(
|
37405
|
+
globalSegment && syncWordIndex >= 0 && syncWordIndex < globalSegment.words.length && globalSegment.words[syncWordIndex] && segment.words.some((w) => w.id === globalSegment.words[syncWordIndex].id)
|
37406
|
+
);
|
37407
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
37408
|
+
SegmentProgressItem,
|
37409
|
+
{
|
37410
|
+
segment,
|
37411
|
+
index,
|
37412
|
+
isActive
|
37413
|
+
},
|
37414
|
+
segment.id
|
37415
|
+
);
|
37416
|
+
}) })
|
37417
|
+
] });
|
37418
|
+
});
|
36624
37419
|
const generateStorageKey = (data) => {
|
36625
37420
|
var _a;
|
36626
37421
|
const text = ((_a = data.original_segments[0]) == null ? void 0 : _a.text) || "";
|
@@ -36888,11 +37683,13 @@ function AudioPlayer({ apiClient, onTimeUpdate, audioHash }) {
|
|
36888
37683
|
const win = window;
|
36889
37684
|
win.seekAndPlayAudio = seekAndPlay;
|
36890
37685
|
win.toggleAudioPlayback = togglePlayback;
|
37686
|
+
win.getAudioDuration = () => duration2;
|
36891
37687
|
return () => {
|
36892
37688
|
delete win.seekAndPlayAudio;
|
36893
37689
|
delete win.toggleAudioPlayback;
|
37690
|
+
delete win.getAudioDuration;
|
36894
37691
|
};
|
36895
|
-
}, [apiClient, togglePlayback]);
|
37692
|
+
}, [apiClient, togglePlayback, duration2]);
|
36896
37693
|
if (!apiClient) return null;
|
36897
37694
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: {
|
36898
37695
|
display: "flex",
|
@@ -37873,11 +38670,7 @@ function LyricsAnalyzer({ data: initialData, onFileLoad, apiClient, isReadOnly,
|
|
37873
38670
|
const [isShiftPressed, setIsShiftPressed] = reactExports.useState(false);
|
37874
38671
|
const [isCtrlPressed, setIsCtrlPressed] = reactExports.useState(false);
|
37875
38672
|
const [editModalSegment, setEditModalSegment] = reactExports.useState(null);
|
37876
|
-
const [
|
37877
|
-
const [globalEditSegment, setGlobalEditSegment] = reactExports.useState(null);
|
37878
|
-
const [originalGlobalSegment, setOriginalGlobalSegment] = reactExports.useState(null);
|
37879
|
-
const [originalTranscribedGlobalSegment, setOriginalTranscribedGlobalSegment] = reactExports.useState(null);
|
37880
|
-
const [isLoadingGlobalEdit, setIsLoadingGlobalEdit] = reactExports.useState(false);
|
38673
|
+
const [isReplaceAllLyricsModalOpen, setIsReplaceAllLyricsModalOpen] = reactExports.useState(false);
|
37881
38674
|
const [isReviewModalOpen, setIsReviewModalOpen] = reactExports.useState(false);
|
37882
38675
|
const [currentAudioTime, setCurrentAudioTime] = reactExports.useState(0);
|
37883
38676
|
const [isUpdatingHandlers, setIsUpdatingHandlers] = reactExports.useState(false);
|
@@ -37938,10 +38731,10 @@ function LyricsAnalyzer({ data: initialData, onFileLoad, apiClient, isReadOnly,
|
|
37938
38731
|
}, [setIsShiftPressed, setIsCtrlPressed, isAnyModalOpen]);
|
37939
38732
|
reactExports.useEffect(() => {
|
37940
38733
|
const modalOpen = Boolean(
|
37941
|
-
modalContent || editModalSegment || isReviewModalOpen || isAddLyricsModalOpen || isFindReplaceModalOpen ||
|
38734
|
+
modalContent || editModalSegment || isReviewModalOpen || isAddLyricsModalOpen || isFindReplaceModalOpen || isReplaceAllLyricsModalOpen || isTimingOffsetModalOpen
|
37942
38735
|
);
|
37943
38736
|
setIsAnyModalOpen(modalOpen);
|
37944
|
-
}, [modalContent, editModalSegment, isReviewModalOpen, isAddLyricsModalOpen, isFindReplaceModalOpen,
|
38737
|
+
}, [modalContent, editModalSegment, isReviewModalOpen, isAddLyricsModalOpen, isFindReplaceModalOpen, isReplaceAllLyricsModalOpen, isTimingOffsetModalOpen]);
|
37945
38738
|
const effectiveMode = isCtrlPressed ? "delete_word" : isShiftPressed ? "highlight" : interactionMode;
|
37946
38739
|
const handleFlash = reactExports.useCallback((type, info) => {
|
37947
38740
|
setFlashingType(null);
|
@@ -38201,144 +38994,21 @@ function LyricsAnalyzer({ data: initialData, onFileLoad, apiClient, isReadOnly,
|
|
38201
38994
|
const newData = findAndReplace(data, findText, replaceText, options);
|
38202
38995
|
updateDataWithHistory(newData, "find/replace");
|
38203
38996
|
};
|
38204
|
-
const
|
38205
|
-
console.log("
|
38206
|
-
|
38207
|
-
|
38208
|
-
|
38209
|
-
|
38210
|
-
|
38211
|
-
|
38212
|
-
};
|
38213
|
-
setGlobalEditSegment(placeholderSegment);
|
38214
|
-
setOriginalGlobalSegment(placeholderSegment);
|
38215
|
-
setIsLoadingGlobalEdit(true);
|
38216
|
-
console.log("EditAll - Set loading state to true");
|
38217
|
-
setIsEditAllModalOpen(true);
|
38218
|
-
console.log("EditAll - Set modal open to true");
|
38219
|
-
requestAnimationFrame(() => {
|
38220
|
-
console.log("EditAll - Inside requestAnimationFrame");
|
38221
|
-
setTimeout(() => {
|
38222
|
-
var _a, _b, _c, _d;
|
38223
|
-
console.log("EditAll - Inside setTimeout, starting data processing");
|
38224
|
-
try {
|
38225
|
-
console.time("EditAll - Data processing");
|
38226
|
-
const allWords = data.corrected_segments.flatMap((segment) => segment.words);
|
38227
|
-
console.log(`EditAll - Collected ${allWords.length} words from all segments`);
|
38228
|
-
const sortedWords = [...allWords].sort((a, b) => {
|
38229
|
-
const aTime = a.start_time ?? 0;
|
38230
|
-
const bTime = b.start_time ?? 0;
|
38231
|
-
return aTime - bTime;
|
38232
|
-
});
|
38233
|
-
console.log("EditAll - Sorted words by start time");
|
38234
|
-
const globalSegment = {
|
38235
|
-
id: "global-edit",
|
38236
|
-
words: sortedWords,
|
38237
|
-
text: sortedWords.map((w) => w.text).join(" "),
|
38238
|
-
start_time: ((_a = sortedWords[0]) == null ? void 0 : _a.start_time) ?? null,
|
38239
|
-
end_time: ((_b = sortedWords[sortedWords.length - 1]) == null ? void 0 : _b.end_time) ?? null
|
38240
|
-
};
|
38241
|
-
console.log("EditAll - Created global segment");
|
38242
|
-
setGlobalEditSegment(globalSegment);
|
38243
|
-
console.log("EditAll - Set global edit segment");
|
38244
|
-
setOriginalGlobalSegment(JSON.parse(JSON.stringify(globalSegment)));
|
38245
|
-
console.log("EditAll - Set original global segment");
|
38246
|
-
if (originalData.original_segments) {
|
38247
|
-
console.log("EditAll - Processing original segments for Un-Correct functionality");
|
38248
|
-
const originalWords = originalData.original_segments.flatMap((segment) => segment.words);
|
38249
|
-
console.log(`EditAll - Collected ${originalWords.length} words from original segments`);
|
38250
|
-
const sortedOriginalWords = [...originalWords].sort((a, b) => {
|
38251
|
-
const aTime = a.start_time ?? 0;
|
38252
|
-
const bTime = b.start_time ?? 0;
|
38253
|
-
return aTime - bTime;
|
38254
|
-
});
|
38255
|
-
console.log("EditAll - Sorted original words by start time");
|
38256
|
-
const originalTranscribedGlobal = {
|
38257
|
-
id: "original-transcribed-global",
|
38258
|
-
words: sortedOriginalWords,
|
38259
|
-
text: sortedOriginalWords.map((w) => w.text).join(" "),
|
38260
|
-
start_time: ((_c = sortedOriginalWords[0]) == null ? void 0 : _c.start_time) ?? null,
|
38261
|
-
end_time: ((_d = sortedOriginalWords[sortedOriginalWords.length - 1]) == null ? void 0 : _d.end_time) ?? null
|
38262
|
-
};
|
38263
|
-
console.log("EditAll - Created original transcribed global segment");
|
38264
|
-
setOriginalTranscribedGlobalSegment(originalTranscribedGlobal);
|
38265
|
-
console.log("EditAll - Set original transcribed global segment");
|
38266
|
-
} else {
|
38267
|
-
setOriginalTranscribedGlobalSegment(null);
|
38268
|
-
console.log("EditAll - No original segments found, set original transcribed global segment to null");
|
38269
|
-
}
|
38270
|
-
console.timeEnd("EditAll - Data processing");
|
38271
|
-
} catch (error) {
|
38272
|
-
console.error("Error preparing global edit data:", error);
|
38273
|
-
} finally {
|
38274
|
-
console.log("EditAll - Finished processing, setting loading state to false");
|
38275
|
-
setIsLoadingGlobalEdit(false);
|
38276
|
-
}
|
38277
|
-
}, 100);
|
38278
|
-
});
|
38279
|
-
}, [data.corrected_segments, originalData.original_segments]);
|
38280
|
-
const handleSaveGlobalEdit = reactExports.useCallback((updatedSegment) => {
|
38281
|
-
var _a;
|
38282
|
-
console.log("Global Edit - Saving with new approach:", {
|
38283
|
-
updatedSegmentId: updatedSegment.id,
|
38284
|
-
wordCount: updatedSegment.words.length,
|
38285
|
-
originalSegmentCount: data.corrected_segments.length,
|
38286
|
-
originalTotalWordCount: data.corrected_segments.reduce((count, segment) => count + segment.words.length, 0)
|
38287
|
-
});
|
38288
|
-
const updatedWords = updatedSegment.words;
|
38289
|
-
const updatedSegments = [];
|
38290
|
-
let wordIndex = 0;
|
38291
|
-
for (const segment of data.corrected_segments) {
|
38292
|
-
const originalWordCount = segment.words.length;
|
38293
|
-
const segmentWords = [];
|
38294
|
-
const endIndex = Math.min(wordIndex + originalWordCount, updatedWords.length);
|
38295
|
-
for (let i = wordIndex; i < endIndex; i++) {
|
38296
|
-
segmentWords.push(updatedWords[i]);
|
38297
|
-
}
|
38298
|
-
wordIndex = endIndex;
|
38299
|
-
if (segmentWords.length > 0) {
|
38300
|
-
const validStartTimes = segmentWords.map((w) => w.start_time).filter((t) => t !== null);
|
38301
|
-
const validEndTimes = segmentWords.map((w) => w.end_time).filter((t) => t !== null);
|
38302
|
-
const segmentStartTime = validStartTimes.length > 0 ? Math.min(...validStartTimes) : null;
|
38303
|
-
const segmentEndTime = validEndTimes.length > 0 ? Math.max(...validEndTimes) : null;
|
38304
|
-
updatedSegments.push({
|
38305
|
-
...segment,
|
38306
|
-
words: segmentWords,
|
38307
|
-
text: segmentWords.map((w) => w.text).join(" "),
|
38308
|
-
start_time: segmentStartTime,
|
38309
|
-
end_time: segmentEndTime
|
38310
|
-
});
|
38311
|
-
}
|
38312
|
-
}
|
38313
|
-
if (wordIndex < updatedWords.length) {
|
38314
|
-
const remainingWords = updatedWords.slice(wordIndex);
|
38315
|
-
const lastSegment = updatedSegments[updatedSegments.length - 1];
|
38316
|
-
const combinedWords = [...lastSegment.words, ...remainingWords];
|
38317
|
-
const validStartTimes = combinedWords.map((w) => w.start_time).filter((t) => t !== null);
|
38318
|
-
const validEndTimes = combinedWords.map((w) => w.end_time).filter((t) => t !== null);
|
38319
|
-
const segmentStartTime = validStartTimes.length > 0 ? Math.min(...validStartTimes) : null;
|
38320
|
-
const segmentEndTime = validEndTimes.length > 0 ? Math.max(...validEndTimes) : null;
|
38321
|
-
updatedSegments[updatedSegments.length - 1] = {
|
38322
|
-
...lastSegment,
|
38323
|
-
words: combinedWords,
|
38324
|
-
text: combinedWords.map((w) => w.text).join(" "),
|
38325
|
-
start_time: segmentStartTime,
|
38326
|
-
end_time: segmentEndTime
|
38327
|
-
};
|
38328
|
-
}
|
38329
|
-
console.log("Global Edit - Updated Segments with new approach:", {
|
38330
|
-
segmentCount: updatedSegments.length,
|
38331
|
-
firstSegmentWordCount: (_a = updatedSegments[0]) == null ? void 0 : _a.words.length,
|
38332
|
-
totalWordCount: updatedSegments.reduce((count, segment) => count + segment.words.length, 0),
|
38333
|
-
originalTotalWordCount: data.corrected_segments.reduce((count, segment) => count + segment.words.length, 0)
|
38997
|
+
const handleReplaceAllLyrics = reactExports.useCallback(() => {
|
38998
|
+
console.log("ReplaceAllLyrics - Opening modal");
|
38999
|
+
setIsReplaceAllLyricsModalOpen(true);
|
39000
|
+
}, []);
|
39001
|
+
const handleSaveReplaceAllLyrics = reactExports.useCallback((newSegments) => {
|
39002
|
+
console.log("ReplaceAllLyrics - Saving new segments:", {
|
39003
|
+
segmentCount: newSegments.length,
|
39004
|
+
totalWords: newSegments.reduce((count, segment) => count + segment.words.length, 0)
|
38334
39005
|
});
|
38335
39006
|
const newData = {
|
38336
39007
|
...data,
|
38337
|
-
corrected_segments:
|
39008
|
+
corrected_segments: newSegments
|
38338
39009
|
};
|
38339
|
-
updateDataWithHistory(newData, "
|
38340
|
-
|
38341
|
-
setGlobalEditSegment(null);
|
39010
|
+
updateDataWithHistory(newData, "replace all lyrics");
|
39011
|
+
setIsReplaceAllLyricsModalOpen(false);
|
38342
39012
|
}, [data, updateDataWithHistory]);
|
38343
39013
|
const handleUndo = reactExports.useCallback(() => {
|
38344
39014
|
if (historyIndex > 0) {
|
@@ -38399,7 +39069,7 @@ function LyricsAnalyzer({ data: initialData, onFileLoad, apiClient, isReadOnly,
|
|
38399
39069
|
isUpdatingHandlers,
|
38400
39070
|
onHandlerClick: handleHandlerClick,
|
38401
39071
|
onFindReplace: () => setIsFindReplaceModalOpen(true),
|
38402
|
-
onEditAll:
|
39072
|
+
onEditAll: handleReplaceAllLyrics,
|
38403
39073
|
onTimingOffset: handleOpenTimingOffsetModal,
|
38404
39074
|
timingOffsetMs,
|
38405
39075
|
onUndo: handleUndo,
|
@@ -38477,29 +39147,6 @@ function LyricsAnalyzer({ data: initialData, onFileLoad, apiClient, isReadOnly,
|
|
38477
39147
|
}
|
38478
39148
|
) })
|
38479
39149
|
] }),
|
38480
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
38481
|
-
EditModal,
|
38482
|
-
{
|
38483
|
-
open: isEditAllModalOpen,
|
38484
|
-
onClose: () => {
|
38485
|
-
setIsEditAllModalOpen(false);
|
38486
|
-
setGlobalEditSegment(null);
|
38487
|
-
setOriginalGlobalSegment(null);
|
38488
|
-
setOriginalTranscribedGlobalSegment(null);
|
38489
|
-
handleSetModalSpacebarHandler(void 0);
|
38490
|
-
},
|
38491
|
-
segment: globalEditSegment ? timingOffsetMs !== 0 ? applyOffsetToSegment(globalEditSegment, timingOffsetMs) : globalEditSegment : null,
|
38492
|
-
segmentIndex: null,
|
38493
|
-
originalSegment: originalGlobalSegment ? timingOffsetMs !== 0 ? applyOffsetToSegment(originalGlobalSegment, timingOffsetMs) : originalGlobalSegment : null,
|
38494
|
-
onSave: handleSaveGlobalEdit,
|
38495
|
-
onPlaySegment: handlePlaySegment,
|
38496
|
-
currentTime: currentAudioTime,
|
38497
|
-
setModalSpacebarHandler: handleSetModalSpacebarHandler,
|
38498
|
-
originalTranscribedSegment: originalTranscribedGlobalSegment ? timingOffsetMs !== 0 ? applyOffsetToSegment(originalTranscribedGlobalSegment, timingOffsetMs) : originalTranscribedGlobalSegment : null,
|
38499
|
-
isGlobal: true,
|
38500
|
-
isLoading: isLoadingGlobalEdit
|
38501
|
-
}
|
38502
|
-
),
|
38503
39150
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
38504
39151
|
EditModal,
|
38505
39152
|
{
|
@@ -38566,6 +39213,17 @@ function LyricsAnalyzer({ data: initialData, onFileLoad, apiClient, isReadOnly,
|
|
38566
39213
|
currentOffset: timingOffsetMs,
|
38567
39214
|
onApply: handleApplyTimingOffset
|
38568
39215
|
}
|
39216
|
+
),
|
39217
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
39218
|
+
ReplaceAllLyricsModal,
|
39219
|
+
{
|
39220
|
+
open: isReplaceAllLyricsModalOpen,
|
39221
|
+
onClose: () => setIsReplaceAllLyricsModalOpen(false),
|
39222
|
+
onSave: handleSaveReplaceAllLyrics,
|
39223
|
+
onPlaySegment: handlePlaySegment,
|
39224
|
+
currentTime: currentAudioTime,
|
39225
|
+
setModalSpacebarHandler: handleSetModalSpacebarHandler
|
39226
|
+
}
|
38569
39227
|
)
|
38570
39228
|
] });
|
38571
39229
|
}
|
@@ -38915,7 +39573,7 @@ const theme = createTheme({
|
|
38915
39573
|
spacing: (factor) => `${0.6 * factor}rem`
|
38916
39574
|
// Further reduced from 0.8 * factor
|
38917
39575
|
});
|
38918
|
-
const version = "0.
|
39576
|
+
const version = "0.69.0";
|
38919
39577
|
const packageJson = {
|
38920
39578
|
version
|
38921
39579
|
};
|
@@ -38926,4 +39584,4 @@ ReactDOM$1.createRoot(document.getElementById("root")).render(
|
|
38926
39584
|
/* @__PURE__ */ jsxRuntimeExports.jsx(App, {})
|
38927
39585
|
] })
|
38928
39586
|
);
|
38929
|
-
//# sourceMappingURL=index-
|
39587
|
+
//# sourceMappingURL=index-izP9z1oB.js.map
|