From 5e44a4b1ef48f53d7bc9442e981781f6f78cd5ed Mon Sep 17 00:00:00 2001 From: Dark25 Date: Tue, 10 Dec 2024 23:16:35 +0100 Subject: [PATCH] feat(src/zh): new extension added: xiaoxintv and Anime1 (#148) --- lib/bangumi-scraper/build.gradle.kts | 7 + .../lib/bangumiscraper/BangumiDTO.kt | 83 ++++++ .../lib/bangumiscraper/BangumiScraper.kt | 126 ++++++++ .../bangumiscraper/BangumiScraperException.kt | 3 + src/zh/anime1/build.gradle | 13 + src/zh/anime1/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2734 bytes src/zh/anime1/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1602 bytes .../anime1/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3829 bytes .../anime1/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6694 bytes .../anime1/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9251 bytes .../animeextension/zh/anime1/Anime1.kt | 272 +++++++++++++++++ src/zh/xiaoxintv/build.gradle | 7 + .../xiaoxintv/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3656 bytes .../xiaoxintv/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2067 bytes .../res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 5607 bytes .../res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 10171 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 15387 bytes .../animeextension/zh/xiaoxintv/Filters.kt | 221 ++++++++++++++ .../animeextension/zh/xiaoxintv/Xiaoxintv.kt | 278 ++++++++++++++++++ 19 files changed, 1010 insertions(+) create mode 100644 lib/bangumi-scraper/build.gradle.kts create mode 100644 lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiDTO.kt create mode 100644 lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraper.kt create mode 100644 lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraperException.kt create mode 100644 src/zh/anime1/build.gradle create mode 100644 src/zh/anime1/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/zh/anime1/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/zh/anime1/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/zh/anime1/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/zh/anime1/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/zh/anime1/src/eu/kanade/tachiyomi/animeextension/zh/anime1/Anime1.kt create mode 100644 src/zh/xiaoxintv/build.gradle create mode 100644 src/zh/xiaoxintv/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/zh/xiaoxintv/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/zh/xiaoxintv/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/zh/xiaoxintv/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/zh/xiaoxintv/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/zh/xiaoxintv/src/eu/kanade/tachiyomi/animeextension/zh/xiaoxintv/Filters.kt create mode 100644 src/zh/xiaoxintv/src/eu/kanade/tachiyomi/animeextension/zh/xiaoxintv/Xiaoxintv.kt diff --git a/lib/bangumi-scraper/build.gradle.kts b/lib/bangumi-scraper/build.gradle.kts new file mode 100644 index 0000000000..c49026e416 --- /dev/null +++ b/lib/bangumi-scraper/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("lib-android") +} + +dependencies { + compileOnly(libs.aniyomi.lib) +} \ No newline at end of file diff --git a/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiDTO.kt b/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiDTO.kt new file mode 100644 index 0000000000..1f130ad25f --- /dev/null +++ b/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiDTO.kt @@ -0,0 +1,83 @@ +@file:UseSerializers(BoxItemSerializer::class) +package eu.kanade.tachiyomi.lib.bangumiscraper + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.Serializer +import kotlinx.serialization.UseSerializers +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.json.JsonDecoder +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive + +@Serializable +internal data class Images( + val large: String, + val common: String, + val medium: String, + val small: String, +) + +@Serializable +internal data class BoxItem( + val key: String, + val value: String, +) + +@OptIn(ExperimentalSerializationApi::class) +@Serializer(forClass = BoxItem::class) +internal object BoxItemSerializer : KSerializer { + override fun deserialize(decoder: Decoder): BoxItem { + val item = (decoder as JsonDecoder).decodeJsonElement().jsonObject + val key = item["key"]!!.jsonPrimitive.content + val value = (item["value"] as? JsonPrimitive)?.contentOrNull ?: "" + return BoxItem(key, value) + } +} + +@Serializable +internal data class Subject( + val name: String, + @SerialName("name_cn") + val nameCN: String, + val summary: String, + val images: Images, + @SerialName("meta_tags") + val metaTags: List, + @SerialName("infobox") + val infoBox: List, +) { + fun findAuthor(): String? { + return findInfo("导演", "原作") + } + + fun findArtist(): String? { + return findInfo("美术监督", "总作画监督", "动画制作") + } + + fun findInfo(vararg keys: String): String? { + keys.forEach { key -> + return infoBox.find { item -> + item.key == key + }?.value ?: return@forEach + } + return null + } +} + +@Serializable +internal data class SearchItem( + val id: Int, + val name: String, + @SerialName("name_cn") + val nameCN: String, + val summary: String, + val images: Images, +) + +@Serializable +internal data class SearchResponse(val results: Int, val list: List) diff --git a/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraper.kt b/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraper.kt new file mode 100644 index 0000000000..3653314e06 --- /dev/null +++ b/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraper.kt @@ -0,0 +1,126 @@ +package eu.kanade.tachiyomi.lib.bangumiscraper + +import eu.kanade.tachiyomi.animesource.model.SAnime +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.awaitSuccess +import eu.kanade.tachiyomi.util.parseAs +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response + +enum class BangumiSubjectType(val value: Int) { + BOOK(1), + ANIME(2), + MUSIC(3), + GAME(4), + REAL(6), +} + +enum class BangumiFetchType { + /** + * Give cover and summary info. + */ + SHORT, + + /** + * Give all require info include genre and author info. + */ + ALL, +} + +/** + * A helper class to fetch anime details from Bangumi + */ +object BangumiScraper { + private const val SEARCH_URL = "https://api.bgm.tv/search/subject" + private const val SUBJECTS_URL = "https://api.bgm.tv/v0/subjects" + + /** + * Fetch anime details info from Bangumi + * @param fetchType check [BangumiFetchType] to get detail + * @param subjectType check [BangumiSubjectType] to get detail + * @param requestProducer used to custom request + */ + suspend fun fetchDetail( + client: OkHttpClient, + keyword: String, + fetchType: BangumiFetchType = BangumiFetchType.SHORT, + subjectType: BangumiSubjectType = BangumiSubjectType.ANIME, + requestProducer: (url: HttpUrl) -> Request = { url -> GET(url) }, + ): SAnime { + val httpUrl = SEARCH_URL.toHttpUrl().newBuilder() + .addPathSegment(keyword) + .addQueryParameter( + "responseGroup", + if (fetchType == BangumiFetchType.ALL) { + "small" + } else { + "medium" + }, + ) + .addQueryParameter("type", "${subjectType.value}") + .addQueryParameter("start", "0") + .addQueryParameter("max_results", "1") + .build() + val searchResponse = client.newCall(requestProducer(httpUrl)).awaitSuccess() + .checkErrorMessage().parseAs() + return if (searchResponse.list.isEmpty()) { + SAnime.create() + } else { + val item = searchResponse.list[0] + if (fetchType == BangumiFetchType.ALL) { + fetchSubject(client, "${item.id}", requestProducer) + } else { + SAnime.create().apply { + thumbnail_url = item.images.large + description = item.summary + } + } + } + } + + private suspend fun fetchSubject( + client: OkHttpClient, + id: String, + requestProducer: (url: HttpUrl) -> Request, + ): SAnime { + val httpUrl = SUBJECTS_URL.toHttpUrl().newBuilder().addPathSegment(id).build() + val subject = client.newCall(requestProducer(httpUrl)).awaitSuccess() + .checkErrorMessage().parseAs() + return SAnime.create().apply { + thumbnail_url = subject.images.large + description = subject.summary + genre = buildList { + addAll(subject.metaTags) + subject.findInfo("动画制作")?.let { add(it) } + subject.findInfo("放送开始")?.let { add(it) } + }.joinToString() + author = subject.findAuthor() + artist = subject.findArtist() + if (subject.findInfo("播放结束") != null) { + status = SAnime.COMPLETED + } else if (subject.findInfo("放送开始") != null) { + status = SAnime.ONGOING + } + } + } + + private fun Response.checkErrorMessage(): String { + val responseStr = body.string() + val errorMessage = + responseStr.parseAs().jsonObject["error"]?.jsonPrimitive?.contentOrNull + if (errorMessage != null) { + throw BangumiScraperException(errorMessage) + } + return responseStr + } +} + + + diff --git a/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraperException.kt b/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraperException.kt new file mode 100644 index 0000000000..08d1e30835 --- /dev/null +++ b/lib/bangumi-scraper/src/main/java/eu/kanade/tachiyomi/lib/bangumiscraper/BangumiScraperException.kt @@ -0,0 +1,3 @@ +package eu.kanade.tachiyomi.lib.bangumiscraper + +class BangumiScraperException(message: String) : Exception(message) diff --git a/src/zh/anime1/build.gradle b/src/zh/anime1/build.gradle new file mode 100644 index 0000000000..96c45c2dd5 --- /dev/null +++ b/src/zh/anime1/build.gradle @@ -0,0 +1,13 @@ +ext { + extName = 'Anime1.me' + extClass = '.Anime1' + extVersionCode = 3 +} + +apply from: "$rootDir/common.gradle" + +dependencies { + implementation(project(":lib:bangumi-scraper")) + //noinspection UseTomlInstead + implementation "com.github.houbb:opencc4j:1.8.1" +} diff --git a/src/zh/anime1/res/mipmap-hdpi/ic_launcher.png b/src/zh/anime1/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..985857355dc606ff9a3be09fc4c3ecdd0de003cb GIT binary patch literal 2734 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 Ah5!Hn literal 0 HcmV?d00001 diff --git a/src/zh/anime1/res/mipmap-xhdpi/ic_launcher.png b/src/zh/anime1/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..195d9a27924da499f75a3464858ed394c28036fd GIT binary patch literal 3829 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 literal 0 HcmV?d00001 diff --git a/src/zh/anime1/res/mipmap-xxxhdpi/ic_launcher.png b/src/zh/anime1/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..20dda2b2a1e1b47d9189ca8ec91be5540d3f64d4 GIT binary patch literal 9251 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 literal 0 HcmV?d00001 diff --git a/src/zh/anime1/src/eu/kanade/tachiyomi/animeextension/zh/anime1/Anime1.kt b/src/zh/anime1/src/eu/kanade/tachiyomi/animeextension/zh/anime1/Anime1.kt new file mode 100644 index 0000000000..5901449267 --- /dev/null +++ b/src/zh/anime1/src/eu/kanade/tachiyomi/animeextension/zh/anime1/Anime1.kt @@ -0,0 +1,272 @@ +package eu.kanade.tachiyomi.animeextension.zh.anime1 + +import android.app.Application +import android.content.SharedPreferences +import android.webkit.CookieManager +import androidx.preference.CheckBoxPreference +import androidx.preference.ListPreference +import androidx.preference.PreferenceScreen +import com.github.houbb.opencc4j.util.ZhTwConverterUtil +import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource +import eu.kanade.tachiyomi.animesource.model.AnimeFilterList +import eu.kanade.tachiyomi.animesource.model.AnimesPage +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.AnimeHttpSource +import eu.kanade.tachiyomi.lib.bangumiscraper.BangumiFetchType +import eu.kanade.tachiyomi.lib.bangumiscraper.BangumiScraper +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.network.awaitSuccess +import eu.kanade.tachiyomi.util.asJsoup +import eu.kanade.tachiyomi.util.parseAs +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonPrimitive +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.text.SimpleDateFormat +import java.util.Locale + +class Anime1 : AnimeHttpSource(), ConfigurableAnimeSource { + override val baseUrl: String + get() = "https://anime1.me" + override val lang: String + get() = "zh-hant" + override val name: String + get() = "Anime1.me" + override val supportsLatest: Boolean + get() = true + + override fun headersBuilder() = super.headersBuilder().add("referer", "$baseUrl/") + + private val videoApiUrl = "https://v.anime1.me/api" + private val dataUrl = "https://d1zquzjgwo9yb.cloudfront.net" + private val uploadDateFormat: SimpleDateFormat by lazy { + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()) + } + private lateinit var data: JsonArray + private val cookieManager + get() = CookieManager.getInstance() + private val preferences: SharedPreferences by lazy { + Injekt.get().getSharedPreferences("source_$id", 0x0000) + } + + override fun animeDetailsParse(response: Response) = throw UnsupportedOperationException() + + override suspend fun getAnimeDetails(anime: SAnime): SAnime { + return if (bangumiEnable) { + BangumiScraper.fetchDetail( + client, + ZhTwConverterUtil.toSimple(anime.title.removeSuffixMark()), + fetchType = bangumiFetchType, + ) + } else { + anime.thumbnail_url = FIX_COVER + anime + } + } + + override fun episodeListParse(response: Response): List { + var document: Document? = response.asJsoup() + val episodes = mutableListOf() + val requestUrl = response.request.url.toString() + while (document != null) { + val items = document.select("article.post").map { + SEpisode.create().apply { + name = it.select(".entry-title").text() + val url = it.selectFirst(".entry-title a")?.attr("href") ?: requestUrl + setUrlWithoutDomain(url) + date_upload = it.select("time.updated").attr("datetime").let { date -> + runCatching { uploadDateFormat.parse(date)?.time }.getOrNull() ?: 0L + } + } + } + episodes.addAll(items) + val previousUrl = document.select(".nav-previous a").attr("href") + document = if (previousUrl.isBlank()) { + null + } else { + client.newCall(GET(previousUrl)).execute().asJsoup() + } + } + return episodes + } + + override fun videoListParse(response: Response): List