@remotion/captions 4.0.529 → 4.0.530
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/esm/index.mjs +62 -1
- package/dist/parse-srt.d.ts +2 -1
- package/dist/parse-srt.js +65 -1
- package/package.json +2 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -142,12 +142,73 @@ function toMilliseconds(time) {
|
|
|
142
142
|
}
|
|
143
143
|
return parseInt(first, 10) * 3600000 + parseInt(second, 10) * 60000 + parseInt(seconds, 10) * 1000 + parseInt(millis, 10);
|
|
144
144
|
}
|
|
145
|
-
var parseSrt = ({
|
|
145
|
+
var parseSrt = ({
|
|
146
|
+
input,
|
|
147
|
+
strict = false
|
|
148
|
+
}) => {
|
|
146
149
|
const inputLines = input.replace(/^\uFEFF/, "").replace(/\r\n/g, `
|
|
147
150
|
`).replace(/\r/g, `
|
|
148
151
|
`).split(`
|
|
149
152
|
`);
|
|
150
153
|
const captions = [];
|
|
154
|
+
if (strict) {
|
|
155
|
+
const timestamp = (token, cue, line) => {
|
|
156
|
+
const match = /^(\d+):(\d{2}):(\d{2})[,.](\d{3})$/.exec(token);
|
|
157
|
+
if (!match || Number(match[2]) > 59 || Number(match[3]) > 59) {
|
|
158
|
+
throw new Error(`SRT cue ${cue}, line ${line}: invalid timestamp "${token}". Use HH:MM:SS,mmm.`);
|
|
159
|
+
}
|
|
160
|
+
const value = Number(match[1]) * 3600000 + Number(match[2]) * 60000 + Number(match[3]) * 1000 + Number(match[4]);
|
|
161
|
+
if (!Number.isFinite(value)) {
|
|
162
|
+
throw new Error(`SRT cue ${cue}, line ${line}: timestamp is too large.`);
|
|
163
|
+
}
|
|
164
|
+
return value;
|
|
165
|
+
};
|
|
166
|
+
let i = 0;
|
|
167
|
+
while (i < inputLines.length) {
|
|
168
|
+
if (inputLines[i].trim() === "") {
|
|
169
|
+
i++;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
const cue = captions.length + 1;
|
|
173
|
+
const headerLine = i + 1;
|
|
174
|
+
if (!/^\d+$/.test(inputLines[i].trim())) {
|
|
175
|
+
throw new Error(`SRT cue ${cue}, line ${headerLine}: expected a numeric cue index.`);
|
|
176
|
+
}
|
|
177
|
+
i++;
|
|
178
|
+
const timingLine = inputLines[i];
|
|
179
|
+
const timing = timingLine?.match(/^\s*(\S+)\s+-->\s+(\S+)(.*)$/);
|
|
180
|
+
const settings = timing?.[3].trim();
|
|
181
|
+
if (!timing || settings && !settings.split(/\s+/).every((setting) => /^(?:(?:X[12]|Y[12]):\d+|(?:align|position|line|size|vertical):\S+)$/.test(setting))) {
|
|
182
|
+
throw new Error(`SRT cue ${cue}, line ${i + 1}: expected start --> end timestamps.`);
|
|
183
|
+
}
|
|
184
|
+
const startMs = timestamp(timing[1], cue, i + 1);
|
|
185
|
+
const endMs = timestamp(timing[2], cue, i + 1);
|
|
186
|
+
if (endMs < startMs) {
|
|
187
|
+
throw new Error(`SRT cue ${cue}, line ${i + 1}: end must not be earlier than start.`);
|
|
188
|
+
}
|
|
189
|
+
i++;
|
|
190
|
+
const text = [];
|
|
191
|
+
while (i < inputLines.length && inputLines[i].trim() !== "") {
|
|
192
|
+
text.push(inputLines[i]);
|
|
193
|
+
i++;
|
|
194
|
+
}
|
|
195
|
+
if (text.length === 0) {
|
|
196
|
+
throw new Error(`SRT cue ${cue}, line ${i + 1}: expected cue text.`);
|
|
197
|
+
}
|
|
198
|
+
captions.push({
|
|
199
|
+
text: text.join(`
|
|
200
|
+
`).trimEnd(),
|
|
201
|
+
startMs,
|
|
202
|
+
endMs,
|
|
203
|
+
timestampMs: (startMs + endMs) / 2,
|
|
204
|
+
confidence: 1
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (captions.length === 0) {
|
|
208
|
+
throw new Error("SRT: No timed captions found. Provide numbered cues with timestamps and text.");
|
|
209
|
+
}
|
|
210
|
+
return { captions };
|
|
211
|
+
}
|
|
151
212
|
for (let i = 0;i < inputLines.length; i++) {
|
|
152
213
|
const line = inputLines[i];
|
|
153
214
|
const nextLine = inputLines[i + 1];
|
package/dist/parse-srt.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Caption } from './caption';
|
|
2
2
|
export type ParseSrtInput = {
|
|
3
3
|
input: string;
|
|
4
|
+
strict?: boolean;
|
|
4
5
|
};
|
|
5
6
|
export type ParseSrtOutput = {
|
|
6
7
|
captions: Caption[];
|
|
7
8
|
};
|
|
8
|
-
export declare const parseSrt: ({ input }: ParseSrtInput) => ParseSrtOutput;
|
|
9
|
+
export declare const parseSrt: ({ input, strict, }: ParseSrtInput) => ParseSrtOutput;
|
package/dist/parse-srt.js
CHANGED
|
@@ -24,13 +24,77 @@ function toMilliseconds(time) {
|
|
|
24
24
|
parseInt(seconds, 10) * 1000 +
|
|
25
25
|
parseInt(millis, 10));
|
|
26
26
|
}
|
|
27
|
-
const parseSrt = ({ input }) => {
|
|
27
|
+
const parseSrt = ({ input, strict = false, }) => {
|
|
28
28
|
const inputLines = input
|
|
29
29
|
.replace(/^\uFEFF/, '')
|
|
30
30
|
.replace(/\r\n/g, '\n')
|
|
31
31
|
.replace(/\r/g, '\n')
|
|
32
32
|
.split('\n');
|
|
33
33
|
const captions = [];
|
|
34
|
+
if (strict) {
|
|
35
|
+
const timestamp = (token, cue, line) => {
|
|
36
|
+
const match = /^(\d+):(\d{2}):(\d{2})[,.](\d{3})$/.exec(token);
|
|
37
|
+
if (!match || Number(match[2]) > 59 || Number(match[3]) > 59) {
|
|
38
|
+
throw new Error(`SRT cue ${cue}, line ${line}: invalid timestamp "${token}". Use HH:MM:SS,mmm.`);
|
|
39
|
+
}
|
|
40
|
+
const value = Number(match[1]) * 3600000 +
|
|
41
|
+
Number(match[2]) * 60000 +
|
|
42
|
+
Number(match[3]) * 1000 +
|
|
43
|
+
Number(match[4]);
|
|
44
|
+
if (!Number.isFinite(value)) {
|
|
45
|
+
throw new Error(`SRT cue ${cue}, line ${line}: timestamp is too large.`);
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
};
|
|
49
|
+
let i = 0;
|
|
50
|
+
while (i < inputLines.length) {
|
|
51
|
+
if (inputLines[i].trim() === '') {
|
|
52
|
+
i++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const cue = captions.length + 1;
|
|
56
|
+
const headerLine = i + 1;
|
|
57
|
+
if (!/^\d+$/.test(inputLines[i].trim())) {
|
|
58
|
+
throw new Error(`SRT cue ${cue}, line ${headerLine}: expected a numeric cue index.`);
|
|
59
|
+
}
|
|
60
|
+
i++;
|
|
61
|
+
const timingLine = inputLines[i];
|
|
62
|
+
const timing = timingLine === null || timingLine === void 0 ? void 0 : timingLine.match(/^\s*(\S+)\s+-->\s+(\S+)(.*)$/);
|
|
63
|
+
const settings = timing === null || timing === void 0 ? void 0 : timing[3].trim();
|
|
64
|
+
if (!timing ||
|
|
65
|
+
(settings &&
|
|
66
|
+
!settings
|
|
67
|
+
.split(/\s+/)
|
|
68
|
+
.every((setting) => /^(?:(?:X[12]|Y[12]):\d+|(?:align|position|line|size|vertical):\S+)$/.test(setting)))) {
|
|
69
|
+
throw new Error(`SRT cue ${cue}, line ${i + 1}: expected start --> end timestamps.`);
|
|
70
|
+
}
|
|
71
|
+
const startMs = timestamp(timing[1], cue, i + 1);
|
|
72
|
+
const endMs = timestamp(timing[2], cue, i + 1);
|
|
73
|
+
if (endMs < startMs) {
|
|
74
|
+
throw new Error(`SRT cue ${cue}, line ${i + 1}: end must not be earlier than start.`);
|
|
75
|
+
}
|
|
76
|
+
i++;
|
|
77
|
+
const text = [];
|
|
78
|
+
while (i < inputLines.length && inputLines[i].trim() !== '') {
|
|
79
|
+
text.push(inputLines[i]);
|
|
80
|
+
i++;
|
|
81
|
+
}
|
|
82
|
+
if (text.length === 0) {
|
|
83
|
+
throw new Error(`SRT cue ${cue}, line ${i + 1}: expected cue text.`);
|
|
84
|
+
}
|
|
85
|
+
captions.push({
|
|
86
|
+
text: text.join('\n').trimEnd(),
|
|
87
|
+
startMs,
|
|
88
|
+
endMs,
|
|
89
|
+
timestampMs: (startMs + endMs) / 2,
|
|
90
|
+
confidence: 1,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (captions.length === 0) {
|
|
94
|
+
throw new Error('SRT: No timed captions found. Provide numbered cues with timestamps and text.');
|
|
95
|
+
}
|
|
96
|
+
return { captions };
|
|
97
|
+
}
|
|
34
98
|
for (let i = 0; i < inputLines.length; i++) {
|
|
35
99
|
const line = inputLines[i];
|
|
36
100
|
const nextLine = inputLines[i + 1];
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"url": "https://github.com/remotion-dev/remotion/tree/main/packages/captions"
|
|
4
4
|
},
|
|
5
5
|
"name": "@remotion/captions",
|
|
6
|
-
"version": "4.0.
|
|
6
|
+
"version": "4.0.530",
|
|
7
7
|
"description": "Primitives for dealing with captions",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dependencies": {},
|
|
24
24
|
"peerDependencies": {},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
26
|
+
"@remotion/eslint-config-internal": "4.0.530",
|
|
27
27
|
"eslint": "9.19.0",
|
|
28
28
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|
|
29
29
|
},
|