diff --git a/multisrc/overrides/grouple/allhentai/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/grouple/allhentai/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..d7626a6f9 Binary files /dev/null and b/multisrc/overrides/grouple/allhentai/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/allhentai/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/grouple/allhentai/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..016fbc954 Binary files /dev/null and b/multisrc/overrides/grouple/allhentai/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/allhentai/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/grouple/allhentai/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..d2d35dd5b Binary files /dev/null and b/multisrc/overrides/grouple/allhentai/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/allhentai/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/grouple/allhentai/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..ff4efdd56 Binary files /dev/null and b/multisrc/overrides/grouple/allhentai/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/allhentai/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/grouple/allhentai/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..541d18e42 Binary files /dev/null and b/multisrc/overrides/grouple/allhentai/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/allhentai/res/web_hi_res_512.png b/multisrc/overrides/grouple/allhentai/res/web_hi_res_512.png new file mode 100644 index 000000000..f73d9a578 Binary files /dev/null and b/multisrc/overrides/grouple/allhentai/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/grouple/allhentai/src/AllHentai.kt b/multisrc/overrides/grouple/allhentai/src/AllHentai.kt new file mode 100644 index 000000000..2217b9217 --- /dev/null +++ b/multisrc/overrides/grouple/allhentai/src/AllHentai.kt @@ -0,0 +1,259 @@ +package eu.kanade.tachiyomi.extension.ru.allhentai + +import eu.kanade.tachiyomi.multisrc.grouple.GroupLe +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.Request + +class AllHentai : GroupLe("AllHentai", "http://23.allhen.online", "ru"){ + + override val id: Long = 1809051393403180443 + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() + (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> + when (filter) { + is GenreList -> filter.state.forEach { genre -> + if (genre.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) + } + } + is Category -> filter.state.forEach { category -> + if (category.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) + } + } + is FilList -> filter.state.forEach { fils -> + if (fils.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(fils.id, arrayOf("=", "=in", "=ex")[fils.state]) + } + } + is OrderBy -> { + if (filter.state > 0) { + val ord = arrayOf("not", "year", "rate", "popularity", "votes", "created", "updated")[filter.state] + val ordUrl = "$baseUrl/list?sortType=$ord&offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() + return GET(ordUrl.toString(), headers) + } + } + is Tags -> { + if (filter.state > 0) { + val tagName = getTagsList()[filter.state].url + val tagUrl = "$baseUrl/list/tag/$tagName?offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() + return GET(tagUrl.toString(), headers) + } + } + else -> return@forEach + } + } + if (query.isNotEmpty()) { + url.addQueryParameter("q", query) + } + return if (url.toString().contains("?")) + GET(url.toString().replace("=%3D", "="), headers) + else popularMangaRequest(page) + } + + private class OrderBy : Filter.Select<String>( + "Сортировка (только)", + arrayOf("Без сортировки", "По году", "По популярности", "Популярно сейчас", "По рейтингу", "Новинки", "По дате обновления") + ) + + private class Genre(name: String, val id: String) : Filter.TriState(name) + + private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres) + private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories) + private class FilList(fils: List<Genre>) : Filter.Group<Genre>("Фильтры", fils) + private class Tags(tags: Array<String>) : Filter.Select<String>("Тэг (только)", tags) + + private data class Tag(val name: String, val url: String) + + override fun getFilterList() = FilterList( + OrderBy(), + Tags(tagsName), + GenreList(getGenreList()), + Category(getCategoryList()), + FilList(getFilList()) + ) + + private fun getGenreList() = listOf( + Genre("ahegao", "el_855"), + Genre("анал", "el_828"), + Genre("бдсм", "el_78"), + Genre("без цензуры", "el_888"), + Genre("большая грудь", "el_837"), + Genre("большая попка", "el_3156"), + Genre("большой член", "el_884"), + Genre("бондаж", "el_5754"), + Genre("в первый раз", "el_811"), + Genre("в цвете", "el_290"), + Genre("гарем", "el_87"), + Genre("гендарная интрига", "el_89"), + Genre("групповой секс", "el_88"), + Genre("драма", "el_95"), + Genre("зрелые женщины", "el_5679"), + Genre("измена", "el_291"), + Genre("изнасилование", "el_124"), + Genre("инцест", "el_85"), + Genre("исторический", "el_93"), + Genre("комедия", "el_73"), + Genre("маленькая грудь", "el_870"), + Genre("научная фантастика", "el_76"), + Genre("нетораре", "el_303"), + Genre("оральный секс", "el_853"), + Genre("романтика", "el_74"), + Genre("тентакли", "el_69"), + Genre("трагедия", "el_1321"), + Genre("ужасы", "el_75"), + Genre("футанари", "el_77"), + Genre("фэнтези", "el_70"), + Genre("чикан", "el_1059"), + Genre("этти", "el_798"), + Genre("юри", "el_84"), + Genre("яой", "el_83") + ) + + private fun getCategoryList() = listOf( + Genre("3D", "el_626"), + Genre("Анимация", "el_5777"), + Genre("Без текста", "el_3157"), + Genre("Порно комикс", "el_1003"), + Genre("Порно манхва", "el_1104") + ) + + private fun getFilList() = listOf( + Genre("Высокий рейтинг", "s_high_rate"), + Genre("Сингл", "s_single"), + Genre("Для взрослых", "s_mature"), + Genre("Завершенная", "s_completed"), + Genre("Переведено", "s_translated"), + Genre("Длинная", "s_many_chapters"), + Genre("Ожидает загрузки", "s_wait_upload"), + Genre("Продается", "s_sale") + ) + + private fun getTagsList() = listOf( + Tag("Без тега", "not"), + Tag("handjob", "handjob"), + Tag("inseki", "inseki"), + Tag("алкоголь", "alcohol"), + Tag("андроид", "android"), + Tag("анилингус", "anilingus"), + Tag("бассейн", "pool"), + Tag("без трусиков", "without_panties"), + Tag("беременность", "pregnancy"), + Tag("бикини", "bikini"), + Tag("близнецы", "twins"), + Tag("боди-арт", "body_art"), + Tag("больница", "hospital"), + Tag("буккакэ", "bukkake"), + Tag("в ванной", "in_bathroom"), + Tag("в общественном месте", "in_public_place"), + Tag("в транспорте", "in_vehicle"), + Tag("вампиры", "vampires"), + Tag("вибратор", "vibrator"), + Tag("втянутые соски", "inverted_nipples"), + Tag("гипноз", "hypnosis"), + Tag("глубокий минет", "deepthroat"), + Tag("горничные", "maids"), + Tag("горячий источник", "hot_spring"), + Tag("гэнгбэнг", "gangbang"), + Tag("гяру", "gyaru"), + Tag("двойное проникновение", "double_penetration"), + Tag("Девочки волшебницы", "magical_girl"), + Tag("демоны", "demons"), + Tag("дефекация", "scat"), + Tag("дилдо", "dildo"), + Tag("додзинси", "doujinshi"), + Tag("домохозяйки", "housewives"), + Tag("дыра в стене", "hole_in_the_wall"), + Tag("жестокость", "cruelty"), + Tag("загар", "tan_lines"), + Tag("зомби", "zombie"), + Tag("инопланетяне", "aliens"), + Tag("исполнение желаний", "granting_wish"), + Tag("камера", "camera"), + Tag("косплей", "cosplay"), + Tag("кремпай", "creampie"), + Tag("куннилингус", "cunnilingus"), + Tag("купальник", "swimsuit"), + Tag("лактация", "lactation"), + Tag("латекс и кожа", "latex"), + Tag("Ломка Психики", "mind_break"), + Tag("магия", "magic"), + Tag("мастурбация", "masturbation"), + Tag("медсестра", "nurse"), + Tag("мерзкий дядька", "terrible_oyaji"), + Tag("много девушек", "many_girls"), + Tag("много спермы", "a_lot_of_sperm"), + Tag("монстрдевушки", "monstergirl"), + Tag("монстры", "monsters"), + Tag("мужчина крепкого телосложения", "muscle_man"), + Tag("на природе", "outside"), + Tag("не бритая киска", "hairy_pussy"), + Tag("не бритые подмышки", "hairy_armpits"), + Tag("нетори", "netori"), + Tag("нижнее бельё", "lingerie"), + Tag("обмен партнерами", "swinging"), + Tag("обмен телами", "body_swap"), + Tag("обычный секс", "normal_sex"), + Tag("огромная грудь", "super_big_boobs"), + Tag("орки", "orcs"), + Tag("очки", "megane"), + Tag("пайзури", "titsfuck"), + Tag("парень пассив", "passive_guy"), + Tag("пацанка", "tomboy"), + Tag("пеггинг", "pegging"), + Tag("переодевание", "disguise"), + Tag("пирсинг", "piercing"), + Tag("писают", "peeing"), + Tag("пляж", "beach"), + Tag("повседневность", "slice_of_life"), + Tag("повязка на глаза", "blindfold"), + Tag("подглядывание", "peeping"), + Tag("подчинение", "submission"), + Tag("похищение", "kidnapping"), + Tag("принуждение", "forced"), + Tag("прозрачная одежда", "transparent_clothes"), + Tag("проституция", "prostitution"), + Tag("психические отклонения", "mental_illness"), + Tag("публичный секс", "public_sex"), + Tag("пьяные", "drunk"), + Tag("рабы", "slaves"), + Tag("рентген зрение", "x_ray"), + Tag("сверхъестественное", "supernatural"), + Tag("секс втроем", "threesome"), + Tag("секс игрушки", "sex_toys"), + Tag("сексуально возбужденная", "horny"), + Tag("спортивная форма", "sports_uniform"), + Tag("спящие", "sleeping"), + Tag("страпон", "strapon"), + Tag("Суккуб", "succubus"), + Tag("темнокожие", "dark_skin"), + Tag("толстушки", "fatties"), + Tag("трап", "trap"), + Tag("униформа", "uniform"), + Tag("ушастые", "eared"), + Tag("фантазии", "dreams"), + Tag("фемдом", "femdom"), + Tag("фестиваль", "festival"), + Tag("фетиш", "fetish"), + Tag("фистинг", "fisting"), + Tag("фурри", "furry"), + Tag("футанари имеет парня", "futanari_on_boy"), + Tag("футджаб", "footfuck"), + Tag("цельный купальник", "full_swimsuit"), + Tag("цундэрэ", "tsundere"), + Tag("чулки", "hose"), + Tag("шалава", "slut"), + Tag("шантаж", "blackmail"), + Tag("эксгибиционизм", "exhibitionism"), + Tag("эльфы", "elves"), + Tag("яндере", "yandere") + ) + + private val tagsName = getTagsList().map { + it.name + }.toTypedArray() +} diff --git a/src/ru/mintmanga/AndroidManifest.xml b/multisrc/overrides/grouple/default/AndroidManifest.xml similarity index 74% rename from src/ru/mintmanga/AndroidManifest.xml rename to multisrc/overrides/grouple/default/AndroidManifest.xml index 79da42000..87f96afd9 100644 --- a/src/ru/mintmanga/AndroidManifest.xml +++ b/multisrc/overrides/grouple/default/AndroidManifest.xml @@ -4,7 +4,7 @@ <application> <activity - android:name=".ru.mintmanga.MintmangaActivity" + android:name="eu.kanade.tachiyomi.multisrc.grouple.GroupLeUrlActivity" android:excludeFromRecents="true" android:exported="true" android:theme="@android:style/Theme.NoDisplay"> @@ -14,11 +14,11 @@ <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> - <!-- ReadmangaActivity sites can be added here. --> + <!-- GroupLeUrlActivity sites can be added here. --> <data - android:host="mintmanga.live" + android:host="${SOURCEHOST}" android:pathPattern="/..*/vol..*" - android:scheme="https" /> + android:scheme="${SOURCESCHEME}" /> </intent-filter> </activity> </application> diff --git a/multisrc/overrides/grouple/mintmanga/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/grouple/mintmanga/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..cbc0d3927 Binary files /dev/null and b/multisrc/overrides/grouple/mintmanga/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/mintmanga/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/grouple/mintmanga/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..b7a7d167e Binary files /dev/null and b/multisrc/overrides/grouple/mintmanga/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/mintmanga/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/grouple/mintmanga/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..cdc090f10 Binary files /dev/null and b/multisrc/overrides/grouple/mintmanga/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/mintmanga/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/grouple/mintmanga/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..626bfc7d1 Binary files /dev/null and b/multisrc/overrides/grouple/mintmanga/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/mintmanga/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/grouple/mintmanga/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..56bc00e18 Binary files /dev/null and b/multisrc/overrides/grouple/mintmanga/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/mintmanga/res/web_hi_res_512.png b/multisrc/overrides/grouple/mintmanga/res/web_hi_res_512.png new file mode 100644 index 000000000..659735502 Binary files /dev/null and b/multisrc/overrides/grouple/mintmanga/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/grouple/mintmanga/src/MintManga.kt b/multisrc/overrides/grouple/mintmanga/src/MintManga.kt new file mode 100644 index 000000000..56f492561 --- /dev/null +++ b/multisrc/overrides/grouple/mintmanga/src/MintManga.kt @@ -0,0 +1,157 @@ +package eu.kanade.tachiyomi.extension.ru.mintmanga + +import eu.kanade.tachiyomi.multisrc.grouple.GroupLe +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.Request + +class MintManga : GroupLe("MintManga", "https://mintmanga.live", "ru"){ + + override val id: Long = 6 + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() + (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> + when (filter) { + is GenreList -> filter.state.forEach { genre -> + if (genre.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) + } + } + is Category -> filter.state.forEach { category -> + if (category.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) + } + } + is AgeList -> filter.state.forEach { age -> + if (age.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(age.id, arrayOf("=", "=in", "=ex")[age.state]) + } + } + is More -> filter.state.forEach { more -> + if (more.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(more.id, arrayOf("=", "=in", "=ex")[more.state]) + } + } + is FilList -> filter.state.forEach { fils -> + if (fils.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(fils.id, arrayOf("=", "=in", "=ex")[fils.state]) + } + } + is OrderBy -> { + if (filter.state > 0) { + val ord = arrayOf("not", "year", "rate", "popularity", "votes", "created", "updated")[filter.state] + val ordUrl = "$baseUrl/list?sortType=$ord&offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() + return GET(ordUrl.toString(), headers) + } + } + else -> return@forEach + } + } + if (query.isNotEmpty()) { + url.addQueryParameter("q", query) + } + return if (url.toString().contains("?")) + GET(url.toString().replace("=%3D", "="), headers) + else popularMangaRequest(page) + } + + private class OrderBy : Filter.Select<String>( + "Сортировка (только)", + arrayOf("Без сортировки", "По году", "По популярности", "Популярно сейчас", "По рейтингу", "Новинки", "По дате обновления") + ) + + private class Genre(name: String, val id: String) : Filter.TriState(name) + + private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres) + private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories) + private class AgeList(ages: List<Genre>) : Filter.Group<Genre>("Возрастная рекомендация", ages) + private class More(moren: List<Genre>) : Filter.Group<Genre>("Прочее", moren) + private class FilList(fils: List<Genre>) : Filter.Group<Genre>("Фильтры", fils) + + override fun getFilterList() = FilterList( + OrderBy(), + Category(getCategoryList()), + GenreList(getGenreList()), + AgeList(getAgeList()), + More(getMore()), + FilList(getFilList()) + ) + private fun getFilList() = listOf( + Genre("Высокий рейтинг", "s_high_rate"), + Genre("Сингл", "s_single"), + Genre("Для взрослых", "s_mature"), + Genre("Завершенная", "s_completed"), + Genre("Переведено", "s_translated"), + Genre("Длинная", "s_many_chapters"), + Genre("Ожидает загрузки", "s_wait_upload"), + ) + private fun getMore() = listOf( + Genre("В цвете", "el_4614"), + Genre("Веб", "el_1355"), + Genre("Выпуск приостановлен", "el_5232"), + Genre("Не Яой", "el_1874"), + Genre("Сборник", "el_1348") + ) + + private fun getAgeList() = listOf( + Genre("R(16+)", "el_3968"), + Genre("NC-17(18+)", "el_3969"), + Genre("R18+(18+)", "el_3990") + ) + + private fun getCategoryList() = listOf( + Genre("Ёнкома", "el_2741"), + Genre("Комикс западный", "el_1903"), + Genre("Комикс русский", "el_2173"), + Genre("Манхва", "el_1873"), + Genre("Маньхуа", "el_1875"), + Genre("Ранобэ", "el_5688"), + ) + + private fun getGenreList() = listOf( + Genre("арт", "el_2220"), + Genre("бара", "el_1353"), + Genre("боевик", "el_1346"), + Genre("боевые искусства", "el_1334"), + Genre("вампиры", "el_1339"), + Genre("гарем", "el_1333"), + Genre("гендерная интрига", "el_1347"), + Genre("героическое фэнтези", "el_1337"), + Genre("детектив", "el_1343"), + Genre("дзёсэй", "el_1349"), + Genre("додзинси", "el_1332"), + Genre("драма", "el_1310"), + Genre("игра", "el_5229"), + Genre("история", "el_1311"), + Genre("киберпанк", "el_1351"), + Genre("комедия", "el_1328"), + Genre("меха", "el_1318"), + Genre("научная фантастика", "el_1325"), + Genre("омегаверс", "el_5676"), + Genre("повседневность", "el_1327"), + Genre("постапокалиптика", "el_1342"), + Genre("приключения", "el_1322"), + Genre("психология", "el_1335"), + Genre("романтика", "el_1313"), + Genre("самурайский боевик", "el_1316"), + Genre("сверхъестественное", "el_1350"), + Genre("сёдзё", "el_1314"), + Genre("сёдзё-ай", "el_1320"), + Genre("сёнэн", "el_1326"), + Genre("сёнэн-ай", "el_1330"), + Genre("спорт", "el_1321"), + Genre("сэйнэн", "el_1329"), + Genre("трагедия", "el_1344"), + Genre("триллер", "el_1341"), + Genre("ужасы", "el_1317"), + Genre("фэнтези", "el_1323"), + Genre("школа", "el_1319"), + Genre("эротика", "el_1340"), + Genre("этти", "el_1354"), + Genre("юри", "el_1315"), + Genre("яой", "el_1336") + ) +} diff --git a/multisrc/overrides/grouple/readmanga/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/grouple/readmanga/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..3a287acfc Binary files /dev/null and b/multisrc/overrides/grouple/readmanga/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/readmanga/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/grouple/readmanga/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..8ebcb6940 Binary files /dev/null and b/multisrc/overrides/grouple/readmanga/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/readmanga/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/grouple/readmanga/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..51af633ab Binary files /dev/null and b/multisrc/overrides/grouple/readmanga/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/readmanga/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/grouple/readmanga/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..37d39ba2e Binary files /dev/null and b/multisrc/overrides/grouple/readmanga/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/readmanga/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/grouple/readmanga/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..88764f0bb Binary files /dev/null and b/multisrc/overrides/grouple/readmanga/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/readmanga/res/web_hi_res_512.png b/multisrc/overrides/grouple/readmanga/res/web_hi_res_512.png new file mode 100644 index 000000000..a2cba1ddc Binary files /dev/null and b/multisrc/overrides/grouple/readmanga/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/grouple/readmanga/src/ReadManga.kt b/multisrc/overrides/grouple/readmanga/src/ReadManga.kt new file mode 100644 index 000000000..0e622a559 --- /dev/null +++ b/multisrc/overrides/grouple/readmanga/src/ReadManga.kt @@ -0,0 +1,156 @@ +package eu.kanade.tachiyomi.extension.ru.readmanga + +import android.widget.Toast +import eu.kanade.tachiyomi.multisrc.grouple.GroupLe +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.Request + +class ReadManga : GroupLe("ReadManga", "https://readmanga.io", "ru"){ + + override val id: Long = 5 + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() + (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> + when (filter) { + is GenreList -> filter.state.forEach { genre -> + if (genre.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) + } + } + is Category -> filter.state.forEach { category -> + if (category.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) + } + } + is AgeList -> filter.state.forEach { age -> + if (age.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(age.id, arrayOf("=", "=in", "=ex")[age.state]) + } + } + is More -> filter.state.forEach { more -> + if (more.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(more.id, arrayOf("=", "=in", "=ex")[more.state]) + } + } + is FilList -> filter.state.forEach { fils -> + if (fils.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(fils.id, arrayOf("=", "=in", "=ex")[fils.state]) + } + } + is OrderBy -> { + if (filter.state > 0) { + val ord = arrayOf("not", "year", "rate", "popularity", "votes", "created", "updated")[filter.state] + val ordUrl = "$baseUrl/list?sortType=$ord&offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() + return GET(ordUrl.toString(), headers) + } + } + else -> return@forEach + } + } + if (query.isNotEmpty()) { + url.addQueryParameter("q", query) + } + return if (url.toString().contains("?")) + GET(url.toString().replace("=%3D", "="), headers) + else popularMangaRequest(page) + } + + private class OrderBy : Filter.Select<String>( + "Сортировка (только)", + arrayOf("Без сортировки", "По году", "По популярности", "Популярно сейчас", "По рейтингу", "Новинки", "По дате обновления") + ) + + private class Genre(name: String, val id: String) : Filter.TriState(name) + + private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres) + private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories) + private class AgeList(ages: List<Genre>) : Filter.Group<Genre>("Возрастная рекомендация", ages) + private class More(moren: List<Genre>) : Filter.Group<Genre>("Прочее", moren) + private class FilList(fils: List<Genre>) : Filter.Group<Genre>("Фильтры", fils) + + override fun getFilterList() = FilterList( + OrderBy(), + Category(getCategoryList()), + GenreList(getGenreList()), + AgeList(getAgeList()), + More(getMore()), + FilList(getFilList()) + ) + + private fun getFilList() = listOf( + Genre("Высокий рейтинг", "s_high_rate"), + Genre("Сингл", "s_single"), + Genre("Для взрослых", "s_mature"), + Genre("Завершенная", "s_completed"), + Genre("Переведено", "s_translated"), + Genre("Длинная", "s_many_chapters"), + Genre("Ожидает загрузки", "s_wait_upload"), + Genre("Продается", "s_sale") + ) + private fun getMore() = listOf( + Genre("В цвете", "el_7290"), + Genre("Веб", "el_2160"), + Genre("Выпуск приостановлен", "el_8033"), + Genre("Сборник", "el_2157") + ) + + private fun getAgeList() = listOf( + Genre("G(0+)", "el_6180"), + Genre("PG-13(12+)", "el_6181"), + Genre("PG(16+)", "el_6179") + ) + + private fun getCategoryList() = listOf( + Genre("Ёнкома", "el_2161"), + Genre("Комикс западный", "el_3515"), + Genre("Манхва", "el_3001"), + Genre("Маньхуа", "el_3002"), + Genre("Ранобэ", "el_8575"), + ) + + private fun getGenreList() = listOf( + Genre("арт", "el_5685"), + Genre("боевик", "el_2155"), + Genre("боевые искусства", "el_2143"), + Genre("вампиры", "el_2148"), + Genre("гарем", "el_2142"), + Genre("гендерная интрига", "el_2156"), + Genre("героическое фэнтези", "el_2146"), + Genre("детектив", "el_2152"), + Genre("дзёсэй", "el_2158"), + Genre("додзинси", "el_2141"), + Genre("драма", "el_2118"), + Genre("игра", "el_2154"), + Genre("история", "el_2119"), + Genre("киберпанк", "el_8032"), + Genre("кодомо", "el_2137"), + Genre("комедия", "el_2136"), + Genre("махо-сёдзё", "el_2147"), + Genre("меха", "el_2126"), + Genre("научная фантастика", "el_2133"), + Genre("повседневность", "el_2135"), + Genre("постапокалиптика", "el_2151"), + Genre("приключения", "el_2130"), + Genre("психология", "el_2144"), + Genre("романтика", "el_2121"), + Genre("самурайский боевик", "el_2124"), + Genre("сверхъестественное", "el_2159"), + Genre("сёдзё", "el_2122"), + Genre("сёдзё-ай", "el_2128"), + Genre("сёнэн", "el_2134"), + Genre("сёнэн-ай", "el_2139"), + Genre("спорт", "el_2129"), + Genre("сэйнэн", "el_2138"), + Genre("трагедия", "el_2153"), + Genre("триллер", "el_2150"), + Genre("ужасы", "el_2125"), + Genre("фэнтези", "el_2131"), + Genre("школа", "el_2127"), + Genre("этти", "el_2149"), + Genre("юри", "el_2123") + ) +} diff --git a/multisrc/overrides/grouple/rumix/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/grouple/rumix/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..26dea9c1c Binary files /dev/null and b/multisrc/overrides/grouple/rumix/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/rumix/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/grouple/rumix/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..1b214efa4 Binary files /dev/null and b/multisrc/overrides/grouple/rumix/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/rumix/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/grouple/rumix/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..73a45df39 Binary files /dev/null and b/multisrc/overrides/grouple/rumix/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/rumix/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/grouple/rumix/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..dc8aaaf40 Binary files /dev/null and b/multisrc/overrides/grouple/rumix/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/rumix/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/grouple/rumix/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..2d263c880 Binary files /dev/null and b/multisrc/overrides/grouple/rumix/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/rumix/res/web_hi_res_512.png b/multisrc/overrides/grouple/rumix/res/web_hi_res_512.png new file mode 100644 index 000000000..87cb89581 Binary files /dev/null and b/multisrc/overrides/grouple/rumix/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/grouple/rumix/src/RuMIX.kt b/multisrc/overrides/grouple/rumix/src/RuMIX.kt new file mode 100644 index 000000000..26b7e355f --- /dev/null +++ b/multisrc/overrides/grouple/rumix/src/RuMIX.kt @@ -0,0 +1,23 @@ +package eu.kanade.tachiyomi.extension.ru.rumix + +import android.widget.Toast +import eu.kanade.tachiyomi.multisrc.grouple.GroupLe +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.Request + +class RuMIX : GroupLe("RuMIX", "https://rumix.me", "ru"){ + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() + if (query.isNotEmpty()) { + url.addQueryParameter("q", query) + } + return if (url.toString().contains("?")) + GET(url.toString().replace("=%3D", "="), headers) + else popularMangaRequest(page) + } + +} diff --git a/multisrc/overrides/grouple/selfmanga/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/grouple/selfmanga/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..43778af35 Binary files /dev/null and b/multisrc/overrides/grouple/selfmanga/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/selfmanga/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/grouple/selfmanga/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..7d991c0ad Binary files /dev/null and b/multisrc/overrides/grouple/selfmanga/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/selfmanga/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/grouple/selfmanga/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..b4ea98529 Binary files /dev/null and b/multisrc/overrides/grouple/selfmanga/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/selfmanga/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/grouple/selfmanga/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..54fea1b05 Binary files /dev/null and b/multisrc/overrides/grouple/selfmanga/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/selfmanga/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/grouple/selfmanga/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..a7f0a9e56 Binary files /dev/null and b/multisrc/overrides/grouple/selfmanga/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/grouple/selfmanga/res/web_hi_res_512.png b/multisrc/overrides/grouple/selfmanga/res/web_hi_res_512.png new file mode 100644 index 000000000..85a865456 Binary files /dev/null and b/multisrc/overrides/grouple/selfmanga/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/grouple/selfmanga/src/SelfManga.kt b/multisrc/overrides/grouple/selfmanga/src/SelfManga.kt new file mode 100644 index 000000000..86bc21516 --- /dev/null +++ b/multisrc/overrides/grouple/selfmanga/src/SelfManga.kt @@ -0,0 +1,93 @@ +package eu.kanade.tachiyomi.extension.ru.selfmanga + +import eu.kanade.tachiyomi.multisrc.grouple.GroupLe +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.model.FilterList +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.Request + +class SelfManga : GroupLe("SelfManga", "https://selfmanga.live", "ru") { + + override val id: Long = 5227602742162454547 + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() + (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> + when (filter) { + is GenreList -> filter.state.forEach { genre -> + if (genre.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) + } + } + is Category -> filter.state.forEach { category -> + if (category.state != Filter.TriState.STATE_IGNORE) { + url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) + } + } + else -> return@forEach + } + } + if (query.isNotEmpty()) { + url.addQueryParameter("q", query) + } + return if (url.toString().contains("?")) + GET(url.toString().replace("=%3D", "="), headers) + else popularMangaRequest(page) + } + + private class Genre(name: String, val id: String) : Filter.TriState(name) + private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) + private class Category(categories: List<Genre>) : Filter.Group<Genre>("Category", categories) + + override fun getFilterList() = FilterList( + Category(getCategoryList()), + GenreList(getGenreList()) + ) + + private fun getCategoryList() = listOf( + Genre("Артбук", "el_5894"), + Genre("Веб", "el_2160"), + Genre("Журнал", "el_4983"), + Genre("Ранобэ", "el_5215"), + Genre("Сборник", "el_2157") + ) + + private fun getGenreList() = listOf( + Genre("боевик", "el_2155"), + Genre("боевые искусства", "el_2143"), + Genre("вампиры", "el_2148"), + Genre("гарем", "el_2142"), + Genre("гендерная интрига", "el_2156"), + Genre("героическое фэнтези", "el_2146"), + Genre("детектив", "el_2152"), + Genre("дзёсэй", "el_2158"), + Genre("додзинси", "el_2141"), + Genre("драма", "el_2118"), + Genre("ёнкома", "el_2161"), + Genre("история", "el_2119"), + Genre("комедия", "el_2136"), + Genre("махо-сёдзё", "el_2147"), + Genre("мистика", "el_2132"), + Genre("научная фантастика", "el_2133"), + Genre("повседневность", "el_2135"), + Genre("постапокалиптика", "el_2151"), + Genre("приключения", "el_2130"), + Genre("психология", "el_2144"), + Genre("романтика", "el_2121"), + Genre("сверхъестественное", "el_2159"), + Genre("сёдзё", "el_2122"), + Genre("сёдзё-ай", "el_2128"), + Genre("сёнэн", "el_2134"), + Genre("сёнэн-ай", "el_2139"), + Genre("спорт", "el_2129"), + Genre("сэйнэн", "el_5838"), + Genre("трагедия", "el_2153"), + Genre("триллер", "el_2150"), + Genre("ужасы", "el_2125"), + Genre("фантастика", "el_2140"), + Genre("фэнтези", "el_2131"), + Genre("школа", "el_2127"), + Genre("этти", "el_4982") + ) +} diff --git a/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/Readmanga.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLe.kt similarity index 67% rename from src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/Readmanga.kt rename to multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLe.kt index 6212ad4e2..b4680d840 100644 --- a/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/Readmanga.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLe.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.extension.ru.readmanga +package eu.kanade.tachiyomi.multisrc.grouple import android.app.Application import android.content.SharedPreferences @@ -32,17 +32,15 @@ import java.text.SimpleDateFormat import java.util.Locale import java.util.regex.Pattern -class Readmanga : ConfigurableSource, ParsedHttpSource() { +abstract class GroupLe( + override val name: String, + override val baseUrl: String, + final override val lang: String +) : ConfigurableSource, ParsedHttpSource() { - override val id: Long = 5 private val preferences: SharedPreferences by lazy { Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) } - override val name = "Readmanga" - - override val baseUrl = "https://readmanga.io" - - override val lang = "ru" override val supportsLatest = true @@ -90,50 +88,6 @@ class Readmanga : ConfigurableSource, ParsedHttpSource() { override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is GenreList -> filter.state.forEach { genre -> - if (genre.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) - } - } - is Category -> filter.state.forEach { category -> - if (category.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) - } - } - is AgeList -> filter.state.forEach { age -> - if (age.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(age.id, arrayOf("=", "=in", "=ex")[age.state]) - } - } - is More -> filter.state.forEach { more -> - if (more.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(more.id, arrayOf("=", "=in", "=ex")[more.state]) - } - } - is FilList -> filter.state.forEach { fils -> - if (fils.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(fils.id, arrayOf("=", "=in", "=ex")[fils.state]) - } - } - is OrderBy -> { - if (filter.state > 0) { - val ord = arrayOf("not", "year", "rate", "popularity", "votes", "created", "updated")[filter.state] - val ordUrl = "$baseUrl/list?sortType=$ord&offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() - return GET(ordUrl.toString(), headers) - } - } - } - } - if (query.isNotEmpty()) { - url.addQueryParameter("q", query) - } - return GET(url.toString().replace("=%3D", "="), headers) - } - override fun searchMangaSelector() = popularMangaSelector() override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) @@ -344,101 +298,6 @@ class Readmanga : ConfigurableSource, ParsedHttpSource() { } } - private class OrderBy : Filter.Select<String>( - "Сортировка (только)", - arrayOf("Без сортировки", "По году", "По популярности", "Популярно сейчас", "По рейтингу", "Новинки", "По дате обновления") - ) - - private class Genre(name: String, val id: String) : Filter.TriState(name) - - private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres) - private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories) - private class AgeList(ages: List<Genre>) : Filter.Group<Genre>("Возрастная рекомендация", ages) - private class More(moren: List<Genre>) : Filter.Group<Genre>("Прочее", moren) - private class FilList(fils: List<Genre>) : Filter.Group<Genre>("Фильтры", fils) - - override fun getFilterList() = FilterList( - OrderBy(), - Category(getCategoryList()), - GenreList(getGenreList()), - AgeList(getAgeList()), - More(getMore()), - FilList(getFilList()) - ) - - private fun getFilList() = listOf( - Genre("Высокий рейтинг", "s_high_rate"), - Genre("Сингл", "s_single"), - Genre("Для взрослых", "s_mature"), - Genre("Завершенная", "s_completed"), - Genre("Переведено", "s_translated"), - Genre("Длинная", "s_many_chapters"), - Genre("Ожидает загрузки", "s_wait_upload"), - Genre("Продается", "s_sale") - ) - private fun getMore() = listOf( - Genre("В цвете", "el_7290"), - Genre("Веб", "el_2160"), - Genre("Выпуск приостановлен", "el_8033"), - Genre("Сборник", "el_2157") - ) - - private fun getAgeList() = listOf( - Genre("G(0+)", "el_6180"), - Genre("PG-13(12+)", "el_6181"), - Genre("PG(16+)", "el_6179") - ) - - private fun getCategoryList() = listOf( - Genre("Ёнкома", "el_2161"), - Genre("Комикс западный", "el_3515"), - Genre("Манхва", "el_3001"), - Genre("Маньхуа", "el_3002"), - Genre("Ранобэ", "el_8575"), - ) - - private fun getGenreList() = listOf( - Genre("арт", "el_5685"), - Genre("боевик", "el_2155"), - Genre("боевые искусства", "el_2143"), - Genre("вампиры", "el_2148"), - Genre("гарем", "el_2142"), - Genre("гендерная интрига", "el_2156"), - Genre("героическое фэнтези", "el_2146"), - Genre("детектив", "el_2152"), - Genre("дзёсэй", "el_2158"), - Genre("додзинси", "el_2141"), - Genre("драма", "el_2118"), - Genre("игра", "el_2154"), - Genre("история", "el_2119"), - Genre("киберпанк", "el_8032"), - Genre("кодомо", "el_2137"), - Genre("комедия", "el_2136"), - Genre("махо-сёдзё", "el_2147"), - Genre("меха", "el_2126"), - Genre("научная фантастика", "el_2133"), - Genre("повседневность", "el_2135"), - Genre("постапокалиптика", "el_2151"), - Genre("приключения", "el_2130"), - Genre("психология", "el_2144"), - Genre("романтика", "el_2121"), - Genre("самурайский боевик", "el_2124"), - Genre("сверхъестественное", "el_2159"), - Genre("сёдзё", "el_2122"), - Genre("сёдзё-ай", "el_2128"), - Genre("сёнэн", "el_2134"), - Genre("сёнэн-ай", "el_2139"), - Genre("спорт", "el_2129"), - Genre("сэйнэн", "el_2138"), - Genre("трагедия", "el_2153"), - Genre("триллер", "el_2150"), - Genre("ужасы", "el_2125"), - Genre("фэнтези", "el_2131"), - Genre("школа", "el_2127"), - Genre("этти", "el_2149"), - Genre("юри", "el_2123") - ) - override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) { screen.addPreference(screen.editTextPreference(UAGENT_TITLE, UAGENT_DEFAULT, uagent)) } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLeGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLeGenerator.kt new file mode 100644 index 000000000..d2d95d680 --- /dev/null +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLeGenerator.kt @@ -0,0 +1,28 @@ +package eu.kanade.tachiyomi.multisrc.grouple + +import generator.ThemeSourceData.SingleLang +import generator.ThemeSourceGenerator + +class GroupLeGenerator: ThemeSourceGenerator { + + override val themePkg = "grouple" + + override val themeClass = "GroupLe" + + override val baseVersionCode: Int = 1 + + override val sources = listOf( + SingleLang("ReadManga", "https://readmanga.io", "ru", overrideVersionCode = 45), + SingleLang("MintManga", "https://mintmanga.live", "ru", overrideVersionCode = 46), + SingleLang("AllHentai", "http://23.allhen.online", "ru",isNsfw = true, overrideVersionCode = 22), + SingleLang("SelfManga", "https://selfmanga.live", "ru", overrideVersionCode = 22), + SingleLang("RuMIX", "https://rumix.me", "ru", overrideVersionCode = 1) + ) + + companion object { + @JvmStatic + fun main(args: Array<String>) { + GroupLeGenerator().createAll() + } + } +} diff --git a/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/ReadmangaActivity.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLeUrlActivity.kt similarity index 77% rename from src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/ReadmangaActivity.kt rename to multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLeUrlActivity.kt index 860ff0fd3..c69adf47b 100644 --- a/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/ReadmangaActivity.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/grouple/GroupLeUrlActivity.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.extension.ru.readmanga +package eu.kanade.tachiyomi.multisrc.grouple import android.app.Activity import android.content.ActivityNotFoundException @@ -12,7 +12,7 @@ import kotlin.system.exitProcess * you have this extension installed, but still let the main tachiyomi app control * things. */ -class ReadmangaActivity : Activity() { +class GroupLeUrlActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -21,17 +21,17 @@ class ReadmangaActivity : Activity() { val titleid = pathSegments[0] val mainIntent = Intent().apply { action = "eu.kanade.tachiyomi.SEARCH" - putExtra("query", "${Readmanga.PREFIX_SLUG_SEARCH}$titleid") + putExtra("query", "${GroupLe.PREFIX_SLUG_SEARCH}$titleid") putExtra("filter", packageName) } try { startActivity(mainIntent) } catch (e: ActivityNotFoundException) { - Log.e("ReadmangaActivity", e.toString()) + Log.e("GroupLeUrlActivity", e.toString()) } } else { - Log.e("ReadmangaActivity", "could not parse uri from intent $intent") + Log.e("GroupLeUrlActivity", "could not parse uri from intent $intent") } finish() diff --git a/src/ru/allhentai/AndroidManifest.xml b/src/ru/allhentai/AndroidManifest.xml deleted file mode 100644 index 30deb7f79..000000000 --- a/src/ru/allhentai/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest package="eu.kanade.tachiyomi.extension" /> diff --git a/src/ru/allhentai/build.gradle b/src/ru/allhentai/build.gradle deleted file mode 100644 index 362abd013..000000000 --- a/src/ru/allhentai/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -ext { - extName = 'AllHentai' - pkgNameSuffix = 'ru.allhentai' - extClass = '.AllHentai' - extVersionCode = 22 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" diff --git a/src/ru/allhentai/res/mipmap-hdpi/ic_launcher.png b/src/ru/allhentai/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 359610927..000000000 Binary files a/src/ru/allhentai/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/allhentai/res/mipmap-mdpi/ic_launcher.png b/src/ru/allhentai/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c23a8e98d..000000000 Binary files a/src/ru/allhentai/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/allhentai/res/mipmap-xhdpi/ic_launcher.png b/src/ru/allhentai/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 6b6ce16c8..000000000 Binary files a/src/ru/allhentai/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/allhentai/res/mipmap-xxhdpi/ic_launcher.png b/src/ru/allhentai/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index ecbb34fd2..000000000 Binary files a/src/ru/allhentai/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/allhentai/res/mipmap-xxxhdpi/ic_launcher.png b/src/ru/allhentai/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d45ddd771..000000000 Binary files a/src/ru/allhentai/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/allhentai/res/web_hi_res_512.png b/src/ru/allhentai/res/web_hi_res_512.png deleted file mode 100644 index 2bb4c600f..000000000 Binary files a/src/ru/allhentai/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ru/allhentai/src/eu/kanade/tachiyomi/extension/ru/allhentai/AllHentai.kt b/src/ru/allhentai/src/eu/kanade/tachiyomi/extension/ru/allhentai/AllHentai.kt deleted file mode 100644 index 101f78eb1..000000000 --- a/src/ru/allhentai/src/eu/kanade/tachiyomi/extension/ru/allhentai/AllHentai.kt +++ /dev/null @@ -1,565 +0,0 @@ -package eu.kanade.tachiyomi.extension.ru.allhentai - -import android.app.Application -import android.content.SharedPreferences -import android.widget.Toast -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.asObservableSuccess -import eu.kanade.tachiyomi.network.interceptor.rateLimit -import eu.kanade.tachiyomi.source.ConfigurableSource -import eu.kanade.tachiyomi.source.model.Filter -import eu.kanade.tachiyomi.source.model.FilterList -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.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 uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.io.IOException -import java.text.DecimalFormat -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.Locale -import java.util.regex.Pattern - -class AllHentai : ConfigurableSource, ParsedHttpSource() { - - private val preferences: SharedPreferences by lazy { - Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) - } - - override val name = "AllHentai" - - private var domain: String = preferences.getString(DOMAIN_TITLE, DOMAIN_DEFAULT)!! - override val baseUrl: String = domain - - override val lang = "ru" - - override val supportsLatest = true - - override val client: OkHttpClient = network.client.newBuilder() - .rateLimit(2) - .addNetworkInterceptor { chain -> - val originalRequest = chain.request() - val response = chain.proceed(originalRequest) - if (originalRequest.url.toString().contains(baseUrl) and (originalRequest.url.toString().contains("internal/redirect") or (response.code == 301))) - throw IOException("Манга переехала на другой адрес/ссылку!") - response - } - .build() - - override fun popularMangaSelector() = "div.tile" - - override fun latestUpdatesSelector() = popularMangaSelector() - - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/list?sortType=rate&offset=${70 * (page - 1)}", headers) - - override fun latestUpdatesRequest(page: Int): Request = - GET("$baseUrl/list?sortType=updated&offset=${70 * (page - 1)}", headers) - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.thumbnail_url = element.select("img.lazy").first()?.attr("data-original")?.replace("_p.", ".") - element.select("h3 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.attr("title") - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga = - popularMangaFromElement(element) - - override fun popularMangaNextPageSelector() = "a.nextLink" - - override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is GenreList -> filter.state.forEach { genre -> - if (genre.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) - } - } - is Category -> filter.state.forEach { category -> - if (category.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) - } - } - is FilList -> filter.state.forEach { fils -> - if (fils.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(fils.id, arrayOf("=", "=in", "=ex")[fils.state]) - } - } - is OrderBy -> { - if (filter.state > 0) { - val ord = arrayOf("not", "year", "rate", "popularity", "votes", "created", "updated")[filter.state] - val ordUrl = "$baseUrl/list?sortType=$ord&offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() - return GET(ordUrl.toString(), headers) - } - } - is Tags -> { - if (filter.state > 0) { - val tagName = getTagsList()[filter.state].url - val tagUrl = "$baseUrl/list/tag/$tagName?offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() - return GET(tagUrl.toString(), headers) - } - } - else -> return@forEach - } - } - if (query.isNotEmpty()) { - url.addQueryParameter("q", query) - } - return GET(url.toString().replace("=%3D", "="), headers) - } - - override fun searchMangaSelector() = popularMangaSelector() - - override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) - - // max 200 results (exception OrderBy,Tags) - override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select(".expandable").first() - val rawCategory = infoElement.select("span.elem_category").text() - val category = if (rawCategory.isNotEmpty()) { - rawCategory.lowercase() - } else { - "манга" - } - - val manga = SManga.create() - var authorElement = infoElement.select("span.elem_author").first()?.text() - if (authorElement == null) { - authorElement = infoElement.select("span.elem_screenwriter").first()?.text() - } - manga.title = document.select("h1.names .name").text() - manga.author = authorElement - manga.artist = infoElement.select("span.elem_illustrator").first()?.text() - manga.genre = category + ", " + infoElement.select("span.elem_genre").text().split(",").joinToString { it.trim() } - manga.description = document.select("div#tab-description .manga-description").text() - manga.status = parseStatus(infoElement.html()) - manga.thumbnail_url = infoElement.select("img").attr("data-full") - return manga - } - - private fun parseStatus(element: String): Int = when { - element.contains("Запрещена публикация произведения по копирайту") || element.contains("ЗАПРЕЩЕНА К ПУБЛИКАЦИИ НА ТЕРРИТОРИИ РФ!") -> SManga.LICENSED - element.contains("<b>Перевод:</b> продолжается") -> SManga.ONGOING - element.contains("<b>Сингл</b>") || element.contains("<b>Перевод:</b> завер") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { - return if (manga.status != SManga.LICENSED) { - client.newCall(chapterListRequest(manga)) - .asObservableSuccess() - .map { response -> - chapterListParse(response, manga) - } - } else { - Observable.error(java.lang.Exception("Licensed - No chapters to show")) - } - } - - private fun chapterListParse(response: Response, manga: SManga): List<SChapter> { - val document = response.asJsoup() - return document.select(chapterListSelector()).map { chapterFromElement(it, manga) } - } - - override fun chapterListSelector() = "div.chapters-link > table > tbody > tr:has(td > a):has(td.date:not(.text-info))" - - private fun chapterFromElement(element: Element, manga: SManga): SChapter { - val urlElement = element.select("a").first() - val chapterInf = element.select("td.item-title").first() - val urlText = urlElement.text() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=true") // mtr is 18+ skip - - var translators = "" - val translatorElement = urlElement.attr("title") - if (!translatorElement.isNullOrBlank()) { - translators = translatorElement - .replace("(Переводчик),", "&") - .removeSuffix(" (Переводчик)") - } - chapter.scanlator = translators - - chapter.name = urlText.removeSuffix(" новое").trim() - if (manga.title.length > 25) { - for (word in manga.title.split(' ')) { - chapter.name = chapter.name.removePrefix(word).trim() - } - } - val dots = chapter.name.indexOf("…") - val numbers = chapter.name.findAnyOf(IntRange(0, 9).map { it.toString() })?.first ?: 0 - - if (dots in 0 until numbers) { - chapter.name = chapter.name.substringAfter("…").trim() - } - - chapter.chapter_number = chapterInf.attr("data-num").toFloat() / 10 - - chapter.date_upload = element.select("td.d-none").last()?.text()?.let { - try { - SimpleDateFormat("dd.MM.yy", Locale.US).parse(it)?.time ?: 0L - } catch (e: ParseException) { - SimpleDateFormat("dd/MM/yy", Locale.US).parse(it)?.time ?: 0L - } - } ?: 0 - return chapter - } - - override fun chapterFromElement(element: Element): SChapter { - throw Exception("Not used") - } - - override fun prepareNewChapter(chapter: SChapter, manga: SManga) { - val extra = Regex("""\s*([0-9]+\sЭкстра)\s*""") - val single = Regex("""\s*Сингл\s*""") - when { - extra.containsMatchIn(chapter.name) -> { - if (chapter.name.substringAfter("Экстра").trim().isEmpty()) - chapter.name = chapter.name.replaceFirst(" ", " - " + DecimalFormat("#,###.##").format(chapter.chapter_number).replace(",", ".") + " ") - } - - single.containsMatchIn(chapter.name) -> { - if (chapter.name.substringAfter("Сингл").trim().isEmpty()) - chapter.name = DecimalFormat("#,###.##").format(chapter.chapter_number).replace(",", ".") + " " + chapter.name - } - } - } - - override fun pageListParse(response: Response): List<Page> { - val html = response.body!!.string() - val trimmedHtml = html.substringAfter("rm_h.initReader(").substringBefore(");") - - val p = Pattern.compile("'.*?','.*?',\".*?\"") - val m = p.matcher(trimmedHtml) - - val pages = mutableListOf<Page>() - - var i = 0 - while (m.find()) { - val urlParts = m.group().replace("[\"\']+".toRegex(), "").split(',') - val url = when { - (urlParts[1].isEmpty() && urlParts[2].startsWith("/static/")) -> { - baseUrl + urlParts[2] - } - urlParts[1].endsWith("/manga/") -> { - urlParts[0] + urlParts[2] - } - urlParts[1].isEmpty() -> { - val imageUrl = urlParts[2].split('?') - "https:" + urlParts[0] + imageUrl[0] - } - else -> { - urlParts[1] + urlParts[0] + urlParts[2] - } - } - - pages.add(Page(i++, "", url)) - } - return pages - } - - override fun pageListParse(document: Document): List<Page> { - throw Exception("Not used") - } - - override fun imageUrlParse(document: Document) = "" - - override fun imageRequest(page: Page): Request { - val imgHeader = Headers.Builder().apply { - add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)") - add("Referer", baseUrl) - }.build() - return GET(page.imageUrl!!, imgHeader) - } - - private class OrderBy : Filter.Select<String>( - "Сортировка (только)", - arrayOf("Без сортировки", "По году", "По популярности", "Популярно сейчас", "По рейтингу", "Новинки", "По дате обновления") - ) - - private class Genre(name: String, val id: String) : Filter.TriState(name) - - private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres) - private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories) - private class FilList(fils: List<Genre>) : Filter.Group<Genre>("Фильтры", fils) - private class Tags(tags: Array<String>) : Filter.Select<String>("Тэг (только)", tags) - - private data class Tag(val name: String, val url: String) - - override fun getFilterList() = FilterList( - OrderBy(), - Tags(tagsName), - GenreList(getGenreList()), - Category(getCategoryList()), - FilList(getFilList()) - ) - - /* - * [...document.querySelectorAll('.search-form > .form-group')[1].querySelectorAll('span.js-link')] - * .map((el) => - * `Genre("${el.textContent.trim()}", "${el - * .getAttribute('onclick') - * .match(/el_\d+/)}")` - * ) - * .join(',\n'); - * on allhen.live/search/advanced - */ - private fun getGenreList() = listOf( - Genre("ahegao", "el_855"), - Genre("анал", "el_828"), - Genre("бдсм", "el_78"), - Genre("без цензуры", "el_888"), - Genre("большая грудь", "el_837"), - Genre("большая попка", "el_3156"), - Genre("большой член", "el_884"), - Genre("бондаж", "el_5754"), - Genre("в первый раз", "el_811"), - Genre("в цвете", "el_290"), - Genre("гарем", "el_87"), - Genre("гендарная интрига", "el_89"), - Genre("групповой секс", "el_88"), - Genre("драма", "el_95"), - Genre("зрелые женщины", "el_5679"), - Genre("измена", "el_291"), - Genre("изнасилование", "el_124"), - Genre("инцест", "el_85"), - Genre("исторический", "el_93"), - Genre("комедия", "el_73"), - Genre("маленькая грудь", "el_870"), - Genre("научная фантастика", "el_76"), - Genre("нетораре", "el_303"), - Genre("оральный секс", "el_853"), - Genre("романтика", "el_74"), - Genre("тентакли", "el_69"), - Genre("трагедия", "el_1321"), - Genre("ужасы", "el_75"), - Genre("футанари", "el_77"), - Genre("фэнтези", "el_70"), - Genre("чикан", "el_1059"), - Genre("этти", "el_798"), - Genre("юри", "el_84"), - Genre("яой", "el_83") - ) - - /* - * [...document.querySelectorAll('.search-form > .form-group')[2].querySelectorAll('span.js-link')] - * .map((el) => - * `Genre("${el.textContent.trim()}", "${el - * .getAttribute('onclick') - * .match(/el_\d+/)}")` - * ) - * .join(',\n'); - * on allhen.live/search/advanced - */ - private fun getCategoryList() = listOf( - Genre("3D", "el_626"), - Genre("Анимация", "el_5777"), - Genre("Без текста", "el_3157"), - Genre("Порно комикс", "el_1003"), - Genre("Порно манхва", "el_1104") - ) - - /* - * [...document.querySelectorAll('.search-form > .form-group')[1].querySelectorAll('span.js-link')] - * .map((el) => - * `Genre("${el.textContent.trim()}", "${el - * .getAttribute('onclick') - * .match(/s_\w+/)}")` - * ) - * .join(',\n'); - * on allhen.live/search/advanced - */ - private fun getFilList() = listOf( - Genre("Высокий рейтинг", "s_high_rate"), - Genre("Сингл", "s_single"), - Genre("Для взрослых", "s_mature"), - Genre("Завершенная", "s_completed"), - Genre("Переведено", "s_translated"), - Genre("Длинная", "s_many_chapters"), - Genre("Ожидает загрузки", "s_wait_upload"), - Genre("Продается", "s_sale") - ) - - /** - * [...document.querySelectorAll('tbody .element-link')] - * .map((it) => - * `Tag("${it.textContent.trim()}", "${it - * .getAttribute('href') - * .split('tag/') - * .pop()}")` - * ) - * .join(',\n'); - * on allhen.live/list/tags/sort_NAME - */ - private fun getTagsList() = listOf( - Tag("Без тега", "not"), - Tag("handjob", "handjob"), - Tag("inseki", "inseki"), - Tag("алкоголь", "alcohol"), - Tag("андроид", "android"), - Tag("анилингус", "anilingus"), - Tag("бассейн", "pool"), - Tag("без трусиков", "without_panties"), - Tag("беременность", "pregnancy"), - Tag("бикини", "bikini"), - Tag("близнецы", "twins"), - Tag("боди-арт", "body_art"), - Tag("больница", "hospital"), - Tag("буккакэ", "bukkake"), - Tag("в ванной", "in_bathroom"), - Tag("в общественном месте", "in_public_place"), - Tag("в транспорте", "in_vehicle"), - Tag("вампиры", "vampires"), - Tag("вибратор", "vibrator"), - Tag("втянутые соски", "inverted_nipples"), - Tag("гипноз", "hypnosis"), - Tag("глубокий минет", "deepthroat"), - Tag("горничные", "maids"), - Tag("горячий источник", "hot_spring"), - Tag("гэнгбэнг", "gangbang"), - Tag("гяру", "gyaru"), - Tag("двойное проникновение", "double_penetration"), - Tag("Девочки волшебницы", "magical_girl"), - Tag("демоны", "demons"), - Tag("дефекация", "scat"), - Tag("дилдо", "dildo"), - Tag("додзинси", "doujinshi"), - Tag("домохозяйки", "housewives"), - Tag("дыра в стене", "hole_in_the_wall"), - Tag("жестокость", "cruelty"), - Tag("загар", "tan_lines"), - Tag("зомби", "zombie"), - Tag("инопланетяне", "aliens"), - Tag("исполнение желаний", "granting_wish"), - Tag("камера", "camera"), - Tag("косплей", "cosplay"), - Tag("кремпай", "creampie"), - Tag("куннилингус", "cunnilingus"), - Tag("купальник", "swimsuit"), - Tag("лактация", "lactation"), - Tag("латекс и кожа", "latex"), - Tag("Ломка Психики", "mind_break"), - Tag("магия", "magic"), - Tag("мастурбация", "masturbation"), - Tag("медсестра", "nurse"), - Tag("мерзкий дядька", "terrible_oyaji"), - Tag("много девушек", "many_girls"), - Tag("много спермы", "a_lot_of_sperm"), - Tag("монстрдевушки", "monstergirl"), - Tag("монстры", "monsters"), - Tag("мужчина крепкого телосложения", "muscle_man"), - Tag("на природе", "outside"), - Tag("не бритая киска", "hairy_pussy"), - Tag("не бритые подмышки", "hairy_armpits"), - Tag("нетори", "netori"), - Tag("нижнее бельё", "lingerie"), - Tag("обмен партнерами", "swinging"), - Tag("обмен телами", "body_swap"), - Tag("обычный секс", "normal_sex"), - Tag("огромная грудь", "super_big_boobs"), - Tag("орки", "orcs"), - Tag("очки", "megane"), - Tag("пайзури", "titsfuck"), - Tag("парень пассив", "passive_guy"), - Tag("пацанка", "tomboy"), - Tag("пеггинг", "pegging"), - Tag("переодевание", "disguise"), - Tag("пирсинг", "piercing"), - Tag("писают", "peeing"), - Tag("пляж", "beach"), - Tag("повседневность", "slice_of_life"), - Tag("повязка на глаза", "blindfold"), - Tag("подглядывание", "peeping"), - Tag("подчинение", "submission"), - Tag("похищение", "kidnapping"), - Tag("принуждение", "forced"), - Tag("прозрачная одежда", "transparent_clothes"), - Tag("проституция", "prostitution"), - Tag("психические отклонения", "mental_illness"), - Tag("публичный секс", "public_sex"), - Tag("пьяные", "drunk"), - Tag("рабы", "slaves"), - Tag("рентген зрение", "x_ray"), - Tag("сверхъестественное", "supernatural"), - Tag("секс втроем", "threesome"), - Tag("секс игрушки", "sex_toys"), - Tag("сексуально возбужденная", "horny"), - Tag("спортивная форма", "sports_uniform"), - Tag("спящие", "sleeping"), - Tag("страпон", "strapon"), - Tag("Суккуб", "succubus"), - Tag("темнокожие", "dark_skin"), - Tag("толстушки", "fatties"), - Tag("трап", "trap"), - Tag("униформа", "uniform"), - Tag("ушастые", "eared"), - Tag("фантазии", "dreams"), - Tag("фемдом", "femdom"), - Tag("фестиваль", "festival"), - Tag("фетиш", "fetish"), - Tag("фистинг", "fisting"), - Tag("фурри", "furry"), - Tag("футанари имеет парня", "futanari_on_boy"), - Tag("футджаб", "footfuck"), - Tag("цельный купальник", "full_swimsuit"), - Tag("цундэрэ", "tsundere"), - Tag("чулки", "hose"), - Tag("шалава", "slut"), - Tag("шантаж", "blackmail"), - Tag("эксгибиционизм", "exhibitionism"), - Tag("эльфы", "elves"), - Tag("яндере", "yandere") - ) - - private val tagsName = getTagsList().map { - it.name - }.toTypedArray() - - override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) { - screen.addPreference(screen.editTextPreference(DOMAIN_TITLE, DOMAIN_DEFAULT, domain)) - } - - private fun androidx.preference.PreferenceScreen.editTextPreference(title: String, default: String, value: String): androidx.preference.EditTextPreference { - return androidx.preference.EditTextPreference(context).apply { - key = title - this.title = title - summary = value - this.setDefaultValue(default) - dialogTitle = title - setOnPreferenceChangeListener { _, newValue -> - try { - val res = preferences.edit().putString(title, newValue as String).commit() - Toast.makeText(context, "Для смены домена необходимо перезапустить приложение с полной остановкой.", Toast.LENGTH_LONG).show() - res - } catch (e: Exception) { - e.printStackTrace() - false - } - } - } - } - companion object { - private const val DOMAIN_TITLE = "Домен" - private const val DOMAIN_DEFAULT = "http://23.allhen.online" - } -} diff --git a/src/ru/mintmanga/build.gradle b/src/ru/mintmanga/build.gradle deleted file mode 100644 index eefc6de02..000000000 --- a/src/ru/mintmanga/build.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -ext { - extName = 'Mintmanga' - pkgNameSuffix = 'ru.mintmanga' - extClass = '.Mintmanga' - extVersionCode = 46 -} - -apply from: "$rootDir/common.gradle" diff --git a/src/ru/mintmanga/res/mipmap-hdpi/ic_launcher.png b/src/ru/mintmanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 78bc7512c..000000000 Binary files a/src/ru/mintmanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/mintmanga/res/mipmap-mdpi/ic_launcher.png b/src/ru/mintmanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index ff183f248..000000000 Binary files a/src/ru/mintmanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/mintmanga/res/mipmap-xhdpi/ic_launcher.png b/src/ru/mintmanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 6a6ef9e52..000000000 Binary files a/src/ru/mintmanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/mintmanga/res/mipmap-xxhdpi/ic_launcher.png b/src/ru/mintmanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 8b12a60a8..000000000 Binary files a/src/ru/mintmanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/mintmanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/ru/mintmanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index c555bd882..000000000 Binary files a/src/ru/mintmanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/Mintmanga.kt b/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/Mintmanga.kt deleted file mode 100644 index 6d7aec6f6..000000000 --- a/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/Mintmanga.kt +++ /dev/null @@ -1,469 +0,0 @@ -package eu.kanade.tachiyomi.extension.ru.mintmanga - -import android.app.Application -import android.content.SharedPreferences -import android.widget.Toast -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.asObservableSuccess -import eu.kanade.tachiyomi.network.interceptor.rateLimit -import eu.kanade.tachiyomi.source.ConfigurableSource -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.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 uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.io.IOException -import java.text.DecimalFormat -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.Locale -import java.util.regex.Pattern - -class Mintmanga : ConfigurableSource, ParsedHttpSource() { - - override val id: Long = 6 - private val preferences: SharedPreferences by lazy { - Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) - } - override val name = "Mintmanga" - - override val baseUrl = "https://mintmanga.live" - - override val lang = "ru" - - override val supportsLatest = true - - override val client: OkHttpClient = network.client.newBuilder() - .rateLimit(2) - .addNetworkInterceptor { chain -> - val originalRequest = chain.request() - val response = chain.proceed(originalRequest) - if (originalRequest.url.toString().contains(baseUrl) and (originalRequest.url.toString().contains("internal/redirect") or (response.code == 301))) - throw IOException("Манга переехала на другой адрес/ссылку!") - response - } - .build() - - private var uagent: String = preferences.getString(UAGENT_TITLE, UAGENT_DEFAULT)!! - override fun headersBuilder() = Headers.Builder().apply { - add("User-Agent", uagent) - add("Referer", baseUrl) - } - - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/list?sortType=rate&offset=${70 * (page - 1)}", headers) - - override fun latestUpdatesRequest(page: Int): Request = - GET("$baseUrl/list?sortType=updated&offset=${70 * (page - 1)}", headers) - - override fun popularMangaSelector() = "div.tile" - - override fun latestUpdatesSelector() = popularMangaSelector() - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.thumbnail_url = element.select("img.lazy").first()?.attr("data-original")?.replace("_p.", ".") - element.select("h3 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.attr("title") - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga = - popularMangaFromElement(element) - - override fun popularMangaNextPageSelector() = "a.nextLink" - - override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is GenreList -> filter.state.forEach { genre -> - if (genre.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) - } - } - is Category -> filter.state.forEach { category -> - if (category.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) - } - } - is AgeList -> filter.state.forEach { age -> - if (age.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(age.id, arrayOf("=", "=in", "=ex")[age.state]) - } - } - is More -> filter.state.forEach { more -> - if (more.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(more.id, arrayOf("=", "=in", "=ex")[more.state]) - } - } - is FilList -> filter.state.forEach { fils -> - if (fils.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(fils.id, arrayOf("=", "=in", "=ex")[fils.state]) - } - } - is OrderBy -> { - if (filter.state > 0) { - val ord = arrayOf("not", "year", "rate", "popularity", "votes", "created", "updated")[filter.state] - val ordUrl = "$baseUrl/list?sortType=$ord&offset=${70 * (page - 1)}".toHttpUrlOrNull()!!.newBuilder() - return GET(ordUrl.toString(), headers) - } - } - } - } - if (query.isNotEmpty()) { - url.addQueryParameter("q", query) - } - return GET(url.toString().replace("=%3D", "="), headers) - } - - override fun searchMangaSelector() = popularMangaSelector() - - override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) - - // max 200 results (exception OrderBy) - override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select(".expandable").first() - val rawCategory = infoElement.select("span.elem_category").text() - val category = if (rawCategory.isNotEmpty()) { - rawCategory.lowercase() - } else { - "манга" - } - val ratingValue = infoElement.select(".col-sm-7 .rating-block").attr("data-score").toFloat() * 2 - val ratingValueOver = infoElement.select(".info-icon").attr("data-content").substringBeforeLast("/5</b><br/>").substringAfterLast(": <b>").replace(",", ".").toFloat() * 2 - val ratingVotes = infoElement.select(".col-sm-7 .user-rating meta[itemprop=\"ratingCount\"]").attr("content") - val ratingStar = when { - ratingValue > 9.5 -> "★★★★★" - ratingValue > 8.5 -> "★★★★✬" - ratingValue > 7.5 -> "★★★★☆" - ratingValue > 6.5 -> "★★★✬☆" - ratingValue > 5.5 -> "★★★☆☆" - ratingValue > 4.5 -> "★★✬☆☆" - ratingValue > 3.5 -> "★★☆☆☆" - ratingValue > 2.5 -> "★✬☆☆☆" - ratingValue > 1.5 -> "★☆☆☆☆" - ratingValue > 0.5 -> "✬☆☆☆☆" - else -> "☆☆☆☆☆" - } - val rawAgeValue = infoElement.select(".elem_limitation .element-link").first()?.text() - val rawAgeStop = when (rawAgeValue) { - "NC-17" -> "18+" - "R18+" -> "18+" - else -> "16+" - } - val manga = SManga.create() - var authorElement = infoElement.select("span.elem_author").first()?.text() - if (authorElement == null) { - authorElement = infoElement.select("span.elem_screenwriter").first()?.text() - } - manga.title = document.select("h1.names .name").text() - manga.author = authorElement - manga.artist = infoElement.select("span.elem_illustrator").first()?.text() - manga.genre = category + ", " + rawAgeStop + ", " + infoElement.select("span.elem_genre").text().split(",").joinToString { it.trim() } - var altName = "" - if (infoElement.select(".another-names").isNotEmpty()) { - altName = "Альтернативные названия:\n" + infoElement.select(".another-names").text() + "\n\n" - } - manga.description = ratingStar + " " + ratingValue + "[ⓘ" + ratingValueOver + "]" + " (голосов: " + ratingVotes + ")\n" + altName + document.select("div#tab-description .manga-description").text() - manga.status = parseStatus(infoElement.html()) - manga.thumbnail_url = infoElement.select("img").attr("data-full") - return manga - } - - private fun parseStatus(element: String): Int = when { - element.contains("Запрещена публикация произведения по копирайту") || element.contains("ЗАПРЕЩЕНА К ПУБЛИКАЦИИ НА ТЕРРИТОРИИ РФ!") -> SManga.LICENSED - element.contains("<b>Перевод:</b> продолжается") -> SManga.ONGOING - element.contains("<b>Сингл</b>") || element.contains("<b>Перевод:</b> завер") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { - return if (manga.status != SManga.LICENSED) { - client.newCall(chapterListRequest(manga)) - .asObservableSuccess() - .map { response -> - chapterListParse(response, manga) - } - } else { - Observable.error(java.lang.Exception("Licensed - No chapters to show")) - } - } - - private fun chapterListParse(response: Response, manga: SManga): List<SChapter> { - val document = response.asJsoup() - return document.select(chapterListSelector()).map { chapterFromElement(it, manga) } - } - - override fun chapterListSelector() = "div.chapters-link > table > tbody > tr:has(td > a):has(td.date:not(.text-info))" - - private fun chapterFromElement(element: Element, manga: SManga): SChapter { - val urlElement = element.select("a").first() - val chapterInf = element.select("td.item-title").first() - val urlText = urlElement.text() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=true") // mtr is 18+ skip - - var translators = "" - val translatorElement = urlElement.attr("title") - if (!translatorElement.isNullOrBlank()) { - translators = translatorElement - .replace("(Переводчик),", "&") - .removeSuffix(" (Переводчик)") - } - chapter.scanlator = translators - - chapter.name = urlText.removeSuffix(" новое").trim() - if (manga.title.length > 25) { - for (word in manga.title.split(' ')) { - chapter.name = chapter.name.removePrefix(word).trim() - } - } - val dots = chapter.name.indexOf("…") - val numbers = chapter.name.findAnyOf(IntRange(0, 9).map { it.toString() })?.first ?: 0 - - if (dots in 0 until numbers) { - chapter.name = chapter.name.substringAfter("…").trim() - } - - chapter.chapter_number = chapterInf.attr("data-num").toFloat() / 10 - - chapter.date_upload = element.select("td.d-none").last()?.text()?.let { - try { - SimpleDateFormat("dd.MM.yy", Locale.US).parse(it)?.time ?: 0L - } catch (e: ParseException) { - SimpleDateFormat("dd/MM/yy", Locale.US).parse(it)?.time ?: 0L - } - } ?: 0 - return chapter - } - - override fun chapterFromElement(element: Element): SChapter { - throw Exception("Not used") - } - - override fun prepareNewChapter(chapter: SChapter, manga: SManga) { - val extra = Regex("""\s*([0-9]+\sЭкстра)\s*""") - val single = Regex("""\s*Сингл\s*""") - when { - extra.containsMatchIn(chapter.name) -> { - if (chapter.name.substringAfter("Экстра").trim().isEmpty()) - chapter.name = chapter.name.replaceFirst(" ", " - " + DecimalFormat("#,###.##").format(chapter.chapter_number).replace(",", ".") + " ") - } - - single.containsMatchIn(chapter.name) -> { - if (chapter.name.substringAfter("Сингл").trim().isEmpty()) - chapter.name = DecimalFormat("#,###.##").format(chapter.chapter_number).replace(",", ".") + " " + chapter.name - } - } - } - - override fun pageListParse(response: Response): List<Page> { - val html = response.body!!.string() - val beginIndex = html.indexOf("rm_h.initReader( [") - val endIndex = html.indexOf(");", beginIndex) - val trimmedHtml = html.substring(beginIndex, endIndex) - - val p = Pattern.compile("'.*?','.*?',\".*?\"") - val m = p.matcher(trimmedHtml) - - val pages = mutableListOf<Page>() - - var i = 0 - while (m.find()) { - val urlParts = m.group().replace("[\"\']+".toRegex(), "").split(',') - val url = if (urlParts[1].isEmpty() && urlParts[2].startsWith("/static/")) { - baseUrl + urlParts[2] - } else { - if (urlParts[1].endsWith("/manga/")) { - urlParts[0] + urlParts[2] - } else { - urlParts[1] + urlParts[0] + urlParts[2] - } - } - pages.add(Page(i++, "", url)) - } - return pages - } - - override fun pageListParse(document: Document): List<Page> { - throw Exception("Not used") - } - - override fun imageUrlParse(document: Document) = "" - - override fun imageRequest(page: Page): Request { - val imgHeader = Headers.Builder().apply { - add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)") - add("Referer", baseUrl) - }.build() - return GET(page.imageUrl!!, imgHeader) - } - private fun searchMangaByIdRequest(id: String): Request { - return GET("$baseUrl/$id", headers) - } - - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { - return if (query.startsWith(PREFIX_SLUG_SEARCH)) { - val realQuery = query.removePrefix(PREFIX_SLUG_SEARCH) - client.newCall(searchMangaByIdRequest(realQuery)) - .asObservableSuccess() - .map { response -> - val details = mangaDetailsParse(response) - details.url = "/$realQuery" - MangasPage(listOf(details), false) - } - } else { - client.newCall(searchMangaRequest(page, query, filters)) - .asObservableSuccess() - .map { response -> - searchMangaParse(response) - } - } - } - - private class OrderBy : Filter.Select<String>( - "Сортировка (только)", - arrayOf("Без сортировки", "По году", "По популярности", "Популярно сейчас", "По рейтингу", "Новинки", "По дате обновления") - ) - - private class Genre(name: String, val id: String) : Filter.TriState(name) - - private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres) - private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories) - private class AgeList(ages: List<Genre>) : Filter.Group<Genre>("Возрастная рекомендация", ages) - private class More(moren: List<Genre>) : Filter.Group<Genre>("Прочее", moren) - private class FilList(fils: List<Genre>) : Filter.Group<Genre>("Фильтры", fils) - - override fun getFilterList() = FilterList( - OrderBy(), - Category(getCategoryList()), - GenreList(getGenreList()), - AgeList(getAgeList()), - More(getMore()), - FilList(getFilList()) - ) - private fun getFilList() = listOf( - Genre("Высокий рейтинг", "s_high_rate"), - Genre("Сингл", "s_single"), - Genre("Для взрослых", "s_mature"), - Genre("Завершенная", "s_completed"), - Genre("Переведено", "s_translated"), - Genre("Длинная", "s_many_chapters"), - Genre("Ожидает загрузки", "s_wait_upload"), - ) - private fun getMore() = listOf( - Genre("В цвете", "el_4614"), - Genre("Веб", "el_1355"), - Genre("Выпуск приостановлен", "el_5232"), - Genre("Не Яой", "el_1874"), - Genre("Сборник", "el_1348") - ) - - private fun getAgeList() = listOf( - Genre("R(16+)", "el_3968"), - Genre("NC-17(18+)", "el_3969"), - Genre("R18+(18+)", "el_3990") - ) - - private fun getCategoryList() = listOf( - Genre("Ёнкома", "el_2741"), - Genre("Комикс западный", "el_1903"), - Genre("Комикс русский", "el_2173"), - Genre("Манхва", "el_1873"), - Genre("Маньхуа", "el_1875"), - Genre("Ранобэ", "el_5688"), - ) - - private fun getGenreList() = listOf( - Genre("арт", "el_2220"), - Genre("бара", "el_1353"), - Genre("боевик", "el_1346"), - Genre("боевые искусства", "el_1334"), - Genre("вампиры", "el_1339"), - Genre("гарем", "el_1333"), - Genre("гендерная интрига", "el_1347"), - Genre("героическое фэнтези", "el_1337"), - Genre("детектив", "el_1343"), - Genre("дзёсэй", "el_1349"), - Genre("додзинси", "el_1332"), - Genre("драма", "el_1310"), - Genre("игра", "el_5229"), - Genre("история", "el_1311"), - Genre("киберпанк", "el_1351"), - Genre("комедия", "el_1328"), - Genre("меха", "el_1318"), - Genre("научная фантастика", "el_1325"), - Genre("омегаверс", "el_5676"), - Genre("повседневность", "el_1327"), - Genre("постапокалиптика", "el_1342"), - Genre("приключения", "el_1322"), - Genre("психология", "el_1335"), - Genre("романтика", "el_1313"), - Genre("самурайский боевик", "el_1316"), - Genre("сверхъестественное", "el_1350"), - Genre("сёдзё", "el_1314"), - Genre("сёдзё-ай", "el_1320"), - Genre("сёнэн", "el_1326"), - Genre("сёнэн-ай", "el_1330"), - Genre("спорт", "el_1321"), - Genre("сэйнэн", "el_1329"), - Genre("трагедия", "el_1344"), - Genre("триллер", "el_1341"), - Genre("ужасы", "el_1317"), - Genre("фэнтези", "el_1323"), - Genre("школа", "el_1319"), - Genre("эротика", "el_1340"), - Genre("этти", "el_1354"), - Genre("юри", "el_1315"), - Genre("яой", "el_1336") - ) - override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) { - screen.addPreference(screen.editTextPreference(UAGENT_TITLE, UAGENT_DEFAULT, uagent)) - } - - private fun androidx.preference.PreferenceScreen.editTextPreference(title: String, default: String, value: String): androidx.preference.EditTextPreference { - return androidx.preference.EditTextPreference(context).apply { - key = title - this.title = title - summary = value - this.setDefaultValue(default) - dialogTitle = title - setOnPreferenceChangeListener { _, newValue -> - try { - val res = preferences.edit().putString(title, newValue as String).commit() - Toast.makeText(context, "Для смены User-Agent необходимо перезапустить приложение с полной остановкой.", Toast.LENGTH_LONG).show() - res - } catch (e: Exception) { - e.printStackTrace() - false - } - } - } - } - companion object { - private const val UAGENT_TITLE = "User-Agent(для некоторых стран)" - private const val UAGENT_DEFAULT = "arora" - const val PREFIX_SLUG_SEARCH = "slug:" - } -} diff --git a/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/MintmangaActivity.kt b/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/MintmangaActivity.kt deleted file mode 100644 index 34432a5eb..000000000 --- a/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/MintmangaActivity.kt +++ /dev/null @@ -1,40 +0,0 @@ -package eu.kanade.tachiyomi.extension.ru.mintmanga - -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://mintmanga.live/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 MintmangaActivity : 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", "${Mintmanga.PREFIX_SLUG_SEARCH}$titleid") - putExtra("filter", packageName) - } - - try { - startActivity(mainIntent) - } catch (e: ActivityNotFoundException) { - Log.e("MintmangaActivity", e.toString()) - } - } else { - Log.e("MintmangaaActivity", "could not parse uri from intent $intent") - } - - finish() - exitProcess(0) - } -} diff --git a/src/ru/readmanga/AndroidManifest.xml b/src/ru/readmanga/AndroidManifest.xml deleted file mode 100644 index 711a7fa3e..000000000 --- a/src/ru/readmanga/AndroidManifest.xml +++ /dev/null @@ -1,25 +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=".ru.readmanga.ReadmangaActivity" - 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" /> - - <!-- ReadmangaActivity sites can be added here. --> - <data - android:host="readmanga.io" - android:pathPattern="/..*/vol..*" - android:scheme="https" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/src/ru/readmanga/build.gradle b/src/ru/readmanga/build.gradle deleted file mode 100644 index ac07bf6a2..000000000 --- a/src/ru/readmanga/build.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -ext { - extName = 'Readmanga' - pkgNameSuffix = 'ru.readmanga' - extClass = '.Readmanga' - extVersionCode = 45 -} - -apply from: "$rootDir/common.gradle" diff --git a/src/ru/readmanga/res/mipmap-hdpi/ic_launcher.png b/src/ru/readmanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 3e550725e..000000000 Binary files a/src/ru/readmanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/readmanga/res/mipmap-mdpi/ic_launcher.png b/src/ru/readmanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index b3df119e7..000000000 Binary files a/src/ru/readmanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/readmanga/res/mipmap-xhdpi/ic_launcher.png b/src/ru/readmanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index b3158fb26..000000000 Binary files a/src/ru/readmanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/readmanga/res/mipmap-xxhdpi/ic_launcher.png b/src/ru/readmanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 35ef8d93a..000000000 Binary files a/src/ru/readmanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/readmanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/ru/readmanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index e63084ad6..000000000 Binary files a/src/ru/readmanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/selfmanga/AndroidManifest.xml b/src/ru/selfmanga/AndroidManifest.xml deleted file mode 100644 index 30deb7f79..000000000 --- a/src/ru/selfmanga/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest package="eu.kanade.tachiyomi.extension" /> diff --git a/src/ru/selfmanga/build.gradle b/src/ru/selfmanga/build.gradle deleted file mode 100644 index 4f036c3b7..000000000 --- a/src/ru/selfmanga/build.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -ext { - extName = 'Selfmanga' - pkgNameSuffix = 'ru.selfmanga' - extClass = '.Selfmanga' - extVersionCode = 22 -} - -apply from: "$rootDir/common.gradle" diff --git a/src/ru/selfmanga/res/mipmap-hdpi/ic_launcher.png b/src/ru/selfmanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index b66a27888..000000000 Binary files a/src/ru/selfmanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/selfmanga/res/mipmap-mdpi/ic_launcher.png b/src/ru/selfmanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 4feafbdc7..000000000 Binary files a/src/ru/selfmanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/selfmanga/res/mipmap-xhdpi/ic_launcher.png b/src/ru/selfmanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 9677de7dd..000000000 Binary files a/src/ru/selfmanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/selfmanga/res/mipmap-xxhdpi/ic_launcher.png b/src/ru/selfmanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 1c86beed1..000000000 Binary files a/src/ru/selfmanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/selfmanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/ru/selfmanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 58d7f343c..000000000 Binary files a/src/ru/selfmanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/ru/selfmanga/res/web_hi_res_512.png b/src/ru/selfmanga/res/web_hi_res_512.png deleted file mode 100644 index 52aa54712..000000000 Binary files a/src/ru/selfmanga/res/web_hi_res_512.png and /dev/null differ diff --git a/src/ru/selfmanga/src/eu/kanade/tachiyomi/extension/ru/selfmanga/Selfmanga.kt b/src/ru/selfmanga/src/eu/kanade/tachiyomi/extension/ru/selfmanga/Selfmanga.kt deleted file mode 100644 index 3641440b4..000000000 --- a/src/ru/selfmanga/src/eu/kanade/tachiyomi/extension/ru/selfmanga/Selfmanga.kt +++ /dev/null @@ -1,266 +0,0 @@ -package eu.kanade.tachiyomi.extension.ru.selfmanga - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.interceptor.rateLimit -import eu.kanade.tachiyomi.source.model.Filter -import eu.kanade.tachiyomi.source.model.FilterList -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 okhttp3.Headers -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 java.io.IOException -import java.text.DecimalFormat -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.Locale -import java.util.regex.Pattern - -class Selfmanga : ParsedHttpSource() { - - override val name = "Selfmanga" - - override val baseUrl = "https://selfmanga.live" - - override val lang = "ru" - - override val supportsLatest = true - - override val client: OkHttpClient = network.client.newBuilder() - .rateLimit(2) - .addNetworkInterceptor { chain -> - val originalRequest = chain.request() - val response = chain.proceed(originalRequest) - if (originalRequest.url.toString().contains(baseUrl) and (originalRequest.url.toString().contains("internal/redirect") or (response.code == 301))) - throw IOException("Манга переехала на другой адрес/ссылку!") - response - } - .build() - - override fun popularMangaSelector() = "div.tile" - - override fun latestUpdatesSelector() = popularMangaSelector() - - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/list?sortType=rate&offset=${70 * (page - 1)}", headers) - - override fun latestUpdatesRequest(page: Int): Request = - GET("$baseUrl/list?sortType=updated&offset=${70 * (page - 1)}", headers) - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.thumbnail_url = element.select("img.lazy").first()?.attr("data-original")?.replace("_p.", ".") - element.select("h3 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.attr("title") - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga = - popularMangaFromElement(element) - - override fun popularMangaNextPageSelector() = "a.nextLink" - - override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = "$baseUrl/search/advanced".toHttpUrlOrNull()!!.newBuilder() - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is GenreList -> filter.state.forEach { genre -> - if (genre.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) - } - } - is Category -> filter.state.forEach { category -> - if (category.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) - } - } - } - } - if (query.isNotEmpty()) { - url.addQueryParameter("q", query) - } - return GET(url.toString().replace("=%3D", "="), headers) - } - - override fun searchMangaSelector() = popularMangaSelector() - - override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) - - // max 200 results - override fun searchMangaNextPageSelector(): Nothing? = null - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select(".expandable").first() - - val manga = SManga.create() - manga.title = document.select("h1.names .name").text() - manga.author = infoElement.select("span.elem_author").first()?.text() - manga.genre = infoElement.select("span.elem_genre").text().split(",").joinToString { it.trim() } - manga.description = document.select("div#tab-description .manga-description").text() - manga.status = parseStatus(infoElement.html()) - manga.thumbnail_url = infoElement.select("img").attr("data-full") - return manga - } - - private fun parseStatus(element: String): Int = when { - element.contains("Запрещена публикация произведения по копирайту") || element.contains("ЗАПРЕЩЕНА К ПУБЛИКАЦИИ НА ТЕРРИТОРИИ РФ!") -> SManga.LICENSED - element.contains("<b>Перевод:</b> продолжается") -> SManga.ONGOING - element.contains("<b>Сингл</b>") || element.contains(", завер") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "div.chapters-link > table > tbody > tr:has(td > a):has(td.date:not(.text-info))" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() - val chapterInf = element.select("td.item-title").first() - val urlText = urlElement.text() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=true") // mtr is 18+ skip - if (urlText.endsWith(" новое")) { - chapter.name = urlText.dropLast(6) - } else { - chapter.name = urlText - } - - chapter.chapter_number = chapterInf.attr("data-num").toFloat() / 10 - - chapter.date_upload = element.select("td.d-none").last()?.text()?.let { - try { - SimpleDateFormat("dd/MM/yy", Locale.US).parse(it)?.time ?: 0L - } catch (e: ParseException) { - SimpleDateFormat("dd.MM.yy", Locale.US).parse(it)?.time ?: 0L - } - } ?: 0 - return chapter - } - - override fun prepareNewChapter(chapter: SChapter, manga: SManga) { - val extra = Regex("""\s*([0-9]+\sЭкстра)\s*""") - val single = Regex("""\s*Сингл\s*""") - when { - extra.containsMatchIn(chapter.name) -> { - if (chapter.name.substringAfter("Экстра").trim().isEmpty()) - chapter.name = chapter.name.replaceFirst(" ", " - " + DecimalFormat("#,###.##").format(chapter.chapter_number).replace(",", ".") + " ") - } - - single.containsMatchIn(chapter.name) -> { - if (chapter.name.substringAfter("Сингл").trim().isEmpty()) - chapter.name = DecimalFormat("#,###.##").format(chapter.chapter_number).replace(",", ".") + " " + chapter.name - } - } - } - - override fun pageListParse(response: Response): List<Page> { - val html = response.body!!.string() - val beginIndex = html.indexOf("rm_h.initReader( [") - val endIndex = html.indexOf(");", beginIndex) - val trimmedHtml = html.substring(beginIndex, endIndex) - - val p = Pattern.compile("'.*?','.*?',\".*?\"") - val m = p.matcher(trimmedHtml) - - val pages = mutableListOf<Page>() - - var i = 0 - while (m.find()) { - val urlParts = m.group().replace("[\"\']+".toRegex(), "").split(',') - val url = if (urlParts[1].isEmpty() && urlParts[2].startsWith("/static/")) { - baseUrl + urlParts[2] - } else { - if (urlParts[1].endsWith("/manga/")) { - urlParts[0] + urlParts[2] - } else { - urlParts[1] + urlParts[0] + urlParts[2] - } - } - pages.add(Page(i++, "", url)) - } - return pages - } - - override fun pageListParse(document: Document): List<Page> { - throw Exception("Not used") - } - - override fun imageUrlParse(document: Document) = "" - - override fun imageRequest(page: Page): Request { - val imgHeader = Headers.Builder().apply { - add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)") - add("Referer", baseUrl) - }.build() - return GET(page.imageUrl!!, imgHeader) - } - - private class Genre(name: String, val id: String) : Filter.TriState(name) - private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) - private class Category(categories: List<Genre>) : Filter.Group<Genre>("Category", categories) - - /* [...document.querySelectorAll("tr.advanced_option:nth-child(1) > td:nth-child(3) span.js-link")] - * .map(el => `Genre("${el.textContent.trim()}", $"{el.getAttribute('onclick') - * .substr(31,el.getAttribute('onclick').length-33)"})`).join(',\n') - * on https://selfmanga.ru/search/advanced - */ - override fun getFilterList() = FilterList( - Category(getCategoryList()), - GenreList(getGenreList()) - ) - - private fun getCategoryList() = listOf( - Genre("Артбук", "el_5894"), - Genre("Веб", "el_2160"), - Genre("Журнал", "el_4983"), - Genre("Ранобэ", "el_5215"), - Genre("Сборник", "el_2157") - ) - - private fun getGenreList() = listOf( - Genre("боевик", "el_2155"), - Genre("боевые искусства", "el_2143"), - Genre("вампиры", "el_2148"), - Genre("гарем", "el_2142"), - Genre("гендерная интрига", "el_2156"), - Genre("героическое фэнтези", "el_2146"), - Genre("детектив", "el_2152"), - Genre("дзёсэй", "el_2158"), - Genre("додзинси", "el_2141"), - Genre("драма", "el_2118"), - Genre("ёнкома", "el_2161"), - Genre("история", "el_2119"), - Genre("комедия", "el_2136"), - Genre("махо-сёдзё", "el_2147"), - Genre("мистика", "el_2132"), - Genre("научная фантастика", "el_2133"), - Genre("повседневность", "el_2135"), - Genre("постапокалиптика", "el_2151"), - Genre("приключения", "el_2130"), - Genre("психология", "el_2144"), - Genre("романтика", "el_2121"), - Genre("сверхъестественное", "el_2159"), - Genre("сёдзё", "el_2122"), - Genre("сёдзё-ай", "el_2128"), - Genre("сёнэн", "el_2134"), - Genre("сёнэн-ай", "el_2139"), - Genre("спорт", "el_2129"), - Genre("сэйнэн", "el_5838"), - Genre("трагедия", "el_2153"), - Genre("триллер", "el_2150"), - Genre("ужасы", "el_2125"), - Genre("фантастика", "el_2140"), - Genre("фэнтези", "el_2131"), - Genre("школа", "el_2127"), - Genre("этти", "el_4982") - ) -}