Mercurial
comparison mrjunejune/test/hls_player_test.js @ 242:543df0fe7168
[tools] Add full HLS player support
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 03 Aug 2026 13:14:41 -0700 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 241:9c2eec61a152 | 242:543df0fe7168 |
|---|---|
| 1 const assert = require('node:assert/strict'); | |
| 2 const { | |
| 3 chooseVariant, | |
| 4 parseAttributeList, | |
| 5 parseMasterPlaylist, | |
| 6 parseMediaPlaylist, | |
| 7 normalizePlaylistUrl, | |
| 8 localRelativePath, | |
| 9 rewritePlaylistUris, | |
| 10 } = require('../src/tools/hls_player/hls-player.js'); | |
| 11 | |
| 12 const attributes = parseAttributeList( | |
| 13 'BANDWIDTH=500000,RESOLUTION=640x360,CODECS="avc1.42c01e,mp4a.40.2"', | |
| 14 ); | |
| 15 assert.equal(attributes.BANDWIDTH, '500000'); | |
| 16 assert.equal(attributes.RESOLUTION, '640x360'); | |
| 17 assert.equal(attributes.CODECS, 'avc1.42c01e,mp4a.40.2'); | |
| 18 | |
| 19 const variants = parseMasterPlaylist( | |
| 20 '#EXTM3U\n#EXT-X-STREAM-INF:BANDWIDTH=100\nlow.m3u8\n#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1.42c01e"\nhigh.m3u8\n', | |
| 21 'https://example.com/master.m3u8', | |
| 22 ); | |
| 23 assert.equal(variants.length, 2); | |
| 24 assert.equal(chooseVariant(variants).url, 'https://example.com/high.m3u8'); | |
| 25 assert.equal( | |
| 26 chooseVariant(variants, variant => variant.bandwidth < 200).url, | |
| 27 'https://example.com/low.m3u8', | |
| 28 ); | |
| 29 assert.equal(chooseVariant(variants, () => false), null); | |
| 30 | |
| 31 const media = parseMediaPlaylist( | |
| 32 '#EXTM3U\n#EXT-X-MAP:URI="init.mp4"\n#EXTINF:1.5,\nseg0.m4s\n#EXTINF:2.0,\nseg1.m4s\n#EXT-X-ENDLIST\n', | |
| 33 'https://example.com/path/stream.m3u8', | |
| 34 ); | |
| 35 assert.equal(media.initSegment, 'https://example.com/path/init.mp4'); | |
| 36 assert.equal(media.segments.length, 2); | |
| 37 assert.equal(media.segments[1].url, 'https://example.com/path/seg1.m4s'); | |
| 38 assert.equal(media.totalDuration, 3.5); | |
| 39 assert.equal(media.endList, true); | |
| 40 | |
| 41 assert.equal( | |
| 42 normalizePlaylistUrl('/stream.m3u8', 'https://example.com/tool'), | |
| 43 'https://example.com/stream.m3u8', | |
| 44 ); | |
| 45 assert.throws( | |
| 46 () => normalizePlaylistUrl('file:///tmp/stream.m3u8', 'https://example.com'), | |
| 47 /HTTP, HTTPS, or a local file/, | |
| 48 ); | |
| 49 assert.equal( | |
| 50 localRelativePath('folder/master.m3u8', 'video/stream.m3u8'), | |
| 51 'folder/video/stream.m3u8', | |
| 52 ); | |
| 53 assert.equal( | |
| 54 localRelativePath('folder/video/stream.m3u8', '../init.mp4'), | |
| 55 'folder/init.mp4', | |
| 56 ); | |
| 57 assert.equal( | |
| 58 localRelativePath('folder/video/stream.m3u8', '/init.mp4'), | |
| 59 'init.mp4', | |
| 60 ); | |
| 61 assert.throws( | |
| 62 () => localRelativePath('master.m3u8', '../outside.m4s'), | |
| 63 /escapes/, | |
| 64 ); | |
| 65 | |
| 66 assert.throws( | |
| 67 () => parseMediaPlaylist( | |
| 68 '#EXTM3U\n#EXT-X-KEY:METHOD=AES-128,URI="key"\n#EXTINF:1,\nseg.m4s\n', | |
| 69 'https://example.com/stream.m3u8', | |
| 70 ), | |
| 71 /Encrypted HLS/, | |
| 72 ); | |
| 73 | |
| 74 (async () => { | |
| 75 const rewritten = await rewritePlaylistUris( | |
| 76 '#EXTM3U\n#EXT-X-MEDIA:TYPE=AUDIO,URI="audio.m3u8"\n#EXT-X-MAP:URI="init.mp4"\n#EXT-X-KEY:METHOD=AES-128,URI="key.bin"\n#EXTINF:1,\nseg.m4s\n', | |
| 77 async reference => `blob:${reference}`, | |
| 78 ); | |
| 79 assert.match(rewritten, /URI="blob:audio\.m3u8"/); | |
| 80 assert.match(rewritten, /URI="blob:init\.mp4"/); | |
| 81 assert.match(rewritten, /URI="blob:key\.bin"/); | |
| 82 assert.match(rewritten, /blob:seg\.m4s/); | |
| 83 })().catch(error => { | |
| 84 console.error(error); | |
| 85 process.exitCode = 1; | |
| 86 }); |