Giter Site home page Giter Site logo

m3u8-parser's Introduction

m3u8-parser

Build Status Maven Central Javadocs

A simple HLS playlist parser for Java.

The goal of this project was to implement parsers and a consistent Java object model according to RFC 8216 HTTP Live Streaming.

This parser is very similar to iHeartRadio's open-m3u8. The main differences are:

  • m3u8-parser does not try to validate playlists. You are responsible for creating valid playlists.
  • m3u8-parser uses java.util.Optional instead of null.
  • m3u8-parser uses Immutables to generate all builders.
  • The parser objects are thread safe & reusable and could be used as a singleton (like Jackson's ObjectMapper).
  • m3u8-parser requires Java 8 or later.

Artifacts

Maven:

<dependency>
    <groupId>io.lindstrom</groupId>
    <artifactId>m3u8-parser</artifactId>
    <version>0.27</version>
</dependency>

Gradle:

implementation 'io.lindstrom:m3u8-parser:0.27'

Usage

Create master playlist

MasterPlaylist playlist = MasterPlaylist.builder()
    .version(4)
    .independentSegments(true)
    .addAlternativeRenditions(AlternativeRendition.builder()
        .type(MediaType.AUDIO)
        .name("Default audio")
        .groupId("AUDIO")
        .build())
    .addVariants(
        Variant.builder()
            .addCodecs("avc1.4d401f", "mp4a.40.2")
            .bandwidth(900000)
            .uri("v0.m3u8")
            .build(),
        Variant.builder()
            .addCodecs("avc1.4d401f", "mp4a.40.2")
            .bandwidth(900000)
            .uri("v1.m3u8")
            .resolution(1280, 720)
            .build())
    .build();

MasterPlaylistParser parser = new MasterPlaylistParser();
System.out.println(parser.writePlaylistAsString(playlist));

This code should produce the following master playlist:

#EXTM3U
#EXT-X-VERSION:4
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="AUDIO",NAME="Default audio"
#EXT-X-STREAM-INF:BANDWIDTH=900000,CODECS="avc1.4d401f,mp4a.40.2"
v0.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=900000,CODECS="avc1.4d401f,mp4a.40.2",RESOLUTION=1280x720
v1.m3u8

Create media playlist

MediaPlaylist mediaPlaylist = MediaPlaylist.builder()
    .version(3)
    .targetDuration(10)
    .mediaSequence(1)
    .ongoing(false)
    .addMediaSegments(
        MediaSegment.builder()
            .duration(9.009)
            .uri("http://media.example.com/first.ts")
            .build(),
        MediaSegment.builder()
            .duration(9.009)
            .uri("http://media.example.com/second.ts")
            .build(),
        MediaSegment.builder()
            .duration(3.003)
            .uri("http://media.example.com/third.ts")
            .build())
    .build();

MediaPlaylistParser parser = new MediaPlaylistParser();
System.out.println(parser.writePlaylistAsString(mediaPlaylist));

This code should produce the following media playlist:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:9.009,
http://media.example.com/first.ts
#EXTINF:9.009,
http://media.example.com/second.ts
#EXTINF:3.003,
http://media.example.com/third.ts
#EXT-X-ENDLIST

Parse master playlist

MasterPlaylistParser parser = new MasterPlaylistParser();

// Parse playlist
MasterPlaylist playlist = parser.readPlaylist(Paths.get("path/to/master.m3u8"));

// Update playlist version
MasterPlaylist updated = MasterPlaylist.builder()
                                        .from(playlist)
                                        .version(2)
                                        .build();

// Write playlist to standard out
System.out.println(parser.writePlaylistAsString(updated));

Parse media playlist

MediaPlaylistParser parser = new MediaPlaylistParser();

// Parse playlist
MediaPlaylist playlist = parser.readPlaylist(Paths.get("path/to/media-playlist.m3u8"));

// Update playlist version
MediaPlaylist updated = MediaPlaylist.builder()
                                     .from(playlist)
                                     .version(2)
                                     .build();

// Write playlist to standard out
System.out.println(parser.writePlaylistAsString(updated));

Parsing mode

By default, the parser will throw an exception on unsupported tags and attributes. This can be configured by passing a ParsingMode to the parser. Example:

MasterPlaylistParser lenientParser = new MasterPlaylistParser(ParsingMode.LENIENT);

Currently two modes are available:

ParsingMode.STRICT   // fail on unsupported things (this is default)
ParsingMode.LENIENT  // ignore unsupported things

Supported tags

The following tags should be fully supported:

EXTM3U
EXT-X-VERSION
EXTINF
EXT-X-BYTERANGE
EXT-X-DISCONTINUITY
EXT-X-KEY
EXT-X-MAP
EXT-X-PROGRAM-DATE-TIME
EXT-X-TARGETDURATION
EXT-X-MEDIA-SEQUENCE
EXT-X-ENDLIST
EXT-X-PLAYLIST-TYPE
EXT-X-I-FRAMES-ONLY
EXT-X-MEDIA
EXT-X-STREAM-INF
EXT-X-I-FRAME-STREAM-INF
EXT-X-INDEPENDENT-SEGMENTS
EXT-X-START
EXT-X-ALLOW-CACHE
EXT-X-SESSION-DATA
EXT-X-SESSION-KEY
EXT-X-DISCONTINUITY-SEQUENCE
EXT-X-DATERANGE

EXT-X-DEFINE
EXT-X-GAP
EXT-X-BITRATE
EXT-X-SERVER-CONTROL
EXT-X-CONTENT-STEERING

EXT-X-PART
EXT-X-PRELOAD-HINT
EXT-X-RENDITION-REPORT
EXT-X-SKIP
EXT-X-PART-INF

EXT-X-CUE-OUT:<duration>
EXT-X-CUE-IN

The following tags are currently not implemented:

Android

This library uses java.time.* which requires core library desugaring when running on Android API level < 26.

m3u8-parser's People

Contributors

ashutoshgngwr avatar brendonmoss avatar carlanton avatar dig3rati avatar estigma88 avatar fhermansson avatar hiroyukitamura avatar johanspaedtke avatar jonaswijk avatar kaktooss avatar ow-ro avatar simonerni avatar swpalmer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

m3u8-parser's Issues

Rename reference from master to main

Hey Guys , as a part of language inclusiveness , could you please accept the request to update all references changed from master to main .
for instance io.lindstrom.m3u8.model.MasterPlaylist to io.lindstrom.m3u8.model.MainPlaylist or io.lindstrom.m3u8.model.PrimaryPlaylist

I can raise a PR for the changes, but would like to hear your thoughts before this

EXT-X-KEY tag only applies to the first segment after it

Some HLS media playlists provide only one EXT-X-KEY tag to indicate how to decrypt the segments rather than provide it before every segments. Like below.

https://bitmovin-a.akamaihd.net/content/art-of-motion_drm/m3u8s/11331_video_1080_4800000.m3u8

#EXTM3U

#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:4
#EXT-X-KEY:METHOD=AES-128,URI="../video/1080_4800000/enc_hls/encryption.key",IV=0x613E8B8CE9CE208C4EAD4A0E03636371

#EXTINF:4.0
../video/1080_4800000/enc_hls/segment_0.ts
#EXTINF:4.0
../video/1080_4800000/enc_hls/segment_1.ts
#EXTINF:4.0
../video/1080_4800000/enc_hls/segment_2.ts
#EXTINF:4.0
../video/1080_4800000/enc_hls/segment_3.ts

It seems that all segments are encrypted and can be decrypt by the key. However, If I use MediaPlaylistParser to parse the playlist, only the first segment has SegmentKey object. Other segments have no SegmentKey. Would you set the same SegmentKey object to other segments?

waiting for supporting EXT_X_DISCONTINUITY_SEQUENCE

Thank you for your hard work.

I want to handle EXT_X_DISCONTINUITY_SEQUENCE in my project.
I know you're working on unsupported tags and refactoring.
Is there any work to contribute to this project?
I'll take on if you give me a task.

#EXT-X-BITRATE not implemented.

Hi. You have said that the Tag #EXT-X-BITRATE is supported but it isn't. Here is my java error:

io.lindstrom.m3u8.parser.PlaylistParserException: Tag not implemented: #EXT-X-BITRATE
	at io.lindstrom.m3u8.parser.MediaPlaylistParser.onTag(MediaPlaylistParser.java:128)
	at io.lindstrom.m3u8.parser.MediaPlaylistParser.onTag(MediaPlaylistParser.java:38)
	at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:95)
	at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:61)
	at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:21)

Here is my m3u8 file:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:55119
#EXT-X-PROGRAM-DATE-TIME:2020-07-21T08:14:29.379Z
#EXT-X-BITRATE:1674
#EXTINF:9.600,
test1.ts
#EXT-X-BITRATE:1625
#EXTINF:9.600,
test2.ts
#EXT-X-BITRATE:1679
#EXTINF:9.600,
test3.ts
#EXT-X-BITRATE:1590
#EXTINF:9.600,
test4.ts
#EXT-X-BITRATE:1641
#EXTINF:9.600,
test5.ts
#EXT-X-BITRATE:1648
#EXTINF:9.600,
test6.ts
#EXT-X-BITRATE:1670
#EXTINF:9.600,
test7.ts
#EXT-X-BITRATE:1683
#EXTINF:9.600,
test8.ts
#EXT-X-BITRATE:1594
#EXTINF:9.600,
test9.ts
#EXT-X-BITRATE:1639
#EXTINF:9.600,
test10.ts

Thanks in advance!

Tag not implemented: EXT-X-TARGETDURATION

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="/20221211/hGKuzpcg/1500kb/hls/key.key"
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/H6kcZjkM.ts
#EXTINF:4.84,
/20221211/hGKuzpcg/1500kb/hls/hVa10ceo.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/t93ZYtwk.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YynHXxcs.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/hpWkhm7D.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YbPLJtQ8.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/74K7LqLE.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/AsSoNd4o.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/w0nVIgk0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/wbxOh1zM.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1L719Sr5.ts
#EXTINF:1.64,
/20221211/hGKuzpcg/1500kb/hls/zntTQniq.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/60uf8psw.ts
#EXTINF:4.84,
/20221211/hGKuzpcg/1500kb/hls/oavI1dp3.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/55THwDFE.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/6wgLNOFh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/hiT1e3En.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/NQIIsQFU.ts
#EXTINF:2.08,
/20221211/hGKuzpcg/1500kb/hls/gjzwANjy.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Ag6Jb7m2.ts
#EXTINF:2.96,
/20221211/hGKuzpcg/1500kb/hls/UtZDBKGd.ts
#EXTINF:2.6,
/20221211/hGKuzpcg/1500kb/hls/Xoy3nUqO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/oD23MYOi.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/FjKs57B1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/oBrFveVH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/l0yjFW4I.ts
#EXTINF:3.8,
/20221211/hGKuzpcg/1500kb/hls/Dq0GPngW.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/yWv1faW5.ts
#EXTINF:1.24,
/20221211/hGKuzpcg/1500kb/hls/ftYab3iT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/sDDsft8a.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/FXrFLeSF.ts
#EXTINF:3.8,
/20221211/hGKuzpcg/1500kb/hls/j8OGsDVu.ts
#EXTINF:2.76,
/20221211/hGKuzpcg/1500kb/hls/TeRJtK58.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/8W6vG3dU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xTNbVCSD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/BPqOd40G.ts
#EXTINF:4.24,
/20221211/hGKuzpcg/1500kb/hls/PBlF3bOb.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/WHmEKvfZ.ts
#EXTINF:1.6,
/20221211/hGKuzpcg/1500kb/hls/aU1BnaTi.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/bGRGlrXD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/a4ag2c76.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/EQl16W7x.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Rjzf4WvJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/4V0afxfs.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/jEhjeKL0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/60qqiNA2.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Wcebv6VW.ts
#EXTINF:5.4,
/20221211/hGKuzpcg/1500kb/hls/BNjwGrPc.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Ccbujc0h.ts
#EXTINF:0.44,
/20221211/hGKuzpcg/1500kb/hls/VNXivbaB.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/85aFoK9T.ts
#EXTINF:2.84,
/20221211/hGKuzpcg/1500kb/hls/k2X2EKDH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/i3JjiSbX.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/fTBGLtpu.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/WTtLefuQ.ts
#EXTINF:3.92,
/20221211/hGKuzpcg/1500kb/hls/IVhnZlAf.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/eLVzk3Fd.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PnQLY9g6.ts
#EXTINF:2.24,
/20221211/hGKuzpcg/1500kb/hls/L2JWCSjF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HHnVHaJS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YRsNnhJP.ts
#EXTINF:4.96,
/20221211/hGKuzpcg/1500kb/hls/U3ql6Zq6.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/SPuqVW5U.ts
#EXTINF:1.44,
/20221211/hGKuzpcg/1500kb/hls/udweY393.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/h3GxRpvS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/N6a7m5uV.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xU2AkJ5E.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/x7FW3nCG.ts
#EXTINF:5.32,
/20221211/hGKuzpcg/1500kb/hls/3DDVpagu.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/yVUzYuEn.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/FkMMUPBM.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/MXuarMiV.ts
#EXTINF:2.04,
/20221211/hGKuzpcg/1500kb/hls/HQjleT3Y.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/eHpEbOLL.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YxCdeP7K.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/0R4Rjkkd.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/6TVOg0h0.ts
#EXTINF:2.4,
/20221211/hGKuzpcg/1500kb/hls/HAWu84nm.ts
#EXTINF:1.76,
/20221211/hGKuzpcg/1500kb/hls/TAsGunR3.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ASDADp63.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HgOefR5o.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/UFUK05BL.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/M5txMMMH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/rkjZDXtp.ts
#EXTINF:5.72,
/20221211/hGKuzpcg/1500kb/hls/lZdmHTBm.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/lKogFYiU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/wjXncSW2.ts
#EXTINF:0.92,
/20221211/hGKuzpcg/1500kb/hls/jbSXSWoU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/7n5Xh338.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/dAmyscv0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/tdKHaKFr.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/y90aH8WY.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/hbauCbi7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/luuRiMHN.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RzdQVOkQ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/lVjRkvJ9.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/x9LI416I.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/MoIV4cUu.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/WLEV81JL.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Qsh45hPf.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/i0NW5JFK.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/O6UT3iDK.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/nNLYGzsN.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RevbZPd0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/L3H9REUn.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/JU2aKgtF.ts
#EXTINF:2.68,
/20221211/hGKuzpcg/1500kb/hls/M4frOqU2.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YRBAVazN.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/sWTcCEc5.ts
#EXTINF:5.24,
/20221211/hGKuzpcg/1500kb/hls/4H7CdHbM.ts
#EXTINF:1,
/20221211/hGKuzpcg/1500kb/hls/3fBAoNAI.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/XG8EpxNP.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/sPpU1swT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/tkaEqjKx.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/lZpOmhCf.ts
#EXTINF:4.64,
/20221211/hGKuzpcg/1500kb/hls/ml6G5pcw.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/IP7OVShr.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/s66aOZFM.ts
#EXTINF:2.04,
/20221211/hGKuzpcg/1500kb/hls/lZ2BK05v.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/sJK1W3of.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/4pAlJCrT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9Ll8JOko.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/0vCZG2wo.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/el3l52EF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/eiUj67VF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RNHEoDjD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9mGyNmT0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/BmWaxhtm.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9JzbCqXB.ts
#EXTINF:3.64,
/20221211/hGKuzpcg/1500kb/hls/gNgzcBD8.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/z14A5AtU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/zv9GhRd9.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ec8xlAsr.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1FJFuLhE.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/l5Z8a2Au.ts
#EXTINF:2.12,
/20221211/hGKuzpcg/1500kb/hls/Q29aUdjo.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/pZxxOUlA.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/dSBLPYFf.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/DTkQb385.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kJasWmkE.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/VNmZckoH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ppypL4nh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ygcflsOz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/t8SZYyAK.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PVmneBgz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/dEFbpuwc.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/370Z2F7S.ts
#EXTINF:2.84,
/20221211/hGKuzpcg/1500kb/hls/eNfTa1JI.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/8dGgcbSQ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kp8BxpDz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RPYpjscD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/BmMYZHLJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/WWMI1XkJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PKv8xRBS.ts
#EXTINF:2.32,
/20221211/hGKuzpcg/1500kb/hls/1VCsKa3q.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/WZ2wTVFC.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/BhNBYOt9.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/eXUqnqs7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1vSGhaFj.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Iumi9IgV.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/UNQgBabx.ts
#EXTINF:3.92,
/20221211/hGKuzpcg/1500kb/hls/PhnZ8fMh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HN9CokTb.ts
#EXTINF:2.12,
/20221211/hGKuzpcg/1500kb/hls/RCQSCkZO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/v4Avu5PT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/MX2Ntizs.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/66CZNzal.ts
#EXTINF:5.2,
/20221211/hGKuzpcg/1500kb/hls/EWwcIoIZ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/AMpzHNzF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Ch61LbkY.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/NGoVEMTJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/uDou2oPp.ts
#EXTINF:1.48,
/20221211/hGKuzpcg/1500kb/hls/RW0vgTOO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/IWL3pZ4J.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/yAwa6S0o.ts
#EXTINF:2.8,
/20221211/hGKuzpcg/1500kb/hls/mCoaPEKu.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/4lXaJHx6.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/rvgKAnhv.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/3wvSFWQO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/3BZHvoBs.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/gVlQDIrn.ts
#EXTINF:2.56,
/20221211/hGKuzpcg/1500kb/hls/k7Yf0JPv.ts
#EXTINF:2.52,
/20221211/hGKuzpcg/1500kb/hls/OV1nq01v.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1aQLGdk9.ts
#EXTINF:5.12,
/20221211/hGKuzpcg/1500kb/hls/5ukssgy1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xgHF2xK2.ts
#EXTINF:2.44,
/20221211/hGKuzpcg/1500kb/hls/Sxi4iCbt.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/r5Qx4TVC.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/qUBGSYFZ.ts
#EXTINF:1.6,
/20221211/hGKuzpcg/1500kb/hls/JrtFsjzf.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/SgC5793u.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/gThtbsQL.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/NUucLVSy.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kscWjEl0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/KSfCRcNy.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YtemEUW3.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/k0Uec2r6.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/7FLd2DzP.ts
#EXTINF:2.92,
/20221211/hGKuzpcg/1500kb/hls/5MShzBqa.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Qlg0YNnm.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/s2hQBkQS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/V74FvrPE.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kej2TzNm.ts
#EXTINF:5.08,
/20221211/hGKuzpcg/1500kb/hls/Q09M3pDR.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/jKJdaVbh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/qYi5kuJc.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/6E8oQaZE.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/j6PE2rpH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Uzy1zTca.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Jgaw2ZuD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xKqnh88q.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/qQfeUmjc.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/MarAlpHS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/7H3cuL3f.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/uKFYgt2M.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/hXipEEDT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ITPcIC0i.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/GuQ2YydG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/yRQMMnYX.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RPqqzLjV.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/eAONqTeg.ts
#EXTINF:2,
/20221211/hGKuzpcg/1500kb/hls/5WAP4LZ7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/OWQekzry.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/u7WImoiY.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/dfQAUrJO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/2qomzxel.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/dZj8jrKN.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/z4Zemvrg.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/egnnmuVS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/x8tS8amy.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Ts3hX4pt.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/OD0mx1Xb.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/vFWoBglU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Y9yAHler.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xdBlN8pT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/gdhkztwQ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Rkuvd3aQ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ViuXTWfk.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/K5Md0ZsV.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/6sEnCWN3.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/2BnC5WAU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/5ryPAczb.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/0DjWRpW9.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/asQXksXl.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1rEhvrwP.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/zCzYnkZt.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RMSrdhfn.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9HVNorzt.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/sWgy5x1R.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/7bmVCeJz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/wfAEK1mu.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/WcwfbxXr.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HR3cuRIr.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/6G8W49n8.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9Cbn1Ri0.ts
#EXTINF:2.04,
/20221211/hGKuzpcg/1500kb/hls/ldSFI5s2.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Czs0EKmy.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/K0PZb2ON.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/hZWqwWRz.ts
#EXTINF:2.96,
/20221211/hGKuzpcg/1500kb/hls/4gg2jTuy.ts
#EXTINF:2.92,
/20221211/hGKuzpcg/1500kb/hls/HnHvekSY.ts
#EXTINF:3.48,
/20221211/hGKuzpcg/1500kb/hls/1AgKtMJ2.ts
#EXTINF:5.28,
/20221211/hGKuzpcg/1500kb/hls/PvIQ1ewF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/2zPUf3vj.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/IZneWtNW.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/cvxhcvSV.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/KTKZiLdC.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/UXT9wCMB.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/m01fUcT2.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/N2iw9ZHG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/7VOhVpP5.ts
#EXTINF:2.24,
/20221211/hGKuzpcg/1500kb/hls/svEAr375.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/hRvUKIDy.ts
#EXTINF:2.8,
/20221211/hGKuzpcg/1500kb/hls/tLCTGPv1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/CBgufhVe.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HTnajSLh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/wEGtFI78.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/aWvjMXmk.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9E8XYyYA.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/rSfxVZgd.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/412JxgqO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9W0fwfjj.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/rVaEfh2w.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/7UHW08tC.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/yfSc4Lbs.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/SvPQLOag.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/T7Mbzhca.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/IzUiHmNm.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/awvFujPL.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PNOQWfif.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ilQ5cP1b.ts
#EXTINF:2.8,
/20221211/hGKuzpcg/1500kb/hls/CnCjyDNp.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/cWJlKkol.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/sOMQ2f5u.ts
#EXTINF:4,
/20221211/hGKuzpcg/1500kb/hls/zw9xf54P.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/lyjlUtco.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/iausbjgL.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/A9E5HkiW.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/lIGw3xqu.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/UTBKdg1I.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/L2pL3qEW.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/dL63VJzx.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/c2x976Sa.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1cI69GO5.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HqiPGpo1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/0Ugu9PuO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RV1VXwe0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/4jWIt85V.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Mj1Ask4K.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/O2T8OOfx.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/pXeMcWqY.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/XuSM5Ffs.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/mO2Ch895.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/fjgjRz7d.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/AU60gHe6.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/mAFuXOBn.ts
#EXTINF:2.88,
/20221211/hGKuzpcg/1500kb/hls/8KjrNcFi.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YfvTNcTo.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xzTFPepa.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/P9QK7cul.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/OenhLOxG.ts
#EXTINF:2.16,
/20221211/hGKuzpcg/1500kb/hls/fZg28cQk.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/i9wfexpB.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/p2XbIkaD.ts
#EXTINF:4,
/20221211/hGKuzpcg/1500kb/hls/TJj5RLCa.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/E2IqbDME.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/r1ckkOmF.ts
#EXTINF:1.16,
/20221211/hGKuzpcg/1500kb/hls/Ux9UsYMw.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RHajJVqi.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/G0bZhXKU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/KjFhwIeE.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/vqg7h1dH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/68LsklIB.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/AjHYl2Mv.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9S11XgqJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Vk0Jcrqb.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/6hdYgUU1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/B6CLi3Yb.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/yc6CWkzR.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/FCPPOR6p.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/s6AhRlP7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/cuQZASvy.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1gnqOWss.ts
#EXTINF:3.72,
/20221211/hGKuzpcg/1500kb/hls/oW4WHEJK.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/QZlsn08X.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/p6lqiqxv.ts
#EXTINF:2.36,
/20221211/hGKuzpcg/1500kb/hls/8szv7uTq.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/M9vsiOUq.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/d8UdBlBT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/9y17kXW5.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/jCfy0UtL.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/cICjjV5y.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/AmngsmIe.ts
#EXTINF:5,
/20221211/hGKuzpcg/1500kb/hls/xDCDR6Sa.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/iBAEcQoN.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/DmgqmOwD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/D9kAmpsc.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ZZoMd2zp.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kr2Kv6Ir.ts
#EXTINF:1.72,
/20221211/hGKuzpcg/1500kb/hls/hyt1k9QT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/pK4Y7DkJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/8kwo1FIt.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/IMmGqcaQ.ts
#EXTINF:2.12,
/20221211/hGKuzpcg/1500kb/hls/npgQ6sRX.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/EcAdHvmT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/gx7Zg2ES.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/tGL2P2gM.ts
#EXTINF:2.4,
/20221211/hGKuzpcg/1500kb/hls/i4YUsedU.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/2KEsN1oA.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/MJrqfoCi.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/YEanQTlo.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/bDhTMGO5.ts
#EXTINF:5.72,
/20221211/hGKuzpcg/1500kb/hls/c4WCethp.ts
#EXTINF:1.92,
/20221211/hGKuzpcg/1500kb/hls/XLeXKlpV.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/OQQCSlQO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/dr3RMmFr.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/uADX8Sp2.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/8RyZ0T6x.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/JWQJz3Wy.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/k6SOTRpX.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/C9rJGjOz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/LHQjSdrA.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/07KXFbKR.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/fFuTCwta.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/8Zk6FCuS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PiY3TkVo.ts
#EXTINF:2.44,
/20221211/hGKuzpcg/1500kb/hls/0YZLlkX1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/P2246tm9.ts
#EXTINF:2.92,
/20221211/hGKuzpcg/1500kb/hls/dXcOUudD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/DdJEyxHT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/4cXzBphH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/GTAaGklJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/iQErF1k8.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PiOeiu4s.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/wI1gEd8w.ts
#EXTINF:4.2,
/20221211/hGKuzpcg/1500kb/hls/iO91VTab.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/euDXWw5o.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kn0FwDUN.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/nvOVz2FF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/FQ6vaZW5.ts
#EXTINF:2.2,
/20221211/hGKuzpcg/1500kb/hls/SQLL6Hqc.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kKg8rhRA.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/0m9MmSq3.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ewYNMU2O.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/MVQoRx1X.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/sMElGr4M.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PL85xClC.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/DYdFOyg6.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Cpg7ud5W.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/741sEaBj.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Dg2nTdu7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/4uvh4BGj.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HYEQASO1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/tjWVAe3e.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xqTIMEwS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/qmImKjd3.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/zbgHSi6z.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/H80hWM4j.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/llkfeAoh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/J2kxPyDm.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Ocwuphyq.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/AWEjMLZF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/vsSkRxXr.ts
#EXTINF:1.56,
/20221211/hGKuzpcg/1500kb/hls/tjvU36lt.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/cNrph6Mz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/XBgYTcU4.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/mcKdWSov.ts
#EXTINF:2.92,
/20221211/hGKuzpcg/1500kb/hls/TqNvZWk8.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/fa7Q6ioG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/CTfmz9IY.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/icJukMtG.ts
#EXTINF:5.28,
/20221211/hGKuzpcg/1500kb/hls/q14kdABk.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/f3jzrS76.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/LDHPMEbG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/pQl1U0XP.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/LZe73L26.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/zA6neevg.ts
#EXTINF:1.16,
/20221211/hGKuzpcg/1500kb/hls/dZO9dVJM.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/gGTqppz5.ts
#EXTINF:2.84,
/20221211/hGKuzpcg/1500kb/hls/B5Gj6j8b.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/8KPK14XW.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/VVsd9XEw.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/crW65O2K.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/w8Bzrw6M.ts
#EXTINF:2.84,
/20221211/hGKuzpcg/1500kb/hls/MF8mht7R.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/PYSzDOBX.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/AgnYZqEW.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/4I76fvhi.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/6gc7giI5.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/lBEB1vJB.ts
#EXTINF:4.44,
/20221211/hGKuzpcg/1500kb/hls/rrYFAcpF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ijb5fN2Q.ts
#EXTINF:2.92,
/20221211/hGKuzpcg/1500kb/hls/h1PJqy8f.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/g4yxTrc2.ts
#EXTINF:1.56,
/20221211/hGKuzpcg/1500kb/hls/ResJn4hg.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/0lDKk2XJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/w047I8lx.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/OSQIcWYv.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/DetZe5RA.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ANwFaA6V.ts
#EXTINF:4.96,
/20221211/hGKuzpcg/1500kb/hls/ybBwUcHr.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/oA0m6peT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/K3t6hxP6.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/vEa6oac7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/3z4xdXkh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/idP0VIs6.ts
#EXTINF:3.88,
/20221211/hGKuzpcg/1500kb/hls/VPUZvdCp.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xeQk64Un.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/8Miujvm2.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/IqNs0iDY.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/GwaAdmf1.ts
#EXTINF:2.24,
/20221211/hGKuzpcg/1500kb/hls/MFQE0uCZ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Y19MELpn.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/CrdYrK0f.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/656wMCj1.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/W0Rvk4Ar.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ZDVysGjf.ts
#EXTINF:2.76,
/20221211/hGKuzpcg/1500kb/hls/Mabswgkn.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/3JYponPG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/SCR8qdT0.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/OjfViHMd.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/I0fiyW70.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/HZ9b8VQz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/virWt4vn.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/F7KTlIft.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/VDSrv8Eh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/32ykR0RJ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/M0LVjz5w.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/hy7nOU2k.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/jh5ERg8L.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/DZjjhg0I.ts
#EXTINF:1.72,
/20221211/hGKuzpcg/1500kb/hls/ijpkkFDT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/1Egf4hXt.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/pZ3hMD8j.ts
#EXTINF:2.72,
/20221211/hGKuzpcg/1500kb/hls/PFW5kR1Z.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/q76c6S5B.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/QjqgvhvO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/l2O8Vu5l.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/QpMhN4T7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/wgfFG7TP.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kz9Gy8Xn.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/NP6rDfEu.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xhR5pwyG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/rf1ogMWm.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/duFLU787.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/xBjCF0uS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/pPedbNdf.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/SK2haOHO.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/0SHeb2RZ.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/v7ikAG3d.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/qQU8zoB2.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/TD6LdkfF.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/KVZAT7FD.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/RPGok0L5.ts
#EXTINF:5.04,
/20221211/hGKuzpcg/1500kb/hls/fb2ZEUqf.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/cJ4jeuYh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/kZ3xlxwR.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/5zyNu2mh.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/N0Es2XYa.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/VXsy4BI2.ts
#EXTINF:2.08,
/20221211/hGKuzpcg/1500kb/hls/na7vKGpH.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/cx9SSLTG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/Fd1JMCsl.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/gVLRydGJ.ts
#EXTINF:2.44,
/20221211/hGKuzpcg/1500kb/hls/b4KhwvfG.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/mTN4FU2z.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ldPmNZmi.ts
#EXTINF:2.68,
/20221211/hGKuzpcg/1500kb/hls/wx8mo0R7.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/lKHUGtek.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/InZNQjgS.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/2Nmb5TXB.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/rZmQrgIv.ts
#EXTINF:4.64,
/20221211/hGKuzpcg/1500kb/hls/mjz5JAQY.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/nhCx9hQV.ts
#EXTINF:1.64,
/20221211/hGKuzpcg/1500kb/hls/17zySDyz.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/MAq4InnT.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/3LWWajPx.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/gL1ecw3L.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/ojJzhQQN.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/UgYMvyW8.ts
#EXTINF:3,
/20221211/hGKuzpcg/1500kb/hls/uJ321Hys.ts
#EXTINF:5,
/20221211/hGKuzpcg/1500kb/hls/16sQ0nr7.ts
#EXTINF:1.08,
/20221211/hGKuzpcg/1500kb/hls/2xtvGzjP.ts
#EXT-X-ENDLIST

Extensions to RFC 8216 HTTP Live Streaming

Hi,
We're working on implementing a parser dealing with a scte-35 Dynamic Ad Insertion extension.
Is that something you would be potentially interested in as a contribution to the library?

We currently are using the m3u8-parser library for playlist parsing. We need to add support for the SCTE-35. For us it would make sense to support it as a lib extension. We wanted to know your opinion. We are happy to discuss the format of this extension and contribute if you're interested.

Provider "http" not installed

I am getting this error

java.nio.file.FileSystemNotFoundException: Provider "http" not installed at java.base/java.nio.file.Path.of(Path.java:212) at java.base/java.nio.file.Paths.get(Paths.java:98)

When I read playlist

MasterPlaylist playlist = parser.readPlaylist(Paths.get(new URI(sourceUrl)));

Parser doesn't like PROGRAM-ID attribute

Hi,

I'm generating manifests via AWS Elastic Transcoder, and they come with PROGRAM-ID:

#EXT-X-I-FRAME-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=29971000,CODECS="avc1.4d001f",URI="output/2M_iframe.m3u8"

But when I try to parse, I get:

io.lindstrom.m3u8.parser.PlaylistParserException: Unknown key PROGRAM-ID
at io.lindstrom.m3u8.parser.IFrameParser.parseAttributes(IFrameParser.java:43)
at io.lindstrom.m3u8.parser.IFrameParser.parseAttributes(IFrameParser.java:9)
at io.lindstrom.m3u8.parser.AbstractLineParser.parse(AbstractLineParser.java:33)
at io.lindstrom.m3u8.parser.AbstractLineParser.parse(AbstractLineParser.java:24)
at io.lindstrom.m3u8.parser.MasterPlaylistParser.onTag(MasterPlaylistParser.java:65)
at io.lindstrom.m3u8.parser.MasterPlaylistParser.onTag(MasterPlaylistParser.java:34)
at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:93)
at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:59)
at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:19)

Thanks.

EXT-X-CUE-OUT parsing fails on non-integer data

Occasionally I see the following exception:

 java.lang.NumberFormatException: For input string: "89.990"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
    at java.base/java.lang.Integer.parseInt(Integer.java:660)
    at java.base/java.lang.Integer.parseInt(Integer.java:778)
    at io.lindstrom.m3u8.parser.MediaSegmentTag$5.read(MediaSegmentTag.java:69)
    at io.lindstrom.m3u8.parser.MediaSegmentTag$5.read(MediaSegmentTag.java:66)
    at io.lindstrom.m3u8.parser.MediaPlaylistParser.onTag(MediaPlaylistParser.java:53)
    at io.lindstrom.m3u8.parser.MediaPlaylistParser.onTag(MediaPlaylistParser.java:32)
    at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:92)
    at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:58)
    at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:18)

See https://docs.aws.amazon.com/medialive/latest/ug/sample-manifests-hls.html

How to add tag "#EXT-X-DISCONTINUITY" between mediaSegments

I want to build a m3u8 like this

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:15
#EXTINF:15.034000
a.ts
#EXT-X-DISCONTINUITY
#EXTINF:15.034000
a.ts
#EXT-X-ENDLIST

and my code

MediaPlaylist src = parser.readPlaylist(Paths.get("1.m3u8"));

        System.out.println(parser.writePlaylistAsString(src));
        MediaPlaylist.Builder builder = MediaPlaylist.builder()
            .version(src.version())
                .allowCache(true)
                .targetDuration(20)
                .mediaSequence(0);
        builder.addAllMediaSegments(src.mediaSegments());
        builder.addAllMediaSegments(src.mediaSegments());
 MediaPlaylist dst = builder.build();
        System.out.println(parser.writePlaylistAsString(dst));

product

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:15
#EXTINF:15.034000
a.ts
#EXTINF:15.034000
a.ts
#EXT-X-ENDLIST

Consider removing the dependency on java.util.Optional

java.util.Optional was only introduced on Android at API level 24 (7.0)

This can be restrictive for a lot of Android projects out there. The most common supported version is currently API level 21 (5.0)

There are multiple different approaches on how to replace this dependency, but I reckon the best would probably be implementing an Optional Class in the same structure as the java.util one.

something like this would probably be enough:

import java.util.Objects;

public class Optional<T> {

    private T value;

    private Optional() {
        this.value = null;
    }

    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    public static<T> Optional<T> empty() {
        return new Optional<>();
    }

    public static<T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    public interface Action<T> {
        void apply(T value);
    }

    public void ifPresent(Action<T> action) {
        if (value != null) {
            action.apply(value);
        }
    }
}

Missing sourcecode of MediaSegmentBuilder.java for m3u8-parser:0.17

While experimenting with m8u playlist-files using m3u8-parser:0.17 from https://repo1.maven.org/maven2/io/lindstrom/m3u8-parser/0.17/ i got an excpetion

Cannot build MediaSegment, some of required attributes are not set [duration]
java.lang.IllegalStateException: Cannot build MediaSegment, some of required attributes are not set [duration]
	at io.lindstrom.m3u8.model.MediaSegmentBuilder.build(MediaSegmentBuilder.java:325)
	at io.lindstrom.m3u8.model.MediaSegment$Builder.build(MediaSegment.java:52)
	at io.lindstrom.m3u8.parser.MediaPlaylistParser.onURI(MediaPlaylistParser.java:53)
	at io.lindstrom.m3u8.parser.MediaPlaylistParser.onURI(MediaPlaylistParser.java:32)

When looking into the sourcecode at https://github.com/carlanton/m3u8-parser/ i saw that there is no class io.lindstrom.m3u8.model.MediaSegmentBuilder so i assume that some files are missing at https://github.com/carlanton/m3u8-parser/ that where used to create m3u8-parser:0.17

Add comments to a generated playlist

RFC 8216 allows for comments to be included in a manifest. They are any line that starts with a # and does not then have EXT as the following three characters. (section 4.1, paragraph 3)

Options

    • (media playlist) Have all comments as a block immediately preceding the media segments.
    • (master playlist) Have all comments as a block immediately preceding the renditions.
  1. (both playlists) Attempt to introduce some ordering to the tags, allowing for comments between tags, and around media segments, renditions and variants.

Option (1) looks to be the easiest, however, (2) allows for more flexibility.

Feature Request: Support writing individual media segment to string

Hello! Not sure if this is already possible (I couldn't find how to do this), but I'm interested in getting the string representation of individual media segments instead of the entire playlist.

The reason is that we maintain an HLS server where we append segments to a playlist on disk as we construct new media segments, and it would be nice if we could use the m3u8-parser logic to generate the string representation instead of either having to parse the existing playlist or try to construct the string representation externally.

I'm happy to put up a PR for this, but wanted to check if this generally seems like a sensible addition?

Thank you!

Consider adding support for CODECS attribute on EXT-X-MEDIA:TYPE=AUDIO

Support for CODECS attribute for EXT-X-MEDIA tag is missing. Here is a sample HLS Live manifest:

#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",CODECS="ac-3",LANGUAGE="spa",NAME="spa-487",AUTOSELECT=YES,DEFAULT=YES,URI=".swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_1/index_new_a_1_0.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",CODECS="ac-3",LANGUAGE="fra",NAME="fra-488",AUTOSELECT=YES,DEFAULT=NO,URI=".swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_1/index_new_a_1_1.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",CODECS="ac-3",LANGUAGE="eng",NAME="eng-486",AUTOSELECT=YES,DEFAULT=NO,URI=".swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_1/index_new_a_1_2.m3u8"
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4023828,CODECS="avc1.64002A,ac-3",RESOLUTION=1920x1080,AUDIO="audio"
.swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_4023828/index_new_v_4023828_5.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2710228,CODECS="avc1.42801F,ac-3",RESOLUTION=1280x720,AUDIO="audio"
.swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_2710228/index_new_v_2710228_4.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2355328,CODECS="avc1.42801F,ac-3",RESOLUTION=960x540,AUDIO="audio"
.swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_2355328/index_new_v_2355328_3.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2200728,CODECS="avc1.42801E,ac-3",RESOLUTION=640x360,AUDIO="audio"
.swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_2200728/index_new_v_2200728_2.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2073728,CODECS="avc1.42801E,ac-3",RESOLUTION=480x360,AUDIO="audio"
.swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_2073728/index_new_v_2073728_1.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2044928,CODECS="avc1.42801E,ac-3",RESOLUTION=320x180,AUDIO="audio"
.swn3c0d53a7-eb88-490f-a643-000000000000apple2apple/.rate_2044928/index_new_v_2044928_0.m3u8

Unrecognized field "laurl"

SEVERE: An exception happened during parsing MPD with message : Unrecognized field "laurl" (class io.lindstrom.mpd.data.descriptor.protection.WidewineProtection), not marked as ignorable (4 known properties: "pssh", "value", "id", "schemeIdUri"])
at [Source: (StringReader); line: 2, column: 1108] (through reference chain: io.lindstrom.mpd.data.MPD["Period"]->java.util.ArrayList[0]->io.lindstrom.mpd.data.Period["AdaptationSet"]->java.util.ArrayList[0]->io.lindstrom.mpd.data.AdaptationSet["ContentProtection"]->java.util.ArrayList[1]->io.lindstrom.mpd.data.descriptor.protection.WidewineProtection["laurl"])

Documentation:
https://dashif-documents.azurewebsites.net/Guidelines-Security/master/Guidelines-Security.html#CPS-mpd-drm-config

Handle URI's containing a comma character

Hello, in our system we have a common appearance of a live stream HLS master playlist that contains a comma character (for rerouting between streamers/servers) in URIs, like so:

`
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:BANDWIDTH=1496000,FRAME-RATE=25.000,RESOLUTION=856x480
http://5.22.186.164:8080/stream/?fw=true&route=sbb-bg-ku-h1-22,sbb-bg-ne-h1-14&rule=11,null&sp=unitedcloud&asset=masaimedved102srb-hd-p-srpsub&stream=hp1400&conn=UNKNOWN&nf=3&b=3&player=m3u8v&t=36000&adaptive=false&orig=true

#EXT-X-STREAM-INF:BANDWIDTH=446000,FRAME-RATE=25.000,RESOLUTION=512x288
http://5.22.186.164:8080/stream/playlist/hls/?session=e02569a4-5fee-4503-81a2-03ffd859c193&stream=hp350&player=m3u8v

#EXT-X-STREAM-INF:BANDWIDTH=3596000,FRAME-RATE=25.000,RESOLUTION=1920x1080
http://5.22.186.164:8080/stream/playlist/hls/?session=e02569a4-5fee-4503-81a2-03ffd859c193&stream=hp3500&player=m3u8v

#EXT-X-STREAM-INF:BANDWIDTH=7096000,FRAME-RATE=25.000,RESOLUTION=1920x1080
http://5.22.186.164:8080/stream/playlist/hls/?session=e02569a4-5fee-4503-81a2-03ffd859c193&stream=hp7000&player=m3u8v
`

We love using your library, however the URL of the first variant list here is read only until the first ',' character, and thus is incomplete. Would you consider patching so that these kind of URI's are handled properly?

Thanks and keep up the excellent work and contribution!

#EXT-X-DATERANGE limited to 1 per media segment

First off, great library, it's very useful!

I have an issue where I need to add multiple dateRange objects within a playlist. (For simplicity, let's say it's an example where I have 1 media segment that is 10 seconds long, and I want to fire timed meta data at the 0 second mark and the 5 second mark).

Currently, there is no way to do this, as dateRange is a single attribute of MediaSegmentBuilder. I am only able to associate 1 dateRange object with 1 Media Segment.

According to the spec, I think dateRange should not be an attribute of MediaSegmentBuilder, but instead, MediaPlaylist.Builder and should be a collection: https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.2.7

Alternatively, I considered two other solutions:

  1. Change the dateRange attribute on MediaSegmentBuilder to be a collection
    or
  2. Allow the creation of Media Segments without a duration/uri (which is currently required), and create Media Segment containers that are essentially empty except for 1 date range attribute.

What are your thoughts?

#EXT-X-PART BYTERANGE attribute serialization doesn't comply with the HLS spec

What's the issue?

As for the HLS spec, the #EXT-X-PART BYTERANGE attribute:

BYTERANGE: Indicates that the Partial Segment is a sub-range of the resource specified by the URI attribute. The value is a quoted-string whose contents have the same format as the EXT-X-BYTERANGE tag: "[@]". If o is not present, the sub-range begins at the next byte following the sub-range of the previous Partial Segment belonging to the same Parent Segment.

The value is a quoted-string, however, the current serialization doesn't add quotes to the BYTERANGE, as we can see here.

Expected solution

Add quotes to the BYTERANGE string

Why such strict attribute parsing?

I noticed that the attribute parsing was fairly strict. Throwing an exception for unknown attributes.

I've run into an issue where an older playlist fails to parse because it follows v12 of the spec. Which used to include the FRAME-RATE attribute in the EXT-X-I-FRAME-STREAM-INF tag.

I know that your README specifies the spec that it complies with, I was just curious why you didn't continue the loop at the line of code linked above? We really like this library, and will likely end up just publishing a modified version to our internal Maven repo.

Before we do that, I was just wondering if you had a solution to this that wouldn't require modifying the library code? From briefly looking through the code it looks like I could extend some of the models and implement my own MasterPlaylistParser that uses an alternative master playlist class, etc. Would there be a more simple approach?

Overall really nice implementation tho!

Consider formatting the output of MediaSegment's duration

I found a input M3u8 playlist like this:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:53
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:11.528000,
5UkiTad9_3021444571_copy0.ts
#EXTINF:9.118000,
5UkiTad9_3021444571_copy1.ts
#EXTINF:52.569000,
5UkiTad9_3021444571_copy2.ts
#EXTINF:6.658000,
5UkiTad9_3021444571_copy3.ts
#EXTINF:0.673000,
5UkiTad9_3021444571_copy4.ts
#EXTINF:2.254000,
5UkiTad9_3021444571_copy5.ts
#EXTINF:2.239000,
5UkiTad9_3021444571_copy6.ts
#EXTINF:0.960000,
5UkiTad9_3021444571_copy7.ts
#EXTINF:0.000011,
5UkiTad9_3021444571_copy8.ts
#EXT-X-ENDLIST

Notice the last media segment, it's duration is very small(0.000011), if I use this lib to parse and output this file, the output will be:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:53
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:11.528,
5UkiTad9_3021444571_copy0.ts
#EXTINF:9.118,
5UkiTad9_3021444571_copy1.ts
#EXTINF:52.569,
5UkiTad9_3021444571_copy2.ts
#EXTINF:6.658,
5UkiTad9_3021444571_copy3.ts
#EXTINF:0.673,
5UkiTad9_3021444571_copy4.ts
#EXTINF:2.254,
5UkiTad9_3021444571_copy5.ts
#EXTINF:2.239,
5UkiTad9_3021444571_copy6.ts
#EXTINF:0.96,
5UkiTad9_3021444571_copy7.ts
#EXTINF:1.1E-5,
5UkiTad9_3021444571_copy8.ts
#EXT-X-ENDLIST

The parse code is very simple:

MediaPlaylist newPlaylist = MediaPlaylist.builder().allowCache(true).from(playlist).build();
System.out.println(parser.writePlaylistAsString(newPlaylist));

You can see that the duration of the last segment is expressed in scientific notation, which will cause play problems. If I play this m3u8 file in the default HLS player of iOS, the media will be treated as a live stream instead of a ended playList.

So I wonder if formatting can be used to output the media segment's duration? like String.fromat("%.6f", duration)

Support VIDEO-RANGE attribute

Hi Anton,

After packaging my media with the Shaka Packager and trying to parse the resulting m3u8 with this parser, it throws the exception

io.lindstrom.m3u8.parser.PlaylistParserException: Unknown key VIDEO-RANGE

VIDEO-RANGE is an attribute in a draft of RFC 8216 and has the values "PQ" or "SDR":
https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-06

Is it possible to add this attribute? I'll create a pull request for it as well.

always NoClassDefFoundError is thrown on Android under api 26

Reproduce

run MediaPlaylistParser().readPlaylist(string) on android that is under api 26

Stacktrace

Caused by java.lang.ClassNotFoundException: Didn't find class "java.time.format.DateTimeFormatterBuilder" on path: DexPathList[[zip file "/data/app/${MyPackageName}-1/base.apk", zip file "/data/app/${MyPackageName}-1/split_config.arm64_v8a.apk", zip file "/data/app/${MyPackageName}-1/split_config.ja.apk", zip file "/data/app/${MyPackageName}-1/split_config.xhdpi.apk"],nativeLibraryDirectories=[/data/app/${MyPackageName}-1/lib/arm64, /vendor/lib64, /system/lib64]]
       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
       at io.lindstrom.m3u8.parser.MediaPlaylistParser.<clinit>(MediaPlaylistParser.java)
       at be.tramckrijte.workmanager.DownloadClient$requestMediaPlaylist$1.onFailure(DownloadClient.java)
       at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.java)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:831)

this is because some Java 8 APIs(ex. java.time.*) isn't supported under android api level 26.

So when running code on android that is older than 26, we must apply core library desugaring to the app.
I think it's worth to append that to the readme file.

Missing url when parsing m3u8

When I parse a lot of m3u8 in a linux environment, I find that some of the files are missing the last url, but I can't reproduce it locally
MediaPlaylist playlist = parser.readPlaylist(Paths.get(file.getAbsolutePath()));
List<MediaSegment> mediaSegments = playlist.mediaSegments();
LOG.info("m3u8 parser from sdk size is {}", mediaSegments.size());

sometime is nīŧŒ sometime is n-1

#EXT-X-DEFINE uses "NAME" as value of variable name

in master playlist, there were multiple variables in #EXT-X-DEFINE. I used variable.name().get(), the return value is "NAME", not the value of name=

for instance:
#EXT-X-DEFINE:NAME="my issue report", VALUE="variable tag issue"
the return of variable.name().get()=NAME

Defect with `EXT_X_PROGRAM_DATE_TIME` format

Regarding to https://tools.ietf.org/html/rfc8216#section-4.3.2.6

#EXT-X-PROGRAM-DATE-TIME:

where date-time-msec is an ISO/IEC 8601:2004 [ISO_8601] date/time
representation, such as YYYY-MM-DDThh:mm:ss.SSSZ. It SHOULD indicate
a time zone and fractional parts of seconds, to millisecond accuracy.

For example:

#EXT-X-PROGRAM-DATE-TIME:2010-02-19T14:54:23.031+08:00

but

mediaSegment.programDateTime().ifPresent(value -> textBuilder.addTag(tag(), value.toString()));

here value is an object of OffsetDateTime, which toString() calls java.time.LocalDateTime#toString, then let's check java.time.LocalTime#toString, notice this is not a fixed format, does not meet the requirement of rfc8216 in case of System.out.println(OffsetDateTime.parse("2020-06-30T23:52:00+08:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME).toString());

Tag not implemented: EXT-X-TARGETDURATION

W/System.err: io.lindstrom.m3u8.parser.PlaylistParserException: Tag not implemented: EXT-X-TARGETDURATION
at io.lindstrom.m3u8.parser.MasterPlaylistParser.onTag(MasterPlaylistParser.java:67)
at io.lindstrom.m3u8.parser.MasterPlaylistParser.onTag(MasterPlaylistParser.java:31)
W/System.err: at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:92)
at io.lindstrom.m3u8.parser.AbstractPlaylistParser.readPlaylist(AbstractPlaylistParser.java:58
Capture3
)

Unknown attribute: NAME

File master.m3u8

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1662976,RESOLUTION=1280x720,NAME="720"
720p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=884736,RESOLUTION=854x480,NAME="480"
480p.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2691072,RESOLUTION=1920x1080,NAME="1080"
1080p.m3u8

Code:

new MasterPlaylistParser().readPlaylist(dir.resolve("master.m3u8"));

Throws: io.lindstrom.m3u8.parser.PlaylistParserException: Unknown attribute: NAME
Expected: parsed playlist.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤ī¸ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.