@bendyline/squisq 2.11.5 → 2.11.7
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.
- package/dist/{chunk-AIB5WEK2.js → chunk-3YNFMFNK.js} +30 -345
- package/dist/chunk-44BJ42GT.js +165 -0
- package/dist/chunk-EF353KGH.js +332 -0
- package/dist/{chunk-67L6WRJN.js → chunk-GHOPHGOK.js} +28 -1
- package/dist/{chunk-ZSU5DJLX.js → chunk-IYZTF4VO.js} +318 -6
- package/dist/{chunk-2P44EZLI.js → chunk-SKKBRLLM.js} +4 -2
- package/dist/{chunk-NUS5YAI5.js → chunk-SOIV7KDO.js} +13 -12
- package/dist/{chunk-NKNMGIIN.js → chunk-SVN7T6BK.js} +0 -3
- package/dist/{chunk-DQRELU4S.js → chunk-VU4T74LI.js} +1 -1
- package/dist/{chunk-RXYKU6EX.js → chunk-Y4D6TDZT.js} +212 -3
- package/dist/{chunk-XV4SF2N5.js → chunk-YGGYYBJS.js} +3 -2
- package/dist/chunk-ZP5F7LUH.js +223 -0
- package/dist/doc/index.js +8 -10
- package/dist/generate/index.d.ts +61 -1
- package/dist/generate/index.js +14 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +56 -38
- package/dist/jsonForm/index.js +3 -4
- package/dist/narration/index.js +5 -6
- package/dist/schemas/index.js +17 -19
- package/dist/timing/index.d.ts +29 -1
- package/dist/timing/index.js +6 -4
- package/dist/transform/index.d.ts +97 -2
- package/dist/transform/index.js +17 -6
- package/package.json +1 -1
- package/dist/chunk-BAOV476U.js +0 -214
- package/dist/chunk-XOFT65EX.js +0 -34
|
@@ -2,18 +2,24 @@ import {
|
|
|
2
2
|
extractContent,
|
|
3
3
|
mapElementToBlock,
|
|
4
4
|
stripMarkdown
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SVN7T6BK.js";
|
|
6
|
+
import {
|
|
7
|
+
markdownToDoc
|
|
8
|
+
} from "./chunk-3YNFMFNK.js";
|
|
6
9
|
import {
|
|
7
10
|
cloneAndFreezeData,
|
|
8
11
|
isTemplateBlock
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Y4D6TDZT.js";
|
|
13
|
+
import {
|
|
14
|
+
parseMarkdown
|
|
15
|
+
} from "./chunk-CW24CH7I.js";
|
|
10
16
|
import {
|
|
11
17
|
extractPlainText,
|
|
12
18
|
getChildren
|
|
13
19
|
} from "./chunk-X7BNDUNI.js";
|
|
14
20
|
import {
|
|
15
21
|
estimateTimeFromText
|
|
16
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-GHOPHGOK.js";
|
|
17
23
|
import {
|
|
18
24
|
SeededRandom,
|
|
19
25
|
hashString
|
|
@@ -506,7 +512,7 @@ function buildBlockSequence(analyzed, selected, config, images, rng) {
|
|
|
506
512
|
elementsSinceImage++;
|
|
507
513
|
if (config.interleaveImages && imageIndex < images.length && elementsSinceImage >= imageInterval) {
|
|
508
514
|
const img = images[imageIndex];
|
|
509
|
-
const
|
|
515
|
+
const imageBlock2 = {
|
|
510
516
|
template: "imageWithCaption",
|
|
511
517
|
id: `transform-img-${blockIdCounter++}`,
|
|
512
518
|
duration: 4,
|
|
@@ -516,7 +522,7 @@ function buildBlockSequence(analyzed, selected, config, images, rng) {
|
|
|
516
522
|
ambientMotion: rng.pick(AMBIENT_MOTIONS) ?? "zoomIn",
|
|
517
523
|
sourceBlockId: ab.block.id
|
|
518
524
|
};
|
|
519
|
-
blocks.push(
|
|
525
|
+
blocks.push(imageBlock2);
|
|
520
526
|
imageIndex++;
|
|
521
527
|
insertedCount++;
|
|
522
528
|
elementsSinceImage = 0;
|
|
@@ -839,6 +845,310 @@ function firstTitle(doc) {
|
|
|
839
845
|
return void 0;
|
|
840
846
|
}
|
|
841
847
|
|
|
848
|
+
// src/transform/narratedSegment.ts
|
|
849
|
+
var DEFAULT_SLIDES_PER_MINUTE = 5;
|
|
850
|
+
var DEFAULT_MAX_SLIDE_DURATION = 15;
|
|
851
|
+
var DEFAULT_MIN_SLIDE_DURATION = 6;
|
|
852
|
+
var DEFAULT_MAX_VIDEOS = 2;
|
|
853
|
+
var AMBIENT_MOTIONS2 = [
|
|
854
|
+
"zoomIn",
|
|
855
|
+
"zoomOut",
|
|
856
|
+
"panLeft",
|
|
857
|
+
"panRight"
|
|
858
|
+
];
|
|
859
|
+
function transformNarratedSegment(input, options = {}) {
|
|
860
|
+
const seed = options.seed ?? hashString(`${input.articleId}-${input.segmentId}`);
|
|
861
|
+
const heading = input.title.replace(/[\r\n]+/g, " ").trim() || input.segmentId;
|
|
862
|
+
const pacing = {
|
|
863
|
+
slidesPerMinute: options.slidesPerMinute ?? DEFAULT_SLIDES_PER_MINUTE,
|
|
864
|
+
maxSlideDuration: options.maxSlideDuration ?? DEFAULT_MAX_SLIDE_DURATION,
|
|
865
|
+
minSlideDuration: options.minSlideDuration ?? DEFAULT_MIN_SLIDE_DURATION,
|
|
866
|
+
maxVideos: options.maxVideos ?? DEFAULT_MAX_VIDEOS
|
|
867
|
+
};
|
|
868
|
+
const images = uniqueImages(input.images ?? []);
|
|
869
|
+
const videos = input.videos ?? [];
|
|
870
|
+
const contentTarget = contentSlotCount(
|
|
871
|
+
input.duration,
|
|
872
|
+
pacing,
|
|
873
|
+
images.length + Math.min(videos.length, pacing.maxVideos),
|
|
874
|
+
!!input.includeTitleBlock
|
|
875
|
+
);
|
|
876
|
+
const markdown = chunkNarration(input.text, contentTarget).map((chunk) => `# ${heading}
|
|
877
|
+
|
|
878
|
+
${chunk}`).join("\n\n");
|
|
879
|
+
const source = markdownToDoc(parseMarkdown(markdown), {
|
|
880
|
+
articleId: `${input.articleId}:${input.segmentId}`,
|
|
881
|
+
defaultDuration: Math.max(3, input.duration)
|
|
882
|
+
});
|
|
883
|
+
const sourceDoc = {
|
|
884
|
+
...source,
|
|
885
|
+
articleId: input.articleId,
|
|
886
|
+
duration: input.duration,
|
|
887
|
+
audio: {
|
|
888
|
+
segments: [
|
|
889
|
+
{
|
|
890
|
+
src: input.audioSrc,
|
|
891
|
+
name: input.audioName ?? input.segmentId,
|
|
892
|
+
duration: input.duration,
|
|
893
|
+
startTime: 0
|
|
894
|
+
}
|
|
895
|
+
]
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
const transformed = applyTransform(sourceDoc, options.style ?? "documentary", {
|
|
899
|
+
seed,
|
|
900
|
+
images: input.images,
|
|
901
|
+
themeId: options.themeId,
|
|
902
|
+
registry: options.registry,
|
|
903
|
+
overrides: {
|
|
904
|
+
// The style's transformRatio is a share of source blocks, and a
|
|
905
|
+
// narrated segment is one block — so it would always cap promotion at
|
|
906
|
+
// a single extraction. Size the cap by content slots instead; the
|
|
907
|
+
// slides-per-minute budget and blocksPerSection still apply.
|
|
908
|
+
transformRatio: (contentTarget + 0.5) / Math.max(1, source.blocks.length),
|
|
909
|
+
...options.minConfidence === void 0 ? {} : { minConfidence: options.minConfidence },
|
|
910
|
+
...options.slidesPerMinute === void 0 ? {} : { budget: { slidesPerMinute: options.slidesPerMinute } }
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
const title = input.includeTitleBlock ? {
|
|
914
|
+
template: "title",
|
|
915
|
+
id: `${input.segmentId}-title`,
|
|
916
|
+
duration: 4,
|
|
917
|
+
audioSegment: 0,
|
|
918
|
+
title: input.title
|
|
919
|
+
} : void 0;
|
|
920
|
+
const transformedBlocks = transformed.doc.blocks;
|
|
921
|
+
const sourceIds = new Set(source.blocks.map((block) => block.id));
|
|
922
|
+
const promoted = transformedBlocks.filter((block) => !sourceIds.has(block.id));
|
|
923
|
+
const kept = promoted.length > 0 ? promoted : transformedBlocks.slice(0, 1);
|
|
924
|
+
const content = kept.map((block) => ({
|
|
925
|
+
...block,
|
|
926
|
+
id: namespacedId(block.id, input.segmentId)
|
|
927
|
+
}));
|
|
928
|
+
const paced = paceSegment({
|
|
929
|
+
segmentId: input.segmentId,
|
|
930
|
+
duration: input.duration,
|
|
931
|
+
title,
|
|
932
|
+
content,
|
|
933
|
+
videos,
|
|
934
|
+
images,
|
|
935
|
+
pacing,
|
|
936
|
+
rng: new SeededRandom(seed ^ 1540483477)
|
|
937
|
+
});
|
|
938
|
+
const timedBlocks = allocateTiming(paced, input.duration).map((block) => ({
|
|
939
|
+
...block,
|
|
940
|
+
audioSegment: 0
|
|
941
|
+
}));
|
|
942
|
+
return {
|
|
943
|
+
...transformed,
|
|
944
|
+
seed,
|
|
945
|
+
doc: {
|
|
946
|
+
...transformed.doc,
|
|
947
|
+
articleId: input.articleId,
|
|
948
|
+
duration: input.duration,
|
|
949
|
+
audio: sourceDoc.audio,
|
|
950
|
+
blocks: timedBlocks
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
function paceTarget(duration, pacing) {
|
|
955
|
+
return Math.max(
|
|
956
|
+
1,
|
|
957
|
+
Math.round(duration / 60 * pacing.slidesPerMinute),
|
|
958
|
+
Math.ceil(duration / pacing.maxSlideDuration)
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
function contentSlotCount(duration, pacing, visualCount, hasTitle) {
|
|
962
|
+
const target = paceTarget(duration, pacing);
|
|
963
|
+
const share = visualCount >= 3 ? 0.2 : 0.4;
|
|
964
|
+
return Math.max(1, Math.round(target * share), target - (hasTitle ? 1 : 0) - visualCount);
|
|
965
|
+
}
|
|
966
|
+
function paceSegment(args) {
|
|
967
|
+
const { segmentId, duration, title, content, pacing, rng } = args;
|
|
968
|
+
const fixedCount = (title ? 1 : 0) + content.length;
|
|
969
|
+
const maxCount = Math.max(1, Math.floor(duration / pacing.minSlideDuration));
|
|
970
|
+
const target = paceTarget(duration, pacing);
|
|
971
|
+
const videoCount = args.videos.length === 0 ? 0 : Math.min(
|
|
972
|
+
args.videos.length,
|
|
973
|
+
pacing.maxVideos,
|
|
974
|
+
Math.max(1, Math.floor(target * 0.3)),
|
|
975
|
+
Math.max(0, maxCount - fixedCount)
|
|
976
|
+
);
|
|
977
|
+
const videos = pickVideos(args.videos, videoCount);
|
|
978
|
+
const pool = standaloneImagePool(args.images, content);
|
|
979
|
+
let count = Math.max(target, fixedCount + videos.length);
|
|
980
|
+
let imageCount = 0;
|
|
981
|
+
for (; ; ) {
|
|
982
|
+
imageCount = Math.min(pool.length, Math.max(0, count - fixedCount - videos.length));
|
|
983
|
+
const longest = longestFittedSlide(duration, count, title, content, videos, imageCount, pacing);
|
|
984
|
+
if (longest <= pacing.maxSlideDuration || imageCount >= pool.length || count >= maxCount) {
|
|
985
|
+
break;
|
|
986
|
+
}
|
|
987
|
+
count++;
|
|
988
|
+
}
|
|
989
|
+
const slot = duration / Math.max(1, count);
|
|
990
|
+
const items = [];
|
|
991
|
+
if (title) {
|
|
992
|
+
items.push({
|
|
993
|
+
block: { ...title, duration: Math.min(slot, pacing.minSlideDuration) },
|
|
994
|
+
at: -1,
|
|
995
|
+
rank: 0
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
content.forEach((block, index) => {
|
|
999
|
+
const anchor = typeof block.sourceStartTime === "number" ? block.sourceStartTime : (index + 0.5) / content.length * duration;
|
|
1000
|
+
items.push({ block: { ...unanchored(block), duration: slot }, at: anchor, rank: 1 });
|
|
1001
|
+
});
|
|
1002
|
+
videos.forEach((video, index) => {
|
|
1003
|
+
items.push({
|
|
1004
|
+
block: videoBlock(video, index, segmentId, videoNominal(video, slot, pacing)),
|
|
1005
|
+
at: videoPosition(index, videos.length) * duration,
|
|
1006
|
+
rank: 2
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
for (let index = 0; index < imageCount; index++) {
|
|
1010
|
+
items.push({
|
|
1011
|
+
block: imageBlock(pool[index], index, segmentId, slot, rng),
|
|
1012
|
+
at: (index + 0.5) / imageCount * duration,
|
|
1013
|
+
rank: 3
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
return items.map((item, order) => ({ ...item, order })).sort((a, b) => a.at - b.at || a.rank - b.rank || a.order - b.order).map((item) => item.block);
|
|
1017
|
+
}
|
|
1018
|
+
function longestFittedSlide(duration, count, title, content, videos, imageCount, pacing) {
|
|
1019
|
+
const slot = duration / Math.max(1, count);
|
|
1020
|
+
const nominal = [
|
|
1021
|
+
...title ? [Math.min(slot, pacing.minSlideDuration)] : [],
|
|
1022
|
+
...content.map(() => slot),
|
|
1023
|
+
...videos.map((video) => videoNominal(video, slot, pacing)),
|
|
1024
|
+
...Array.from({ length: imageCount }, () => slot)
|
|
1025
|
+
];
|
|
1026
|
+
const total = nominal.reduce((sum, d) => sum + d, 0);
|
|
1027
|
+
return total > 0 ? Math.max(...nominal) * (duration / total) : duration;
|
|
1028
|
+
}
|
|
1029
|
+
function videoNominal(video, slot, pacing) {
|
|
1030
|
+
return Math.min(slot, Math.max(pacing.minSlideDuration, video.clipEnd - video.clipStart));
|
|
1031
|
+
}
|
|
1032
|
+
function videoPosition(index, count) {
|
|
1033
|
+
if (count === 1) return 0.4;
|
|
1034
|
+
if (count === 2) return index === 0 ? 0.3 : 0.7;
|
|
1035
|
+
return (index + 1) / (count + 1);
|
|
1036
|
+
}
|
|
1037
|
+
function pickVideos(videos, count) {
|
|
1038
|
+
const picked = [];
|
|
1039
|
+
const seenSources = /* @__PURE__ */ new Set();
|
|
1040
|
+
for (const video of videos) {
|
|
1041
|
+
if (picked.length >= count) break;
|
|
1042
|
+
if (seenSources.has(video.src)) continue;
|
|
1043
|
+
seenSources.add(video.src);
|
|
1044
|
+
picked.push(video);
|
|
1045
|
+
}
|
|
1046
|
+
for (const video of videos) {
|
|
1047
|
+
if (picked.length >= count) break;
|
|
1048
|
+
if (!picked.includes(video)) picked.push(video);
|
|
1049
|
+
}
|
|
1050
|
+
return picked;
|
|
1051
|
+
}
|
|
1052
|
+
function standaloneImagePool(images, content) {
|
|
1053
|
+
const shown = /* @__PURE__ */ new Set();
|
|
1054
|
+
const accents = /* @__PURE__ */ new Set();
|
|
1055
|
+
for (const block of content) {
|
|
1056
|
+
const media = block;
|
|
1057
|
+
if (block.template === "imageWithCaption" && media.imageSrc) shown.add(media.imageSrc);
|
|
1058
|
+
if (media.accentImage?.src) accents.add(media.accentImage.src);
|
|
1059
|
+
if (media.backgroundImage?.src) accents.add(media.backgroundImage.src);
|
|
1060
|
+
}
|
|
1061
|
+
const available = images.filter((image) => !shown.has(image.src));
|
|
1062
|
+
return [
|
|
1063
|
+
...available.filter((image) => !accents.has(image.src)),
|
|
1064
|
+
...available.filter((image) => accents.has(image.src))
|
|
1065
|
+
];
|
|
1066
|
+
}
|
|
1067
|
+
function chunkNarration(text, count) {
|
|
1068
|
+
if (count <= 1) return [text];
|
|
1069
|
+
const sentences = [];
|
|
1070
|
+
const boundary = /[.!?]["'’”)\]]*\s+/g;
|
|
1071
|
+
let start = 0;
|
|
1072
|
+
let match;
|
|
1073
|
+
while ((match = boundary.exec(text)) !== null) {
|
|
1074
|
+
const end = match.index + match[0].length;
|
|
1075
|
+
const sentence = text.slice(start, end).trim();
|
|
1076
|
+
if (sentence) sentences.push(sentence);
|
|
1077
|
+
start = end;
|
|
1078
|
+
}
|
|
1079
|
+
const tail = text.slice(start).trim();
|
|
1080
|
+
if (tail) sentences.push(tail);
|
|
1081
|
+
if (sentences.length < 2) return [text];
|
|
1082
|
+
const chunkCount = Math.min(count, sentences.length);
|
|
1083
|
+
const words = sentences.map((sentence) => sentence.split(/\s+/).length);
|
|
1084
|
+
const totalWords = words.reduce((sum, n) => sum + n, 0);
|
|
1085
|
+
const chunks = [];
|
|
1086
|
+
let current = [];
|
|
1087
|
+
let seenWords = 0;
|
|
1088
|
+
sentences.forEach((sentence, index) => {
|
|
1089
|
+
current.push(sentence);
|
|
1090
|
+
seenWords += words[index];
|
|
1091
|
+
const due = totalWords * (chunks.length + 1) / chunkCount;
|
|
1092
|
+
if (seenWords >= due && chunks.length < chunkCount - 1) {
|
|
1093
|
+
chunks.push(current);
|
|
1094
|
+
current = [];
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
1097
|
+
if (current.length > 0) chunks.push(current);
|
|
1098
|
+
return chunks.map((chunk) => chunk.join(" "));
|
|
1099
|
+
}
|
|
1100
|
+
function uniqueImages(images) {
|
|
1101
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1102
|
+
return images.filter((image) => {
|
|
1103
|
+
if (!image.src || seen.has(image.src)) return false;
|
|
1104
|
+
seen.add(image.src);
|
|
1105
|
+
return true;
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
function namespacedId(id, segmentId) {
|
|
1109
|
+
return id.startsWith(`${segmentId}-`) ? id : `${segmentId}-${id}`;
|
|
1110
|
+
}
|
|
1111
|
+
function unanchored(block) {
|
|
1112
|
+
const { sourceStartTime: _start, sourceDuration: _duration, ...rest } = block;
|
|
1113
|
+
return rest;
|
|
1114
|
+
}
|
|
1115
|
+
function imageBlock(image, index, segmentId, duration, rng) {
|
|
1116
|
+
const caption = image.alt && !/\.(jpe?g|png|gif|svg|webp)/i.test(image.alt) ? image.alt : "";
|
|
1117
|
+
return {
|
|
1118
|
+
template: "imageWithCaption",
|
|
1119
|
+
id: `${segmentId}-image-${index}`,
|
|
1120
|
+
duration,
|
|
1121
|
+
audioSegment: 0,
|
|
1122
|
+
imageSrc: image.src,
|
|
1123
|
+
imageAlt: image.alt ?? "",
|
|
1124
|
+
caption,
|
|
1125
|
+
captionPosition: "bottom",
|
|
1126
|
+
ambientMotion: rng.pick(AMBIENT_MOTIONS2) ?? "zoomIn",
|
|
1127
|
+
imageCredit: image.credit,
|
|
1128
|
+
imageLicense: image.license
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
function videoBlock(video, index, segmentId, duration) {
|
|
1132
|
+
return {
|
|
1133
|
+
template: "videoWithCaption",
|
|
1134
|
+
id: `${segmentId}-video-${index}`,
|
|
1135
|
+
duration,
|
|
1136
|
+
audioSegment: 0,
|
|
1137
|
+
videoSrc: video.src,
|
|
1138
|
+
posterSrc: video.posterSrc,
|
|
1139
|
+
videoAlt: video.alt ?? "",
|
|
1140
|
+
clipStart: video.clipStart,
|
|
1141
|
+
clipEnd: video.clipEnd,
|
|
1142
|
+
// The clip's source file length (VideoWithCaptionInput's meaning), not a
|
|
1143
|
+
// narration timing hint.
|
|
1144
|
+
sourceDuration: video.sourceDuration,
|
|
1145
|
+
caption: video.alt,
|
|
1146
|
+
captionPosition: "bottom",
|
|
1147
|
+
videoCredit: video.credit,
|
|
1148
|
+
videoLicense: video.license
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
|
|
842
1152
|
export {
|
|
843
1153
|
DEFAULT_TRANSFORM_STYLE_ID,
|
|
844
1154
|
createTransformStyleRegistry,
|
|
@@ -847,5 +1157,7 @@ export {
|
|
|
847
1157
|
getTransformStyleSummaries,
|
|
848
1158
|
extractDocImages,
|
|
849
1159
|
analyzeBlocks,
|
|
850
|
-
|
|
1160
|
+
allocateTiming,
|
|
1161
|
+
applyTransform,
|
|
1162
|
+
transformNarratedSegment
|
|
851
1163
|
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildNarrationScript,
|
|
3
3
|
expectedSyllablesAt,
|
|
4
|
-
flattenRenderableBlocks,
|
|
5
4
|
wordPosAtExpectedSyllables
|
|
6
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EF353KGH.js";
|
|
6
|
+
import {
|
|
7
|
+
flattenRenderableBlocks
|
|
8
|
+
} from "./chunk-3YNFMFNK.js";
|
|
7
9
|
|
|
8
10
|
// src/narration/types.ts
|
|
9
11
|
var DEFAULT_FEATURE_CONFIG = Object.freeze({
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildNarrationScript,
|
|
3
|
+
parseNarrationTimingJson
|
|
4
|
+
} from "./chunk-EF353KGH.js";
|
|
1
5
|
import {
|
|
2
6
|
SHAPE_NAMES,
|
|
3
7
|
buildChartData,
|
|
4
|
-
buildNarrationScript,
|
|
5
8
|
buildRegistry,
|
|
6
9
|
coerceTemplateParams,
|
|
7
10
|
deriveTemplateInputs,
|
|
@@ -22,7 +25,6 @@ import {
|
|
|
22
25
|
nearestName,
|
|
23
26
|
normalizeShapeKind,
|
|
24
27
|
parseDataFence,
|
|
25
|
-
parseNarrationTimingJson,
|
|
26
28
|
parseStandaloneAnnotation,
|
|
27
29
|
placeLayersInRect,
|
|
28
30
|
readCustomThemesFromFrontmatter,
|
|
@@ -30,7 +32,7 @@ import {
|
|
|
30
32
|
templateRegistry,
|
|
31
33
|
writeCustomTemplatesToFrontmatter,
|
|
32
34
|
writeCustomThemesToFrontmatter
|
|
33
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-3YNFMFNK.js";
|
|
34
36
|
import {
|
|
35
37
|
iconMarker
|
|
36
38
|
} from "./chunk-7ZAAICW4.js";
|
|
@@ -59,21 +61,19 @@ import {
|
|
|
59
61
|
DEFAULT_THEME,
|
|
60
62
|
FRONTMATTER_CUSTOM_TEMPLATES_KEY,
|
|
61
63
|
FRONTMATTER_CUSTOM_THEMES_KEY,
|
|
64
|
+
VIEWPORT_PRESETS,
|
|
65
|
+
calculateFontScale,
|
|
66
|
+
createTemplateContext,
|
|
67
|
+
getViewportOrientation,
|
|
62
68
|
hexHueDegrees,
|
|
69
|
+
isTemplateBlock,
|
|
63
70
|
oklchDarken,
|
|
64
71
|
oklchLighten,
|
|
65
72
|
relativeLuminance,
|
|
66
73
|
resolveFontFamily,
|
|
67
74
|
resolveTheme,
|
|
68
75
|
withAlpha
|
|
69
|
-
} from "./chunk-
|
|
70
|
-
import {
|
|
71
|
-
VIEWPORT_PRESETS,
|
|
72
|
-
calculateFontScale,
|
|
73
|
-
createTemplateContext,
|
|
74
|
-
getViewportOrientation,
|
|
75
|
-
isTemplateBlock
|
|
76
|
-
} from "./chunk-BAOV476U.js";
|
|
76
|
+
} from "./chunk-Y4D6TDZT.js";
|
|
77
77
|
import {
|
|
78
78
|
parseMarkdown
|
|
79
79
|
} from "./chunk-CW24CH7I.js";
|
|
@@ -94,7 +94,7 @@ import {
|
|
|
94
94
|
} from "./chunk-X7BNDUNI.js";
|
|
95
95
|
import {
|
|
96
96
|
estimateTimeFromText
|
|
97
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-GHOPHGOK.js";
|
|
98
98
|
|
|
99
99
|
// src/doc/utils/animationUtils.ts
|
|
100
100
|
function getAnimationStyle(animation, _currentTime = 0) {
|
|
@@ -4216,6 +4216,7 @@ function autoMatchBlocks(blocks, audioFiles) {
|
|
|
4216
4216
|
async function resolveAudioMapping(doc, container) {
|
|
4217
4217
|
const narration = await applyNarrationTiming(doc, container);
|
|
4218
4218
|
doc = narration.doc;
|
|
4219
|
+
if (doc.audio?.segments?.length > 0) return doc;
|
|
4219
4220
|
const audioFiles = await discoverNarrationAudio(container);
|
|
4220
4221
|
const scheduledSrcs = new Set(resolveMediaSchedule(doc).map((clip) => clip.src));
|
|
4221
4222
|
const available = audioFiles.filter((f) => !scheduledSrcs.has(f.path));
|
|
@@ -538,9 +538,6 @@ function cleanDescription(sentence, value) {
|
|
|
538
538
|
for (const pattern of prepositionPatterns) {
|
|
539
539
|
desc = desc.replace(pattern, "");
|
|
540
540
|
}
|
|
541
|
-
if (desc === sentence) {
|
|
542
|
-
desc = sentence.replace(value, "").trim();
|
|
543
|
-
}
|
|
544
541
|
desc = desc.replace(/^[,:\-–—]+\s*/, "").replace(/\s*[,:\-–—]+$/, "");
|
|
545
542
|
desc = desc.replace(
|
|
546
543
|
/\s+(?:of|on|in|at|by|to|for|from|with|about|over|under|between|than|into|onto|upon)\s*([,.])/gi,
|