[RU]Multi Lib (MangaLib and HentaiLib) + fixes/updates (#12104)

This commit is contained in:
Ejan 2022-06-07 15:12:22 +05:00 committed by GitHub
parent d33f0fe903
commit 20f2a5e67a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 548 additions and 1294 deletions

View File

@ -4,7 +4,7 @@
<application> <application>
<activity <activity
android:name=".ru.libhentai.LibHentaiActivity" android:name="eu.kanade.tachiyomi.multisrc.libgroup.LibUrlActivity"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:exported="true" android:exported="true"
android:theme="@android:style/Theme.NoDisplay"> android:theme="@android:style/Theme.NoDisplay">
@ -14,7 +14,7 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<!-- LibHentaiActivity sites can be added here. --> <!-- LibUrlActivity sites can be added here. -->
<data <data
android:host="hentailib.me" android:host="hentailib.me"
android:pathPattern="/..*/v..*" android:pathPattern="/..*/v..*"

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,254 @@
package eu.kanade.tachiyomi.extension.ru.hentailib
import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.multisrc.libgroup.LibGroup
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
class HentaiLib : LibGroup("HentaiLib", "https://hentailib.me", "ru") {
override val id: Long = 6425650164840473547
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::imageContentTypeIntercept)
.addInterceptor { chain ->
val originalRequest = chain.request()
if (originalRequest.url.toString().contains(baseUrl))
if (!network.cloudflareClient.newCall(GET(baseUrl, headers))
.execute().body!!.string().contains("m-menu__user-info")
)
throw IOException("Для просмотра 18+ контента необходима авторизация через WebView")
return@addInterceptor chain.proceed(originalRequest)
}
.build()
private var csrfToken: String = ""
private fun catalogHeaders() = Headers.Builder()
.apply {
add("Accept", "application/json, text/plain, */*")
add("X-Requested-With", "XMLHttpRequest")
add("x-csrf-token", csrfToken)
}
.build()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (csrfToken.isEmpty()) {
val tokenResponse = client.newCall(popularMangaRequest(page)).execute()
val resBody = tokenResponse.body!!.string()
csrfToken = "_token\" content=\"(.*)\"".toRegex().find(resBody)!!.groups[1]!!.value
}
val url = super.searchMangaRequest(page, query, filters).url.newBuilder()
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is TagList -> filter.state.forEach { tag ->
if (tag.state != Filter.TriState.STATE_IGNORE) {
url.addQueryParameter(
if (tag.isIncluded()) "tags[include][]" else "tags[exclude][]",
tag.id
)
}
}
}
}
return POST(url.toString(), catalogHeaders())
}
// Filters
private class SearchFilter(name: String, val id: String) : Filter.TriState(name)
private class TagList(tags: List<SearchFilter>) : Filter.Group<SearchFilter>("Теги", tags)
override fun getFilterList(): FilterList {
val filters = super.getFilterList().toMutableList()
filters.add(4, TagList(getTagList()))
return FilterList(filters)
}
private fun getTagList() = listOf(
SearchFilter("3D", "1"),
SearchFilter("Defloration", "287"),
SearchFilter("FPP(Вид от первого лица)", "289"),
SearchFilter("Footfuck", "5"),
SearchFilter("Handjob", "6"),
SearchFilter("Lactation", "7"),
SearchFilter("Living clothes", "284"),
SearchFilter("Mind break", "9"),
SearchFilter("Scat", "13"),
SearchFilter("Selfcest", "286"),
SearchFilter("Shemale", "220"),
SearchFilter("Tomboy", "14"),
SearchFilter("Unbirth", "283"),
SearchFilter("X-Ray", "15"),
SearchFilter("Алкоголь", "16"),
SearchFilter("Анал", "17"),
SearchFilter("Андроид", "18"),
SearchFilter("Анилингус", "19"),
SearchFilter("Анимация (GIF)", "350"),
SearchFilter("Арт", "20"),
SearchFilter("Ахэгао", "2"),
SearchFilter("БДСМ", "22"),
SearchFilter("Бакуню", "21"),
SearchFilter("Бара", "293"),
SearchFilter("Без проникновения", "336"),
SearchFilter("Без текста", "23"),
SearchFilter("Без трусиков", "24"),
SearchFilter("Без цензуры", "25"),
SearchFilter("Беременность", "26"),
SearchFilter("Бикини", "27"),
SearchFilter("Близнецы", "28"),
SearchFilter("Боди-арт", "29"),
SearchFilter("Больница", "30"),
SearchFilter("Большая грудь", "31"),
SearchFilter("Большая попка", "32"),
SearchFilter("Борьба", "33"),
SearchFilter("Буккакэ", "34"),
SearchFilter("В бассейне", "35"),
SearchFilter("В ванной", "36"),
SearchFilter("В государственном учреждении", "37"),
SearchFilter("В общественном месте", "38"),
SearchFilter("В очках", "8"),
SearchFilter("В первый раз", "39"),
SearchFilter("В транспорте", "40"),
SearchFilter("Вампиры", "41"),
SearchFilter("Вибратор", "42"),
SearchFilter("Втроём", "43"),
SearchFilter("Гипноз", "44"),
SearchFilter("Глубокий минет", "45"),
SearchFilter("Горячий источник", "46"),
SearchFilter("Групповой секс", "47"),
SearchFilter("Гуро", "307"),
SearchFilter("Гяру и Гангуро", "48"),
SearchFilter("Двойное проникновение", "49"),
SearchFilter("Девочки-волшебницы", "50"),
SearchFilter("Девушка-туалет", "51"),
SearchFilter("Демон", "52"),
SearchFilter("Дилдо", "53"),
SearchFilter("Домохозяйка", "54"),
SearchFilter("Дыра в стене", "55"),
SearchFilter("Жестокость", "56"),
SearchFilter("Золотой дождь", "57"),
SearchFilter("Зомби", "58"),
SearchFilter("Зоофилия", "351"),
SearchFilter("Зрелые женщины", "59"),
SearchFilter("Избиение", "223"),
SearchFilter("Измена", "60"),
SearchFilter("Изнасилование", "61"),
SearchFilter("Инопланетяне", "62"),
SearchFilter("Инцест", "63"),
SearchFilter("Исполнение желаний", "64"),
SearchFilter("Историческое", "65"),
SearchFilter("Камера", "66"),
SearchFilter("Кляп", "288"),
SearchFilter("Колготки", "67"),
SearchFilter("Косплей", "68"),
SearchFilter("Кримпай", "3"),
SearchFilter("Куннилингус", "69"),
SearchFilter("Купальники", "70"),
SearchFilter("ЛГБТ", "343"),
SearchFilter("Латекс и кожа", "71"),
SearchFilter("Магия", "72"),
SearchFilter("Маленькая грудь", "73"),
SearchFilter("Мастурбация", "74"),
SearchFilter("Медсестра", "221"),
SearchFilter("Мейдочка", "75"),
SearchFilter("Мерзкий дядька", "76"),
SearchFilter("Милф", "77"),
SearchFilter("Много девушек", "78"),
SearchFilter("Много спермы", "79"),
SearchFilter("Молоко", "80"),
SearchFilter("Монашка", "353"),
SearchFilter("Монстродевушки", "81"),
SearchFilter("Монстры", "82"),
SearchFilter("Мочеиспускание", "83"),
SearchFilter("На природе", "84"),
SearchFilter("Наблюдение", "85"),
SearchFilter("Насекомые", "285"),
SearchFilter("Небритая киска", "86"),
SearchFilter("Небритые подмышки", "87"),
SearchFilter("Нетораре", "88"),
SearchFilter("Нэтори", "11"),
SearchFilter("Обмен телами", "89"),
SearchFilter("Обычный секс", "90"),
SearchFilter("Огромная грудь", "91"),
SearchFilter("Огромный член", "92"),
SearchFilter("Омораси", "93"),
SearchFilter("Оральный секс", "94"),
SearchFilter("Орки", "95"),
SearchFilter("Остановка времени", "296"),
SearchFilter("Пайзури", "96"),
SearchFilter("Парень пассив", "97"),
SearchFilter("Переодевание", "98"),
SearchFilter("Пирсинг", "308"),
SearchFilter("Пляж", "99"),
SearchFilter("Повседневность", "100"),
SearchFilter("Подвязки", "282"),
SearchFilter("Подглядывание", "101"),
SearchFilter("Подчинение", "102"),
SearchFilter("Похищение", "103"),
SearchFilter("Превозмогание", "104"),
SearchFilter("Принуждение", "105"),
SearchFilter("Прозрачная одежда", "106"),
SearchFilter("Проституция", "107"),
SearchFilter("Психические отклонения", "108"),
SearchFilter("Публично", "109"),
SearchFilter("Пытки", "224"),
SearchFilter("Пьяные", "110"),
SearchFilter("Рабы", "356"),
SearchFilter("Рабыни", "111"),
SearchFilter("С Сюжетом", "337"),
SearchFilter("Сuminside", "4"),
SearchFilter("Секс-игрушки", "112"),
SearchFilter("Сексуально возбуждённая", "113"),
SearchFilter("Сибари", "114"),
SearchFilter("Спортивная форма", "117"),
SearchFilter("Спортивное тело", "335"),
SearchFilter("Спящие", "118"),
SearchFilter("Страпон", "119"),
SearchFilter("Суккуб", "120"),
SearchFilter("Темнокожие", "121"),
SearchFilter("Тентакли", "122"),
SearchFilter("Толстушки", "123"),
SearchFilter("Трагедия", "124"),
SearchFilter("Трап", "125"),
SearchFilter("Ужасы", "126"),
SearchFilter("Униформа", "127"),
SearchFilter("Учитель и ученик", "352"),
SearchFilter("Ушастые", "128"),
SearchFilter("Фантазии", "129"),
SearchFilter("Фемдом", "130"),
SearchFilter("Фестиваль", "131"),
SearchFilter("Фетиш", "132"),
SearchFilter("Фистинг", "133"),
SearchFilter("Фурри", "134"),
SearchFilter("Футанари", "136"),
SearchFilter("Футанари имеет парня", "137"),
SearchFilter("Цельный купальник", "138"),
SearchFilter("Цундэрэ", "139"),
SearchFilter("Чикан", "140"),
SearchFilter("Чулки", "141"),
SearchFilter("Шлюха", "142"),
SearchFilter("Эксгибиционизм", "143"),
SearchFilter("Эльф", "144"),
SearchFilter("Юные", "145"),
SearchFilter("Яндэрэ", "146")
)
companion object {
const val PREFIX_SLUG_SEARCH = "slug:"
}
}

View File

@ -4,7 +4,7 @@
<application> <application>
<activity <activity
android:name=".ru.libmanga.LibMangaActivity" android:name="eu.kanade.tachiyomi.multisrc.libgroup.LibUrlActivity"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:exported="true" android:exported="true"
android:theme="@android:style/Theme.NoDisplay"> android:theme="@android:style/Theme.NoDisplay">
@ -14,7 +14,7 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<!-- LibMangaActivity sites can be added here. --> <!-- LibUrlActivity sites can be added here. -->
<data <data
android:host="mangalib.me" android:host="mangalib.me"
android:pathPattern="/..*/v..*" android:pathPattern="/..*/v..*"

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

View File

@ -0,0 +1,222 @@
package eu.kanade.tachiyomi.extension.ru.mangalib
import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.multisrc.libgroup.LibGroup
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class MangaLib : LibGroup("MangaLib", "https://mangalib.me", "ru") {
override val id: Long = 6111047689498497237
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_${id}_2", 0x0000)
}
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::imageContentTypeIntercept)
.build()
private var csrfToken: String = ""
private fun catalogHeaders() = Headers.Builder()
.apply {
add("Accept", "application/json, text/plain, */*")
add("X-Requested-With", "XMLHttpRequest")
add("x-csrf-token", csrfToken)
}
.build()
private val baseOrig: String = "https://mangalib.me"
private val baseMirr: String = "https://mangalib.org"
private var domain: String? = preferences.getString(DOMAIN_PREF, baseOrig)
override val baseUrl: String = domain.toString()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (csrfToken.isEmpty()) {
val tokenResponse = client.newCall(popularMangaRequest(page)).execute()
val resBody = tokenResponse.body!!.string()
csrfToken = "_token\" content=\"(.*)\"".toRegex().find(resBody)!!.groups[1]!!.value
}
val url = super.searchMangaRequest(page, query, filters).url.newBuilder()
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is AgeList -> filter.state.forEach { age ->
if (age.state) {
url.addQueryParameter("caution[]", age.id)
}
}
is TagList -> filter.state.forEach { tag ->
if (tag.state != Filter.TriState.STATE_IGNORE) {
url.addQueryParameter(
if (tag.isIncluded()) "tags[include][]" else "tags[exclude][]",
tag.id
)
}
}
}
}
return POST(url.toString(), catalogHeaders())
}
// Filters
private class SearchFilter(name: String, val id: String) : Filter.TriState(name)
private class CheckFilter(name: String, val id: String) : Filter.CheckBox(name)
private class TagList(tags: List<SearchFilter>) : Filter.Group<SearchFilter>("Теги", tags)
private class AgeList(ages: List<CheckFilter>) : Filter.Group<CheckFilter>("Возрастное ограничение", ages)
override fun getFilterList(): FilterList {
val filters = super.getFilterList().toMutableList()
filters.add(4, TagList(getTagList()))
filters.add(7, AgeList(getAgeList()))
return FilterList(filters)
}
private fun getTagList() = listOf(
SearchFilter("Азартные игры", "304"),
SearchFilter("Алхимия", "225"),
SearchFilter("Ангелы", "226"),
SearchFilter("Антигерой", "175"),
SearchFilter("Антиутопия", "227"),
SearchFilter("Апокалипсис", "228"),
SearchFilter("Армия", "229"),
SearchFilter("Артефакты", "230"),
SearchFilter("Боги", "215"),
SearchFilter("Бои на мечах", "231"),
SearchFilter("Борьба за власть", "231"),
SearchFilter("Брат и сестра", "233"),
SearchFilter("Будущее", "234"),
SearchFilter("Ведьма", "338"),
SearchFilter("Вестерн", "235"),
SearchFilter("Видеоигры", "185"),
SearchFilter("Виртуальная реальность", "195"),
SearchFilter("Владыка демонов", "236"),
SearchFilter("Военные", "179"),
SearchFilter("Война", "237"),
SearchFilter("Волшебники / маги", "281"),
SearchFilter("Волшебные существа", "239"),
SearchFilter("Воспоминания из другого мира", "240"),
SearchFilter("Выживание", "193"),
SearchFilter("ГГ женщина", "243"),
SearchFilter("ГГ имба", "291"),
SearchFilter("ГГ мужчина", "244"),
SearchFilter("Геймеры", "241"),
SearchFilter("Гильдии", "242"),
SearchFilter("Глупый ГГ", "297"),
SearchFilter("Гоблины", "245"),
SearchFilter("Горничные", "169"),
SearchFilter("Гяру", "178"),
SearchFilter("Демоны", "151"),
SearchFilter("Драконы", "246"),
SearchFilter("Дружба", "247"),
SearchFilter("Жестокий мир", "249"),
SearchFilter("Животные компаньоны", "250"),
SearchFilter("Завоевание мира", "251"),
SearchFilter("Зверолюди", "162"),
SearchFilter("Злые духи", "252"),
SearchFilter("Зомби", "149"),
SearchFilter("Игровые элементы", "253"),
SearchFilter("Империи", "254"),
SearchFilter("Квесты", "255"),
SearchFilter("Космос", "256"),
SearchFilter("Кулинария", "152"),
SearchFilter("Культивация", "160"),
SearchFilter("Легендарное оружие", "257"),
SearchFilter("Лоли", "187"),
SearchFilter("Магическая академия", "258"),
SearchFilter("Магия", "168"),
SearchFilter("Мафия", "172"),
SearchFilter("Медицина", "153"),
SearchFilter("Месть", "259"),
SearchFilter("Монстр Девушки", "188"),
SearchFilter("Монстры", "189"),
SearchFilter("Музыка", "190"),
SearchFilter("Навыки / способности", "260"),
SearchFilter("Насилие / жестокость", "262"),
SearchFilter("Наёмники", "261"),
SearchFilter("Нежить", "263"),
SearchFilter("Ниндая", "180"),
SearchFilter("Обратный Гарем", "191"),
SearchFilter("Огнестрельное оружие", "264"),
SearchFilter("Офисные Работники", "181"),
SearchFilter("Пародия", "265"),
SearchFilter("Пираты", "340"),
SearchFilter("Подземелья", "266"),
SearchFilter("Политика", "267"),
SearchFilter("Полиция", "182"),
SearchFilter("Преступники / Криминал", "186"),
SearchFilter("Призраки / Духи", "177"),
SearchFilter("Путешествие во времени", "194"),
SearchFilter("Разумные расы", "268"),
SearchFilter("Ранги силы", "248"),
SearchFilter("Реинкарнация", "148"),
SearchFilter("Роботы", "269"),
SearchFilter("Рыцари", "270"),
SearchFilter("Самураи", "183"),
SearchFilter("Система", "271"),
SearchFilter("Скрытие личности", "273"),
SearchFilter("Спасение мира", "274"),
SearchFilter("Спортивное тело", "334"),
SearchFilter("Средневековье", "173"),
SearchFilter("Стимпанк", "272"),
SearchFilter("Супергерои", "275"),
SearchFilter("Традиционные игры", "184"),
SearchFilter("Умный ГГ", "302"),
SearchFilter("Учитель / ученик", "276"),
SearchFilter("Философия", "277"),
SearchFilter("Хикикомори", "166"),
SearchFilter("Холодное оружие", "278"),
SearchFilter("Шантаж", "279"),
SearchFilter("Эльфы", "216"),
SearchFilter("Якудза", "164"),
SearchFilter("Япония", "280")
)
private fun getAgeList() = listOf(
CheckFilter("Отсутствует", "0"),
CheckFilter("16+", "1"),
CheckFilter("18+", "2")
)
companion object {
const val PREFIX_SLUG_SEARCH = "slug:"
private const val DOMAIN_PREF = "MangaLibDomain"
private const val DOMAIN_PREF_Title = "Выбор домена"
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
super.setupPreferenceScreen(screen)
ListPreference(screen.context).apply {
key = DOMAIN_PREF
title = DOMAIN_PREF_Title
entries = arrayOf("Основной (mangalib.me)", "Зеркало (mangalib.org)")
entryValues = arrayOf(baseOrig, baseMirr)
summary = "%s"
setDefaultValue(baseOrig)
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit().putString(DOMAIN_PREF, newValue as String).commit()
val warning = "Для смены домена необходимо перезапустить приложение с полной остановкой."
Toast.makeText(screen.context, warning, Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}.let(screen::addPreference)
}
}

View File

@ -0,0 +1,25 @@
package eu.kanade.tachiyomi.multisrc.libgroup
import generator.ThemeSourceData.SingleLang
import generator.ThemeSourceGenerator
class LibGenerator: ThemeSourceGenerator {
override val themePkg = "libgroup"
override val themeClass = "LibGroup"
override val baseVersionCode: Int = 1
override val sources = listOf(
SingleLang("MangaLib", "https://mangalib.me", "ru", overrideVersionCode = 74),
SingleLang("HentaiLib", "https://hentailib.me", "ru",isNsfw = true, overrideVersionCode = 19)
)
companion object {
@JvmStatic
fun main(args: Array<String>) {
LibGenerator().createAll()
}
}
}

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.extension.ru.libmanga package eu.kanade.tachiyomi.multisrc.libgroup
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
@ -13,6 +13,8 @@ import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
@ -32,8 +34,6 @@ import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -46,7 +46,11 @@ import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class LibManga : ConfigurableSource, HttpSource() { abstract class LibGroup(
override val name: String,
override val baseUrl: String,
final override val lang: String
) : ConfigurableSource, HttpSource() {
private val json: Json by injectLazy() private val json: Json by injectLazy()
@ -54,12 +58,9 @@ class LibManga : ConfigurableSource, HttpSource() {
Injekt.get<Application>().getSharedPreferences("source_${id}_2", 0x0000) Injekt.get<Application>().getSharedPreferences("source_${id}_2", 0x0000)
} }
override val name: String = "Mangalib"
override val lang = "ru"
override val supportsLatest = true override val supportsLatest = true
private fun imageContentTypeIntercept(chain: Interceptor.Chain): Response {
protected fun imageContentTypeIntercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request() val originalRequest = chain.request()
val response = chain.proceed(originalRequest) val response = chain.proceed(originalRequest)
val urlRequest = originalRequest.url.toString() val urlRequest = originalRequest.url.toString()
@ -75,14 +76,8 @@ class LibManga : ConfigurableSource, HttpSource() {
.connectTimeout(10, TimeUnit.SECONDS) .connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS)
.rateLimit(3) .rateLimit(3)
.addInterceptor { imageContentTypeIntercept(it) }
.build() .build()
private val baseOrig: String = "https://mangalib.me"
private val baseMirr: String = "https://mangalib.org"
private var domain: String? = preferences.getString(DOMAIN_PREF, baseOrig)
override val baseUrl: String = domain.toString()
override fun headersBuilder() = Headers.Builder().apply { override fun headersBuilder() = Headers.Builder().apply {
// User-Agent required for authorization through third-party accounts (mobile version for correct display in WebView) // User-Agent required for authorization through third-party accounts (mobile version for correct display in WebView)
add("User-Agent", "Mozilla/5.0 (Linux; Android 10; SM-G980F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36") add("User-Agent", "Mozilla/5.0 (Linux; Android 10; SM-G980F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Mobile Safari/537.36")
@ -248,12 +243,14 @@ class LibManga : ConfigurableSource, HttpSource() {
SManga.LICENSED SManga.LICENSED
} else } else
when ( when (
body.select("div.media-info-list__title:contains(Статус перевода) + div") body.select("div.media-info-list__title:contains(Статус тайтла) + div")
.text() .text()
.lowercase(Locale.ROOT) .lowercase(Locale.ROOT)
) { ) {
"продолжается" -> SManga.ONGOING "онгоинг" -> SManga.ONGOING
"завершен" -> SManga.COMPLETED "завершён" -> SManga.COMPLETED
"приостановлен" -> SManga.ON_HIATUS
"выпуск прекращён" -> SManga.CANCELLED
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
manga.genre = category + ", " + rawAgeStop + ", " + genres.joinToString { it.trim() } manga.genre = category + ", " + rawAgeStop + ", " + genres.joinToString { it.trim() }
@ -303,59 +300,45 @@ class LibManga : ConfigurableSource, HttpSource() {
} }
private fun sortChaptersByTranslator private fun sortChaptersByTranslator
(sortingList: String?, chaptersList: JsonArray?, slug: String, branches: List<JsonElement>): List<SChapter>? { (sortingList: String?, chaptersList: JsonArray?, slug: String, branches: List<JsonElement>): List<SChapter>? {
var chapters: List<SChapter>? = null var chapters: List<SChapter>? = null
val volume = "(?<=/v)[0-9]+(?=/c[0-9]+)".toRegex() val volume = "(?<=/v)[0-9]+(?=/c[0-9]+)".toRegex()
when (sortingList) { val tempChaptersList = mutableListOf<SChapter>()
"ms_mixing" -> { for (currentBranch in branches.withIndex()) {
val tempChaptersList = mutableListOf<SChapter>() val branch = branches[currentBranch.index]
for (currentBranch in branches.withIndex()) { val teamId = branch.jsonObject["id"]!!.jsonPrimitive.int
val branch = branches[currentBranch.index] val teams = branch.jsonObject["teams"]!!.jsonArray
val teamId = branch.jsonObject["id"]!!.jsonPrimitive.int val isActive = teams.filter { it.jsonObject["is_active"]?.jsonPrimitive?.intOrNull == 1 }
val teams = branch.jsonObject["teams"]!!.jsonArray.filter { it.jsonObject["is_active"]?.jsonPrimitive?.intOrNull == 1 } val teamsBranch = if (isActive.size == 1)
val teamsBranch = if (teams.size == 1) isActive[0].jsonObject["name"]?.jsonPrimitive?.contentOrNull
teams[0].jsonObject["name"]?.jsonPrimitive?.contentOrNull else if (teams.isNotEmpty() && isActive.isEmpty())
else if (teams.isEmpty()) teams[0].jsonObject["name"]?.jsonPrimitive?.contentOrNull
branch.jsonObject["teams"]!!.jsonArray[0].jsonObject["name"]!!.jsonPrimitive.content else "Неизвестный"
else null chapters = chaptersList
chapters = chaptersList ?.filter { it.jsonObject["branch_id"]?.jsonPrimitive?.intOrNull == teamId && it.jsonObject["status"]?.jsonPrimitive?.intOrNull != 2 }
?.filter { it.jsonObject["branch_id"]?.jsonPrimitive?.intOrNull == teamId && it.jsonObject["status"]?.jsonPrimitive?.intOrNull != 2 } ?.map { chapterFromElement(it, sortingList, slug, teamId, branches) }
?.map { chapterFromElement(it, sortingList, slug, teamId, branches) } when (sortingList) {
"ms_mixing" -> {
chapters?.let { chapters?.let {
if ((tempChaptersList.size < it.size) && !groupTranslates.contains(teamsBranch.toString())) if ((tempChaptersList.size < it.size) && !groupTranslates.contains(teamsBranch.toString()))
tempChaptersList.addAll(0, it) tempChaptersList.addAll(0, it)
else else
tempChaptersList.addAll(it) tempChaptersList.addAll(it)
} }
chapters = tempChaptersList.distinctBy { volume.find(it.url)?.value + "--" + it.chapter_number }.sortedWith(compareBy({ -it.chapter_number }, { volume.find(it.url)?.value }))
} }
chapters = tempChaptersList.distinctBy { volume.find(it.url)?.value + "--" + it.chapter_number }.sortedWith(compareBy({ -it.chapter_number }, { volume.find(it.url)?.value })) "ms_combining" -> {
}
"ms_combining" -> {
val tempChaptersList = mutableListOf<SChapter>()
for (currentBranch in branches.withIndex()) {
val branch = branches[currentBranch.index]
val teamId = branch.jsonObject["id"]!!.jsonPrimitive.int
val teams = branch.jsonObject["teams"]!!.jsonArray.filter { it.jsonObject["is_active"]?.jsonPrimitive?.intOrNull == 1 }
val teamsBranch = if (teams.size == 1)
teams[0].jsonObject["name"]?.jsonPrimitive?.contentOrNull
else if (teams.isEmpty())
branch.jsonObject["teams"]!!.jsonArray[0].jsonObject["name"]!!.jsonPrimitive.content
else null
chapters = chaptersList
?.filter { it.jsonObject["branch_id"]?.jsonPrimitive?.intOrNull == teamId && it.jsonObject["status"]?.jsonPrimitive?.intOrNull != 2 }
?.map { chapterFromElement(it, sortingList, slug, teamId, branches) }
if (!groupTranslates.contains(teamsBranch.toString())) if (!groupTranslates.contains(teamsBranch.toString()))
chapters?.let { tempChaptersList.addAll(it) } chapters?.let { tempChaptersList.addAll(it) }
chapters = tempChaptersList
} }
chapters = tempChaptersList
} }
} }
return chapters return chapters
} }
private fun chapterFromElement private fun chapterFromElement
(chapterItem: JsonElement, sortingList: String?, slug: String, teamIdParam: Int? = null, branches: List<JsonElement>? = null, teams: List<JsonElement>? = null, chaptersList: JsonArray? = null): SChapter { (chapterItem: JsonElement, sortingList: String?, slug: String, teamIdParam: Int? = null, branches: List<JsonElement>? = null, teams: List<JsonElement>? = null, chaptersList: JsonArray? = null): SChapter {
val chapter = SChapter.create() val chapter = SChapter.create()
val volume = chapterItem.jsonObject["chapter_volume"]!!.jsonPrimitive.int val volume = chapterItem.jsonObject["chapter_volume"]!!.jsonPrimitive.int
@ -384,7 +367,7 @@ class LibManga : ConfigurableSource, HttpSource() {
for (currentBranch in branches.withIndex()) { for (currentBranch in branches.withIndex()) {
val branch = branches[currentBranch.index].jsonObject val branch = branches[currentBranch.index].jsonObject
val teams = branch["teams"]!!.jsonArray val teams = branch["teams"]!!.jsonArray
if (chapterItem.jsonObject["branch_id"]!!.jsonPrimitive.int == branch["id"]!!.jsonPrimitive.int) { if (chapterItem.jsonObject["branch_id"]!!.jsonPrimitive.int == branch["id"]!!.jsonPrimitive.int && teams.isNotEmpty()) {
for (currentTeam in teams.withIndex()) { for (currentTeam in teams.withIndex()) {
val team = teams[currentTeam.index].jsonObject val team = teams[currentTeam.index].jsonObject
val scanlatorId = chapterItem.jsonObject["chapter_scanlator_id"]!!.jsonPrimitive.int val scanlatorId = chapterItem.jsonObject["chapter_scanlator_id"]!!.jsonPrimitive.int
@ -539,16 +522,6 @@ class LibManga : ConfigurableSource, HttpSource() {
url.addQueryParameter("dir", if (filter.state!!.ascending) "asc" else "desc") url.addQueryParameter("dir", if (filter.state!!.ascending) "asc" else "desc")
url.addQueryParameter("sort", arrayOf("rate", "name", "views", "created_at", "last_chapter_at", "chap_count")[filter.state!!.index]) url.addQueryParameter("sort", arrayOf("rate", "name", "views", "created_at", "last_chapter_at", "chap_count")[filter.state!!.index])
} }
is AgeList -> filter.state.forEach { age ->
if (age.state) {
url.addQueryParameter("caution[]", age.id)
}
}
is TagList -> filter.state.forEach { tag ->
if (tag.state != Filter.TriState.STATE_IGNORE) {
url.addQueryParameter(if (tag.isIncluded()) "tags[include][]" else "tags[exclude][]", tag.id)
}
}
is MyList -> filter.state.forEach { favorite -> is MyList -> filter.state.forEach { favorite ->
if (favorite.state != Filter.TriState.STATE_IGNORE) { if (favorite.state != Filter.TriState.STATE_IGNORE) {
url.addQueryParameter(if (favorite.isIncluded()) "bookmarks[include][]" else "bookmarks[exclude][]", favorite.id) url.addQueryParameter(if (favorite.isIncluded()) "bookmarks[include][]" else "bookmarks[exclude][]", favorite.id)
@ -603,8 +576,6 @@ class LibManga : ConfigurableSource, HttpSource() {
private class StatusList(statuses: List<CheckFilter>) : Filter.Group<CheckFilter>("Статус перевода", statuses) private class StatusList(statuses: List<CheckFilter>) : Filter.Group<CheckFilter>("Статус перевода", statuses)
private class StatusTitleList(titles: List<CheckFilter>) : Filter.Group<CheckFilter>("Статус тайтла", titles) private class StatusTitleList(titles: List<CheckFilter>) : Filter.Group<CheckFilter>("Статус тайтла", titles)
private class GenreList(genres: List<SearchFilter>) : Filter.Group<SearchFilter>("Жанры", genres) private class GenreList(genres: List<SearchFilter>) : Filter.Group<SearchFilter>("Жанры", genres)
private class TagList(tags: List<SearchFilter>) : Filter.Group<SearchFilter>("Теги", tags)
private class AgeList(ages: List<CheckFilter>) : Filter.Group<CheckFilter>("Возрастное ограничение", ages)
private class MyList(favorites: List<SearchFilter>) : Filter.Group<SearchFilter>("Мои списки", favorites) private class MyList(favorites: List<SearchFilter>) : Filter.Group<SearchFilter>("Мои списки", favorites)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
@ -612,10 +583,8 @@ class LibManga : ConfigurableSource, HttpSource() {
CategoryList(getCategoryList()), CategoryList(getCategoryList()),
FormatList(getFormatList()), FormatList(getFormatList()),
GenreList(getGenreList()), GenreList(getGenreList()),
TagList(getTagList()),
StatusList(getStatusList()), StatusList(getStatusList()),
StatusTitleList(getStatusTitleList()), StatusTitleList(getStatusTitleList()),
AgeList(getAgeList()),
MyList(getMyList()) MyList(getMyList())
) )
@ -625,11 +594,6 @@ class LibManga : ConfigurableSource, HttpSource() {
Selection(2, false) Selection(2, false)
) )
/*
* Use console
* Object.entries(__FILTER_ITEMS__.types).map(([k, v]) => `SearchFilter("${v.label}", "${v.id}")`).join(',\n')
* on /manga-list
*/
private fun getCategoryList() = listOf( private fun getCategoryList() = listOf(
CheckFilter("Манга", "1"), CheckFilter("Манга", "1"),
CheckFilter("OEL-манга", "4"), CheckFilter("OEL-манга", "4"),
@ -648,11 +612,6 @@ class LibManga : ConfigurableSource, HttpSource() {
SearchFilter("Веб", "6") SearchFilter("Веб", "6")
) )
/*
* Use console
* Object.entries(__FILTER_ITEMS__.status).map(([k, v]) => `SearchFilter("${v.label}", "${v.id}")`).join(',\n')
* on /manga-list
*/
private fun getStatusList() = listOf( private fun getStatusList() = listOf(
CheckFilter("Продолжается", "1"), CheckFilter("Продолжается", "1"),
CheckFilter("Завершен", "2"), CheckFilter("Завершен", "2"),
@ -668,11 +627,6 @@ class LibManga : ConfigurableSource, HttpSource() {
CheckFilter("Выпуск прекращён", "5"), CheckFilter("Выпуск прекращён", "5"),
) )
/*
* Use console
* __FILTER_ITEMS__.genres.map(it => `SearchFilter("${it.name}", "${it.id}")`).join(',\n')
* on /manga-list
*/
private fun getGenreList() = listOf( private fun getGenreList() = listOf(
SearchFilter("арт", "32"), SearchFilter("арт", "32"),
SearchFilter("боевик", "34"), SearchFilter("боевик", "34"),
@ -720,113 +674,6 @@ class LibManga : ConfigurableSource, HttpSource() {
SearchFilter("яой", "74") SearchFilter("яой", "74")
) )
private fun getTagList() = listOf(
SearchFilter("Азартные игры", "304"),
SearchFilter("Алхимия", "225"),
SearchFilter("Ангелы", "226"),
SearchFilter("Антигерой", "175"),
SearchFilter("Антиутопия", "227"),
SearchFilter("Апокалипсис", "228"),
SearchFilter("Армия", "229"),
SearchFilter("Артефакты", "230"),
SearchFilter("Боги", "215"),
SearchFilter("Бои на мечах", "231"),
SearchFilter("Борьба за власть", "231"),
SearchFilter("Брат и сестра", "233"),
SearchFilter("Будущее", "234"),
SearchFilter("Ведьма", "338"),
SearchFilter("Вестерн", "235"),
SearchFilter("Видеоигры", "185"),
SearchFilter("Виртуальная реальность", "195"),
SearchFilter("Владыка демонов", "236"),
SearchFilter("Военные", "179"),
SearchFilter("Война", "237"),
SearchFilter("Волшебники / маги", "281"),
SearchFilter("Волшебные существа", "239"),
SearchFilter("Воспоминания из другого мира", "240"),
SearchFilter("Выживание", "193"),
SearchFilter("ГГ женщина", "243"),
SearchFilter("ГГ имба", "291"),
SearchFilter("ГГ мужчина", "244"),
SearchFilter("Геймеры", "241"),
SearchFilter("Гильдии", "242"),
SearchFilter("Глупый ГГ", "297"),
SearchFilter("Гоблины", "245"),
SearchFilter("Горничные", "169"),
SearchFilter("Гяру", "178"),
SearchFilter("Демоны", "151"),
SearchFilter("Драконы", "246"),
SearchFilter("Дружба", "247"),
SearchFilter("Жестокий мир", "249"),
SearchFilter("Животные компаньоны", "250"),
SearchFilter("Завоевание мира", "251"),
SearchFilter("Зверолюди", "162"),
SearchFilter("Злые духи", "252"),
SearchFilter("Зомби", "149"),
SearchFilter("Игровые элементы", "253"),
SearchFilter("Империи", "254"),
SearchFilter("Квесты", "255"),
SearchFilter("Космос", "256"),
SearchFilter("Кулинария", "152"),
SearchFilter("Культивация", "160"),
SearchFilter("Легендарное оружие", "257"),
SearchFilter("Лоли", "187"),
SearchFilter("Магическая академия", "258"),
SearchFilter("Магия", "168"),
SearchFilter("Мафия", "172"),
SearchFilter("Медицина", "153"),
SearchFilter("Месть", "259"),
SearchFilter("Монстр Девушки", "188"),
SearchFilter("Монстры", "189"),
SearchFilter("Музыка", "190"),
SearchFilter("Навыки / способности", "260"),
SearchFilter("Насилие / жестокость", "262"),
SearchFilter("Наёмники", "261"),
SearchFilter("Нежить", "263"),
SearchFilter("Ниндая", "180"),
SearchFilter("Обратный Гарем", "191"),
SearchFilter("Огнестрельное оружие", "264"),
SearchFilter("Офисные Работники", "181"),
SearchFilter("Пародия", "265"),
SearchFilter("Пираты", "340"),
SearchFilter("Подземелья", "266"),
SearchFilter("Политика", "267"),
SearchFilter("Полиция", "182"),
SearchFilter("Преступники / Криминал", "186"),
SearchFilter("Призраки / Духи", "177"),
SearchFilter("Путешествие во времени", "194"),
SearchFilter("Разумные расы", "268"),
SearchFilter("Ранги силы", "248"),
SearchFilter("Реинкарнация", "148"),
SearchFilter("Роботы", "269"),
SearchFilter("Рыцари", "270"),
SearchFilter("Самураи", "183"),
SearchFilter("Система", "271"),
SearchFilter("Скрытие личности", "273"),
SearchFilter("Спасение мира", "274"),
SearchFilter("Спортивное тело", "334"),
SearchFilter("Средневековье", "173"),
SearchFilter("Стимпанк", "272"),
SearchFilter("Супергерои", "275"),
SearchFilter("Традиционные игры", "184"),
SearchFilter("Умный ГГ", "302"),
SearchFilter("Учитель / ученик", "276"),
SearchFilter("Философия", "277"),
SearchFilter("Хикикомори", "166"),
SearchFilter("Холодное оружие", "278"),
SearchFilter("Шантаж", "279"),
SearchFilter("Эльфы", "216"),
SearchFilter("Якудза", "164"),
SearchFilter("Япония", "280")
)
private fun getAgeList() = listOf(
CheckFilter("Отсутствует", "0"),
CheckFilter("16+", "1"),
CheckFilter("18+", "2")
)
private fun getMyList() = listOf( private fun getMyList() = listOf(
SearchFilter("Читаю", "1"), SearchFilter("Читаю", "1"),
SearchFilter("В планах", "2"), SearchFilter("В планах", "2"),
@ -848,13 +695,8 @@ class LibManga : ConfigurableSource, HttpSource() {
private const val TRANSLATORS_TITLE = "Чёрный список переводчиков\n(для красоты через «/» или с новой строки)" private const val TRANSLATORS_TITLE = "Чёрный список переводчиков\n(для красоты через «/» или с новой строки)"
private const val TRANSLATORS_DEFAULT = "" private const val TRANSLATORS_DEFAULT = ""
private const val DOMAIN_PREF = "MangaLibDomain"
private const val DOMAIN_PREF_Title = "Выбор домена"
private const val LANGUAGE_PREF = "MangaLibTitleLanguage" private const val LANGUAGE_PREF = "MangaLibTitleLanguage"
private const val LANGUAGE_PREF_Title = "Выбор языка на обложке" private const val LANGUAGE_PREF_Title = "Выбор языка на обложке"
private const val COVER_URL = "https://staticlib.me"
} }
private var server: String? = preferences.getString(SERVER_PREF, null) private var server: String? = preferences.getString(SERVER_PREF, null)
@ -899,25 +741,6 @@ class LibManga : ConfigurableSource, HttpSource() {
preferences.edit().putBoolean(key, checkValue).commit() preferences.edit().putBoolean(key, checkValue).commit()
} }
} }
val domainPref = ListPreference(screen.context).apply {
key = DOMAIN_PREF
title = DOMAIN_PREF_Title
entries = arrayOf("Основной (mangalib.me)", "Зеркало (mangalib.org)")
entryValues = arrayOf(baseOrig, baseMirr)
summary = "%s"
setDefaultValue(baseOrig)
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit().putString(DOMAIN_PREF, newValue as String).commit()
val warning = "Для смены домена необходимо перезапустить приложение с полной остановкой."
Toast.makeText(screen.context, warning, Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}
val titleLanguagePref = ListPreference(screen.context).apply { val titleLanguagePref = ListPreference(screen.context).apply {
key = LANGUAGE_PREF key = LANGUAGE_PREF
title = LANGUAGE_PREF_Title title = LANGUAGE_PREF_Title
@ -932,8 +755,6 @@ class LibManga : ConfigurableSource, HttpSource() {
titleLanguage titleLanguage
} }
} }
screen.addPreference(domainPref)
screen.addPreference(serverPref) screen.addPreference(serverPref)
screen.addPreference(sortingPref) screen.addPreference(sortingPref)
screen.addPreference(screen.editTextPreference(TRANSLATORS_TITLE, TRANSLATORS_DEFAULT, groupTranslates)) screen.addPreference(screen.editTextPreference(TRANSLATORS_TITLE, TRANSLATORS_DEFAULT, groupTranslates))

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.extension.ru.libmanga package eu.kanade.tachiyomi.multisrc.libgroup
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
@ -8,12 +8,12 @@ import android.util.Log
import kotlin.system.exitProcess import kotlin.system.exitProcess
/** /**
* Springboard that accepts https://mangalib.me/xxx intents and redirects them to * Springboard that accepts https://xxxxlib.me/xxx intents and redirects them to
* the main tachiyomi process. The idea is to not install the intent filter unless * the main tachiyomi process. The idea is to not install the intent filter unless
* you have this extension installed, but still let the main tachiyomi app control * you have this extension installed, but still let the main tachiyomi app control
* things. * things.
*/ */
class LibMangaActivity : Activity() { class LibUrlActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -22,17 +22,17 @@ class LibMangaActivity : Activity() {
val titleid = pathSegments[0] val titleid = pathSegments[0]
val mainIntent = Intent().apply { val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH" action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", "${LibManga.PREFIX_SLUG_SEARCH}$titleid") putExtra("query", "${LibGroup.PREFIX_SLUG_SEARCH}$titleid")
putExtra("filter", packageName) putExtra("filter", packageName)
} }
try { try {
startActivity(mainIntent) startActivity(mainIntent)
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
Log.e("LibMangaActivity", e.toString()) Log.e("LibUrlActivity", e.toString())
} }
} else { } else {
Log.e("LibMangaActivity", "could not parse uri from intent $intent") Log.e("LibUrlActivity", "could not parse uri from intent $intent")
} }
finish() finish()

View File

@ -1,13 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'HentaiLib'
pkgNameSuffix = 'ru.libhentai'
extClass = '.LibHentai'
extVersionCode = 19
isNsfw = true
}
apply from: "$rootDir/common.gradle"

View File

@ -1,41 +0,0 @@
package eu.kanade.tachiyomi.extension.ru.libhentai
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://hentailib.me/xxx intents and redirects them to
* the main tachiyomi process. The idea is to not install the intent filter unless
* you have this extension installed, but still let the main tachiyomi app control
* things.
*/
class LibHentaiActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
if (pathSegments != null && pathSegments.size > 0) {
val titleid = pathSegments[0]
val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", "${LibHentai.PREFIX_SLUG_SEARCH}$titleid")
putExtra("filter", packageName)
}
try {
startActivity(mainIntent)
} catch (e: ActivityNotFoundException) {
Log.e("LibHentaiActivity", e.toString())
}
} else {
Log.e("LibHentaiActivity", "could not parse uri from intent $intent")
}
finish()
exitProcess(0)
}
}

View File

@ -1,12 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'MangaLib'
pkgNameSuffix = 'ru.libmanga'
extClass = '.LibManga'
extVersionCode = 74
}
apply from: "$rootDir/common.gradle"