@amazon/vinyl 3.2.2 → 3.2.3-next.20261001143710
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/README.md +2 -2
- package/dist/index.cjs +62 -21
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +65 -22
- package/dist/index.js.map +3 -3
- package/dist/test/benchmark.es5.js +7 -6
- package/dist/test/benchmark.js +35 -30
- package/dist/test/benchmark.js.map +3 -3
- package/dist/test/integ.es5.js +184 -171
- package/dist/test/integ.js +450 -165
- package/dist/test/integ.js.map +4 -4
- package/dist/types/current/ad/AdControllerImpl.d.ts.map +1 -1
- package/dist/types/current/ad/AdControllerImpl.js +15 -1
- package/dist/types/current/ad/discoverHlsInterstitials.js +13 -1
- package/dist/types/current/drm/commonEme/MsCommonEme.d.ts.map +1 -1
- package/dist/types/current/drm/commonEme/MsCommonEme.js +2 -2
- package/dist/types/current/drm/commonEme/StandardCommonEme.d.ts.map +1 -1
- package/dist/types/current/drm/commonEme/StandardCommonEme.js +3 -2
- package/dist/types/current/drm/commonEme/WebKitCommonEme.d.ts.map +1 -1
- package/dist/types/current/drm/commonEme/WebKitCommonEme.js +2 -2
- package/dist/types/current/drm/dom/MSMediaKeys.d.ts +1 -1
- package/dist/types/current/drm/dom/MSMediaKeys.d.ts.map +1 -1
- package/dist/types/current/drm/dom/WebKitMediaKeys.d.ts +1 -1
- package/dist/types/current/drm/dom/WebKitMediaKeys.d.ts.map +1 -1
- package/dist/types/current/drm/util/extractContentId.js +2 -2
- package/dist/types/current/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/current/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/current/streaming/MediaQualityMetadata.d.ts.map +1 -1
- package/dist/types/current/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/current/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/current/streaming/buffering/BufferingController.d.ts.map +1 -1
- package/dist/types/current/streaming/buffering/BufferingController.js +14 -5
- package/dist/types/current/streaming/buffering/MediaSourceController.d.ts.map +1 -1
- package/dist/types/current/streaming/buffering/MediaSourceController.js +4 -0
- package/dist/types/current/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/current/text/discoverDashTextTracks.js +4 -3
- package/dist/types/current/text/parseWebVtt.d.ts.map +1 -1
- package/dist/types/current/text/parseWebVtt.js +3 -2
- package/dist/types/current/track/TrackController.d.ts.map +1 -1
- package/dist/types/current/track/TrackController.js +7 -0
- package/dist/types/current/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/current/track/hls/HlsManifestData.d.ts.map +1 -1
- package/dist/types/current/track/hls/buildHlsMediaTimeline.d.ts.map +1 -1
- package/dist/types/current/track/hls/buildHlsMediaTimeline.js +10 -2
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.d.ts.map +1 -1
- package/dist/types/current/track/hls/createUrlHlsManifestProvider.js +8 -3
- package/dist/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/ts3.7/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/ts3.7/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/ts3.7/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/ts3.7/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/ts3.7/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/ts3.7/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/ts4.1/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/ts4.1/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/ts4.1/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/ts4.1/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/ts4.1/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/ts4.1/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +1 -1
- package/dist/types/ts4.7/streaming/MediaQualityMetadata.d.ts +3 -1
- package/dist/types/ts4.7/streaming/SegmentControllerImpl.d.ts +1 -1
- package/dist/types/ts4.7/streaming/buffering/BufferingController.d.ts +1 -1
- package/dist/types/ts4.7/text/discoverDashTextTracks.d.ts +2 -2
- package/dist/types/ts4.7/track/hls/HlsManifestData.d.ts +14 -1
- package/dist/types/ts4.7/track/hls/createUrlHlsManifestProvider.d.ts +3 -2
- package/dist/unit/types/current/ad/AdControllerImpl.test.js +66 -0
- package/dist/unit/types/current/ad/discoverHlsInterstitials.test.js +29 -2
- package/dist/unit/types/current/drm/commonEme/StandardCommonEme.test.js +12 -4
- package/dist/unit/types/current/drm/util/extractContentId.test.js +7 -0
- package/dist/unit/types/current/index.d.ts +1 -0
- package/dist/unit/types/current/index.d.ts.map +1 -1
- package/dist/unit/types/current/index.js +1 -0
- package/dist/unit/types/current/streaming/MediaQualityMetadata.test.js +8 -0
- package/dist/unit/types/current/streaming/buffering/BufferingController.test.js +26 -0
- package/dist/unit/types/current/streaming/buffering/MediaSourceController.test.js +29 -0
- package/dist/unit/types/current/text/TextTrack.test.d.ts +2 -0
- package/dist/unit/types/current/text/TextTrack.test.d.ts.map +1 -0
- package/dist/unit/types/current/text/TextTrack.test.js +12 -0
- package/dist/unit/types/current/text/discoverDashTextTracks.test.js +17 -0
- package/dist/unit/types/current/text/parseWebVtt.test.js +26 -0
- package/dist/unit/types/current/track/TrackController.test.js +15 -60
- package/dist/unit/types/current/track/hls/buildHlsMediaTimeline.test.js +22 -0
- package/dist/unit/types/current/track/hls/createUrlHlsManifestProvider.test.js +23 -0
- package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
- package/docs/CUSTOMIZATION_GUIDE.md +310 -0
- package/package.json +10 -10
- package/docs/DASH_MANIFEST_TRANSFORM_GUIDE.md +0 -236
|
@@ -42,6 +42,19 @@ describe('discoverDashTextTracks', () => {
|
|
|
42
42
|
expect(result.length).toBe(1);
|
|
43
43
|
expect(result[0].language).toBe('es');
|
|
44
44
|
});
|
|
45
|
+
it('discovers a text AdaptationSet by its Representation mimeType', () => {
|
|
46
|
+
// DASH allows @mimeType on the Representation instead of the set.
|
|
47
|
+
const m = manifest(`
|
|
48
|
+
<AdaptationSet lang="fr">
|
|
49
|
+
<Representation id="fr-sub" mimeType="text/vtt" bandwidth="100">
|
|
50
|
+
<BaseURL>fr.vtt</BaseURL>
|
|
51
|
+
</Representation>
|
|
52
|
+
</AdaptationSet>`);
|
|
53
|
+
const result = discoverDashTextTracks(m, baseUrl);
|
|
54
|
+
expect(result.length).toBe(1);
|
|
55
|
+
expect(result[0].language).toBe('fr');
|
|
56
|
+
expect(result[0].uri).toBe('https://example.com/dash/fr.vtt');
|
|
57
|
+
});
|
|
45
58
|
it('classifies kind=captions when role=caption is set', () => {
|
|
46
59
|
const m = manifest(`
|
|
47
60
|
<AdaptationSet contentType="text" lang="en" mimeType="text/vtt">
|
|
@@ -96,6 +109,10 @@ describe('discoverDashTextTracks', () => {
|
|
|
96
109
|
</AdaptationSet>`);
|
|
97
110
|
expect(discoverDashTextTracks(m, baseUrl)).toEqual([]);
|
|
98
111
|
});
|
|
112
|
+
it('skips a non-text AdaptationSet with no Representation', () => {
|
|
113
|
+
const m = manifest(`<AdaptationSet contentType="audio"/>`);
|
|
114
|
+
expect(discoverDashTextTracks(m, baseUrl)).toEqual([]);
|
|
115
|
+
});
|
|
99
116
|
it('skips text AdaptationSets carrying segmented codecs (stpp/wvtt)', () => {
|
|
100
117
|
const m = manifest(`
|
|
101
118
|
<AdaptationSet contentType="text" mimeType="application/mp4" codecs="stpp">
|
|
@@ -382,6 +382,32 @@ hi`;
|
|
|
382
382
|
expect(cues.length).toBe(1);
|
|
383
383
|
expect(cues[0].text).toBe('hi');
|
|
384
384
|
});
|
|
385
|
+
it('parses a cue that follows the signature with no blank line', () => {
|
|
386
|
+
// The header block ends at a timing line as well as at a blank line
|
|
387
|
+
// (WebVTT file parsing breaks out of the header loop on `-->`), so a
|
|
388
|
+
// document omitting the blank line still yields its cues.
|
|
389
|
+
const text = `WEBVTT
|
|
390
|
+
00:00:01.000 --> 00:00:02.000
|
|
391
|
+
hi
|
|
392
|
+
|
|
393
|
+
00:00:03.000 --> 00:00:04.000
|
|
394
|
+
there`;
|
|
395
|
+
const cues = parseWebVtt(text).cues;
|
|
396
|
+
expect(cues.length).toBe(2);
|
|
397
|
+
expect(cues[0].startTime).toBe(1);
|
|
398
|
+
expect(cues[0].text).toBe('hi');
|
|
399
|
+
expect(cues[1].text).toBe('there');
|
|
400
|
+
});
|
|
401
|
+
it('keeps header lines as header when a cue follows with no blank line', () => {
|
|
402
|
+
const text = `WEBVTT
|
|
403
|
+
Kind: captions
|
|
404
|
+
00:00:01.000 --> 00:00:02.000
|
|
405
|
+
hi`;
|
|
406
|
+
const cues = parseWebVtt(text).cues;
|
|
407
|
+
expect(cues.length).toBe(1);
|
|
408
|
+
expect(cues[0].id).toBeNull();
|
|
409
|
+
expect(cues[0].text).toBe('hi');
|
|
410
|
+
});
|
|
385
411
|
it('handles trailing identifier without timing line', () => {
|
|
386
412
|
// Identifier with no following timing line - cue is dropped, parser
|
|
387
413
|
// breaks out cleanly without throwing.
|
|
@@ -597,49 +597,6 @@ describe('TrackControllerImpl', () => {
|
|
|
597
597
|
expect(track.clearPrefetch).toHaveBeenCalledTimes(1);
|
|
598
598
|
}
|
|
599
599
|
});
|
|
600
|
-
it('also clears prefetch on preloaded ad tracks', async () => {
|
|
601
|
-
pending('REVIEW: the refactor no longer proactively preloads ad tracks ' +
|
|
602
|
-
'discovered on the current track (ad tracks are created on ' +
|
|
603
|
-
'adEntered only). Decide: intended removal (delete this spec) ' +
|
|
604
|
-
'or regression (restore discovery-time ad preloading).');
|
|
605
|
-
const [main] = createLoadOptionsList(1);
|
|
606
|
-
trackController.load(main);
|
|
607
|
-
const track = trackController.activeTrack;
|
|
608
|
-
const ads = {
|
|
609
|
-
trackUri: main.uri,
|
|
610
|
-
adBreaks: [
|
|
611
|
-
{
|
|
612
|
-
id: 'b1',
|
|
613
|
-
startTime: 5,
|
|
614
|
-
duration: 10,
|
|
615
|
-
placement: 'midroll',
|
|
616
|
-
restrict: {},
|
|
617
|
-
once: false,
|
|
618
|
-
resumeOffset: null,
|
|
619
|
-
playoutLimit: null,
|
|
620
|
-
resolutionTimeOffset: null,
|
|
621
|
-
skipControl: () => null,
|
|
622
|
-
ads: () => Promise.resolve([
|
|
623
|
-
{
|
|
624
|
-
id: 'a1',
|
|
625
|
-
startTime: 5,
|
|
626
|
-
duration: 10,
|
|
627
|
-
uri: 'https://ads/a.m3u8',
|
|
628
|
-
},
|
|
629
|
-
]),
|
|
630
|
-
},
|
|
631
|
-
],
|
|
632
|
-
};
|
|
633
|
-
track.ads = ads;
|
|
634
|
-
track.dispatch('adsChange', { previous: null, current: ads });
|
|
635
|
-
// Ad resolution runs on microtasks.
|
|
636
|
-
await Promise.resolve();
|
|
637
|
-
await Promise.resolve();
|
|
638
|
-
await Promise.resolve();
|
|
639
|
-
const adTrack = trackController.getCachedTrack('https://ads/a.m3u8');
|
|
640
|
-
trackController.clearPrefetch();
|
|
641
|
-
expect(adTrack.clearPrefetch).toHaveBeenCalled();
|
|
642
|
-
});
|
|
643
600
|
});
|
|
644
601
|
describe('clearQueue', () => {
|
|
645
602
|
it('clears the queue without unloading the current track', async () => {
|
|
@@ -1124,6 +1081,21 @@ describe('TrackControllerImpl', () => {
|
|
|
1124
1081
|
expect(adTrack).withContext('midroll ad track warmed').toBeDefined();
|
|
1125
1082
|
expect(adTrack.preload).toHaveBeenCalled();
|
|
1126
1083
|
});
|
|
1084
|
+
it('clears prefetch on a preloaded ad track', async () => {
|
|
1085
|
+
const [main] = createLoadOptionsList(1);
|
|
1086
|
+
factoryGivingBreak(main.uri, []); // records created tracks; no preroll
|
|
1087
|
+
trackController.load(main);
|
|
1088
|
+
await flushAds();
|
|
1089
|
+
deps.adController.dispatch('adPreload', {
|
|
1090
|
+
adBreak: midrollBreak('https://ads/mid.m3u8'),
|
|
1091
|
+
});
|
|
1092
|
+
await flushAds();
|
|
1093
|
+
const adTrack = created.get('https://ads/mid.m3u8');
|
|
1094
|
+
// Ad tracks are not in the content cache, so this only holds if
|
|
1095
|
+
// clearPrefetch reaches the per-parent ad track store too.
|
|
1096
|
+
trackController.clearPrefetch();
|
|
1097
|
+
expect(adTrack.clearPrefetch).toHaveBeenCalledTimes(1);
|
|
1098
|
+
});
|
|
1127
1099
|
it('ignores adPreload when there is no parent track', () => {
|
|
1128
1100
|
expect(() => deps.adController.dispatch('adPreload', {
|
|
1129
1101
|
adBreak: midrollBreak('https://ads/mid.m3u8'),
|
|
@@ -1307,23 +1279,6 @@ describe('TrackControllerImpl', () => {
|
|
|
1307
1279
|
const track = trackController.activeTrack;
|
|
1308
1280
|
expect(track.activate).toHaveBeenCalledWith(objectContaining({ startTime: 3 }));
|
|
1309
1281
|
});
|
|
1310
|
-
it('skips the deferred resume if interrupted before the frame', async () => {
|
|
1311
|
-
pending('REVIEW: content resume on adBreakCompleted is now synchronous ' +
|
|
1312
|
-
'(no deferred/interruptible frame), so this interruption ' +
|
|
1313
|
-
'guard no longer applies. Decide: intended or restore deferral.');
|
|
1314
|
-
const [main] = createLoadOptionsList(1);
|
|
1315
|
-
trackController.load(main);
|
|
1316
|
-
const changeSpy = createEventSpy(trackController, 'trackActivated');
|
|
1317
|
-
deps.adController.dispatch('adBreakCompleted', {
|
|
1318
|
-
adBreak: adBreak('midroll'),
|
|
1319
|
-
resumePosition: 5,
|
|
1320
|
-
});
|
|
1321
|
-
// Interrupt: a new ad becomes current before the deferred resume runs.
|
|
1322
|
-
deps.adController.currentAd = { ...ad, id: 'other' };
|
|
1323
|
-
await clock.tick();
|
|
1324
|
-
// The deferred setQueue was skipped; no track change occurred.
|
|
1325
|
-
expect(changeSpy).not.toHaveBeenCalled();
|
|
1326
|
-
});
|
|
1327
1282
|
it('advances to the next track after a postroll ad when one exists', async () => {
|
|
1328
1283
|
const list = createLoadOptionsList(2);
|
|
1329
1284
|
trackController.load(...list);
|
|
@@ -542,6 +542,28 @@ describe('buildHlsMediaTimeline', () => {
|
|
|
542
542
|
expect(initCall[1]?.headers).toEqual(jasmine.objectContaining({ Range: 'bytes=0-499' }));
|
|
543
543
|
fetchSpy.and.callThrough();
|
|
544
544
|
});
|
|
545
|
+
it('resolves segment and map URIs against the media playlist baseUrl', async () => {
|
|
546
|
+
const variant = createVariant('v1.m3u8', 128000);
|
|
547
|
+
const playlist = {
|
|
548
|
+
...createMediaPlaylist([10]),
|
|
549
|
+
// The media playlist was redirected away from the main playlist's
|
|
550
|
+
// directory.
|
|
551
|
+
baseUrl: 'https://redirect.example.net/hls/v1.m3u8',
|
|
552
|
+
};
|
|
553
|
+
const manifestData = createManifestData([variant], playlist);
|
|
554
|
+
const fetchSpy = spyOn(globalThis, 'fetch').and.callFake(() => Promise.resolve(new Response(new ArrayBuffer(100))));
|
|
555
|
+
const timeline = buildHlsMediaTimeline(deps, manifestData);
|
|
556
|
+
const quality = timeline.periods[0].qualities[0];
|
|
557
|
+
const segment = await quality.getSegment(5);
|
|
558
|
+
await segment.initData();
|
|
559
|
+
await segment.data();
|
|
560
|
+
const urls = fetchSpy.calls.allArgs().map(([input]) => String(input));
|
|
561
|
+
expect(urls).toEqual([
|
|
562
|
+
'https://redirect.example.net/hls/init.mp4',
|
|
563
|
+
'https://redirect.example.net/hls/seg0.m4s',
|
|
564
|
+
]);
|
|
565
|
+
fetchSpy.and.callThrough();
|
|
566
|
+
});
|
|
545
567
|
it('getDuration throws when no variants', async () => {
|
|
546
568
|
const manifestData = createManifestData([], createMediaPlaylist([]));
|
|
547
569
|
const timeline = buildHlsMediaTimeline(deps, manifestData);
|
|
@@ -113,6 +113,29 @@ describe('fetchMediaPlaylist', () => {
|
|
|
113
113
|
expect(playlist.segments.length).toBe(1);
|
|
114
114
|
expect(String(mockRequester.request.calls.argsFor(0)[0])).toBe('https://example.com/path/audio.m3u8');
|
|
115
115
|
});
|
|
116
|
+
it('sets the baseUrl from the response URL', async () => {
|
|
117
|
+
mockRequester.request.and.callFake(() => {
|
|
118
|
+
const resp = new Response(mediaM3u8);
|
|
119
|
+
Object.defineProperty(resp, 'url', {
|
|
120
|
+
value: 'https://redirected.com/hls/audio.m3u8',
|
|
121
|
+
});
|
|
122
|
+
return Promise.resolve(resp);
|
|
123
|
+
});
|
|
124
|
+
const playlist = await fetchMediaPlaylist({
|
|
125
|
+
uri: 'audio.m3u8',
|
|
126
|
+
baseUrl: 'https://example.com/path/main.m3u8',
|
|
127
|
+
defines: undefined,
|
|
128
|
+
});
|
|
129
|
+
expect(playlist.baseUrl).toBe('https://redirected.com/hls/audio.m3u8');
|
|
130
|
+
});
|
|
131
|
+
it('falls back to the requested URL when the response has no URL', async () => {
|
|
132
|
+
const playlist = await fetchMediaPlaylist({
|
|
133
|
+
uri: 'audio.m3u8',
|
|
134
|
+
baseUrl: 'https://example.com/path/main.m3u8',
|
|
135
|
+
defines: undefined,
|
|
136
|
+
});
|
|
137
|
+
expect(playlist.baseUrl).toBe('https://example.com/path/audio.m3u8');
|
|
138
|
+
});
|
|
116
139
|
it('resolves EXT-X-DEFINE:QUERYPARAM from the playlist URL query string', async () => {
|
|
117
140
|
mockRequester.request.and.callFake(() => Promise.resolve(new Response([
|
|
118
141
|
'#EXTM3U',
|