diff --git a/src/en/animetake/AndroidManifest.xml b/src/en/animetake/AndroidManifest.xml new file mode 100644 index 000000000..568741e54 --- /dev/null +++ b/src/en/animetake/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/en/animetake/build.gradle b/src/en/animetake/build.gradle new file mode 100644 index 000000000..b7ce72931 --- /dev/null +++ b/src/en/animetake/build.gradle @@ -0,0 +1,18 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + extName = 'AnimeTake' + pkgNameSuffix = 'en.animetake' + extClass = '.AnimeTake' + extVersionCode = 1 + containsNsfw = false +} + +dependencies { + implementation(project(":lib-dood-extractor")) + implementation(project(":lib-mp4upload-extractor")) + implementation(project(":lib-filemoon-extractor")) +} + +apply from: "$rootDir/common.gradle" \ No newline at end of file diff --git a/src/en/animetake/res/mipmap-hdpi/ic_launcher.png b/src/en/animetake/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..52f981605 Binary files /dev/null and b/src/en/animetake/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/en/animetake/res/mipmap-mdpi/ic_launcher.png b/src/en/animetake/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..473e30b7d Binary files /dev/null and b/src/en/animetake/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/en/animetake/res/mipmap-xhdpi/ic_launcher.png b/src/en/animetake/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..3d3ae7c7e Binary files /dev/null and b/src/en/animetake/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/en/animetake/res/mipmap-xxhdpi/ic_launcher.png b/src/en/animetake/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..570d73776 Binary files /dev/null and b/src/en/animetake/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/en/animetake/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/animetake/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..e2532e5d8 Binary files /dev/null and b/src/en/animetake/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/en/animetake/res/web_hi_res_512.png b/src/en/animetake/res/web_hi_res_512.png new file mode 100644 index 000000000..5741c7d19 Binary files /dev/null and b/src/en/animetake/res/web_hi_res_512.png differ diff --git a/src/en/animetake/src/eu/kanade/tachiyomi/animeextension/en/animetake/AnimeTake.kt b/src/en/animetake/src/eu/kanade/tachiyomi/animeextension/en/animetake/AnimeTake.kt new file mode 100644 index 000000000..b01f81fea --- /dev/null +++ b/src/en/animetake/src/eu/kanade/tachiyomi/animeextension/en/animetake/AnimeTake.kt @@ -0,0 +1,289 @@ +package eu.kanade.tachiyomi.animeextension.en.animetake + +import android.app.Application +import android.content.SharedPreferences +import androidx.preference.ListPreference +import androidx.preference.PreferenceScreen +import eu.kanade.tachiyomi.animeextension.en.animetake.extractors.VidstreamingExtractor +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.filemoonextractor.FilemoonExtractor +import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.runBlocking +import okhttp3.OkHttpClient +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 AnimeTake : ConfigurableAnimeSource, ParsedAnimeHttpSource() { + + override val name = "AnimeTake" + + override val baseUrl = "https://animetake.tv" + + override val lang = "en" + + override val supportsLatest = true + + override val client: OkHttpClient = network.cloudflareClient + + private val preferences: SharedPreferences by lazy { + Injekt.get().getSharedPreferences("source_$id", 0x0000) + } + + // ============================== Popular =============================== + override fun popularAnimeRequest(page: Int) = GET("$baseUrl/animelist/popular") + + override fun popularAnimeSelector() = "div.col-sm-6" + + override fun popularAnimeFromElement(element: Element): SAnime { + return SAnime.create().apply { + setUrlWithoutDomain(element.select("div > a").attr("href")) + thumbnail_url = baseUrl + element.select("div.latestep_image > img").attr("data-src") + title = element.select("span.latestep_title > h4").first()!!.ownText() + } + } + + override fun popularAnimeNextPageSelector() = "ul.pagination > li.page-item:last-child" + + // =============================== Latest =============================== + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/animelist/?page=$page") + + override fun latestUpdatesSelector() = popularAnimeSelector() + + override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector() + + override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element) + + // =============================== Search =============================== + override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { + val params = AnimeTakeFilters.getSearchParameters(filters) + val cleanQuery = query.replace(" ", "+").lowercase() + return if (query.isNotEmpty()) { + GET("$baseUrl/search/?search=$cleanQuery&page=$page") + } else { + val multiString = buildString { + if (params.letters.isNotEmpty()) append(params.letters + "&") + if (params.genres.isNotEmpty()) append(params.genres + "&") + if (params.score.isNotEmpty()) append(params.score + "&") + if (params.years.isNotEmpty()) append(params.years + "&") + if (params.ratings.isNotEmpty()) append(params.ratings + "&") + } + GET("$baseUrl/animelist/?page=$page&$multiString") + } + } + + override fun searchAnimeSelector() = popularAnimeSelector() + + override fun searchAnimeNextPageSelector() = popularAnimeNextPageSelector() + + override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element) + + // ============================== Filters =============================== + override fun getFilterList() = AnimeTakeFilters.FILTER_LIST + + // =========================== Anime Details ============================ + override fun animeDetailsParse(document: Document): SAnime { + val anime = SAnime.create() + anime.title = document.select("h3 > b").text() + anime.genre = document.select("a.animeinfo_label").joinToString { + it.select("span").text() + } + anime.description = document.select("div.visible-md").first()!!.ownText() + anime.status = + parseStatus(document.select("div.well > center:contains(Next Episode)").isNotEmpty()) + document.select("div.well > p").first()!!.text().let { + if (it.isBlank().not()) { + anime.description = when { + anime.description.isNullOrBlank() -> it + else -> anime.description + "\n\n" + it + } + } + } + return anime + } + + // ============================== Episodes ============================== + override fun episodeListSelector() = "div#eps > div > a[href]" + + override fun episodeListParse(response: Response): List { + val document = response.asJsoup() + val episodesLink = document.select(episodeListSelector()) + return episodesLink.map(::episodeFromElement).reversed() + } + + override fun episodeFromElement(element: Element): SEpisode { + return SEpisode.create().apply { + setUrlWithoutDomain(element.attr("href")) + val upDate = element.select("div.col-xs-12 > span.label").text() + date_upload = parseDate(upDate) + val epName = element.select("div.col-xs-12 > div.anime-title > b").text() + name = epName + episode_number = 0F + } + } + + // ============================ Video Links ============================= + private val doodExtractor by lazy { DoodExtractor(client) } + private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) } + private val vidstreamingExtractor by lazy { VidstreamingExtractor(client) } + private val filemoonExtractor by lazy { FilemoonExtractor(client) } + + override fun videoListParse(response: Response): List