Komiic: Add search filter (#9531)
* add comic description * fix manga search results missing descriptions * clean unused variables * clean unused class * Add some config options and refactor some code * refactor some code * modify config option summary * apply comments * modify Queries.kt * small modification * Format code * Format code * replace parse method * optimize check API limit * modify config summary * add search filter * add getChapterUrl() * refactor Query.kt * use filters.firstInstance() * nothing * Replace require() with check()
This commit is contained in:
		
							parent
							
								
									5ec031e3b8
								
							
						
					
					
						commit
						3b64f94ff8
					
				| @ -1,7 +1,7 @@ | |||||||
| ext { | ext { | ||||||
|     extName = 'Komiic' |     extName = 'Komiic' | ||||||
|     extClass = '.Komiic' |     extClass = '.Komiic' | ||||||
|     extVersionCode = 2 |     extVersionCode = 3 | ||||||
|     isNsfw = true |     isNsfw = true | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ class Result<T>(val result: T) | |||||||
| class MultiResult<T, V>(val result1: T, val result2: V) | class MultiResult<T, V>(val result1: T, val result2: V) | ||||||
| 
 | 
 | ||||||
| @Serializable | @Serializable | ||||||
| data class ComicItem(val id: String, val name: String) | data class Item(val id: String, val name: String) | ||||||
| 
 | 
 | ||||||
| @Serializable | @Serializable | ||||||
| data class Comic( | data class Comic( | ||||||
| @ -26,8 +26,8 @@ data class Comic( | |||||||
|     val description: String, |     val description: String, | ||||||
|     val status: String, |     val status: String, | ||||||
|     val imageUrl: String, |     val imageUrl: String, | ||||||
|     var authors: List<ComicItem>, |     var authors: List<Item>, | ||||||
|     val categories: List<ComicItem>, |     val categories: List<Item>, | ||||||
| ) { | ) { | ||||||
|     fun toSManga() = SManga.create().apply { |     fun toSManga() = SManga.create().apply { | ||||||
|         url = "/comic/$id" |         url = "/comic/$id" | ||||||
| @ -0,0 +1,45 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.zh.komiic | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.source.model.Filter | ||||||
|  | import eu.kanade.tachiyomi.source.model.FilterList | ||||||
|  | 
 | ||||||
|  | fun buildFilterList(): FilterList { | ||||||
|  |     val categories = mapOf( | ||||||
|  |         "1" to "愛情", "3" to "神鬼", "4" to "校園", "5" to "搞笑", "6" to "生活", | ||||||
|  |         "7" to "懸疑", "8" to "冒險", "10" to "職場", "11" to "魔幻", "2" to "後宮", | ||||||
|  |         "12" to "魔法", "13" to "格鬥", "14" to "宅男", "15" to "勵志", "16" to "耽美", | ||||||
|  |         "17" to "科幻", "18" to "百合", "19" to "治癒", "20" to "萌系", "21" to "熱血", | ||||||
|  |         "22" to "競技", "23" to "推理", "24" to "雜誌", "25" to "偵探", "26" to "偽娘", | ||||||
|  |         "27" to "美食", "9" to "恐怖", "28" to "四格", "31" to "社會", "32" to "歷史", | ||||||
|  |         "33" to "戰爭", "34" to "舞蹈", "35" to "武俠", "36" to "機戰", "37" to "音樂", | ||||||
|  |         "40" to "體育", "42" to "黑道", "46" to "腐女", "47" to "異世界", "48" to "驚悚", | ||||||
|  |         "51" to "成人", "54" to "戰鬥", "55" to "復仇", "56" to "轉生", "57" to "黑暗奇幻", | ||||||
|  |         "58" to "戲劇", "59" to "生存", "60" to "策略", "61" to "政治", "62" to "黑暗", | ||||||
|  |         "64" to "動作", "70" to "性轉換", "73" to "色情", "181" to "校园", "78" to "日常", | ||||||
|  |         "81" to "青春", "83" to "料理", "85" to "醫療", "86" to "致鬱", "87" to "心理", | ||||||
|  |         "88" to "穿越", "92" to "友情", "93" to "犯罪", "97" to "劇情", | ||||||
|  |         "110" to "運動", "113" to "少女", "114" to "賭博", "119" to "情色", "123" to "女性向", | ||||||
|  |         "128" to "性轉", "129" to "溫馨", "164" to "同人", | ||||||
|  |     ) | ||||||
|  |     return FilterList( | ||||||
|  |         Filter.Header("過濾條件(搜索關鍵字時無效)"), | ||||||
|  |         CategoryFilter(categories), | ||||||
|  |         StatusFilter(), | ||||||
|  |         SortFilter(), | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Category(val id: String, name: String) : Filter.CheckBox(name) | ||||||
|  | 
 | ||||||
|  | class CategoryFilter(categories: Map<String, String>) : | ||||||
|  |     Filter.Group<Category>("類型(篩選同時包含全部所選標簽的漫畫)", categories.map { Category(it.key, it.value) }) { | ||||||
|  |     val selected get() = state.filter(Category::state).map(Category::id) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class StatusFilter : Filter.Select<String>("狀態", arrayOf("全部", "連載", "完結")) { | ||||||
|  |     val value get() = arrayOf("", "ONGOING", "END")[state] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class SortFilter : Filter.Select<String>("排序", arrayOf("更新", "觀看數", "喜愛數")) { | ||||||
|  |     val value get() = arrayOf("DATE_UPDATED", "VIEWS", "FAVORITE_COUNT")[state] | ||||||
|  | } | ||||||
| @ -10,7 +10,8 @@ import eu.kanade.tachiyomi.source.model.Page | |||||||
| import eu.kanade.tachiyomi.source.model.SChapter | import eu.kanade.tachiyomi.source.model.SChapter | ||||||
| import eu.kanade.tachiyomi.source.model.SManga | import eu.kanade.tachiyomi.source.model.SManga | ||||||
| import eu.kanade.tachiyomi.source.online.HttpSource | import eu.kanade.tachiyomi.source.online.HttpSource | ||||||
| import keiyoushi.utils.getPreferences | import keiyoushi.utils.firstInstance | ||||||
|  | import keiyoushi.utils.getPreferencesLazy | ||||||
| import keiyoushi.utils.parseAs | import keiyoushi.utils.parseAs | ||||||
| import keiyoushi.utils.toJsonString | import keiyoushi.utils.toJsonString | ||||||
| import keiyoushi.utils.tryParse | import keiyoushi.utils.tryParse | ||||||
| @ -31,7 +32,7 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
|     override val client = network.cloudflareClient |     override val client = network.cloudflareClient | ||||||
| 
 | 
 | ||||||
|     private val apiUrl = "$baseUrl/api/query" |     private val apiUrl = "$baseUrl/api/query" | ||||||
|     private val preferences = getPreferences() |     private val preferences by getPreferencesLazy() | ||||||
| 
 | 
 | ||||||
|     override fun setupPreferenceScreen(screen: PreferenceScreen) { |     override fun setupPreferenceScreen(screen: PreferenceScreen) { | ||||||
|         preferencesInternal(screen.context).forEach(screen::addPreference) |         preferencesInternal(screen.context).forEach(screen::addPreference) | ||||||
| @ -57,8 +58,8 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
|      * Search the comic based on the ID. |      * Search the comic based on the ID. | ||||||
|      */ |      */ | ||||||
|     private fun comicByIDRequest(id: String): Request { |     private fun comicByIDRequest(id: String): Request { | ||||||
|         val variables = Variables().set("comicId", id).build() |         val variables = Variables().field("comicId", id).build() | ||||||
|         val payload = Payload("comicById", variables, QUERY_COMIC_BY_ID) |         val payload = Payload(Query.COMIC_BY_ID, variables) | ||||||
|         return POST(apiUrl, headers, payload.toRequestBody()) |         return POST(apiUrl, headers, payload.toRequestBody()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -87,11 +88,9 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
|     // Popular Manga =============================================================================== |     // Popular Manga =============================================================================== | ||||||
| 
 | 
 | ||||||
|     override fun popularMangaRequest(page: Int): Request { |     override fun popularMangaRequest(page: Int): Request { | ||||||
|         val variables = Variables().set( |         val pagination = Pagination((page - 1) * PAGE_SIZE, "MONTH_VIEWS") | ||||||
|             "pagination", |         val variables = Variables().field("pagination", pagination).build() | ||||||
|             Pagination((page - 1) * PAGE_SIZE, "MONTH_VIEWS"), |         val payload = Payload(Query.HOT_COMICS, variables) | ||||||
|         ).build() |  | ||||||
|         val payload = Payload("hotComics", variables, QUERY_HOT_COMICS) |  | ||||||
|         return POST(apiUrl, headers, payload.toRequestBody()) |         return POST(apiUrl, headers, payload.toRequestBody()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -104,11 +103,9 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
|     // Latest Updates ============================================================================== |     // Latest Updates ============================================================================== | ||||||
| 
 | 
 | ||||||
|     override fun latestUpdatesRequest(page: Int): Request { |     override fun latestUpdatesRequest(page: Int): Request { | ||||||
|         val variables = Variables().set( |         val pagination = Pagination((page - 1) * PAGE_SIZE, "DATE_UPDATED") | ||||||
|             "pagination", |         val variables = Variables().field("pagination", pagination).build() | ||||||
|             Pagination((page - 1) * PAGE_SIZE, "DATE_UPDATED"), |         val payload = Payload(Query.RECENT_UPDATE, variables) | ||||||
|         ).build() |  | ||||||
|         val payload = Payload("recentUpdate", variables, QUERY_RECENT_UPDATE) |  | ||||||
|         return POST(apiUrl, headers, payload.toRequestBody()) |         return POST(apiUrl, headers, payload.toRequestBody()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -116,19 +113,23 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
| 
 | 
 | ||||||
|     // Search Manga ================================================================================ |     // Search Manga ================================================================================ | ||||||
| 
 | 
 | ||||||
|     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { |     override fun getFilterList() = buildFilterList() | ||||||
|         val variables = Variables().set("keyword", query).build() |  | ||||||
|         val payload = Payload("searchComicAndAuthorQuery", variables, QUERY_SEARCH) |  | ||||||
|         return POST(apiUrl, headers, payload.toRequestBody()) |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { |     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { | ||||||
|         return if (query.startsWith(PREFIX_ID_SEARCH)) { |         if (query.isNotBlank()) { | ||||||
|             client.newCall(comicByIDRequest(query.substringAfter(PREFIX_ID_SEARCH))) |             val variables = Variables().field("keyword", query).build() | ||||||
|                 .asObservableSuccess() |             val payload = Payload(Query.SEARCH, variables) | ||||||
|                 .map(::parseComicByID) |             return POST(apiUrl, headers, payload.toRequestBody()) | ||||||
|         } else { |         } else { | ||||||
|             super.fetchSearchManga(page, query, filters) |             val categories = filters.firstInstance<CategoryFilter>() | ||||||
|  |             val status = filters.firstInstance<StatusFilter>() | ||||||
|  |             val sort = filters.firstInstance<SortFilter>() | ||||||
|  |             val variables = Variables().field( | ||||||
|  |                 "pagination", | ||||||
|  |                 Pagination((page - 1) * PAGE_SIZE, sort.value, status.value, false), | ||||||
|  |             ).field("categoryId", categories.selected).build() | ||||||
|  |             val payload = Payload(Query.COMIC_BY_CATEGORIES, variables) | ||||||
|  |             return POST(apiUrl, headers, payload.toRequestBody()) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -138,6 +139,17 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
|         return MangasPage(comics.map(Comic::toSManga), comics.size == PAGE_SIZE) |         return MangasPage(comics.map(Comic::toSManga), comics.size == PAGE_SIZE) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { | ||||||
|  |         if (query.startsWith(PREFIX_ID_SEARCH)) { | ||||||
|  |             return client.newCall(comicByIDRequest(query.substringAfter(PREFIX_ID_SEARCH))) | ||||||
|  |                 .asObservableSuccess().map(::parseComicByID) | ||||||
|  |         } else if (query.isNotBlank()) { | ||||||
|  |             return super.fetchSearchManga(page, query, filters) | ||||||
|  |         } | ||||||
|  |         return client.newCall(searchMangaRequest(page, query, filters)) | ||||||
|  |             .asObservableSuccess().map(::popularMangaParse) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // Manga Details =============================================================================== |     // Manga Details =============================================================================== | ||||||
| 
 | 
 | ||||||
|     override fun getMangaUrl(manga: SManga) = baseUrl + manga.url |     override fun getMangaUrl(manga: SManga) = baseUrl + manga.url | ||||||
| @ -154,8 +166,8 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
|     override fun getChapterUrl(chapter: SChapter) = baseUrl + chapter.url + "/images/all" |     override fun getChapterUrl(chapter: SChapter) = baseUrl + chapter.url + "/images/all" | ||||||
| 
 | 
 | ||||||
|     override fun chapterListRequest(manga: SManga): Request { |     override fun chapterListRequest(manga: SManga): Request { | ||||||
|         val variables = Variables().set("comicId", manga.id).build() |         val variables = Variables().field("comicId", manga.id).build() | ||||||
|         val payload = Payload("chapterByComicId", variables, QUERY_CHAPTER) |         val payload = Payload(Query.CHAPTERS_BY_COMIC_ID, variables) | ||||||
|         return POST("$apiUrl#${manga.url}", headers, payload.toRequestBody()) |         return POST("$apiUrl#${manga.url}", headers, payload.toRequestBody()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -178,15 +190,15 @@ class Komiic : HttpSource(), ConfigurableSource { | |||||||
|     // Page List =================================================================================== |     // Page List =================================================================================== | ||||||
| 
 | 
 | ||||||
|     override fun pageListRequest(chapter: SChapter): Request { |     override fun pageListRequest(chapter: SChapter): Request { | ||||||
|         val variables = Variables().set("chapterId", chapter.id).build() |         val variables = Variables().field("chapterId", chapter.id).build() | ||||||
|         val payload = Payload("imagesByChapterId", variables, QUERY_PAGE_LIST) |         val payload = Payload(Query.IMAGES_BY_CHAPTER_ID, variables) | ||||||
|         return POST("$apiUrl#${chapter.url}", headers, payload.toRequestBody()) |         return POST("$apiUrl#${chapter.url}", headers, payload.toRequestBody()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun pageListParse(response: Response): List<Page> { |     override fun pageListParse(response: Response): List<Page> { | ||||||
|         val res = response.parseAs<MultiData<Boolean, List<Image>>>() |         val res = response.parseAs<MultiData<Boolean, List<Image>>>() | ||||||
|         val check = preferences.getBoolean(CHECK_API_LIMIT_PREF, true) |         val check = preferences.getBoolean(CHECK_API_LIMIT_PREF, true) | ||||||
|         require(!check || !res.data.result1) { "今日圖片讀取次數已達上限,請登录或明天再來!" } |         check(!check || !res.data.result1) { "今日圖片讀取次數已達上限,請登录或明天再來!" } | ||||||
|         val chapterUrl = response.request.url.fragment!! |         val chapterUrl = response.request.url.fragment!! | ||||||
|         return res.data.result2.mapIndexed { index, image -> |         return res.data.result2.mapIndexed { index, image -> | ||||||
|             Page(index, "$chapterUrl/page/$index", "$baseUrl/api/image/${image.kid}") |             Page(index, "$chapterUrl/page/$index", "$baseUrl/api/image/${image.kid}") | ||||||
|  | |||||||
| @ -12,24 +12,26 @@ data class Payload<T>( | |||||||
|     val operationName: String, |     val operationName: String, | ||||||
|     val variables: T, |     val variables: T, | ||||||
|     val query: String, |     val query: String, | ||||||
| ) | ) { | ||||||
|  |     constructor(query: Query, variables: T) : this(query.operation, variables, query.body) | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @Serializable | @Serializable | ||||||
| data class Pagination( | data class Pagination( | ||||||
|     val offset: Int, |     val offset: Int, | ||||||
|     val orderBy: String, |     val orderBy: String, | ||||||
|     @EncodeDefault |     @EncodeDefault | ||||||
|     val limit: Int = Komiic.PAGE_SIZE, |  | ||||||
|     @EncodeDefault |  | ||||||
|     val status: String = "", |     val status: String = "", | ||||||
|     @EncodeDefault |     @EncodeDefault | ||||||
|     val asc: Boolean = true, |     val asc: Boolean = true, | ||||||
|  |     @EncodeDefault | ||||||
|  |     val limit: Int = Komiic.PAGE_SIZE, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| class Variables { | class Variables { | ||||||
|     val variableMap = mutableMapOf<String, JsonElement>() |     val variableMap = mutableMapOf<String, JsonElement>() | ||||||
| 
 | 
 | ||||||
|     inline fun <reified T> set(key: String, value: T): Variables { |     inline fun <reified T> field(key: String, value: T): Variables { | ||||||
|         variableMap[key] = Json.encodeToJsonElement(value) |         variableMap[key] = Json.encodeToJsonElement(value) | ||||||
|         return this |         return this | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -18,8 +18,8 @@ fun preferencesInternal(context: Context) = arrayOf( | |||||||
|     }, |     }, | ||||||
|     SwitchPreferenceCompat(context).apply { |     SwitchPreferenceCompat(context).apply { | ||||||
|         key = CHECK_API_LIMIT_PREF |         key = CHECK_API_LIMIT_PREF | ||||||
|         title = "自動檢查API受限" |         title = "自動檢查 API 狀態" | ||||||
|         summary = "點擊單個章節請求漫畫圖片時,自動檢查一次圖片API是否達到今日請求上限。若已達上限,則終止後續操作" |         summary = "點擊單個章節請求漫畫圖片時,自動檢查一次圖片API是否達到今日請求上限。若已達上限,則終止後續操作(注:關閉后仍會檢查API,只是不再終止操作)" | ||||||
|         setDefaultValue(true) |         setDefaultValue(true) | ||||||
|     }, |     }, | ||||||
| ) | ) | ||||||
|  | |||||||
| @ -1,90 +0,0 @@ | |||||||
| package eu.kanade.tachiyomi.extension.zh.komiic |  | ||||||
| 
 |  | ||||||
| private fun buildQuery(body: String = "", queryAction: () -> String): String { |  | ||||||
|     return queryAction().trimIndent() |  | ||||||
|         .replace("#{body}", body.trimIndent()) |  | ||||||
|         .replace("%", "$") |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const val COMIC_BODY = |  | ||||||
|     """ |  | ||||||
|     { |  | ||||||
|       id |  | ||||||
|       title |  | ||||||
|       description |  | ||||||
|       status |  | ||||||
|       imageUrl |  | ||||||
|       authors { |  | ||||||
|         id |  | ||||||
|         name |  | ||||||
|       } |  | ||||||
|       categories { |  | ||||||
|         id |  | ||||||
|         name |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
| val QUERY_HOT_COMICS = buildQuery(COMIC_BODY) { |  | ||||||
|     """ |  | ||||||
|     query hotComics(%pagination: Pagination!) { |  | ||||||
|       result: hotComics(pagination: %pagination) #{body} |  | ||||||
|     } |  | ||||||
|     """ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| val QUERY_RECENT_UPDATE = buildQuery(COMIC_BODY) { |  | ||||||
|     """ |  | ||||||
|     query recentUpdate(%pagination: Pagination!) { |  | ||||||
|       result: recentUpdate(pagination: %pagination) #{body} |  | ||||||
|     } |  | ||||||
|     """ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| val QUERY_SEARCH = buildQuery(COMIC_BODY) { |  | ||||||
|     """ |  | ||||||
|     query searchComicAndAuthorQuery(%keyword: String!) { |  | ||||||
|       result: searchComicsAndAuthors(keyword: %keyword) { |  | ||||||
|         result: comics #{body} |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     """ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| val QUERY_COMIC_BY_ID = buildQuery(COMIC_BODY) { |  | ||||||
|     """ |  | ||||||
|     query comicById(%comicId: ID!) { |  | ||||||
|       result: comicById(comicId: %comicId) #{body} |  | ||||||
|     } |  | ||||||
|     """ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| val QUERY_CHAPTER = buildQuery { |  | ||||||
|     """ |  | ||||||
|     query chapterByComicId(%comicId: ID!) { |  | ||||||
|       result: chaptersByComicId(comicId: %comicId) { |  | ||||||
|         id |  | ||||||
|         serial |  | ||||||
|         type |  | ||||||
|         size |  | ||||||
|         dateCreated |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     """ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| val QUERY_PAGE_LIST = buildQuery { |  | ||||||
|     """ |  | ||||||
|     query imagesByChapterId(%chapterId: ID!) { |  | ||||||
|       result1: reachedImageLimit, |  | ||||||
|       result2: imagesByChapterId(chapterId: %chapterId) { |  | ||||||
|         id |  | ||||||
|         kid |  | ||||||
|         height |  | ||||||
|         width |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     """ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // val QUERY_API_LIMIT = buildQuery { "query reachedImageLimit { result: reachedImageLimit }" } |  | ||||||
| @ -0,0 +1,115 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.zh.komiic | ||||||
|  | 
 | ||||||
|  | enum class Query { | ||||||
|  |     HOT_COMICS { | ||||||
|  |         override val operation = "hotComics" | ||||||
|  |         override val body = buildQuery(comicBody) { | ||||||
|  |             """ | ||||||
|  |             query hotComics(%pagination: Pagination!) { | ||||||
|  |               result: hotComics(pagination: %pagination) #{body} | ||||||
|  |             } | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     RECENT_UPDATE { | ||||||
|  |         override val operation = "recentUpdate" | ||||||
|  |         override val body = buildQuery(comicBody) { | ||||||
|  |             """ | ||||||
|  |             query recentUpdate(%pagination: Pagination!) { | ||||||
|  |               result: recentUpdate(pagination: %pagination) #{body} | ||||||
|  |             } | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     SEARCH { | ||||||
|  |         override val operation = "searchComicAndAuthorQuery" | ||||||
|  |         override val body = buildQuery(comicBody) { | ||||||
|  |             """ | ||||||
|  |             query searchComicAndAuthorQuery(%keyword: String!) { | ||||||
|  |               result: searchComicsAndAuthors(keyword: %keyword) { | ||||||
|  |                 result: comics #{body} | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     COMIC_BY_CATEGORIES { | ||||||
|  |         override val operation = "comicByCategories" | ||||||
|  |         override val body = buildQuery(comicBody) { | ||||||
|  |             """ | ||||||
|  |             query comicByCategories(%categoryId: [ID!]!, %pagination: Pagination!) { | ||||||
|  |               result: comicByCategories(categoryId: %categoryId, pagination: %pagination) #{body} | ||||||
|  |             } | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     COMIC_BY_ID { | ||||||
|  |         override val operation = "comicById" | ||||||
|  |         override val body = buildQuery(comicBody) { | ||||||
|  |             """ | ||||||
|  |             query comicById(%comicId: ID!) { | ||||||
|  |               result: comicById(comicId: %comicId) #{body} | ||||||
|  |             } | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     CHAPTERS_BY_COMIC_ID { | ||||||
|  |         override val operation = "chapterByComicId" | ||||||
|  |         override val body = buildQuery { | ||||||
|  |             """ | ||||||
|  |             query chapterByComicId(%comicId: ID!) { | ||||||
|  |               result: chaptersByComicId(comicId: %comicId) { | ||||||
|  |                 id | ||||||
|  |                 serial | ||||||
|  |                 type | ||||||
|  |                 size | ||||||
|  |                 dateCreated | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     IMAGES_BY_CHAPTER_ID { | ||||||
|  |         override val operation = "imagesByChapterId" | ||||||
|  |         override val body = buildQuery { | ||||||
|  |             """ | ||||||
|  |             query imagesByChapterId(%chapterId: ID!) { | ||||||
|  |               result1: reachedImageLimit, | ||||||
|  |               result2: imagesByChapterId(chapterId: %chapterId) { | ||||||
|  |                 id | ||||||
|  |                 kid | ||||||
|  |                 height | ||||||
|  |                 width | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |             """ | ||||||
|  |         } | ||||||
|  |     }, ; | ||||||
|  | 
 | ||||||
|  |     abstract val body: String | ||||||
|  |     abstract val operation: String | ||||||
|  |     val comicBody = | ||||||
|  |         """ | ||||||
|  |         { | ||||||
|  |           id | ||||||
|  |           title | ||||||
|  |           description | ||||||
|  |           status | ||||||
|  |           imageUrl | ||||||
|  |           authors { | ||||||
|  |             id | ||||||
|  |             name | ||||||
|  |           } | ||||||
|  |           categories { | ||||||
|  |             id | ||||||
|  |             name | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |     fun buildQuery(body: String = "", queryAction: () -> String): String { | ||||||
|  |         return queryAction().trimIndent() | ||||||
|  |             .replace("#{body}", body.trimIndent()) | ||||||
|  |             .replace("%", "$") | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Hualiang
						Hualiang