UNPKG

m3u-parser-generator

Version:

Library to parse and generate m3u or m3u8 IPTV playlist files

205 lines (181 loc) 9.16 kB
import {M3uAttributes, M3uMedia, M3uParser, M3uPlaylist} from "../src"; import { complex, extGroupDirectiveOrder, emptyAttributes, invalidPlaylist, urlTvgTags, playlistWithExtAttrFromUrl, playlistWithExtraHTTPHeaders, playlistWithKodiProps, playlistWithExtraProps, invalidExtM3uAttributes, playlistWithCustomDirectives } from "./test-m3u"; import {M3uCustomDataMapping} from "../src/m3u-parser"; describe('Parse and generate test', () => { it('should be same as original after parse and generate', () => { expect(M3uParser.parse(complex).getM3uString()).toEqual(complex); expect(M3uParser.parse(emptyAttributes).getM3uString()).toEqual(emptyAttributes); }); it('should be parsed when random order of #EXTGRP directive is present', () => { const parsed = M3uParser.parse(extGroupDirectiveOrder); expect(parsed.medias[0].group).toEqual('Test TV group 1'); expect(parsed.medias[1].group).toEqual('Test TV group 2'); }); it('should raise exception when first line is missing', () => { const stringWithoutFirstLine = extGroupDirectiveOrder.split('\n').slice(1).join('\n'); expect(() => M3uParser.parse(stringWithoutFirstLine)).toThrow(new Error('Missing #EXTM3U directive!')); }); it('should generate without playlist title', () => { const playlist = new M3uPlaylist(); playlist.medias.push(new M3uMedia('location')); expect(playlist.getM3uString()).toEqual('#EXTM3U\nlocation'); }); it('should be parsed when no attributes are present', () => { const parsed = M3uParser.parse(emptyAttributes); expect(Object.keys(parsed.medias[0].attributes)).toEqual([]); expect(Object.keys(parsed.medias[1].attributes)).not.toEqual([]); }); it('should raise exception when parsing invalid m3u string', () => { expect(() => M3uParser.parse('')).toThrow(new Error(`m3uString can't be null!`)); }); it('should NOT raise exception when parsing invalid m3u string with ignoreErrors argument', () => { expect(() => M3uParser.parse('', {ignoreErrors: true})).not.toThrow(new Error(`m3uString can't be null!`)); }); it('should parse with invalid attributes', () => { const attr = new M3uAttributes(); attr["tvg-id"] = 'Test tv 1'; attr["tvg-language"] = ' CS'; const media1 = new M3uMedia('playlist.m3u'); media1.name = 'Test tv 1 [CZ]'; media1.group = 'Test TV group 1'; media1.attributes = attr; const media2 = new M3uMedia('playlist.m3u'); media2.name = '100 group-title="Test2"Test tv 2 [SK]'; media2.group = ''; media2.duration = 0; const expectedPlaylist = new M3uPlaylist(); expectedPlaylist.medias = [media1, media2] expect(M3uParser.parse(invalidPlaylist, {ignoreErrors: true})).toEqual(expectedPlaylist); }); it('should parse url-tvg attribute', () => { const playlist = M3uParser.parse(urlTvgTags); expect(playlist.urlTvg).toEqual('http://example.com/tvg.xml'); }); it('should write url-tvg attribute', () => { const playlist = new M3uPlaylist(); playlist.urlTvg = 'http://example.com/tvg.xml'; expect(playlist.getM3uString()).toEqual(urlTvgTags); }); it('should parse extra attributes from url', () => { const playlist = M3uParser.parse(playlistWithExtAttrFromUrl); expect(playlist.medias[0].extraAttributesFromUrl).toEqual('https://example.com/attributes.txt'); }); it('should write extra attributes from url', () => { const media = new M3uMedia('http://iptv.test1.com/playlist.m3u8'); media.name = 'Test tv 1 [CZ]'; media.group = 'Test TV group 1'; media.attributes["tvg-id"] = 'Test tv 1'; media.attributes["tvg-country"] = 'CZ'; media.attributes["tvg-language"] = 'CS'; media.attributes["tvg-logo"] = 'logo1.png'; media.attributes["group-title"] = 'Test1'; media.attributes["unknown"] = '0'; media.extraAttributesFromUrl = 'https://example.com/attributes.txt'; const playlist = new M3uPlaylist(); playlist.medias.push(media); expect(playlist.getM3uString()).toEqual(playlistWithExtAttrFromUrl); }); it('should parse extra http headers', () => { const playlist = M3uParser.parse(playlistWithExtraHTTPHeaders); expect(playlist.medias[0].extraHttpHeaders).toEqual(JSON.parse('{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0"}')); }); it('should write extra http headers', () => { const media = new M3uMedia('http://iptv.test1.com/playlist.m3u8'); media.name = 'Test tv 1 [CZ]'; media.name = 'Test tv 1 [CZ]'; media.group = 'Test TV group 1'; media.attributes["tvg-id"] = 'Test tv 1'; media.attributes["tvg-country"] = 'CZ'; media.attributes["tvg-language"] = 'CS'; media.attributes["tvg-logo"] = 'logo1.png'; media.attributes["group-title"] = 'Test1'; media.attributes["unknown"] = '0'; media.extraHttpHeaders = JSON.parse('{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0"}'); const playlist = new M3uPlaylist(); playlist.medias.push(media); expect(playlist.getM3uString()).toEqual(playlistWithExtraHTTPHeaders); }); it('should parse kodi props', () => { const playlist = M3uParser.parse(playlistWithKodiProps); expect(playlist.medias[0].kodiProps).toEqual(new Map([ [ 'inputstream.adaptive.manifest_type', 'm3u8' ], [ 'inputstream.adaptive.license_type', 'org.w3.clearkey' ], [ 'inputstream.adaptive.license_key', 'https://example.com/license.php?id=example' ] ])); }); it('should write kodi props', () => { const media = new M3uMedia('http://iptv.test1.com/playlist.m3u8'); media.name = 'Test tv 1 [CZ]'; media.name = 'Test tv 1 [CZ]'; media.group = 'Test TV group 1'; media.attributes["tvg-id"] = 'Test tv 1'; media.attributes["tvg-country"] = 'CZ'; media.attributes["tvg-language"] = 'CS'; media.attributes["tvg-logo"] = 'logo1.png'; media.attributes["group-title"] = 'Test1'; media.attributes["unknown"] = '0'; media.kodiProps = new Map([ [ 'inputstream.adaptive.manifest_type', 'm3u8' ], [ 'inputstream.adaptive.license_type', 'org.w3.clearkey' ], [ 'inputstream.adaptive.license_key', 'https://example.com/license.php?id=example' ] ]); const playlist = new M3uPlaylist(); playlist.medias.push(media); expect(playlist.getM3uString()).toEqual(playlistWithKodiProps); }); it('should parse extra props/attributes', () => { const playlist = M3uParser.parse(playlistWithExtraProps); expect(playlist.urlTvg).toEqual('http://example.com/tvg.xml'); expect(playlist.attributes['url-tvg']).toEqual('http://example.com/tvg.xml'); expect(playlist.attributes['url-logo']).toEqual('http://path/to/icons/root/'); expect(playlist.medias[0].group).toEqual("Test TV group 1"); expect(playlist.medias[0].bytes).toEqual(123); expect(playlist.medias[0].image).toEqual("cover.jpg"); expect(playlist.medias[0].album).toEqual("test album"); expect(playlist.medias[0].artist).toEqual("test artist"); expect(playlist.medias[0].genre).toEqual("test genre"); }); it('should write extra props/attributes', () => { const media = new M3uMedia('http://iptv.test1.com/playlist.m3u8'); media.name = 'Test tv 1 [CZ]'; media.group = 'Test TV group 1'; media.bytes = 123; media.image = "cover.jpg"; media.album = "test album"; media.artist = "test artist"; media.genre = "test genre"; media.attributes["tvg-id"] = 'Test tv 1'; media.attributes["tvg-country"] = 'CZ'; media.attributes["tvg-language"] = 'CS'; media.attributes["tvg-logo"] = 'logo1.png'; media.attributes["group-title"] = 'Test1'; media.attributes["unknown"] = '0'; const playlist = new M3uPlaylist(); playlist.attributes['url-tvg'] = 'http://example.com/tvg.xml' playlist.attributes['url-logo'] = 'http://path/to/icons/root/' playlist.medias.push(media); expect(playlist.getM3uString()).toEqual(playlistWithExtraProps); }); it('should parse invalid attributes', () => { const playlist = M3uParser.parse(invalidExtM3uAttributes); expect(playlist.attributes).toEqual(new M3uAttributes()); }); it('should parse and generate with custom directives', () => { const customDataMapping: M3uCustomDataMapping = { '#EXTCUSTOMPLAYLIST': false, '#EXTCUSTOMMEDIA': true, } expect(M3uParser.parse(playlistWithCustomDirectives, {customDataMapping}).getM3uString()).toEqual(playlistWithCustomDirectives); }) });