diff --git a/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt b/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt index eb8ff488..6b4d2fcf 100644 --- a/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt +++ b/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt @@ -47,7 +47,7 @@ class MegaCloudExtractor( private var shouldUpdateKey = false private const val PREF_KEY_KEY = "megacloud_key_" private const val PREF_KEY_DEFAULT = "[[0, 0]]" - + private inline fun runLocked(crossinline block: () -> R) = runBlocking(Dispatchers.IO) { MUTEX.withLock { block() } } @@ -132,6 +132,7 @@ class MegaCloudExtractor( ?.filter { it.kind == "captions" } ?.map { Track(it.file, it.label) } .orEmpty() + .let { playlistUtils.fixSubtitles(it) } return playlistUtils.extractFromHls( masterUrl, videoNameGen = { "$name - $it - $type" }, diff --git a/lib/playlist-utils/src/main/java/eu/kanade/tachiyomi/lib/playlistutils/PlaylistUtils.kt b/lib/playlist-utils/src/main/java/eu/kanade/tachiyomi/lib/playlistutils/PlaylistUtils.kt index f7adb84c..2bf6f1de 100644 --- a/lib/playlist-utils/src/main/java/eu/kanade/tachiyomi/lib/playlistutils/PlaylistUtils.kt +++ b/lib/playlist-utils/src/main/java/eu/kanade/tachiyomi/lib/playlistutils/PlaylistUtils.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.lib.playlistutils +import android.net.Uri import eu.kanade.tachiyomi.animesource.model.Track import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.network.GET @@ -8,6 +9,7 @@ import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.internal.commonEmptyHeaders +import java.io.File import kotlin.math.abs class PlaylistUtils(private val client: OkHttpClient, private val headers: Headers = commonEmptyHeaders) { @@ -342,7 +344,32 @@ class PlaylistUtils(private val client: OkHttpClient, private val headers: Heade return "${result}p" } + private fun cleanSubtitleData(matchResult: MatchResult): String { + val lineCount = matchResult.groupValues[1].count { it == '\n' } + return "\n" + " \n".repeat(lineCount - 1) + } + + fun fixSubtitles(subtitleList: List): List { + return subtitleList.mapNotNull { + try { + val subData = client.newCall(GET(it.url)).execute().body.string() + + val file = File.createTempFile("subs", "vtt") + .also(File::deleteOnExit) + + file.writeText(FIX_SUBTITLE_REGEX.replace(subData, ::cleanSubtitleData)) + val uri = Uri.fromFile(file) + + Track(uri.toString(), it.lang) + } catch (_: Exception) { + null + } + } + } + companion object { + private val FIX_SUBTITLE_REGEX = Regex("""${'$'}(\n{2,})(?!(?:\d+:)*\d+(?:\.\d+)?\s-+>\s(?:\d+:)*\d+(?:\.\d+)?)""", RegexOption.MULTILINE) + private const val PLAYLIST_SEPARATOR = "#EXT-X-STREAM-INF:" private val SUBTITLE_REGEX by lazy { Regex("""#EXT-X-MEDIA:TYPE=SUBTITLES.*?NAME="(.*?)".*?URI="(.*?)"""") } diff --git a/src/en/aniplay/src/eu/kanade/tachiyomi/animeextension/en/aniplay/AniPlay.kt b/src/en/aniplay/src/eu/kanade/tachiyomi/animeextension/en/aniplay/AniPlay.kt index d67d4714..ffc65aaa 100644 --- a/src/en/aniplay/src/eu/kanade/tachiyomi/animeextension/en/aniplay/AniPlay.kt +++ b/src/en/aniplay/src/eu/kanade/tachiyomi/animeextension/en/aniplay/AniPlay.kt @@ -291,7 +291,7 @@ class AniPlay : AniListAnimeHttpSource(), ConfigurableAnimeSource { return playlistUtils.extractFromHls( playlistUrl = url, videoNameGen = { quality -> "$serverName - $quality - $typeName" }, - subtitleList = subtitles, + subtitleList = playlistUtils.fixSubtitles(subtitles), masterHeadersGen = { baseHeaders: Headers, _: String -> baseHeaders.newBuilder().apply { set("Accept", "*/*") diff --git a/src/en/dramacool/build.gradle b/src/en/dramacool/build.gradle deleted file mode 100644 index 950c5ea8..00000000 --- a/src/en/dramacool/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ -ext { - extName = 'DramaCool' - extClass = '.DramaCool' - extVersionCode = 54 -} - -apply from: "$rootDir/common.gradle" - -dependencies { - implementation(project(':lib:streamwish-extractor')) - implementation(project(':lib:streamtape-extractor')) - implementation(project(':lib:dood-extractor')) -} \ No newline at end of file diff --git a/src/en/dramacool/res/mipmap-hdpi/ic_launcher.png b/src/en/dramacool/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 386283c6..00000000 Binary files a/src/en/dramacool/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/dramacool/res/mipmap-mdpi/ic_launcher.png b/src/en/dramacool/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 3d81dfbc..00000000 Binary files a/src/en/dramacool/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/dramacool/res/mipmap-xhdpi/ic_launcher.png b/src/en/dramacool/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index d0126fee..00000000 Binary files a/src/en/dramacool/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/dramacool/res/mipmap-xxhdpi/ic_launcher.png b/src/en/dramacool/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 9ab42d45..00000000 Binary files a/src/en/dramacool/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/dramacool/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/dramacool/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 6d99bf28..00000000 Binary files a/src/en/dramacool/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/dramacool/src/eu/kanade/tachiyomi/animeextension/en/dramacool/DramaCool.kt b/src/en/dramacool/src/eu/kanade/tachiyomi/animeextension/en/dramacool/DramaCool.kt deleted file mode 100644 index 4ec49eb0..00000000 --- a/src/en/dramacool/src/eu/kanade/tachiyomi/animeextension/en/dramacool/DramaCool.kt +++ /dev/null @@ -1,202 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.en.dramacool - -import android.app.Application -import androidx.preference.ListPreference -import androidx.preference.PreferenceScreen -import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource -import eu.kanade.tachiyomi.animesource.model.AnimeFilterList -import eu.kanade.tachiyomi.animesource.model.SAnime -import eu.kanade.tachiyomi.animesource.model.SEpisode -import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource -import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor -import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor -import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.text.SimpleDateFormat -import java.util.Locale - -class DramaCool : ConfigurableAnimeSource, ParsedAnimeHttpSource() { - - override val name = "DramaCool" - - // TODO: Check frequency of url changes to potentially - // add back overridable baseurl preference - override val baseUrl = "https://asianc.co/" - - override val lang = "en" - - override val supportsLatest = true - - private val preferences by lazy { - Injekt.get().getSharedPreferences("source_$id", 0x0000) - } - - // ============================== Popular =============================== - override fun popularAnimeRequest(page: Int) = GET("$baseUrl/most-popular-drama?page=$page") // page/$page - - override fun popularAnimeSelector() = "ul.list-episode-item li a" - - override fun popularAnimeFromElement(element: Element) = SAnime.create().apply { - setUrlWithoutDomain(element.attr("href")) - thumbnail_url = element.selectFirst("img")?.attr("data-original")?.replace(" ", "%20") - title = element.selectFirst("h3")?.text() ?: "Serie" - } - - override fun popularAnimeNextPageSelector() = "li.next a" - - // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/recently-added?page=$page") - - override fun latestUpdatesSelector() = "ul.switch-block a" - - override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element) - - override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector() - - // =============================== Search =============================== - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList) = - GET("$baseUrl/search?keyword=$query&page=$page") - - override fun searchAnimeSelector() = popularAnimeSelector() - - override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element) - - override fun searchAnimeNextPageSelector() = popularAnimeNextPageSelector() - - // =========================== Anime Details ============================ - override fun animeDetailsRequest(anime: SAnime): Request { - if (anime.url.contains("-episode-") && anime.url.endsWith(".html")) { - val doc = client.newCall(GET(baseUrl + anime.url)).execute().asJsoup() - anime.setUrlWithoutDomain(doc.selectFirst("div.category a")!!.attr("href")) - } - return GET(baseUrl + anime.url) - } - - override fun animeDetailsParse(document: Document) = SAnime.create().apply { - document.selectFirst("div.img img")!!.run { - title = attr("alt") - thumbnail_url = absUrl("src") - } - - with(document.selectFirst("div.info")!!) { - description = select("p:contains(Description) ~ p:not(:has(span))").eachText() - .joinToString("\n") - .takeUnless(String::isBlank) - author = selectFirst("p:contains(Original Network:) > a")?.text() - genre = select("p:contains(Genre:) > a").joinToString { it.text() }.takeUnless(String::isBlank) - status = parseStatus(selectFirst("p:contains(Status) a")?.text()) - } - } - - // ============================== Episodes ============================== - override fun episodeListSelector() = "ul.all-episode li a" - - override fun episodeFromElement(element: Element) = SEpisode.create().apply { - setUrlWithoutDomain(element.attr("href")) - val epNum = element.selectFirst("h3")!!.text().substringAfterLast("Episode ") - val type = element.selectFirst("span.type")?.text() ?: "RAW" - name = "$type: Episode $epNum".trimEnd() - episode_number = when { - epNum.isNotEmpty() -> epNum.toFloatOrNull() ?: 1F - else -> 1F - } - date_upload = element.selectFirst("span.time")?.text().orEmpty().toDate() - } - - // ============================ Video Links ============================= - override fun videoListSelector() = "ul.list-server-items li" - - override fun videoListParse(response: Response): List