Skip to content

Commit c4d9bf3

Browse files
committed
Fix "Missing format identifier #EXTM3U" playlist parsing errors
Fixes #7531
1 parent 0919731 commit c4d9bf3

File tree

3 files changed

+27
-41
lines changed

3 files changed

+27
-41
lines changed

src/loader/m3u8-parser.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@ export default class M3U8Parser {
119119
const levelsWithKnownCodecs: LevelParsed[] = [];
120120

121121
MASTER_PLAYLIST_REGEX.lastIndex = 0;
122-
122+
if (!string.startsWith('#EXTM3U')) {
123+
parsed.playlistParsingError = new Error('no EXTM3U delimiter');
124+
return parsed;
125+
}
123126
let result: RegExpExecArray | null;
124127
while ((result = MASTER_PLAYLIST_REGEX.exec(string)) != null) {
125128
if (result[1]) {
@@ -710,9 +713,7 @@ export default class M3U8Parser {
710713
}
711714
}
712715
if (!level.targetduration) {
713-
level.playlistParsingError = new Error(
714-
`#EXT-X-TARGETDURATION is required`,
715-
);
716+
level.playlistParsingError = new Error(`Missing Target Duration`);
716717
}
717718
const fragmentLength = fragments.length;
718719
const firstFragment = fragments[0];

src/loader/playlist-loader.ts

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -344,18 +344,6 @@ class PlaylistLoader implements NetworkComponentAPI {
344344

345345
const string = response.data as string;
346346

347-
// Validate if it is an M3U8 at all
348-
if (string.indexOf('#EXTM3U') !== 0) {
349-
this.handleManifestParsingError(
350-
response,
351-
context,
352-
new Error('no EXTM3U delimiter'),
353-
networkDetails || null,
354-
stats,
355-
);
356-
return;
357-
}
358-
359347
stats.parsing.start = performance.now();
360348
if (
361349
M3U8Parser.isMediaPlaylist(string) ||
@@ -730,29 +718,6 @@ class PlaylistLoader implements NetworkComponentAPI {
730718
typeof context.level === 'number' && parent === PlaylistLevelType.MAIN
731719
? (level as number)
732720
: undefined;
733-
if (!levelDetails.fragments.length) {
734-
const error = (levelDetails.playlistParsingError = new Error(
735-
'No Segments found in Playlist',
736-
));
737-
hls.trigger(Events.ERROR, {
738-
type: ErrorTypes.NETWORK_ERROR,
739-
details: ErrorDetails.LEVEL_EMPTY_ERROR,
740-
fatal: false,
741-
url,
742-
error,
743-
reason: error.message,
744-
response,
745-
context,
746-
level: levelIndex,
747-
parent,
748-
networkDetails,
749-
stats,
750-
});
751-
return;
752-
}
753-
if (!levelDetails.targetduration) {
754-
levelDetails.playlistParsingError = new Error('Missing Target Duration');
755-
}
756721
const error = levelDetails.playlistParsingError;
757722
if (error) {
758723
this.hls.logger.warn(`${error} ${levelDetails.url}`);
@@ -775,6 +740,26 @@ class PlaylistLoader implements NetworkComponentAPI {
775740
}
776741
levelDetails.playlistParsingError = null;
777742
}
743+
if (!levelDetails.fragments.length) {
744+
const error = (levelDetails.playlistParsingError = new Error(
745+
'No Segments found in Playlist',
746+
));
747+
hls.trigger(Events.ERROR, {
748+
type: ErrorTypes.NETWORK_ERROR,
749+
details: ErrorDetails.LEVEL_EMPTY_ERROR,
750+
fatal: false,
751+
url,
752+
error,
753+
reason: error.message,
754+
response,
755+
context,
756+
level: levelIndex,
757+
parent,
758+
networkDetails,
759+
stats,
760+
});
761+
return;
762+
}
778763

779764
if (levelDetails.live && loader) {
780765
if (loader.getCacheAge) {

tests/unit/loader/m3u8-parser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ describe('M3U8Parser', function () {
1919
);
2020
expect(result.levels).to.deep.equal([]);
2121
expect(result.sessionData).to.equal(null);
22-
expectPlaylistParsingError(result, 'no levels found in manifest');
22+
expectPlaylistParsingError(result, 'no EXTM3U delimiter');
2323
});
2424

2525
it('manifest with broken syntax returns empty array', function () {
26-
const manifest = `#EXTXSTREAMINF:PROGRAM-ID=1,BANDWIDTH=836280,CODECS="mp4a.40.2,avc1.64001f",RESOLUTION=848x360,NAME="480"
26+
const manifest = `#EXTM3U#EXTXSTREAMINF:PROGRAM-ID=1,BANDWIDTH=836280,CODECS="mp4a.40.2,avc1.64001f",RESOLUTION=848x360,NAME="480"
2727
http://proxy-62.dailymotion.com/sec(3ae40f708f79ca9471f52b86da76a3a8)/video/107/282/158282701_mp4_h264_aac_hq.m3u8#cell=core`;
2828
const result = M3U8Parser.parseMasterPlaylist(
2929
manifest,

0 commit comments

Comments
 (0)