Skip to content
This repository has been archived by the owner on Nov 22, 2022. It is now read-only.

Adding support for tags EXT-X-INDEPENDENT-SEGMENTS, EXT-X-PROGRAM-DATE-TIME. #57

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/java/com/iheartradio/m3u8/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ final class Constants {
public static final String IN_STREAM_ID = "INSTREAM-ID";
public static final String CHARACTERISTICS = "CHARACTERISTICS";

public static final String EXT_X_INDEPENDENT_SEGMENTS = "EXT-X-INDEPENDENT-SEGMENTS";
public static final String EXT_X_STREAM_INF_TAG = "EXT-X-STREAM-INF";
public static final String EXT_X_I_FRAME_STREAM_INF_TAG = "EXT-X-I-FRAME-STREAM-INF";
public static final String BANDWIDTH = "BANDWIDTH";
Expand All @@ -58,6 +59,7 @@ final class Constants {
// media playlist tags

public static final String EXT_X_PLAYLIST_TYPE_TAG = "EXT-X-PLAYLIST-TYPE";
public static final String EXT_X_PROGRAM_DATE_TIME_TAG = "EXT-X-PROGRAM-DATE-TIME";
public static final String EXT_X_TARGETDURATION_TAG = "EXT-X-TARGETDURATION";
public static final String EXT_X_START_TAG = "EXT-X-START";
public static final String TIME_OFFSET = "TIME-OFFSET";
Expand All @@ -83,6 +85,7 @@ final class Constants {
public static final String NO = "NO";
private static final String INTEGER_REGEX = "\\d+";
private static final String SIGNED_FLOAT_REGEX = "-?\\d*\\.?\\d*";
private static final String TIMESTAMP_REGEX = "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3})?(?:Z?|\\+\\d{2}:\\d{2})?";

public static final Pattern HEXADECIMAL_PATTERN = Pattern.compile("^0[x|X]([0-9A-F]+)$");
public static final Pattern RESOLUTION_PATTERN = Pattern.compile("^(" + INTEGER_REGEX + ")x(" + INTEGER_REGEX + ")$");
Expand All @@ -91,6 +94,7 @@ final class Constants {
public static final Pattern EXT_X_TARGETDURATION_PATTERN = Pattern.compile("^#" + EXT_X_TARGETDURATION_TAG + EXT_TAG_END + "(" + INTEGER_REGEX + ")$");
public static final Pattern EXT_X_MEDIA_SEQUENCE_PATTERN = Pattern.compile("^#" + EXT_X_MEDIA_SEQUENCE_TAG + EXT_TAG_END + "(" + INTEGER_REGEX + ")$");
public static final Pattern EXT_X_PLAYLIST_TYPE_PATTERN = Pattern.compile("^#" + EXT_X_PLAYLIST_TYPE_TAG + EXT_TAG_END + "(EVENT|VOD)$");
public static final Pattern EXT_X_PROGRAM_DATE_TIME_PATTERN = Pattern.compile("^#" + EXT_X_PROGRAM_DATE_TIME_TAG + EXT_TAG_END + "(" + TIMESTAMP_REGEX + ")$");
public static final Pattern EXT_X_MEDIA_IN_STREAM_ID_PATTERN = Pattern.compile("^CC[1-4]|SERVICE(?:[1-9]|[1-5]\\d|6[0-3])$");
public static final Pattern EXTINF_PATTERN = Pattern.compile("^#" + EXTINF_TAG + EXT_TAG_END + "(" + SIGNED_FLOAT_REGEX + ")(?:,(.+)?)?$");
public static final Pattern EXT_X_ENDLIST_PATTERN = Pattern.compile("^#" + EXT_X_ENDLIST_TAG + "$");
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/iheartradio/m3u8/ExtendedM3uParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class ExtendedM3uParser extends BaseM3uParser {
ExtLineParser.EXTM3U_HANDLER,
ExtLineParser.EXT_X_VERSION_HANDLER,
MediaPlaylistLineParser.EXT_X_PLAYLIST_TYPE,
MediaPlaylistLineParser.EXT_X_PROGRAM_DATE_TIME,
MediaPlaylistLineParser.EXT_X_KEY,
MediaPlaylistLineParser.EXT_X_TARGETDURATION,
MediaPlaylistLineParser.EXT_X_START,
Expand All @@ -28,6 +29,7 @@ class ExtendedM3uParser extends BaseM3uParser {
MasterPlaylistLineParser.EXT_X_MEDIA,
MediaPlaylistLineParser.EXT_X_ALLOW_CACHE,
MasterPlaylistLineParser.EXT_X_STREAM_INF,
MasterPlaylistLineParser.EXT_X_INDEPENDENT_SEGMENTS,
MasterPlaylistLineParser.EXT_X_I_FRAME_STREAM_INF,
MediaPlaylistLineParser.EXTINF,
MediaPlaylistLineParser.EXT_X_ENDLIST,
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/iheartradio/m3u8/MasterPlaylistLineParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,24 @@ public void parse(String line, ParseState state) throws ParseException {
state.getMaster().streamInfo = builder.build();
}
};

static final IExtTagParser EXT_X_INDEPENDENT_SEGMENTS = new IExtTagParser() {
private final LineParser mLineParser = new MasterPlaylistLineParser(this);
private final Map<String, AttributeParser<StreamInfo.Builder>> HANDLERS = makeExtStreamInfHandlers(getTag());

@Override
public String getTag() {
return Constants.EXT_X_INDEPENDENT_SEGMENTS;
}

@Override
public boolean hasData() {
return false;
}

@Override
public void parse(String line, ParseState state) throws ParseException { }
};

static <T extends StreamInfoBuilder> Map<String, AttributeParser<T>> makeExtStreamInfHandlers(final String tag) {
final Map<String, AttributeParser<T>> handlers = new HashMap<>();
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/iheartradio/m3u8/MediaParseState.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class MediaParseState implements IParseState<MediaPlaylist> {
public TrackInfo trackInfo;
public EncryptionData encryptionData;
public StartData startData;
public String playlistDateTime;
public boolean endOfList;
public boolean hasDiscontinuity;

Expand Down
27 changes: 27 additions & 0 deletions src/main/java/com/iheartradio/m3u8/MediaPlaylistLineParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,33 @@ public void parse(String line, ParseState state) throws ParseException {
}
};

static final IExtTagParser EXT_X_PROGRAM_DATE_TIME = new IExtTagParser() {
private final LineParser lineParser = new MediaPlaylistLineParser(this);

@Override
public String getTag() {
return Constants.EXT_X_PROGRAM_DATE_TIME_TAG;
}

@Override
public boolean hasData() {
return true;
}

@Override
public void parse(String line, ParseState state) throws ParseException {
lineParser.parse(line, state);

final Matcher matcher = ParseUtil.match(Constants.EXT_X_PROGRAM_DATE_TIME_PATTERN, line, getTag());

if (state.getMedia().playlistDateTime != null) {
throw ParseException.create(ParseExceptionType.MULTIPLE_EXT_TAG_INSTANCES, getTag(), line);
}

state.getMedia().playlistDateTime = ParseUtil.parseDateTime(line,getTag());
}
};

static final IExtTagParser EXT_X_START = new IExtTagParser() {
private final LineParser lineParser = new MediaPlaylistLineParser(this);
private final Map<String, AttributeParser<StartData.Builder>> HANDLERS = new HashMap<>();
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/iheartradio/m3u8/ParseExceptionType.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum ParseExceptionType {
INVALID_MEDIA_TYPE("invalid media TYPE"),
INVALID_RESOLUTION_FORMAT("a resolution was not formatted properly"),
INVALID_QUOTED_STRING("a quoted string was not properly formatted"),
INVALID_DATE_TIME_FORMAT("a date-time string was not properly formatted"),
MASTER_IN_MEDIA("master playlist tags we found in a media playlist"),
MEDIA_IN_MASTER("media playlist tags we found in a master playlist"),
MISSING_ATTRIBUTE_NAME("missing the name of an attribute"),
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/iheartradio/m3u8/ParseUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ public static <T extends Enum<T>> T parseEnum(String string, Class<T> enumType,
throw ParseException.create(ParseExceptionType.NOT_JAVA_ENUM, tag, string);
}
}

public static String parseDateTime(String string, String tag) throws ParseException {
Matcher matcher = Constants.EXT_X_PROGRAM_DATE_TIME_PATTERN.matcher(string);

if (!matcher.matches()) {
throw new ParseException(ParseExceptionType.INVALID_DATE_TIME_FORMAT, tag);
}

return matcher.group(1);
}

public static float parseFloat(String string, String tag) throws ParseException {
try {
Expand Down