@mtillmann/chapters 0.1.6 → 0.1.8
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/index.d.ts +76 -6
- package/dist/index.js +211 -18
- package/package.json +3 -2
- package/readme.md +11 -5
package/dist/index.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ declare abstract class Base implements MediaItem {
|
|
|
70
70
|
static create(input?: string | MediaItem, duration?: number): MediaItem;
|
|
71
71
|
from(input?: string | MediaItem): MediaItem;
|
|
72
72
|
detect(inputString: string): boolean;
|
|
73
|
-
test(data:
|
|
73
|
+
test(data: Record<string, any>): {
|
|
74
74
|
errors: string[];
|
|
75
75
|
};
|
|
76
76
|
bump(keepDuration?: boolean): void;
|
|
@@ -82,8 +82,8 @@ declare abstract class Base implements MediaItem {
|
|
|
82
82
|
parse(string: string): void;
|
|
83
83
|
toString(pretty?: boolean, exportOptions?: {}): string;
|
|
84
84
|
applyChapterMinLength(seconds: number): object;
|
|
85
|
-
addChapterAt(index: number, chapter?:
|
|
86
|
-
addChapterAtTime(time: number | string, chapter?:
|
|
85
|
+
addChapterAt(index: number, chapter?: Partial<Chapter>): number;
|
|
86
|
+
addChapterAtTime(time: number | string, chapter?: Partial<Chapter>): boolean;
|
|
87
87
|
rebuildChapterTitles(template?: string): void;
|
|
88
88
|
ensureTitle(index: number): string;
|
|
89
89
|
getChapterTitle(index: number, template?: string): string;
|
|
@@ -129,6 +129,16 @@ declare class AppleHLS extends Base {
|
|
|
129
129
|
toString(pretty?: boolean): string;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
declare class Audible extends Base {
|
|
133
|
+
filename: string;
|
|
134
|
+
mimeType: string;
|
|
135
|
+
test(data: Record<string, any>): {
|
|
136
|
+
errors: string[];
|
|
137
|
+
};
|
|
138
|
+
parse(string: string): void;
|
|
139
|
+
toString(pretty?: boolean): string;
|
|
140
|
+
}
|
|
141
|
+
|
|
132
142
|
declare class ChaptersJson extends Base {
|
|
133
143
|
supportsPrettyPrint: boolean;
|
|
134
144
|
}
|
|
@@ -179,6 +189,39 @@ declare class MP4Chaps extends Base {
|
|
|
179
189
|
toString(): string;
|
|
180
190
|
}
|
|
181
191
|
|
|
192
|
+
declare class TextGeneric extends Base {
|
|
193
|
+
filename: string;
|
|
194
|
+
mimeType: string;
|
|
195
|
+
formats: Record<string, Record<string, any>>;
|
|
196
|
+
detect(inputString: string): boolean;
|
|
197
|
+
parse(string: string): void;
|
|
198
|
+
toString(pretty?: boolean, exportOptions?: string | Record<string, any>): string;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
declare class PodcastPage extends TextGeneric {
|
|
202
|
+
filename: string;
|
|
203
|
+
mimeType: string;
|
|
204
|
+
detect(inputString: string): boolean;
|
|
205
|
+
toString(): string;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
declare class Podigee extends Base {
|
|
209
|
+
filename: string;
|
|
210
|
+
supportsPrettyPrint: boolean;
|
|
211
|
+
test(data: object[]): {
|
|
212
|
+
errors: string[];
|
|
213
|
+
};
|
|
214
|
+
parse(string: string): void;
|
|
215
|
+
toString(pretty?: boolean): string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
declare class PodigeeText extends TextGeneric {
|
|
219
|
+
filename: string;
|
|
220
|
+
mimeType: string;
|
|
221
|
+
detect(inputString: string): boolean;
|
|
222
|
+
toString(): string;
|
|
223
|
+
}
|
|
224
|
+
|
|
182
225
|
declare class PodloveJson extends Base {
|
|
183
226
|
filename: string;
|
|
184
227
|
mimeType: string;
|
|
@@ -224,6 +267,13 @@ declare class Scenecut extends Base {
|
|
|
224
267
|
toString(pretty?: boolean, exportOptions?: {}): string;
|
|
225
268
|
}
|
|
226
269
|
|
|
270
|
+
declare class ShowNotes extends TextGeneric {
|
|
271
|
+
filename: string;
|
|
272
|
+
mimeType: string;
|
|
273
|
+
detect(inputString: string): boolean;
|
|
274
|
+
toString(): string;
|
|
275
|
+
}
|
|
276
|
+
|
|
227
277
|
declare class ShutterEDL extends Base {
|
|
228
278
|
detect(inputString: string): boolean;
|
|
229
279
|
decodeTime(timeString: string): string;
|
|
@@ -232,6 +282,27 @@ declare class ShutterEDL extends Base {
|
|
|
232
282
|
toString(): string;
|
|
233
283
|
}
|
|
234
284
|
|
|
285
|
+
declare class SpotifyA extends TextGeneric {
|
|
286
|
+
filename: string;
|
|
287
|
+
mimeType: string;
|
|
288
|
+
detect(inputString: string): boolean;
|
|
289
|
+
toString(): string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
declare class SpotifyB extends TextGeneric {
|
|
293
|
+
filename: string;
|
|
294
|
+
mimeType: string;
|
|
295
|
+
detect(inputString: string): boolean;
|
|
296
|
+
toString(): string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
declare class TransistorFM extends TextGeneric {
|
|
300
|
+
filename: string;
|
|
301
|
+
mimeType: string;
|
|
302
|
+
detect(inputString: string): boolean;
|
|
303
|
+
toString(): string;
|
|
304
|
+
}
|
|
305
|
+
|
|
235
306
|
declare class VorbisComment extends MKVMergeSimple {
|
|
236
307
|
filename: string;
|
|
237
308
|
mimeType: string;
|
|
@@ -246,11 +317,10 @@ declare class WebVTT extends Base {
|
|
|
246
317
|
toString(): string;
|
|
247
318
|
}
|
|
248
319
|
|
|
249
|
-
declare class Youtube extends
|
|
320
|
+
declare class Youtube extends TextGeneric {
|
|
250
321
|
filename: string;
|
|
251
322
|
mimeType: string;
|
|
252
323
|
detect(inputString: string): boolean;
|
|
253
|
-
parse(string: string): void;
|
|
254
324
|
toString(): string;
|
|
255
325
|
}
|
|
256
326
|
|
|
@@ -294,4 +364,4 @@ declare namespace util {
|
|
|
294
364
|
export { util_Float as Float, util_Floats as Floats, util_Int as Int, util_Ints as Ints, util_NPTToSeconds as NPTToSeconds, util_enforceMilliseconds as enforceMilliseconds, util_escapeRegExpCharacters as escapeRegExpCharacters, util_formatBytes as formatBytes, util_hash as hash, util_indenter as indenter, util_secondsToNPT as secondsToNPT, util_secondsToTimestamp as secondsToTimestamp, util_stringToLines as stringToLines, util_timestampToSeconds as timestampToSeconds, util_toSeconds as toSeconds, util_zeroPad as zeroPad };
|
|
295
365
|
}
|
|
296
366
|
|
|
297
|
-
export { AppleChapters, AppleHLS, AutoFormat, type Chapter, ChaptersJson, FFMetadata, FFMpegInfo, MKVMergeSimple, MKVMergeXML, MP4Chaps, MatroskaXML, type MediaItem, type MediaItemMeta, PodloveJson, PodloveSimpleChapters, PySceneDetect, Scenecut, ShutterEDL, util as Util, VorbisComment, WebVTT, Youtube };
|
|
367
|
+
export { AppleChapters, AppleHLS, Audible, AutoFormat, type Chapter, ChaptersJson, FFMetadata, FFMpegInfo, MKVMergeSimple, MKVMergeXML, MP4Chaps, MatroskaXML, type MediaItem, type MediaItemMeta, PodcastPage, Podigee, PodigeeText, PodloveJson, PodloveSimpleChapters, PySceneDetect, Scenecut, ShowNotes, ShutterEDL, SpotifyA, SpotifyB, TransistorFM, util as Util, VorbisComment, WebVTT, Youtube };
|
package/dist/index.js
CHANGED
|
@@ -909,38 +909,88 @@ var WebVTT = class extends Base {
|
|
|
909
909
|
}
|
|
910
910
|
};
|
|
911
911
|
|
|
912
|
-
// src/Formats/
|
|
913
|
-
var
|
|
914
|
-
filename = "
|
|
912
|
+
// src/Formats/TextGeneric.ts
|
|
913
|
+
var TextGeneric = class extends Base {
|
|
914
|
+
filename = "chapters.txt";
|
|
915
915
|
mimeType = "text/plain";
|
|
916
|
+
formats = {
|
|
917
|
+
spotifya: {
|
|
918
|
+
string: (title, start) => `(${start}) ${title}`,
|
|
919
|
+
hours: "default"
|
|
920
|
+
},
|
|
921
|
+
spotifyb: {
|
|
922
|
+
string: (title, start) => `${start}-${title}`,
|
|
923
|
+
hours: "default"
|
|
924
|
+
},
|
|
925
|
+
youtube: {
|
|
926
|
+
string: (title, start) => `${start} ${title}`,
|
|
927
|
+
hours: "whenOverOneHour",
|
|
928
|
+
enforceZeroStartTime: true
|
|
929
|
+
},
|
|
930
|
+
shownotes: {
|
|
931
|
+
string: (title, start) => [`(${start})`, "", title, ""].join("\n"),
|
|
932
|
+
hours: "default"
|
|
933
|
+
},
|
|
934
|
+
transistorfm: {
|
|
935
|
+
string: (title, start) => `${start} - ${title}`,
|
|
936
|
+
hours: "default"
|
|
937
|
+
},
|
|
938
|
+
podigeetext: {
|
|
939
|
+
string: (title, start) => `${start} - ${title}`,
|
|
940
|
+
hours: "always"
|
|
941
|
+
},
|
|
942
|
+
podcastpage: {
|
|
943
|
+
string: (title, start) => `(${start}) - ${title}`,
|
|
944
|
+
hours: "default"
|
|
945
|
+
}
|
|
946
|
+
};
|
|
916
947
|
detect(inputString) {
|
|
917
|
-
return
|
|
948
|
+
return /^\(?(?<ts>\d?\d:\d\d(?::\d\d)?)\)?[\s-]+(?<title>[^\n]+)/.test(inputString.trim());
|
|
918
949
|
}
|
|
919
950
|
parse(string) {
|
|
920
951
|
if (!this.detect(string)) {
|
|
921
|
-
throw new Error("
|
|
952
|
+
throw new Error("Invalid format, see documentation for supported formats");
|
|
922
953
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const timestamp = String(l.shift());
|
|
954
|
+
const matches = [...string.matchAll(/^\(?(?<ts>\d?\d:\d\d(?::\d\d)?)\)?[\s-]+(?<title>[^\n]+)/gm)];
|
|
955
|
+
this.chapters = matches.map((match) => {
|
|
926
956
|
return {
|
|
927
|
-
startTime: timestampToSeconds(
|
|
928
|
-
title:
|
|
957
|
+
startTime: timestampToSeconds(match.groups.ts),
|
|
958
|
+
title: match.groups.title
|
|
929
959
|
};
|
|
930
960
|
});
|
|
931
961
|
}
|
|
932
|
-
toString() {
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
}
|
|
962
|
+
toString(pretty = false, exportOptions = "youtube") {
|
|
963
|
+
const formatKey = typeof exportOptions === "string" ? exportOptions : exportOptions.format;
|
|
964
|
+
if (!(formatKey in this.formats)) {
|
|
965
|
+
throw new Error("Invalid format: " + formatKey);
|
|
966
|
+
}
|
|
967
|
+
const template = this.formats[formatKey];
|
|
968
|
+
const exceedsOneHour = this.chapters.at(-1).startTime > 3600;
|
|
937
969
|
return this.chapters.map((chapter, index) => {
|
|
938
|
-
const startTime = index === 0 && chapter.startTime !== 0 ? 0 : chapter.startTime;
|
|
939
|
-
|
|
970
|
+
const startTime = template.enforceZeroStartTime && index === 0 && chapter.startTime !== 0 ? 0 : chapter.startTime;
|
|
971
|
+
let hours;
|
|
972
|
+
if (startTime > 3600 || template.hours === "always" || template.hours === "whenOverOneHour" && exceedsOneHour) {
|
|
973
|
+
hours = true;
|
|
974
|
+
} else {
|
|
975
|
+
hours = false;
|
|
976
|
+
}
|
|
977
|
+
return template.string(chapter.title, secondsToTimestamp(startTime, { hours }));
|
|
940
978
|
}).join("\n");
|
|
941
979
|
}
|
|
942
980
|
};
|
|
943
981
|
|
|
982
|
+
// src/Formats/Youtube.ts
|
|
983
|
+
var Youtube = class extends TextGeneric {
|
|
984
|
+
filename = "youtube-chapters.txt";
|
|
985
|
+
mimeType = "text/plain";
|
|
986
|
+
detect(inputString) {
|
|
987
|
+
return /^(?<ts>\d?\d:\d\d(?::\d\d)?) [^-](?<title>[^\n]+)/.test(inputString.trim());
|
|
988
|
+
}
|
|
989
|
+
toString() {
|
|
990
|
+
return super.toString(false, { format: "youtube" });
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
|
|
944
994
|
// src/Formats/ShutterEDL.ts
|
|
945
995
|
var ShutterEDL = class extends Base {
|
|
946
996
|
// this format is based on the shutter encoder edl format
|
|
@@ -1362,6 +1412,134 @@ var Audible = class extends Base {
|
|
|
1362
1412
|
}
|
|
1363
1413
|
};
|
|
1364
1414
|
|
|
1415
|
+
// src/Formats/Podigee.ts
|
|
1416
|
+
var Podigee = class extends Base {
|
|
1417
|
+
filename = "podigee-chapters.json";
|
|
1418
|
+
supportsPrettyPrint = true;
|
|
1419
|
+
test(data) {
|
|
1420
|
+
if (!Array.isArray(data)) {
|
|
1421
|
+
return { errors: ["JSON Structure: must be an array"] };
|
|
1422
|
+
}
|
|
1423
|
+
if (data.length === 0) {
|
|
1424
|
+
return { errors: ["JSON Structure: must not be empty"] };
|
|
1425
|
+
}
|
|
1426
|
+
if (!data.every((chapter) => "start_time" in chapter && "title" in chapter)) {
|
|
1427
|
+
return { errors: ["JSON Structure: every chapter must have a start_time and title property"] };
|
|
1428
|
+
}
|
|
1429
|
+
return { errors: [] };
|
|
1430
|
+
}
|
|
1431
|
+
parse(string) {
|
|
1432
|
+
const data = JSON.parse(string);
|
|
1433
|
+
const { errors } = this.test(data);
|
|
1434
|
+
if (errors.length > 0) {
|
|
1435
|
+
throw new Error(errors.join(""));
|
|
1436
|
+
}
|
|
1437
|
+
this.chapters = data.map((raw) => {
|
|
1438
|
+
const { start_time: start, title, image, url } = raw;
|
|
1439
|
+
const chapter = {
|
|
1440
|
+
startTime: timestampToSeconds(start)
|
|
1441
|
+
};
|
|
1442
|
+
if (title) {
|
|
1443
|
+
chapter.title = title;
|
|
1444
|
+
}
|
|
1445
|
+
if (image) {
|
|
1446
|
+
chapter.img = image;
|
|
1447
|
+
}
|
|
1448
|
+
if (url) {
|
|
1449
|
+
chapter.url = url;
|
|
1450
|
+
}
|
|
1451
|
+
return chapter;
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
toString(pretty = false) {
|
|
1455
|
+
return JSON.stringify(this.chapters.map((chapter, i) => {
|
|
1456
|
+
const output = {
|
|
1457
|
+
start_time: secondsToTimestamp(chapter.startTime),
|
|
1458
|
+
title: this.ensureTitle(i)
|
|
1459
|
+
};
|
|
1460
|
+
if (chapter.img) {
|
|
1461
|
+
output.image = chapter.img;
|
|
1462
|
+
}
|
|
1463
|
+
if (chapter.url) {
|
|
1464
|
+
output.url = chapter.url;
|
|
1465
|
+
}
|
|
1466
|
+
return output;
|
|
1467
|
+
}), null, pretty ? 2 : 0);
|
|
1468
|
+
}
|
|
1469
|
+
};
|
|
1470
|
+
|
|
1471
|
+
// src/Formats/PodigeeText.ts
|
|
1472
|
+
var PodigeeText = class extends TextGeneric {
|
|
1473
|
+
filename = "podigee-chapters.txt";
|
|
1474
|
+
mimeType = "text/plain";
|
|
1475
|
+
detect(inputString) {
|
|
1476
|
+
return /^(?<ts>\d?\d:\d\d(?::\d\d)?) - (?<title>[^\n]+)/.test(inputString.trim());
|
|
1477
|
+
}
|
|
1478
|
+
toString() {
|
|
1479
|
+
return super.toString(false, { format: "podigeetext" });
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
|
|
1483
|
+
// src/Formats/ShowNotes.ts
|
|
1484
|
+
var ShowNotes = class extends TextGeneric {
|
|
1485
|
+
filename = "shownote-chapters.txt";
|
|
1486
|
+
mimeType = "text/plain";
|
|
1487
|
+
detect(inputString) {
|
|
1488
|
+
return /^\((?<ts>\d?\d:\d\d(?::\d\d)?)\)\n\n(?<title>[^\n]+)/.test(inputString.trim());
|
|
1489
|
+
}
|
|
1490
|
+
toString() {
|
|
1491
|
+
return super.toString(false, { format: "shownotes" });
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
|
|
1495
|
+
// src/Formats/SpotifyA.ts
|
|
1496
|
+
var SpotifyA = class extends TextGeneric {
|
|
1497
|
+
filename = "spotify-chapters.txt";
|
|
1498
|
+
mimeType = "text/plain";
|
|
1499
|
+
detect(inputString) {
|
|
1500
|
+
return /^\((?<ts>\d?\d:\d\d(?::\d\d)?)\) [^-](?<title>[^\n]+)/.test(inputString.trim());
|
|
1501
|
+
}
|
|
1502
|
+
toString() {
|
|
1503
|
+
return super.toString(false, { format: "spotifya" });
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1506
|
+
|
|
1507
|
+
// src/Formats/SpotifyB.ts
|
|
1508
|
+
var SpotifyB = class extends TextGeneric {
|
|
1509
|
+
filename = "spotify-chapters.txt";
|
|
1510
|
+
mimeType = "text/plain";
|
|
1511
|
+
detect(inputString) {
|
|
1512
|
+
return /^(?<ts>\d?\d:\d\d(?::\d\d)?)-(?<title>[^\n]+)/.test(inputString.trim());
|
|
1513
|
+
}
|
|
1514
|
+
toString() {
|
|
1515
|
+
return super.toString(false, { format: "spotifyb" });
|
|
1516
|
+
}
|
|
1517
|
+
};
|
|
1518
|
+
|
|
1519
|
+
// src/Formats/PodcastPage.ts
|
|
1520
|
+
var PodcastPage = class extends TextGeneric {
|
|
1521
|
+
filename = "podcastpage-chapters.txt";
|
|
1522
|
+
mimeType = "text/plain";
|
|
1523
|
+
detect(inputString) {
|
|
1524
|
+
return /^\((?<ts>\d?\d:\d\d(?::\d\d)?)\) - (?<title>[^\n]+)/.test(inputString.trim());
|
|
1525
|
+
}
|
|
1526
|
+
toString() {
|
|
1527
|
+
return super.toString(false, { format: "podcastpage" });
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
|
|
1531
|
+
// src/Formats/TransistorFM.ts
|
|
1532
|
+
var TransistorFM = class extends TextGeneric {
|
|
1533
|
+
filename = "transistorfm-chapters.txt";
|
|
1534
|
+
mimeType = "text/plain";
|
|
1535
|
+
detect(inputString) {
|
|
1536
|
+
return /^(?<ts>\d?\d:\d\d(?::\d\d)?) - (?<title>[^\n]+)/.test(inputString.trim());
|
|
1537
|
+
}
|
|
1538
|
+
toString() {
|
|
1539
|
+
return super.toString(false, { format: "transistorfm" });
|
|
1540
|
+
}
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1365
1543
|
// src/Formats/AutoFormat.ts
|
|
1366
1544
|
var classMap = {
|
|
1367
1545
|
chaptersjson: ChaptersJson,
|
|
@@ -1381,7 +1559,14 @@ var classMap = {
|
|
|
1381
1559
|
podlovejson: PodloveJson,
|
|
1382
1560
|
applehls: AppleHLS,
|
|
1383
1561
|
scenecut: Scenecut,
|
|
1384
|
-
audible: Audible
|
|
1562
|
+
audible: Audible,
|
|
1563
|
+
podigee: Podigee,
|
|
1564
|
+
podigeetext: PodigeeText,
|
|
1565
|
+
shownotes: ShowNotes,
|
|
1566
|
+
spotifya: SpotifyA,
|
|
1567
|
+
spotifyb: SpotifyB,
|
|
1568
|
+
podcastpage: PodcastPage,
|
|
1569
|
+
transistorfm: TransistorFM
|
|
1385
1570
|
};
|
|
1386
1571
|
var AutoFormat = {
|
|
1387
1572
|
classMap,
|
|
@@ -1421,6 +1606,7 @@ var AutoFormat = {
|
|
|
1421
1606
|
export {
|
|
1422
1607
|
AppleChapters,
|
|
1423
1608
|
AppleHLS,
|
|
1609
|
+
Audible,
|
|
1424
1610
|
AutoFormat,
|
|
1425
1611
|
ChaptersJson,
|
|
1426
1612
|
FFMetadata,
|
|
@@ -1429,11 +1615,18 @@ export {
|
|
|
1429
1615
|
MKVMergeXML,
|
|
1430
1616
|
MP4Chaps,
|
|
1431
1617
|
MatroskaXML,
|
|
1618
|
+
PodcastPage,
|
|
1619
|
+
Podigee,
|
|
1620
|
+
PodigeeText,
|
|
1432
1621
|
PodloveJson,
|
|
1433
1622
|
PodloveSimpleChapters,
|
|
1434
1623
|
PySceneDetect,
|
|
1435
1624
|
Scenecut,
|
|
1625
|
+
ShowNotes,
|
|
1436
1626
|
ShutterEDL,
|
|
1627
|
+
SpotifyA,
|
|
1628
|
+
SpotifyB,
|
|
1629
|
+
TransistorFM,
|
|
1437
1630
|
util_exports as Util,
|
|
1438
1631
|
VorbisComment,
|
|
1439
1632
|
WebVTT,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mtillmann/chapters",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "library that manages and converts chapters of multiple formats",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"podcast-chapters",
|
|
35
35
|
"edl",
|
|
36
36
|
"hls",
|
|
37
|
-
"scenecut"
|
|
37
|
+
"scenecut",
|
|
38
|
+
"podigee"
|
|
38
39
|
],
|
|
39
40
|
"license": "MIT",
|
|
40
41
|
"devDependencies": {
|
package/readme.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# chapters
|
|
6
6
|
|
|
7
|
-
This is the core library of
|
|
7
|
+
This is the core library of [chaptertool](https://github.com/Mtillmann/chaptertool) and [chapconv](https://github.com/Mtillmann/chapconv/) and provides the functionality to handle the formats below.
|
|
8
8
|
|
|
9
9
|
[Click here to open the web GUI](https://mtillmann.github.io/chaptertool) or go install chaptertool locally for CLI use.
|
|
10
10
|
|
|
@@ -24,12 +24,18 @@ This is the core library of the [chaptertool](https://github.com/Mtillmann/chapt
|
|
|
24
24
|
| VorbisComment | Vorbis Comment Format | vorbiscomment | `txt` | [spec](https://wiki.xiph.org/Chapter_Extension) |
|
|
25
25
|
| AppleChapters | "Apple Chapters" | applechapters | `xml` | [source](https://github.com/rigaya/NVEnc/blob/master/NVEncC_Options.en.md#--chapter-string:~:text=CHAPTER03NAME%3Dchapter%2D3-,apple%20format,-(should%20be%20in)) |
|
|
26
26
|
| ShutterEDL | Shutter EDL | edl | `edl` | [source](https://github.com/paulpacifico/shutter-encoder/blob/f3d6bb6dfcd629861a0b0a50113bf4b062e1ba17/src/application/SceneDetection.java) |
|
|
27
|
+
| Podigee | Podigee Chapters/Chaptermarks | podigee | `json` | [spec](https://app.podigee.com/api-docs#!/ChapterMarks/updateChapterMark:~:text=Model-,Example%20Value,-%7B%0A%20%20%22title%22%3A%20%22string%22%2C%0A%20%20%22start_time) |
|
|
27
28
|
| PodloveSimpleChapters | Podlove Simple Chapters | psc | `xml` | [spec](https://podlove.org/simple-chapters/) |
|
|
28
29
|
| PodloveJson | Podlove Simple Chapters JSON | podlovejson | `json` | [source](https://github.com/podlove/chapters#:~:text=org/%3E-,Encode%20to%20JSON,-iex%3E%20Chapters) |
|
|
29
30
|
| MP4Chaps | MP4Chaps | mp4chaps | `txt` | [source](https://github.com/podlove/chapters#:~:text=%3Achapters%3E-,Encode%20to%20mp4chaps,-iex%3E%20Chapters) |
|
|
30
31
|
| AppleHLS | Apple HLS Chapters | applehls | `json` | [spec](https://developer.apple.com/documentation/http-live-streaming/providing-javascript-object-notation-json-chapters), partial support |
|
|
31
32
|
| Scenecut | Scenecut format | scenecut | `json` | [source](https://github.com/slhck/scenecut-extractor#:~:text=cuts%20in%20JSON-,format,-%3A) |
|
|
32
33
|
| Audible | Audible Chapter Format | audible | `json` | [source](./audible-chapter-spec.md) |
|
|
34
|
+
| Spotify | Spotify Formats A/B | spotifya\|spotifyb | `txt` | [see](misc-text-chapter-spec.md) |
|
|
35
|
+
| Podcastpage | Podcastpage Format | podcastpage | `txt` | [see](misc-text-chapter-spec.md) |
|
|
36
|
+
| Podigee Text | Podigee Text Format | podigeetext | `txt` | [see](misc-text-chapter-spec.md) |
|
|
37
|
+
| TransistorFM | TransistorFM Chapter Format | transistorfm | `txt` | [see](misc-text-chapter-spec.md) |
|
|
38
|
+
| "Show Notes Chapters" | Unknown Shownotes Format | shownotes | `txt` | [see](misc-text-chapter-spec.md) |
|
|
33
39
|
|
|
34
40
|
## Installation
|
|
35
41
|
|
|
@@ -85,7 +91,7 @@ const chapters = (new ChaptersJson(3600)).from(input)
|
|
|
85
91
|
```
|
|
86
92
|
|
|
87
93
|
> the constructor will not accept any input due to javascript's order of initialization which prevents the parse method
|
|
88
|
-
> from having access to
|
|
94
|
+
> from having access to certain locally defined properties and methods.
|
|
89
95
|
|
|
90
96
|
### `static create (input?: string | MediaItem): MediaItem`
|
|
91
97
|
|
|
@@ -96,7 +102,7 @@ const chapters = MatroskaXML.create(input)
|
|
|
96
102
|
// chapters is now an instance of MatroskaXML
|
|
97
103
|
|
|
98
104
|
const chapterString = WebVTT.create(chapters).toString()
|
|
99
|
-
// chapterString is now a string representation of the chapters
|
|
105
|
+
// chapterString is now a WebVTT string representation of the chapters
|
|
100
106
|
```
|
|
101
107
|
|
|
102
108
|
### `from (input?: string | MediaItem): MediaItem`
|
|
@@ -111,11 +117,11 @@ Converts the media item to another format.
|
|
|
111
117
|
|
|
112
118
|
Adds a chapter.
|
|
113
119
|
|
|
114
|
-
### `addChapterAt (index: number, chapter:
|
|
120
|
+
### `addChapterAt (index: number, chapter: Partial<Chapter> = {}): number`
|
|
115
121
|
|
|
116
122
|
Adds a chapter at the given index.
|
|
117
123
|
|
|
118
|
-
### `addChapterAtTime (time: number | string, chapter:
|
|
124
|
+
### `addChapterAtTime (time: number | string, chapter: Partial<Chapter> = {}): boolean`
|
|
119
125
|
|
|
120
126
|
Adds a chapter at the given time.
|
|
121
127
|
|