diff --git a/app/src/main/java/com/antoniegil/astronia/util/parser/M3UParser.kt b/app/src/main/java/com/antoniegil/astronia/util/parser/M3UParser.kt index 6206bbb..0371616 100644 --- a/app/src/main/java/com/antoniegil/astronia/util/parser/M3UParser.kt +++ b/app/src/main/java/com/antoniegil/astronia/util/parser/M3UParser.kt @@ -13,6 +13,7 @@ data class M3UChannel( object M3UParser { + private const val M3U_HEADER_MARK = "#EXTM3U" private const val M3U_INFO_MARK = "#EXTINF:" private const val KODI_MARK = "#KODIPROP:" private const val M3U_TVG_ID_MARK = "tvg-id" @@ -22,40 +23,33 @@ object M3UParser { private const val KODI_LICENSE_TYPE = "inputstream.adaptive.license_type" private const val KODI_LICENSE_KEY = "inputstream.adaptive.license_key" + private val infoRegex = """(-?\d+)(.*),(.+)""".toRegex() private val metadataRegex = """([\w-_.]+)=\s*(?:"([^"]*)"|(\S+))""".toRegex() private val kodiPropRegex = """([^=]+)=(.+)""".toRegex() fun parse(content: String): Pair, String?> { val channels = mutableListOf() - var epgUrl: String? = null + + val epgUrl = content.lineSequence() + .firstOrNull { it.startsWith(M3U_HEADER_MARK) } + ?.let { extractEpgUrl(it) } val lines = content.lineSequence() .filter { it.isNotEmpty() } .map { it.trimEnd() } + .dropWhile { it.startsWith(M3U_HEADER_MARK) } .iterator() var currentLine: String - var metadata = emptyMap() - var title = "" + var infoMatch: MatchResult? = null val kodiMatches = mutableListOf() while (lines.hasNext()) { currentLine = lines.next() - if (currentLine.startsWith("#EXTM3U")) { - epgUrl = extractEpgUrl(currentLine) - continue - } - while (currentLine.startsWith("#")) { if (currentLine.startsWith(M3U_INFO_MARK)) { - val infoContent = currentLine.drop(M3U_INFO_MARK.length).trim() - val commaIndex = infoContent.lastIndexOf(',') - if (commaIndex != -1) { - val metadataText = infoContent.take(commaIndex) - title = infoContent.substring(commaIndex + 1).trim() - metadata = parseMetadata(metadataText) - } + infoMatch = infoRegex.matchEntire(currentLine.drop(M3U_INFO_MARK.length).trim()) } if (currentLine.startsWith(KODI_MARK)) { kodiPropRegex @@ -67,16 +61,19 @@ object M3UParser { } else break } - if (metadata.isEmpty() && !currentLine.startsWith("#")) continue + if (infoMatch == null && !currentLine.startsWith("#")) continue - if (!currentLine.startsWith("#") && - (currentLine.startsWith("http") || currentLine.startsWith("rtmp") || - currentLine.startsWith("rtsp") || currentLine.startsWith("udp"))) { - - val tvgId = metadata[M3U_TVG_ID_MARK].orEmpty() - val tvgName = metadata[M3U_TVG_NAME_MARK].orEmpty() - val relationId = tvgId.ifEmpty { tvgName } - val finalTitle = title.ifEmpty { "Channel ${channels.size + 1}" } + if (!currentLine.startsWith("#")) { + val title = infoMatch?.groups?.get(3)?.value.orEmpty().trim() + val metadata = buildMap { + val text = infoMatch?.groups?.get(2)?.value.orEmpty().trim() + val matches = metadataRegex.findAll(text) + for (match in matches) { + val key = match.groups[1]!!.value + val value = match.groups[2]?.value?.ifBlank { null } ?: continue + put(key.trim(), value.trim()) + } + } val kodiMetadata = buildMap { for (match in kodiMatches) { @@ -86,6 +83,11 @@ object M3UParser { } } + val tvgId = metadata[M3U_TVG_ID_MARK].orEmpty() + val tvgName = metadata[M3U_TVG_NAME_MARK].orEmpty() + val relationId = tvgId.ifEmpty { tvgName } + val finalTitle = title.ifEmpty { "Channel ${channels.size + 1}" } + channels.add( M3UChannel( id = "${currentLine.hashCode()}_${channels.size}", @@ -99,8 +101,7 @@ object M3UParser { ) ) - metadata = emptyMap() - title = "" + infoMatch = null kodiMatches.clear() } } @@ -108,15 +109,6 @@ object M3UParser { return channels to epgUrl } - private fun parseMetadata(text: String): Map = buildMap { - val matches = metadataRegex.findAll(text) - for (match in matches) { - val key = match.groups[1]!!.value - val value = match.groups[2]?.value?.ifBlank { null } ?: continue - put(key.trim(), value.trim()) - } - } - private fun extractEpgUrl(line: String): String? { val xTvgUrlMatch = Regex("""x-tvg-url\s*=\s*"([^"]+)"""").find(line) val urlTvgMatch = Regex("""url-tvg\s*=\s*"([^"]+)"""").find(line)