Remove Koushoku (#13329)
This commit is contained in:
		
							parent
							
								
									2821450458
								
							
						
					
					
						commit
						b56fe66fce
					
				
							
								
								
									
										2
									
								
								.github/workflows/issue_moderator.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/issue_moderator.yml
									
									
									
									
										vendored
									
									
								
							@ -37,7 +37,7 @@ jobs:
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                "type": "both",
 | 
			
		||||
                "regex": ".*(mangago|mangafox|hq\\s*dragon|manga\\s*host|supermangas|superhentais|union\\s*mangas|yes\\s*mangas|manhuascan|heroscan|manhwahot|leitor\\.?net|manga\\s*livre|tsuki\\s*mangas|manga\\s*yabu|mangas\\.in|mangas\\.pw|hentaikai|toptoon\\+?|cocomanga|hitomi\\.la|copymanga|neox|1manga\\.co|mangafox\\.fun|mangahere\\.onl|manga\\s*hub|mangakakalot\\.fun|manganel(?!o)|mangaonline\\.fun|mangapanda\\.onl|mangareader\\.site|mangatoday|manga\\.town|onemanga\\.info).*",
 | 
			
		||||
                "regex": ".*(mangago|mangafox|hq\\s*dragon|manga\\s*host|supermangas|superhentais|union\\s*mangas|yes\\s*mangas|manhuascan|heroscan|manhwahot|leitor\\.?net|manga\\s*livre|tsuki\\s*mangas|manga\\s*yabu|mangas\\.in|mangas\\.pw|hentaikai|toptoon\\+?|cocomanga|hitomi\\.la|copymanga|neox|1manga\\.co|mangafox\\.fun|mangahere\\.onl|manga\\s*hub|mangakakalot\\.fun|manganel(?!o)|mangaonline\\.fun|mangapanda\\.onl|mangareader\\.site|mangatoday|manga\\.town|onemanga\\.info|koushoku).*",
 | 
			
		||||
                "ignoreCase": true,
 | 
			
		||||
                "message": "{match} will not be added back as it is too difficult to maintain. Read #3475 for more information"
 | 
			
		||||
              },
 | 
			
		||||
 | 
			
		||||
@ -1,24 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    package="eu.kanade.tachiyomi.extension">
 | 
			
		||||
 | 
			
		||||
    <application>
 | 
			
		||||
        <activity
 | 
			
		||||
            android:name=".en.koushoku.KoushokuUrlActivity"
 | 
			
		||||
            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="koushoku.org"
 | 
			
		||||
                    android:pathPattern="/archive/..*"
 | 
			
		||||
                    android:scheme="https" />
 | 
			
		||||
            </intent-filter>
 | 
			
		||||
        </activity>
 | 
			
		||||
    </application>
 | 
			
		||||
</manifest>
 | 
			
		||||
@ -1,12 +0,0 @@
 | 
			
		||||
apply plugin: 'com.android.application'
 | 
			
		||||
apply plugin: 'kotlin-android'
 | 
			
		||||
 | 
			
		||||
ext {
 | 
			
		||||
    extName = 'Koushoku'
 | 
			
		||||
    pkgNameSuffix = 'en.koushoku'
 | 
			
		||||
    extClass = '.Koushoku'
 | 
			
		||||
    extVersionCode = 15
 | 
			
		||||
    isNsfw = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: "$rootDir/common.gradle"
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 8.4 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 4.0 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 14 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 29 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 50 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 194 KiB  | 
@ -1,290 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.extension.en.koushoku
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.network.GET
 | 
			
		||||
import eu.kanade.tachiyomi.network.asObservableSuccess
 | 
			
		||||
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.Filter
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.FilterList
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.MangasPage
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.Page
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.SChapter
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.SManga
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
 | 
			
		||||
import eu.kanade.tachiyomi.util.asJsoup
 | 
			
		||||
import okhttp3.Headers
 | 
			
		||||
import okhttp3.HttpUrl
 | 
			
		||||
import okhttp3.HttpUrl.Companion.toHttpUrl
 | 
			
		||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 | 
			
		||||
import okhttp3.OkHttpClient
 | 
			
		||||
import okhttp3.Request
 | 
			
		||||
import okhttp3.Response
 | 
			
		||||
import org.jsoup.nodes.Document
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import java.text.SimpleDateFormat
 | 
			
		||||
import java.util.Locale
 | 
			
		||||
import kotlin.random.Random
 | 
			
		||||
 | 
			
		||||
class Koushoku : ParsedHttpSource() {
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val PREFIX_ID_SEARCH = "id:"
 | 
			
		||||
 | 
			
		||||
        const val thumbnailSelector = "figure img"
 | 
			
		||||
        const val magazinesSelector = ".metadata a[href^='/magazines/']"
 | 
			
		||||
 | 
			
		||||
        private val PATTERN_IMAGES = "(.+/)(\\d+)(.*)".toRegex()
 | 
			
		||||
        private val DATE_FORMAT = SimpleDateFormat("E, d MMM yyy HH:mm:ss 'UTC'", Locale.US)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val baseUrl = "https://koushoku.org"
 | 
			
		||||
    override val name = "Koushoku"
 | 
			
		||||
    override val lang = "en"
 | 
			
		||||
    override val supportsLatest = true
 | 
			
		||||
 | 
			
		||||
    override val client: OkHttpClient = network.cloudflareClient.newBuilder()
 | 
			
		||||
        .addInterceptor(KoushokuWebViewInterceptor())
 | 
			
		||||
        // Site: 40req per 1 minute
 | 
			
		||||
        // Here: 1req per 2 sec -> 30req per 1 minute
 | 
			
		||||
        // (somewhat lower due to caching)
 | 
			
		||||
        .rateLimitHost("https://koushoku.org".toHttpUrl(), 1, 2)
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    override fun headersBuilder(): Headers.Builder {
 | 
			
		||||
        val chromeStableVersion = listOf("104.0.5112.69", "103.0.5060.71", "103.0.5060.70", "103.0.5060.53", "103.0.5060.129", "102.0.5005.99", "102.0.5005.98", "102.0.5005.78", "102.0.5005.125").random()
 | 
			
		||||
        val chromeCanaryVersion = listOf("106.0.5227.0", "106.0.5209.0", "106.0.5206.0", "106.0.5201.2", "106.0.5201.0", "106.0.5200.0", "106.0.5199.0", "106.0.5197.0", "106.0.5196.0", "105.0.5195.2", "105.0.5194.0", "105.0.5193.0", "105.0.5192.0", "105.0.5191.0", "105.0.5190.0", "105.0.5189.0", "105.0.5186.0", "105.0.5185.0", "105.0.5184.0", "105.0.5182.0", "105.0.5180.0", "105.0.5179.3", "105.0.5178.0", "105.0.5177.2", "105.0.5176.0", "105.0.5175.0", "105.0.5174.0", "105.0.5173.0", "105.0.5172.0", "105.0.5171.0").random()
 | 
			
		||||
        val chromeVersion = if (Random.nextFloat() > 0.2) chromeStableVersion else chromeCanaryVersion
 | 
			
		||||
 | 
			
		||||
        val deviceInfo = if (Random.nextFloat() > 0.2) "" else "; " + listOf("SM-S908B", "SM-S908U", "SM-A536B", "SM-A536U", "SM-S901B", "SM-S901U", "SM-A736B", "SM-G973F", "SM-A528B", "SM-G975U", "SM-G990B", "SM-G990U").random()
 | 
			
		||||
        val androidVersion = IntRange(if (deviceInfo.isEmpty()) 9 else 11, 12).random()
 | 
			
		||||
 | 
			
		||||
        return super.headersBuilder()
 | 
			
		||||
            .set("User-Agent", "Mozilla/5.0 (Linux; Android $androidVersion$deviceInfo) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/$chromeVersion Mobile Safari/537.36")
 | 
			
		||||
            .add("Referer", "$baseUrl/")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/?page=$page", headers)
 | 
			
		||||
    override fun latestUpdatesSelector() = "#archives.feed .entries > .entry"
 | 
			
		||||
    override fun latestUpdatesNextPageSelector() = "footer nav li:has(a.active) + li:not(:last-child) > a"
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
 | 
			
		||||
        setUrlWithoutDomain(element.selectFirst("a").attr("href"))
 | 
			
		||||
        title = element.selectFirst("[title]").attr("title")
 | 
			
		||||
        thumbnail_url = element.selectFirst(thumbnailSelector).absUrl("src")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun searchMangaByIdRequest(id: String) = GET("$baseUrl/archive/$id", headers)
 | 
			
		||||
 | 
			
		||||
    // taken from Tsumino ext
 | 
			
		||||
    private fun searchMangaByIdParse(response: Response, id: String): MangasPage {
 | 
			
		||||
        val details = mangaDetailsParse(response)
 | 
			
		||||
        details.url = "/archive/$id"
 | 
			
		||||
        return MangasPage(listOf(details), false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // taken from Tsumino ext
 | 
			
		||||
    override fun fetchSearchManga(
 | 
			
		||||
        page: Int,
 | 
			
		||||
        query: String,
 | 
			
		||||
        filters: FilterList
 | 
			
		||||
    ): Observable<MangasPage> {
 | 
			
		||||
        return if (query.startsWith(PREFIX_ID_SEARCH)) {
 | 
			
		||||
            val id = query.removePrefix(PREFIX_ID_SEARCH)
 | 
			
		||||
            client.newCall(searchMangaByIdRequest(id)).asObservableSuccess()
 | 
			
		||||
                .map { response -> searchMangaByIdParse(response, id) }
 | 
			
		||||
        } else {
 | 
			
		||||
            super.fetchSearchManga(page, query, filters)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
 | 
			
		||||
        val url = "$baseUrl/search".toHttpUrlOrNull()!!.newBuilder()
 | 
			
		||||
            .addQueryParameter("page", page.toString())
 | 
			
		||||
 | 
			
		||||
        val filterList = if (filters.isEmpty()) getFilterList() else filters
 | 
			
		||||
        filterList.findInstance<SortFilter>()?.addQueryParameter(url)
 | 
			
		||||
        url.addQueryParameter("q", buildAdvQuery(query, filterList))
 | 
			
		||||
        return GET(url.toString(), headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun buildAdvQuery(query: String, filterList: FilterList): String {
 | 
			
		||||
        val title = if (query.isNotBlank()) "title*:\"$query\" " else ""
 | 
			
		||||
        val filters: List<String> = filterList.filterIsInstance<Filter.Text>().map { filter ->
 | 
			
		||||
            if (filter.state.isBlank()) return@map ""
 | 
			
		||||
            val included = mutableListOf<String>()
 | 
			
		||||
            val excluded = mutableListOf<String>()
 | 
			
		||||
            val name = if (filter.name.lowercase().contentEquals("tags")) "tag" else filter.name.lowercase()
 | 
			
		||||
            filter.state.split(",").map(String::trim).filterNot(String::isBlank).forEach { entry ->
 | 
			
		||||
                if (entry.startsWith("-")) {
 | 
			
		||||
                    excluded.add(entry.slice(1 until entry.length))
 | 
			
		||||
                } else {
 | 
			
		||||
                    included.add(entry)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            buildString {
 | 
			
		||||
                if (included.isNotEmpty()) append("$name&*:\"${included.joinToString(",")}\" ")
 | 
			
		||||
                if (excluded.isNotEmpty()) append("-$name&*:\"${excluded.joinToString(",")}\"")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return "$title${
 | 
			
		||||
        filters.filterNot(String::isBlank).joinToString(" ", transform = String::trim)
 | 
			
		||||
        }"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun searchMangaSelector() = latestUpdatesSelector()
 | 
			
		||||
    override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector()
 | 
			
		||||
    override fun searchMangaFromElement(element: Element) = latestUpdatesFromElement(element)
 | 
			
		||||
 | 
			
		||||
    override fun popularMangaRequest(page: Int) = GET("$baseUrl/popular?page=$page", headers)
 | 
			
		||||
    override fun popularMangaSelector() = latestUpdatesSelector()
 | 
			
		||||
    override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector()
 | 
			
		||||
    override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element)
 | 
			
		||||
 | 
			
		||||
    override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
 | 
			
		||||
        return if (!manga.initialized) {
 | 
			
		||||
            super.fetchMangaDetails(manga)
 | 
			
		||||
        } else {
 | 
			
		||||
            Observable.just(manga)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun mangaDetailsParse(document: Document) = SManga.create().apply {
 | 
			
		||||
        title = document.selectFirst(".metadata > h1").text()
 | 
			
		||||
 | 
			
		||||
        // Reuse cover from browse
 | 
			
		||||
        thumbnail_url = document.selectFirst(thumbnailSelector).absUrl("src")
 | 
			
		||||
            .replace(Regex("/\\d+\\.webp\$"), "/288.webp")
 | 
			
		||||
 | 
			
		||||
        artist = document.select(".metadata a[href^='/artists/'], .metadata a[href^='/circles/']")
 | 
			
		||||
            .joinToString { it.text() }
 | 
			
		||||
        author = artist
 | 
			
		||||
        genre = document.select(".metadata .tags a, $magazinesSelector")
 | 
			
		||||
            .ifEmpty { null }?.joinToString { it.text() }
 | 
			
		||||
        description = getDesc(document)
 | 
			
		||||
        status = SManga.COMPLETED
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun chapterListParse(response: Response): List<SChapter> {
 | 
			
		||||
        val document = response.asJsoup()
 | 
			
		||||
 | 
			
		||||
        return listOf(
 | 
			
		||||
            SChapter.create().apply {
 | 
			
		||||
                setUrlWithoutDomain(response.request.url.encodedPath)
 | 
			
		||||
                name = "Chapter"
 | 
			
		||||
 | 
			
		||||
                val dateText = document.select("tr > td:first-child:contains(Uploaded Date) + td")
 | 
			
		||||
                    .text()
 | 
			
		||||
                date_upload = runCatching { DATE_FORMAT.parse(dateText) }
 | 
			
		||||
                    .getOrNull()
 | 
			
		||||
                    ?.time
 | 
			
		||||
                    ?: 0
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun chapterFromElement(element: Element) =
 | 
			
		||||
        throw UnsupportedOperationException("Not used")
 | 
			
		||||
 | 
			
		||||
    override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
 | 
			
		||||
 | 
			
		||||
    override fun pageListRequest(chapter: SChapter) = GET("$baseUrl${chapter.url}/1", headers)
 | 
			
		||||
 | 
			
		||||
    override fun pageListParse(response: Response): List<Page> {
 | 
			
		||||
        val document = response.asJsoup()
 | 
			
		||||
 | 
			
		||||
        val totalPages = document.selectFirst(".total")?.text()?.toInt() ?: 0
 | 
			
		||||
        if (totalPages == 0)
 | 
			
		||||
            throw UnsupportedOperationException("Error: Empty pages (try Webview)")
 | 
			
		||||
 | 
			
		||||
        val match = PATTERN_IMAGES.find(response.request.url.toString())!!
 | 
			
		||||
        val prefix = match.groupValues[1]
 | 
			
		||||
        val suffix = match.groupValues[3]
 | 
			
		||||
 | 
			
		||||
        return (1..totalPages).map {
 | 
			
		||||
            Page(it, "$prefix$it$suffix")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun pageListParse(document: Document): List<Page> =
 | 
			
		||||
        throw UnsupportedOperationException("Not used")
 | 
			
		||||
 | 
			
		||||
    override fun imageUrlParse(document: Document): String =
 | 
			
		||||
        document.selectFirst(".main img, main img").absUrl("src")
 | 
			
		||||
 | 
			
		||||
    override fun getFilterList() = FilterList(
 | 
			
		||||
        SortFilter(
 | 
			
		||||
            "Sort",
 | 
			
		||||
            arrayOf(
 | 
			
		||||
                Sortable("ID", "id"),
 | 
			
		||||
                Sortable("Title", "title"),
 | 
			
		||||
                Sortable("Created Date", "created_at"),
 | 
			
		||||
                Sortable("Uploaded Date", "published_at"),
 | 
			
		||||
                Sortable("Pages", "pages"),
 | 
			
		||||
            )
 | 
			
		||||
        ),
 | 
			
		||||
        Filter.Header("Separate tags with commas (,)"),
 | 
			
		||||
        Filter.Header("Prepend with dash (-) to exclude"),
 | 
			
		||||
        ArtistFilter(),
 | 
			
		||||
        CircleFilter(),
 | 
			
		||||
        MagazineFilter(),
 | 
			
		||||
        ParodyFilter(),
 | 
			
		||||
        TagFilter(),
 | 
			
		||||
        PagesFilter()
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    // Adapted from Mangadex ext
 | 
			
		||||
    class SortFilter(displayName: String, private val sortables: Array<Sortable>) :
 | 
			
		||||
        Filter.Sort(
 | 
			
		||||
            displayName,
 | 
			
		||||
            sortables.map(Sortable::title).toTypedArray(),
 | 
			
		||||
            Selection(2, false)
 | 
			
		||||
        ) {
 | 
			
		||||
        fun addQueryParameter(url: HttpUrl.Builder) {
 | 
			
		||||
            if (state != null) {
 | 
			
		||||
                val sort = sortables[state!!.index].value
 | 
			
		||||
                val order = when (state!!.ascending) {
 | 
			
		||||
                    true -> "asc"
 | 
			
		||||
                    false -> "desc"
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                url.addQueryParameter("sort", sort)
 | 
			
		||||
                url.addQueryParameter("order", order)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data class Sortable(val title: String, val value: String) {
 | 
			
		||||
        override fun toString(): String = title
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ArtistFilter : Filter.Text("Artist")
 | 
			
		||||
    class CircleFilter : Filter.Text("Circle")
 | 
			
		||||
    class MagazineFilter : Filter.Text("Magazine")
 | 
			
		||||
    class ParodyFilter : Filter.Text("Parody")
 | 
			
		||||
    class TagFilter : Filter.Text("Tags")
 | 
			
		||||
    class PagesFilter : Filter.Text("Pages")
 | 
			
		||||
 | 
			
		||||
    // Taken from nhentai ext
 | 
			
		||||
    private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T
 | 
			
		||||
 | 
			
		||||
    private fun getDesc(document: Document) = buildString {
 | 
			
		||||
        val magazines = document.select(magazinesSelector)
 | 
			
		||||
        if (magazines.isNotEmpty()) {
 | 
			
		||||
            append("Magazines: ")
 | 
			
		||||
            append(magazines.joinToString { it.text() })
 | 
			
		||||
            append("\n")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val parodies = document.select(".metadata a[href^='/parodies/']")
 | 
			
		||||
        if (parodies.isNotEmpty()) {
 | 
			
		||||
            append("Parodies: ")
 | 
			
		||||
            append(parodies.joinToString { it.text() })
 | 
			
		||||
            append("\n")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val pages = document.selectFirst("tr > td:first-child:contains(Pages) + td")
 | 
			
		||||
        append("Pages: ").append(pages.text()).append("\n")
 | 
			
		||||
 | 
			
		||||
        val size: Element? = document.selectFirst("tr > td:first-child:contains(Size) + td")
 | 
			
		||||
        append("Size: ").append(size?.text() ?: "Unknown")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.extension.en.koushoku
 | 
			
		||||
 | 
			
		||||
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://koushoku.org/archive/xxxxx intents and redirects them to
 | 
			
		||||
 * the main Tachiyomi process.
 | 
			
		||||
 */
 | 
			
		||||
class KoushokuUrlActivity : Activity() {
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        val pathSegments = intent?.data?.pathSegments
 | 
			
		||||
        if (pathSegments != null && pathSegments.size > 1) {
 | 
			
		||||
            val id = pathSegments[1]
 | 
			
		||||
            val mainIntent = Intent().apply {
 | 
			
		||||
                action = "eu.kanade.tachiyomi.SEARCH"
 | 
			
		||||
                putExtra("query", "${Koushoku.PREFIX_ID_SEARCH}$id")
 | 
			
		||||
                putExtra("filter", packageName)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                startActivity(mainIntent)
 | 
			
		||||
            } catch (e: ActivityNotFoundException) {
 | 
			
		||||
                Log.e("KoushokuUrlActivity", e.toString())
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Log.e("KoushokuUrlActivity", "could not parse uri from intent $intent")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        finish()
 | 
			
		||||
        exitProcess(0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,73 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.extension.en.koushoku
 | 
			
		||||
 | 
			
		||||
import android.app.Application
 | 
			
		||||
import android.os.Handler
 | 
			
		||||
import android.os.Looper
 | 
			
		||||
import android.webkit.WebView
 | 
			
		||||
import android.webkit.WebViewClient
 | 
			
		||||
import okhttp3.Interceptor
 | 
			
		||||
import okhttp3.Response
 | 
			
		||||
import org.jsoup.Jsoup
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
import java.util.concurrent.CountDownLatch
 | 
			
		||||
 | 
			
		||||
class KoushokuWebViewInterceptor : Interceptor {
 | 
			
		||||
 | 
			
		||||
    override fun intercept(chain: Interceptor.Chain): Response {
 | 
			
		||||
        val request = chain.request()
 | 
			
		||||
        val response = chain.proceed(request)
 | 
			
		||||
 | 
			
		||||
        if (response.headers("Content-Type").any { it.contains("text/html") }) {
 | 
			
		||||
            val responseBody = response.peekBody(1 * 1024 * 1024).string()
 | 
			
		||||
            if (response.code == 403) {
 | 
			
		||||
                val document = Jsoup.parse(responseBody)
 | 
			
		||||
                if (document.selectFirst("h1")?.text()?.contains(Regex("banned$")) == true) {
 | 
			
		||||
                    throw IOException("You have been banned. Check WebView for details.")
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (response.networkResponse != null) {
 | 
			
		||||
                try {
 | 
			
		||||
                    proceedWithWebView(response, responseBody)
 | 
			
		||||
                } catch (e: Exception) {
 | 
			
		||||
                    throw IOException(e)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun proceedWithWebView(response: Response, responseBody: String) {
 | 
			
		||||
        val latch = CountDownLatch(1)
 | 
			
		||||
        val handler = Handler(Looper.getMainLooper())
 | 
			
		||||
 | 
			
		||||
        handler.post {
 | 
			
		||||
            val webView = WebView(Injekt.get<Application>())
 | 
			
		||||
            with(webView.settings) {
 | 
			
		||||
                loadsImagesAutomatically = false
 | 
			
		||||
                userAgentString = response.request.header("User-Agent")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            webView.webViewClient = object : WebViewClient() {
 | 
			
		||||
                override fun onPageFinished(view: WebView, url: String) {
 | 
			
		||||
                    webView.stopLoading()
 | 
			
		||||
                    webView.destroy()
 | 
			
		||||
                    latch.countDown()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            webView.loadDataWithBaseURL(
 | 
			
		||||
                response.request.url.toString(),
 | 
			
		||||
                responseBody,
 | 
			
		||||
                "text/html",
 | 
			
		||||
                "utf-8",
 | 
			
		||||
                null
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        latch.await()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user