fix(en/hstream): Rewrite the extension to make it work with the new site (#2540)

This commit is contained in:
Claudemirovsky 2023-11-24 16:26:51 -03:00 committed by GitHub
parent 3c71aa539f
commit 380a8346aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 417 additions and 140 deletions

View File

@ -1,113 +0,0 @@
package eu.kanade.tachiyomi.animeextension.en.hstream
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.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
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 java.text.SimpleDateFormat
import java.util.Locale
class Hstream : AnimeStream(
"en",
"Hstream",
"https://hstream.moe",
) {
override val animeListUrl = "$baseUrl/hentai"
override val dateFormatter by lazy {
SimpleDateFormat("yyyy-mm-dd", Locale.ENGLISH)
}
override val client = network.cloudflareClient
override fun headersBuilder() = super.headersBuilder().add("Referer", baseUrl)
// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = GET("$animeListUrl/list")
override fun popularAnimeSelector() = "div.soralist ul > li > a.tip"
override fun popularAnimeFromElement(element: Element) = SAnime.create().apply {
val href = element.attr("href")
setUrlWithoutDomain(href)
title = element.ownText()
thumbnail_url = "$baseUrl/images$href/cover.webp"
}
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = GET("$animeListUrl/search?page=$page&order=latest")
override fun latestUpdatesParse(response: Response) = searchAnimeParse(response)
// =============================== Search ===============================
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = HstreamFilters.getSearchParameters(filters)
val multiString = buildString {
if (params.tags.isNotEmpty()) append(params.tags + "&")
if (params.studios.isNotEmpty()) append(params.studios + "&")
if (query.isNotEmpty()) append("s=$query")
}
return GET("$animeListUrl/search?page=$page&order=${params.order}&$multiString", headers)
}
override fun searchAnimeParse(response: Response): AnimesPage {
val original = super.searchAnimeParse(response)
val animes = original.animes.distinctBy { it.url }
return AnimesPage(animes, original.hasNextPage)
}
override fun searchAnimeFromElement(element: Element) = SAnime.create().apply {
val href = element.attr("href").substringBeforeLast("/")
setUrlWithoutDomain(href)
title = element.selectFirst("div.tt, div.ttl")!!
.ownText()
.substringBeforeLast(" -")
thumbnail_url = "$baseUrl/images$href/cover.webp"
}
override fun searchAnimeNextPageSelector() = "ul.pagination button[rel=next]"
// ============================== Filters ===============================
override val fetchFilters = false
override fun getFilterList() = HstreamFilters.FILTER_LIST
// =========================== Anime Details ============================
override fun getAnimeDescription(document: Document) =
super.getAnimeDescription(document)
?.substringAfter("720p 1080p and (if available) 2160p (4k).")
?.trim()
// ============================== Episodes ==============================
override fun episodeListParse(response: Response) = super.episodeListParse(response).reversed()
// ============================ Video Links =============================
private val urlRegex by lazy { Regex("https?:\\/\\/[^\\s][^']+") }
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val script = document.selectFirst("script:containsData(const player)")!!.data()
val links = urlRegex.findAll(script).map { it.value }.toList()
val subTracks = links.filter { it.endsWith(".ass") }.map {
val name = it.substringAfterLast("/").substringBefore(".").uppercase()
Track(it, name)
}.distinctBy { it.lang }
return links.filter { it.endsWith(".webm") || it.endsWith(".mp4") }.map {
val quality = it.split(".").takeLast(2).firstOrNull() ?: "720p"
Video(it, quality, it, headers, subtitleTracks = subTracks)
}
}
override val prefQualityValues = arrayOf("2160p", "1080p", "720p")
override val prefQualityEntries = prefQualityValues
}

View File

@ -20,7 +20,6 @@ class AnimeStreamGenerator : ThemeSourceGenerator {
SingleLang("ChineseAnime", "https://chineseanime.top", "all", isNsfw = false, overrideVersionCode = 3),
SingleLang("desu-online", "https://desu-online.pl", "pl", className = "DesuOnline", isNsfw = false, overrideVersionCode = 3),
SingleLang("DonghuaStream", "https://donghuastream.co.in", "en", isNsfw = false, overrideVersionCode = 2),
SingleLang("Hstream", "https://hstream.moe", "en", isNsfw = true, overrideVersionCode = 3),
SingleLang("LMAnime", "https://lmanime.com", "all", isNsfw = false, overrideVersionCode = 4),
SingleLang("LuciferDonghua", "https://luciferdonghua.in", "en", isNsfw = false, overrideVersionCode = 3),
SingleLang("MiniOppai", "https://minioppai.org", "id", isNsfw = true, overrideVersionCode = 3),

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".en.hstream.HstreamUrlActivity"
android:excludeFromRecents="true"
android:exported="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="hstream.moe"
android:pathPattern="/hentai/..*"
android:scheme="https" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,16 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.serialization)
}
ext {
extName = 'Hstream'
pkgNameSuffix = 'en.hstream'
extClass = '.Hstream'
extVersionCode = 6
libVersion = '13'
containsNsfw = true
}
apply from: "$rootDir/common.gradle"

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,267 @@
package eu.kanade.tachiyomi.animeextension.en.hstream
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.AnimesPage
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Track
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.net.URLDecoder
import java.text.SimpleDateFormat
import java.util.Locale
class Hstream : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "Hstream"
override val baseUrl = "https://hstream.moe"
override val lang = "en"
override val supportsLatest = true
private val json: Json by injectLazy()
// URLs from the old extension are invalid now, so we're bumping this to
// make aniyomi interpret it as a new source, forcing old users to migrate.
override val versionId = 2
private val preferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/search?order=view-count&page=$page")
override fun popularAnimeSelector() = "div.items-center div.w-full > a"
override fun popularAnimeFromElement(element: Element) = SAnime.create().apply {
setUrlWithoutDomain(element.attr("href"))
title = element.selectFirst("img")!!.attr("alt")
val episode = url.substringAfterLast("-").substringBefore("/")
thumbnail_url = "$baseUrl/images${url.substringBeforeLast("-")}/cover-ep-$episode.webp"
}
override fun popularAnimeNextPageSelector() = "span[aria-current] + a"
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/search?order=recently-uploaded&page=$page")
override fun latestUpdatesSelector() = popularAnimeSelector()
override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element)
override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector()
// =============================== Search ===============================
override fun getFilterList() = HstreamFilters.FILTER_LIST
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
val id = query.removePrefix(PREFIX_SEARCH)
client.newCall(GET("$baseUrl/hentai/$id"))
.asObservableSuccess()
.map(::searchAnimeByIdParse)
} else {
super.fetchSearchAnime(page, query, filters)
}
}
private fun searchAnimeByIdParse(response: Response): AnimesPage {
val details = animeDetailsParse(response.use { it.asJsoup() })
return AnimesPage(listOf(details), false)
}
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = HstreamFilters.getSearchParameters(filters)
val url = "$baseUrl/search".toHttpUrl().newBuilder().apply {
if (query.isNotBlank()) addQueryParameter("s", query)
addQueryParameter("page", page.toString())
addQueryParameter("order", params.order)
params.genres.forEach { addQueryParameter("tags[]", it) }
params.blacklisted.forEach { addQueryParameter("blacklist[]", it) }
params.studios.forEach { addQueryParameter("studios[]", it) }
}.build()
return GET(url.toString())
}
override fun searchAnimeSelector() = popularAnimeSelector()
override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element)
override fun searchAnimeNextPageSelector() = popularAnimeNextPageSelector()
// =========================== Anime Details ============================
override fun animeDetailsParse(document: Document) = SAnime.create().apply {
status = SAnime.COMPLETED
val floatleft = document.selectFirst("div.relative > div.float-left > div")!!
title = floatleft.selectFirst("h1")!!.text()
artist = floatleft.selectFirst("h2 > a")?.text()
thumbnail_url = document.selectFirst("div.float-left > img.object-cover")?.absUrl("src")
genre = document.select("ul.list-none > li > a").eachText().joinToString()
description = document.selectFirst("div.relative > p.leading-tight")?.text()
}
// ============================== Episodes ==============================
override fun episodeListParse(response: Response): List<SEpisode> {
val doc = response.use { it.asJsoup() }
val episode = SEpisode.create().apply {
date_upload = doc.selectFirst("a:has(i.fa-upload)")?.ownText().toDate()
setUrlWithoutDomain(doc.location())
val num = url.substringAfterLast("-").substringBefore("/")
episode_number = num.toFloatOrNull() ?: 1F
name = "Episode $num"
}
return listOf(episode)
}
override fun episodeListSelector(): String {
throw UnsupportedOperationException("Not used.")
}
override fun episodeFromElement(element: Element): SEpisode {
throw UnsupportedOperationException("Not used.")
}
// ============================ Video Links =============================
override fun videoListParse(response: Response): List<Video> {
val doc = response.use { it.asJsoup() }
val token = client.cookieJar.loadForRequest(response.request.url)
.first { it.name.equals("XSRF-TOKEN") }
.value
val episodeId = doc.selectFirst("input#e_id")!!.attr("value")
val newHeaders = headersBuilder().apply {
set("Referer", doc.location())
set("Origin", baseUrl)
set("X-Requested-With", "XMLHttpRequest")
set("X-XSRF-TOKEN", URLDecoder.decode(token, "utf-8"))
}.build()
val body = """{"episode_id": "$episodeId"}""".toRequestBody("application/json".toMediaType())
val data = client.newCall(POST("$baseUrl/player/api", newHeaders, body)).execute()
.parseAs<PlayerApiResponse>()
val urlBase = data.stream_domains.random() + "/" + data.stream_url
val subtitleList = listOf(Track(urlBase, "English"))
val resolutions = listOfNotNull("720", "1080", if (data.resolution == "4k") "2160" else null)
return resolutions.map { resolution ->
val url = urlBase + getVideoUrlPath(data.legacy != 0, resolution)
Video(url, "${resolution}p", url, subtitleTracks = subtitleList)
}
}
private fun getVideoUrlPath(isLegacy: Boolean, resolution: String): String {
return if (isLegacy) {
if (resolution.equals("720")) {
"/x264.720p.mp4"
} else {
"/av1.$resolution.webm"
}
} else {
"/$resolution/manifest.mpd"
}
}
@Serializable
data class PlayerApiResponse(
val legacy: Int = 0,
val resolution: String = "4k",
val stream_url: String,
val stream_domains: List<String>,
)
override fun videoListSelector(): String {
throw UnsupportedOperationException("Not used.")
}
override fun videoFromElement(element: Element): Video {
throw UnsupportedOperationException("Not used.")
}
override fun videoUrlParse(document: Document): String {
throw UnsupportedOperationException("Not used.")
}
// ============================== Settings ==============================
override fun setupPreferenceScreen(screen: PreferenceScreen) {
ListPreference(screen.context).apply {
key = PREF_QUALITY_KEY
title = PREF_QUALITY_TITLE
entries = PREF_QUALITY_ENTRIES
entryValues = PREF_QUALITY_VALUES
setDefaultValue(PREF_QUALITY_DEFAULT)
summary = "%s"
setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String
val index = findIndexOfValue(selected)
val entry = entryValues[index] as String
preferences.edit().putString(key, entry).commit()
}
}.also(screen::addPreference)
}
// ============================= Utilities ==============================
private fun String?.toDate(): Long {
return runCatching { DATE_FORMATTER.parse(orEmpty().trim(' ', '|'))?.time }
.getOrNull() ?: 0L
}
private inline fun <reified T> Response.parseAs(): T {
return use { it.body.string() }.let(json::decodeFromString)
}
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString(PREF_QUALITY_KEY, PREF_QUALITY_DEFAULT)!!
return sortedWith(
compareBy { it.quality.contains(quality) },
).reversed()
}
companion object {
private val DATE_FORMATTER by lazy {
SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
}
const val PREFIX_SEARCH = "id:"
private const val PREF_QUALITY_KEY = "pref_quality_key"
private const val PREF_QUALITY_TITLE = "Preferred quality"
private const val PREF_QUALITY_DEFAULT = "720p"
private val PREF_QUALITY_ENTRIES = arrayOf("720p (HD)", "1080p (FULLHD)", "2160p (4K)")
private val PREF_QUALITY_VALUES = arrayOf("720p", "1080p", "2160p")
}
}

View File

@ -1,57 +1,91 @@
package eu.kanade.tachiyomi.animeextension.en.hstream
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilter.TriState
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.CheckBoxFilterList
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.QueryPartFilter
object HstreamFilters {
private inline fun <reified R> AnimeFilterList.asQueryPart(): String {
return (getFirst<R>() as QueryPartFilter).toQueryPart()
open class QueryPartFilter(
displayName: String,
val vals: Array<Pair<String, String>>,
) : AnimeFilter.Select<String>(
displayName,
vals.map { it.first }.toTypedArray(),
) {
fun toQueryPart() = vals[state].second
}
private inline fun <reified R> AnimeFilterList.getFirst(): R {
return first { it is R } as R
open class CheckBoxFilterList(name: String, val pairs: Array<Pair<String, String>>) :
AnimeFilter.Group<AnimeFilter.CheckBox>(name, pairs.map { CheckBoxVal(it.first, false) })
private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state)
open class TriStateFilterList(name: String, values: List<TriFilterVal>) : AnimeFilter.Group<TriState>(name, values)
class TriFilterVal(name: String) : TriState(name)
private inline fun <reified R> AnimeFilterList.asQueryPart(): String {
return (first { it is R } as QueryPartFilter).toQueryPart()
}
private inline fun <reified R> AnimeFilterList.parseCheckbox(
options: Array<Pair<String, String>>,
name: String,
): String {
return (getFirst<R>() as CheckBoxFilterList).state
): List<String> {
return (first { it is R } as CheckBoxFilterList).state
.asSequence()
.filter { it.state }
.map { checkbox -> options.find { it.first == checkbox.name }!!.second }
.filter(String::isNotBlank)
.joinToString("&") { "$name[]=$it" }
.toList()
}
class TagsFilter : CheckBoxFilterList("Tags", HstreamFiltersData.TAGS_LIST)
class StudiosFilter : CheckBoxFilterList("Studios", HstreamFiltersData.STUDIOS_LIST)
class OrderFilter : QueryPartFilter("Order by", HstreamFiltersData.ORDER_LIST)
private inline fun <reified R> AnimeFilterList.parseTriFilter(
options: Array<Pair<String, String>>,
): List<List<String>> {
return (first { it is R } as TriStateFilterList).state
.filterNot { it.isIgnored() }
.map { filter -> filter.state to options.find { it.first == filter.name }!!.second }
.groupBy { it.first } // group by state
.let { dict ->
val included = dict.get(TriState.STATE_INCLUDE)?.map { it.second }.orEmpty()
val excluded = dict.get(TriState.STATE_EXCLUDE)?.map { it.second }.orEmpty()
listOf(included, excluded)
}
}
class GenresFilter : TriStateFilterList("Genres", HstreamFiltersData.GENRES.map { TriFilterVal(it.first) })
class StudiosFilter : CheckBoxFilterList("Studios", HstreamFiltersData.STUDIOS)
class OrderFilter : QueryPartFilter("Order by", HstreamFiltersData.ORDERS)
val FILTER_LIST get() = AnimeFilterList(
TagsFilter(),
StudiosFilter(),
OrderFilter(),
GenresFilter(),
StudiosFilter(),
)
data class FilterSearchParams(
val tags: String = "",
val studios: String = "",
val order: String = "",
val genres: List<String> = emptyList(),
val blacklisted: List<String> = emptyList(),
val studios: List<String> = emptyList(),
val order: String = "view-count",
)
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
if (filters.isEmpty()) return FilterSearchParams()
val (added, blacklisted) = filters.parseTriFilter<GenresFilter>(HstreamFiltersData.GENRES)
return FilterSearchParams(
filters.parseCheckbox<TagsFilter>(HstreamFiltersData.TAGS_LIST, "tags"),
filters.parseCheckbox<StudiosFilter>(HstreamFiltersData.STUDIOS_LIST, "studios"),
added,
blacklisted,
filters.parseCheckbox<StudiosFilter>(HstreamFiltersData.STUDIOS),
filters.asQueryPart<OrderFilter>(),
)
}
private object HstreamFiltersData {
val TAGS_LIST = arrayOf(
val GENRES = arrayOf(
Pair("3D", "3d"),
Pair("4K", "4k"),
Pair("Ahegao", "ahegao"),
@ -66,6 +100,7 @@ object HstreamFilters {
Pair("Cosplay", "cosplay"),
Pair("Creampie", "creampie"),
Pair("Dark Skin", "dark-skin"),
Pair("Elf", "elf"),
Pair("Facial", "facial"),
Pair("Fantasy", "fantasy"),
Pair("Filmed", "filmed"),
@ -99,6 +134,7 @@ object HstreamFilters {
Pair("Scat", "scat"),
Pair("School Girl", "school-girl"),
Pair("Shota", "shota"),
Pair("Small Boobs", "small-boobs"),
Pair("Succubus", "succubus"),
Pair("Swim Suit", "swim-suit"),
Pair("Teacher", "teacher"),
@ -115,7 +151,7 @@ object HstreamFilters {
Pair("Yuri", "yuri"),
)
val STUDIOS_LIST = arrayOf(
val STUDIOS = arrayOf(
Pair("BOMB! CUTE! BOMB!", "bomb-cute-bomb"),
Pair("BreakBottle", "breakbottle"),
Pair("ChiChinoya", "chichinoya"),
@ -128,6 +164,8 @@ object HstreamFilters {
Pair("Gold Bear", "gold-bear"),
Pair("Green Bunny", "green-bunny"),
Pair("Himajin Planning", "himajin-planning"),
Pair("King Bee", "king-bee"),
Pair("L.", "l"),
Pair("Lune Pictures", "lune-pictures"),
Pair("MS Pictures", "ms-pictures"),
Pair("Majin", "majin"),
@ -144,7 +182,9 @@ object HstreamFilters {
Pair("Pixy", "pixy"),
Pair("PoRO", "poro"),
Pair("Queen Bee", "queen-bee"),
Pair("Rabbit Gate", "rabbit-gate"),
Pair("SELFISH", "selfish"),
Pair("Seven", "seven"),
Pair("Showten", "showten"),
Pair("Studio 1st", "studio-1st"),
Pair("Studio Eromatick", "studio-eromatick"),
@ -154,14 +194,19 @@ object HstreamFilters {
Pair("T-Rex", "t-rex"),
Pair("Toranoana", "toranoana"),
Pair("Union Cho", "union-cho"),
Pair("Valkyria", "valkyria"),
Pair("White Bear", "white-bear"),
Pair("ZIZ", "ziz"),
)
val ORDER_LIST = arrayOf(
Pair("A-Z", "title"),
Pair("Latest Added", "latest"),
Pair("Z-A", "titledesc"),
val ORDERS = arrayOf(
Pair("View Count", "view-count"), // the only reason I'm not using a sort filter
Pair("A-Z", "az"),
Pair("Z-A", "za"),
Pair("Recently Uploaded", "recently-uploaded"),
Pair("Recently Released", "recently-released"),
Pair("Oldest Uploads", "oldest-uploads"),
Pair("Oldest Releases", "oldest-releases"),
)
}
}

View File

@ -0,0 +1,41 @@
package eu.kanade.tachiyomi.animeextension.en.hstream
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
/**
* Springboard that accepts https://hstream.moe/hentai/<item> intents
* and redirects them to the main Aniyomi process.
*/
class HstreamUrlActivity : Activity() {
private val tag = javaClass.simpleName
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
if (pathSegments != null && pathSegments.size > 1) {
val item = pathSegments[1]
val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.ANIMESEARCH"
putExtra("query", "${Hstream.PREFIX_SEARCH}$item")
putExtra("filter", packageName)
}
try {
startActivity(mainIntent)
} catch (e: ActivityNotFoundException) {
Log.e(tag, e.toString())
}
} else {
Log.e(tag, "could not parse uri from intent $intent")
}
finish()
exitProcess(0)
}
}