|
| 1 | +package eu.kanade.tachiyomi.extension.ar.mangacloud |
| 2 | + |
| 3 | +import eu.kanade.tachiyomi.network.GET |
| 4 | +import eu.kanade.tachiyomi.source.model.FilterList |
| 5 | +import eu.kanade.tachiyomi.source.model.MangasPage |
| 6 | +import eu.kanade.tachiyomi.source.model.Page |
| 7 | +import eu.kanade.tachiyomi.source.model.SChapter |
| 8 | +import eu.kanade.tachiyomi.source.model.SManga |
| 9 | +import eu.kanade.tachiyomi.source.online.HttpSource |
| 10 | +import keiyoushi.annotation.Source |
| 11 | +import keiyoushi.utils.firstInstanceOrNull |
| 12 | +import okhttp3.HttpUrl.Companion.toHttpUrl |
| 13 | +import okhttp3.Request |
| 14 | +import okhttp3.Response |
| 15 | + |
| 16 | +@Source |
| 17 | +abstract class MangaCloud : HttpSource() { |
| 18 | + |
| 19 | + override val supportsLatest = true |
| 20 | + |
| 21 | + override fun popularMangaRequest(page: Int): Request { |
| 22 | + val url = FIRESTORE_URL.toHttpUrl().newBuilder() |
| 23 | + .addQueryParameter("pageSize", PAGE_SIZE.toString()) |
| 24 | + .addQueryParameter("key", API_KEY) |
| 25 | + .apply { |
| 26 | + val token = lastPageToken |
| 27 | + if (token != null) addQueryParameter("pageToken", token) |
| 28 | + } |
| 29 | + .build() |
| 30 | + return GET(url, headers) |
| 31 | + } |
| 32 | + |
| 33 | + override fun popularMangaParse(response: Response): MangasPage { |
| 34 | + val json = FirestoreParser.parseList(response) |
| 35 | + lastPageToken = json.nextPageToken |
| 36 | + return MangasPage(json.mangas.map { it.smanga }, json.nextPageToken != null) |
| 37 | + } |
| 38 | + |
| 39 | + override fun latestUpdatesRequest(page: Int): Request { |
| 40 | + val url = FIRESTORE_URL.toHttpUrl().newBuilder() |
| 41 | + .addQueryParameter("pageSize", PAGE_SIZE.toString()) |
| 42 | + .addQueryParameter("key", API_KEY) |
| 43 | + .addQueryParameter("orderBy", "updatedAt desc") |
| 44 | + .build() |
| 45 | + return GET(url, headers) |
| 46 | + } |
| 47 | + |
| 48 | + override fun latestUpdatesParse(response: Response): MangasPage { |
| 49 | + val json = FirestoreParser.parseList(response) |
| 50 | + return MangasPage(json.mangas.map { it.smanga }, false) |
| 51 | + } |
| 52 | + |
| 53 | + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { |
| 54 | + currentSearchQuery = query |
| 55 | + currentSortFilter = filters.firstInstanceOrNull<SortFilter>()?.selected.orEmpty() |
| 56 | + currentGenreFilter = filters.firstInstanceOrNull<GenreFilter>()?.selected.orEmpty() |
| 57 | + currentStatusFilter = filters.firstInstanceOrNull<StatusFilter>()?.selected.orEmpty() |
| 58 | + val url = FIRESTORE_URL.toHttpUrl().newBuilder() |
| 59 | + .addQueryParameter("pageSize", "300") |
| 60 | + .addQueryParameter("key", API_KEY) |
| 61 | + .apply { |
| 62 | + when (currentSortFilter) { |
| 63 | + "new" -> addQueryParameter("orderBy", "createdAt desc") |
| 64 | + "updated" -> addQueryParameter("orderBy", "updatedAt desc") |
| 65 | + } |
| 66 | + } |
| 67 | + .build() |
| 68 | + return GET(url, headers) |
| 69 | + } |
| 70 | + |
| 71 | + override fun searchMangaParse(response: Response): MangasPage { |
| 72 | + val query = currentSearchQuery.trim() |
| 73 | + val genre = currentGenreFilter |
| 74 | + val status = currentStatusFilter |
| 75 | + val json = FirestoreParser.parseList(response) |
| 76 | + val filtered = json.mangas.filter { data -> |
| 77 | + val matchesQuery = if (query.isNotBlank()) { |
| 78 | + val q = query.lowercase() |
| 79 | + data.smanga.title.lowercase().contains(q) || |
| 80 | + data.altTitles.any { it.lowercase().contains(q) } || |
| 81 | + data.genres.any { it.lowercase().contains(q) } || |
| 82 | + data.smanga.description?.lowercase()?.contains(q) == true |
| 83 | + } else { |
| 84 | + true |
| 85 | + } |
| 86 | + val matchesGenre = if (genre.isNotBlank()) { |
| 87 | + data.genres.any { it.lowercase().contains(genre.lowercase()) } |
| 88 | + } else { |
| 89 | + true |
| 90 | + } |
| 91 | + val matchesStatus = if (status.isNotBlank()) { |
| 92 | + data.statusString == status |
| 93 | + } else { |
| 94 | + true |
| 95 | + } |
| 96 | + matchesQuery && matchesGenre && matchesStatus |
| 97 | + } |
| 98 | + return MangasPage(filtered.map { it.smanga }, false) |
| 99 | + } |
| 100 | + |
| 101 | + override fun mangaDetailsRequest(manga: SManga): Request { |
| 102 | + val mangaId = manga.url.substringAfterLast("/") |
| 103 | + val url = "$FIRESTORE_URL/$mangaId?key=$API_KEY".toHttpUrl() |
| 104 | + return GET(url, headers) |
| 105 | + } |
| 106 | + |
| 107 | + override fun mangaDetailsParse(response: Response): SManga = FirestoreParser.parseDetails(response) |
| 108 | + |
| 109 | + override fun chapterListRequest(manga: SManga): Request { |
| 110 | + val mangaId = manga.url.substringAfterLast("/") |
| 111 | + val url = "$FIRESTORE_URL/$mangaId/chapters?pageSize=1000&key=$API_KEY&orderBy=index".toHttpUrl() |
| 112 | + return GET(url, headers) |
| 113 | + } |
| 114 | + |
| 115 | + override fun chapterListParse(response: Response): List<SChapter> = FirestoreParser.parseChapters(response) |
| 116 | + |
| 117 | + override fun pageListRequest(chapter: SChapter): Request { |
| 118 | + val url = "${FIRESTORE_URL}/${chapter.url}?key=$API_KEY".toHttpUrl() |
| 119 | + return GET(url, headers) |
| 120 | + } |
| 121 | + |
| 122 | + override fun pageListParse(response: Response): List<Page> = FirestoreParser.parsePages(response) |
| 123 | + |
| 124 | + override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException() |
| 125 | + |
| 126 | + override fun getMangaUrl(manga: SManga): String { |
| 127 | + val mangaId = manga.url.substringAfterLast("/") |
| 128 | + return "$baseUrl/manga/$mangaId" |
| 129 | + } |
| 130 | + |
| 131 | + override fun getChapterUrl(chapter: SChapter): String { |
| 132 | + val parts = chapter.url.split("/") |
| 133 | + if (parts.size >= 2) { |
| 134 | + return "$baseUrl/manga/${parts[0]}/${parts[1]}" |
| 135 | + } |
| 136 | + return "$baseUrl/manga/${chapter.url}" |
| 137 | + } |
| 138 | + |
| 139 | + override fun getFilterList(): FilterList = FilterList( |
| 140 | + SortFilter("ترتيب حسب", sortingList), |
| 141 | + StatusFilter("الحالة", statusList), |
| 142 | + GenreFilter("التصنيف", genreList), |
| 143 | + ) |
| 144 | + |
| 145 | + private var lastPageToken: String? = null |
| 146 | + private var currentSearchQuery: String = "" |
| 147 | + private var currentSortFilter: String = "" |
| 148 | + private var currentGenreFilter: String = "" |
| 149 | + private var currentStatusFilter: String = "" |
| 150 | + |
| 151 | + companion object { |
| 152 | + private const val API_KEY = "AIzaSyAvdmgz_r_d89Eo8JBs9vAjUAJR451bMYU" |
| 153 | + private const val FIRESTORE_URL = "https://firestore.googleapis.com/v1/projects/ninja-brew-crew-4d79c/databases/(default)/documents/cloudmangas" |
| 154 | + private const val PAGE_SIZE = 20 |
| 155 | + |
| 156 | + private val sortingList = arrayOf( |
| 157 | + Pair("الأشهر", "popular"), |
| 158 | + Pair("آخر التحديثات", "updated"), |
| 159 | + Pair("إضافات جديدة", "new"), |
| 160 | + ) |
| 161 | + |
| 162 | + private val statusList = arrayOf( |
| 163 | + Pair("الكل", ""), |
| 164 | + Pair("مستمر", "مستمر"), |
| 165 | + Pair("مكتمل", "مكتمل"), |
| 166 | + Pair("متروك", "متروك"), |
| 167 | + Pair("متروكة", "متروكة"), |
| 168 | + Pair("معلق", "معلق"), |
| 169 | + ) |
| 170 | + |
| 171 | + private val genreList = arrayOf( |
| 172 | + Pair("الكل", ""), |
| 173 | + Pair("أكشن", "أكشن"), |
| 174 | + Pair("إعادة احياء", "إعادة احياء"), |
| 175 | + Pair("إيسيكاي", "إيسيكاي"), |
| 176 | + Pair("aktions", "aktions"), |
| 177 | + Pair("الفنون القتالية", "الفنون القتالية"), |
| 178 | + Pair("اتصال بالعالم الخارجي", "اتصال بالعالم الخارجي"), |
| 179 | + Pair("اتنين", "اتنين"), |
| 180 | + Pair("اثاره", "اثاره"), |
| 181 | + Pair("اثاره حربيه", "اثاره حربيه"), |
| 182 | + Pair("ادمان", "ادمان"), |
| 183 | + Pair("ادمى", "ادمى"), |
| 184 | + Pair("ادهم", "ادهم"), |
| 185 | + Pair("ارهاب", "ارهاب"), |
| 186 | + Pair("استرجاع", "استرجاع"), |
| 187 | + Pair("استنساخ", "استنساخ"), |
| 188 | + Pair("اسلحة خارقة", "اسلحة خارقة"), |
| 189 | + Pair("اسطوره", "اسطوره"), |
| 190 | + Pair("اشتغال", "اشتغال"), |
| 191 | + Pair("اميرة", "اميرة"), |
| 192 | + Pair("انجي", "انجي"), |
| 193 | + Pair("ببجي", "ببجي"), |
| 194 | + Pair("بزنس", "بزنس"), |
| 195 | + Pair("بطل غير اعتيادي", "بطل غير اعتيادي"), |
| 196 | + Pair("تبديل عوالم", "تبديل عوالم"), |
| 197 | + Pair("تجسيد", "تجسيد"), |
| 198 | + Pair("تقمص شخصيات", "تقمص شخصيات"), |
| 199 | + Pair("جراي", "جراي"), |
| 200 | + Pair("جثث", "جثث"), |
| 201 | + Pair("حريم", "حريم"), |
| 202 | + Pair("حياة مدرسية", "حياة مدرسية"), |
| 203 | + Pair("خوارق", "خوارق"), |
| 204 | + Pair("خيال", "خيال"), |
| 205 | + Pair("خيال علمي", "خيال علمي"), |
| 206 | + Pair("دوار", "دوار"), |
| 207 | + Pair("دراما", "دراما"), |
| 208 | + Pair("رعب", "رعب"), |
| 209 | + Pair("رومانسي", "رومانسي"), |
| 210 | + Pair("زومبي", "زومبي"), |
| 211 | + Pair("سحر", "سحر"), |
| 212 | + Pair("شريحة من الحياة", "شريحة من الحياة"), |
| 213 | + Pair("شونين", "شونين"), |
| 214 | + Pair("شياطين", "شياطين"), |
| 215 | + Pair("عصابات", "عصابات"), |
| 216 | + Pair("عسكري", "عسكري"), |
| 217 | + Pair("غموض", "غموض"), |
| 218 | + Pair("فتى خارق", "فتى خارق"), |
| 219 | + Pair("فنتازيا", "فنتازيا"), |
| 220 | + Pair("فوتون", "فوتون"), |
| 221 | + Pair("فنون قتاليه", "فنون قتاليه"), |
| 222 | + Pair("قراصنة", "قراصنة"), |
| 223 | + Pair("كوميدي", "كوميدي"), |
| 224 | + Pair("كوميديا", "كوميديا"), |
| 225 | + Pair("مغامرة", "مغامرة"), |
| 226 | + Pair("موسيقى", "موسيقى"), |
| 227 | + Pair("نفسي", "نفسي"), |
| 228 | + Pair("نهاية العالم", "نهاية العالم"), |
| 229 | + Pair("وحوش", "وحوش"), |
| 230 | + Pair("ويبتون", "ويبتون"), |
| 231 | + Pair("ياباني", "ياباني"), |
| 232 | + ) |
| 233 | + } |
| 234 | +} |
0 commit comments