diff --git a/src/main/java/com/mykola2312/mptv/parser/M3U.java b/src/main/java/com/mykola2312/mptv/parser/M3U.java index 5a64dae..d3b0938 100644 --- a/src/main/java/com/mykola2312/mptv/parser/M3U.java +++ b/src/main/java/com/mykola2312/mptv/parser/M3U.java @@ -1,64 +1,39 @@ package com.mykola2312.mptv.parser; -import java.util.ArrayList; -import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.checkerframework.checker.nullness.qual.NonNull; -import com.mykola2312.mptv.parser.M3UException.Type; - public class M3U { - public class Item { - @NonNull - public String title; + @NonNull + public String title; - public String groupTitle; - public String tvgLogo; + public String groupTitle; + public String tvgLogo; - @NonNull - public String url; + @NonNull + public String url; + + public M3U(String tags, String title) { + parseTags(tags); + this.title = title; } - public ArrayList items = new ArrayList<>(); + private static final Pattern EXTINF_TAG = Pattern.compile("^(.*)=\"(.*)\""); - public M3U(ArrayList items) { - this.items = items; - } + private void parseTags(String tags) { + for (String tag : tags.split(" ")) { + Matcher matcher = EXTINF_TAG.matcher(tag); + if (matcher.find()) { + String name = matcher.group(1); + String value = matcher.group(2); - private static final Pattern HEADER = Pattern.compile("^#EXTM3U"); - private static final Pattern EXTINF = Pattern.compile("^(?:#EXTINF:-?\\d\\s*)(.*?),(.*)$"); - - public static M3U parse(String data) throws M3UException { - ArrayList items = new ArrayList<>(); - - // state - boolean headerLine = true; - - try (Scanner scanner = new Scanner(data)) { - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - - if (headerLine) { - Matcher matcher = HEADER.matcher(line); - if (!matcher.find()) { - throw new M3UException(Type.NOT_AN_M3U); - } - - headerLine = false; - } else { - Matcher matcher = EXTINF.matcher(line); - if (matcher.find()) { - String tags = matcher.group(1); - String title = matcher.group(2); - - System.out.printf("tags: %s | title: %s\n", tags, title); - } + switch (name) { + case "group-title" -> groupTitle = value; + case "tvg-logo" -> tvgLogo = value; } } } - - return new M3U(items); } } diff --git a/src/main/java/com/mykola2312/mptv/parser/M3UParser.java b/src/main/java/com/mykola2312/mptv/parser/M3UParser.java new file mode 100644 index 0000000..4aaed47 --- /dev/null +++ b/src/main/java/com/mykola2312/mptv/parser/M3UParser.java @@ -0,0 +1,66 @@ +package com.mykola2312.mptv.parser; + +import java.util.ArrayList; +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.mykola2312.mptv.parser.M3UException.Type; + +public class M3UParser { + private static final Pattern HEADER = Pattern.compile("^#EXTM3U"); + private static final Pattern EXTINF = Pattern.compile("^(?:#EXTINF:-?\\d\\s*)(.*?),(.*)$"); + + private enum ParserState { + HEADER_LINE, + EXTINF_LINE, + URL_LINE + } + + public static ArrayList parse(String data) throws M3UException { + ArrayList items = new ArrayList<>(); + + ParserState state = ParserState.HEADER_LINE; + M3U item = null; + + try (Scanner scanner = new Scanner(data)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + + switch (state) { + case HEADER_LINE -> { + Matcher matcher = HEADER.matcher(line); + if (!matcher.find()) { + throw new M3UException(Type.NOT_AN_M3U); + } + + state = ParserState.EXTINF_LINE; + } + + case EXTINF_LINE -> { + Matcher matcher = EXTINF.matcher(line); + if (matcher.find()) { + String tags = matcher.group(1); + String title = matcher.group(2); + + item = new M3U(tags, title); + + state = ParserState.URL_LINE; + } + } + + case URL_LINE -> { + String url = line; + + item.url = url; + items.add(item); + + state = ParserState.EXTINF_LINE; + } + } + } + } + + return items; + } +} diff --git a/src/test/java/com/mykola2312/mptv/TestM3U.java b/src/test/java/com/mykola2312/mptv/TestM3U.java new file mode 100644 index 0000000..80017ce --- /dev/null +++ b/src/test/java/com/mykola2312/mptv/TestM3U.java @@ -0,0 +1,48 @@ +package com.mykola2312.mptv; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +import com.mykola2312.mptv.parser.M3U; +import com.mykola2312.mptv.parser.M3UException; +import com.mykola2312.mptv.parser.M3UParser; + +public class TestM3U { + private static final String M3U_GOOD = """ +#EXTM3U +#EXTINF:-1 group-title="test1" tvg-logo="https://example.com/logo.jpg",Test title 1 +http://example.org/video1.m3u8 + +#EXTINF:-1 group-title="test2" ,Test title 2 +http://example.org/video2.m3u8 + """; + + @Test + public void testM3uGood() { + ArrayList items = M3UParser.parse(M3U_GOOD); + assertNotEquals(0, items.size()); + + M3U item = items.get(0); + assertEquals("Test title 1", item.title); + assertEquals("test1", item.groupTitle); + assertEquals("http://example.org/video1.m3u8", item.url); + assertEquals("https://example.com/logo.jpg", item.tvgLogo); + + item = items.get(1); + assertEquals("Test title 2", item.title); + assertEquals("test2", item.groupTitle); + assertEquals("http://example.org/video2.m3u8", item.url); + assertNull(item.tvgLogo); + } + + @Test + public void testM3uBad() { + assertThrows(M3UException.class, () -> M3UParser.parse("some random gibberish data")); + + ArrayList items = M3UParser.parse("#EXTM3U"); + assertEquals(0, items.size()); + } +}