Compare commits
	
		
			45 Commits
		
	
	
		
			1699cece9f
			...
			c5c6d77479
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | c5c6d77479 | ||
|   | 2556e117be | ||
|   | 925136fc15 | ||
|   | c8ca375c1c | ||
|   | 5b640b1512 | ||
|   | 6850a721c0 | ||
|   | 8bb508d679 | ||
|   | cf5299c188 | ||
|   | 591c65a534 | ||
|   | 731145443b | ||
|   | bc4df5d008 | ||
|   | f71938e357 | ||
|   | 712c3a75be | ||
|   | f09c11a01c | ||
|   | 244fd8f4fa | ||
|   | 3db5f6edc2 | ||
|   | e54743b6c9 | ||
|   | cdd332ee78 | ||
|   | 49c3517510 | ||
|   | 4682cc8752 | ||
|   | 879eb629b1 | ||
|   | d8f4f38676 | ||
|   | 95d3671f3d | ||
|   | c8f24dac99 | ||
|   | aae877a2a3 | ||
|   | bd0b4b0edd | ||
|   | 47e328dc84 | ||
|   | 8dd884535b | ||
|   | 457475fc07 | ||
|   | 82983fb1b9 | ||
|   | ea90594583 | ||
|   | b78d35db07 | ||
|   | b2ddfd348b | ||
|   | 584e00b1dd | ||
|   | 2f244a72ff | ||
|   | 7746e2a3fa | ||
|   | fb88e2ce97 | ||
|   | 48c71e342d | ||
|   | c8c4110a55 | ||
|   | 23e385128e | ||
|   | b0b32918e1 | ||
|   | c02bd36b43 | ||
|   | fe97867cf1 | ||
|   | fdd2c5c6d1 | ||
|   | 8e610e1ea9 | 
							
								
								
									
										12
									
								
								lib/lzstring/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,12 @@ | |||||||
|  | plugins { | ||||||
|  |     `java-library` | ||||||
|  |     kotlin("jvm") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | repositories { | ||||||
|  |     mavenCentral() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | dependencies { | ||||||
|  |     compileOnly(libs.kotlin.stdlib) | ||||||
|  | } | ||||||
| @ -0,0 +1,294 @@ | |||||||
|  | package eu.kanade.tachiyomi.lib.lzstring | ||||||
|  | 
 | ||||||
|  | typealias getCharFromIntFn = (it: Int) -> String | ||||||
|  | typealias getNextValueFn = (it: Int) -> Int | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Reimplementation of [lz-string](https://github.com/pieroxy/lz-string) compression/decompression. | ||||||
|  |  */ | ||||||
|  | object LZString { | ||||||
|  |     private fun compress( | ||||||
|  |         uncompressed: String, | ||||||
|  |         bitsPerChar: Int, | ||||||
|  |         getCharFromInt: getCharFromIntFn, | ||||||
|  |     ): String { | ||||||
|  |         val context = CompressionContext(uncompressed.length, bitsPerChar, getCharFromInt) | ||||||
|  | 
 | ||||||
|  |         for (ii in uncompressed.indices) { | ||||||
|  |             context.c = uncompressed[ii].toString() | ||||||
|  | 
 | ||||||
|  |             if (!context.dictionary.containsKey(context.c)) { | ||||||
|  |                 context.dictionary[context.c] = context.dictSize++ | ||||||
|  |                 context.dictionaryToCreate[context.c] = true | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             context.wc = context.w + context.c | ||||||
|  | 
 | ||||||
|  |             if (context.dictionary.containsKey(context.wc)) { | ||||||
|  |                 context.w = context.wc | ||||||
|  |                 continue | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             context.outputCodeForW() | ||||||
|  | 
 | ||||||
|  |             context.decrementEnlargeIn() | ||||||
|  |             context.dictionary[context.wc] = context.dictSize++ | ||||||
|  |             context.w = context.c | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (context.w.isNotEmpty()) { | ||||||
|  |             context.outputCodeForW() | ||||||
|  |             context.decrementEnlargeIn() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Mark the end of the stream | ||||||
|  |         context.value = 2 | ||||||
|  |         for (i in 0 until context.numBits) { | ||||||
|  |             context.dataVal = (context.dataVal shl 1) or (context.value and 1) | ||||||
|  |             context.appendDataOrAdvancePosition() | ||||||
|  |             context.value = context.value shr 1 | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         while (true) { | ||||||
|  |             context.dataVal = context.dataVal shl 1 | ||||||
|  | 
 | ||||||
|  |             if (context.dataPosition == bitsPerChar - 1) { | ||||||
|  |                 context.data.append(getCharFromInt(context.dataVal)) | ||||||
|  |                 break | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             context.dataPosition++ | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return context.data.toString() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun decompress(length: Int, resetValue: Int, getNextValue: getNextValueFn): String { | ||||||
|  |         val dictionary = mutableListOf<String>() | ||||||
|  |         val result = StringBuilder() | ||||||
|  |         val data = DecompressionContext(resetValue, getNextValue) | ||||||
|  |         var enlargeIn = 4 | ||||||
|  |         var numBits = 3 | ||||||
|  |         var entry: String | ||||||
|  |         var c: Char? = null | ||||||
|  | 
 | ||||||
|  |         for (i in 0 until 3) { | ||||||
|  |             dictionary.add(i.toString()) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         data.loopUntilMaxPower() | ||||||
|  | 
 | ||||||
|  |         when (data.bits) { | ||||||
|  |             0 -> { | ||||||
|  |                 data.bits = 0 | ||||||
|  |                 data.maxPower = 1 shl 8 | ||||||
|  |                 data.power = 1 | ||||||
|  |                 data.loopUntilMaxPower() | ||||||
|  |                 c = data.bits.toChar() | ||||||
|  |             } | ||||||
|  |             1 -> { | ||||||
|  |                 data.bits = 0 | ||||||
|  |                 data.maxPower = 1 shl 16 | ||||||
|  |                 data.power = 1 | ||||||
|  |                 data.loopUntilMaxPower() | ||||||
|  |                 c = data.bits.toChar() | ||||||
|  |             } | ||||||
|  |             2 -> throw IllegalArgumentException("Invalid LZString") | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (c == null) { | ||||||
|  |             throw Exception("No character found") | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         dictionary.add(c.toString()) | ||||||
|  |         var w = c.toString() | ||||||
|  |         result.append(c.toString()) | ||||||
|  | 
 | ||||||
|  |         while (true) { | ||||||
|  |             if (data.index > length) { | ||||||
|  |                 throw IllegalArgumentException("Invalid LZString") | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             data.bits = 0 | ||||||
|  |             data.maxPower = 1 shl numBits | ||||||
|  |             data.power = 1 | ||||||
|  |             data.loopUntilMaxPower() | ||||||
|  | 
 | ||||||
|  |             var cc = data.bits | ||||||
|  | 
 | ||||||
|  |             when (data.bits) { | ||||||
|  |                 0 -> { | ||||||
|  |                     data.bits = 0 | ||||||
|  |                     data.maxPower = 1 shl 8 | ||||||
|  |                     data.power = 1 | ||||||
|  |                     data.loopUntilMaxPower() | ||||||
|  |                     dictionary.add(data.bits.toChar().toString()) | ||||||
|  |                     cc = dictionary.size - 1 | ||||||
|  |                     enlargeIn-- | ||||||
|  |                 } | ||||||
|  |                 1 -> { | ||||||
|  |                     data.bits = 0 | ||||||
|  |                     data.maxPower = 1 shl 16 | ||||||
|  |                     data.power = 1 | ||||||
|  |                     data.loopUntilMaxPower() | ||||||
|  |                     dictionary.add(data.bits.toChar().toString()) | ||||||
|  |                     cc = dictionary.size - 1 | ||||||
|  |                     enlargeIn-- | ||||||
|  |                 } | ||||||
|  |                 2 -> return result.toString() | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (enlargeIn == 0) { | ||||||
|  |                 enlargeIn = 1 shl numBits | ||||||
|  |                 numBits++ | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             entry = if (cc < dictionary.size) { | ||||||
|  |                 dictionary[cc] | ||||||
|  |             } else { | ||||||
|  |                 if (cc == dictionary.size) { | ||||||
|  |                     w + w[0] | ||||||
|  |                 } else { | ||||||
|  |                     throw Exception("Invalid LZString") | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             result.append(entry) | ||||||
|  |             dictionary.add(w + entry[0]) | ||||||
|  |             enlargeIn-- | ||||||
|  |             w = entry | ||||||
|  | 
 | ||||||
|  |             if (enlargeIn == 0) { | ||||||
|  |                 enlargeIn = 1 shl numBits | ||||||
|  |                 numBits++ | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private const val base64KeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" | ||||||
|  | 
 | ||||||
|  |     fun compressToBase64(input: String): String = | ||||||
|  |         compress(input, 6) { base64KeyStr[it].toString() }.let { | ||||||
|  |             return when (it.length % 4) { | ||||||
|  |                 0 -> it | ||||||
|  |                 1 -> "$it===" | ||||||
|  |                 2 -> "$it==" | ||||||
|  |                 3 -> "$it=" | ||||||
|  |                 else -> throw IllegalStateException("Modulo of 4 should not exceed 3.") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     fun decompressFromBase64(input: String): String = | ||||||
|  |         decompress(input.length, 32) { | ||||||
|  |             base64KeyStr.indexOf(input[it]) | ||||||
|  |         } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | private data class DecompressionContext( | ||||||
|  |     val resetValue: Int, | ||||||
|  |     val getNextValue: getNextValueFn, | ||||||
|  |     var value: Int = getNextValue(0), | ||||||
|  |     var position: Int = resetValue, | ||||||
|  |     var index: Int = 1, | ||||||
|  |     var bits: Int = 0, | ||||||
|  |     var maxPower: Int = 1 shl 2, | ||||||
|  |     var power: Int = 1, | ||||||
|  | ) { | ||||||
|  |     fun loopUntilMaxPower() { | ||||||
|  |         while (power != maxPower) { | ||||||
|  |             val resb = value and position | ||||||
|  | 
 | ||||||
|  |             position = position shr 1 | ||||||
|  | 
 | ||||||
|  |             if (position == 0) { | ||||||
|  |                 position = resetValue | ||||||
|  |                 value = getNextValue(index++) | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             bits = bits or ((if (resb > 0) 1 else 0) * power) | ||||||
|  |             power = power shl 1 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | private data class CompressionContext( | ||||||
|  |     val uncompressedLength: Int, | ||||||
|  |     val bitsPerChar: Int, | ||||||
|  |     val getCharFromInt: getCharFromIntFn, | ||||||
|  |     var value: Int = 0, | ||||||
|  |     val dictionary: MutableMap<String, Int> = HashMap(), | ||||||
|  |     val dictionaryToCreate: MutableMap<String, Boolean> = HashMap(), | ||||||
|  |     var c: String = "", | ||||||
|  |     var wc: String = "", | ||||||
|  |     var w: String = "", | ||||||
|  |     var enlargeIn: Int = 2,  // Compensate for the first entry which should not count | ||||||
|  |     var dictSize: Int = 3, | ||||||
|  |     var numBits: Int = 2, | ||||||
|  |     val data: StringBuilder = StringBuilder(uncompressedLength / 3), | ||||||
|  |     var dataVal: Int = 0, | ||||||
|  |     var dataPosition: Int = 0, | ||||||
|  | ) { | ||||||
|  |     fun appendDataOrAdvancePosition() { | ||||||
|  |         if (dataPosition == bitsPerChar - 1) { | ||||||
|  |             dataPosition = 0 | ||||||
|  |             data.append(getCharFromInt(dataVal)) | ||||||
|  |             dataVal = 0 | ||||||
|  |         } else { | ||||||
|  |             dataPosition++ | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun decrementEnlargeIn() { | ||||||
|  |         enlargeIn-- | ||||||
|  |         if (enlargeIn == 0) { | ||||||
|  |             enlargeIn = 1 shl numBits | ||||||
|  |             numBits++ | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Output the code for W. | ||||||
|  |     fun outputCodeForW() { | ||||||
|  |         if (dictionaryToCreate.containsKey(w)) { | ||||||
|  |             if (w[0].code < 256) { | ||||||
|  |                 for (i in 0 until numBits) { | ||||||
|  |                     dataVal = dataVal shl 1 | ||||||
|  |                     appendDataOrAdvancePosition() | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 value = w[0].code | ||||||
|  | 
 | ||||||
|  |                 for (i in 0 until 8) { | ||||||
|  |                     dataVal = (dataVal shl 1) or (value and 1) | ||||||
|  |                     appendDataOrAdvancePosition() | ||||||
|  |                     value = value shr 1 | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 value = 1 | ||||||
|  | 
 | ||||||
|  |                 for (i in 0 until numBits) { | ||||||
|  |                     dataVal = (dataVal shl 1) or value | ||||||
|  |                     appendDataOrAdvancePosition() | ||||||
|  |                     value = 0 | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 value = w[0].code | ||||||
|  | 
 | ||||||
|  |                 for (i in 0 until 16) { | ||||||
|  |                     dataVal = (dataVal shl 1) or (value and 1) | ||||||
|  |                     appendDataOrAdvancePosition() | ||||||
|  |                     value = value shr 1 | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             decrementEnlargeIn() | ||||||
|  |             dictionaryToCreate.remove(w) | ||||||
|  |         } else { | ||||||
|  |             value = dictionary[w]!! | ||||||
|  | 
 | ||||||
|  |             for (i in 0 until numBits) { | ||||||
|  |                 dataVal = (dataVal shl 1) or (value and 1) | ||||||
|  |                 appendDataOrAdvancePosition() | ||||||
|  |                 value = value shr 1 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								multisrc/overrides/colamanga/default/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <application> | ||||||
|  |         <activity | ||||||
|  |             android:name="eu.kanade.tachiyomi.multisrc.colamanga.ColaMangaUrlActivity" | ||||||
|  |             android:excludeFromRecents="true" | ||||||
|  |             android:exported="true" | ||||||
|  |             android:theme="@android:style/Theme.NoDisplay"> | ||||||
|  |             <intent-filter> | ||||||
|  |                 <action android:name="android.intent.action.VIEW"/> | ||||||
|  |                 <category android:name="android.intent.category.DEFAULT"/> | ||||||
|  |                 <category android:name="android.intent.category.BROWSABLE"/> | ||||||
|  | 
 | ||||||
|  |                 <data | ||||||
|  |                     android:host="${SOURCEHOST}" | ||||||
|  |                     android:scheme="${SOURCESCHEME}" | ||||||
|  |                     android:pathPattern="/manga-..*/" /> | ||||||
|  |             </intent-filter> | ||||||
|  |         </activity> | ||||||
|  |     </application> | ||||||
|  | </manifest> | ||||||
							
								
								
									
										3
									
								
								multisrc/overrides/colamanga/default/additional.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,3 @@ | |||||||
|  | dependencies { | ||||||
|  |     implementation(project(":lib:synchrony")) | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 2.7 KiB | 
| After Width: | Height: | Size: 5.0 KiB | 
| After Width: | Height: | Size: 6.0 KiB | 
							
								
								
									
										123
									
								
								multisrc/overrides/colamanga/mangadig/src/MangaDig.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,123 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.en.mangadig | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.colamanga.ColaManga | ||||||
|  | import eu.kanade.tachiyomi.multisrc.colamanga.UriPartFilter | ||||||
|  | import eu.kanade.tachiyomi.source.model.FilterList | ||||||
|  | 
 | ||||||
|  | class MangaDig : ColaManga("MangaDig", "https://mangadig.com", "en") { | ||||||
|  | 
 | ||||||
|  |     override fun popularMangaNextPageSelector() = "a:contains(Next):not(.fed-btns-disad)" | ||||||
|  | 
 | ||||||
|  |     override val statusTitle = "Status" | ||||||
|  |     override val authorTitle = "Author" | ||||||
|  |     override val genreTitle = "Category" | ||||||
|  |     override val statusOngoing = "OnGoing" | ||||||
|  |     override val statusCompleted = "Complete" | ||||||
|  | 
 | ||||||
|  |     override fun getFilterList(): FilterList { | ||||||
|  |         val filters = buildList { | ||||||
|  |             addAll(super.getFilterList().list) | ||||||
|  |             add(SortFilter()) | ||||||
|  |             add(CategoryFilter()) | ||||||
|  |             add(CharFilter()) | ||||||
|  |             add(StatusFilter()) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return FilterList(filters) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private class StatusFilter : UriPartFilter( | ||||||
|  |         "Status", | ||||||
|  |         "status", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("All", ""), | ||||||
|  |             Pair("Ongoing", "1"), | ||||||
|  |             Pair("Complete", "2"), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     private class SortFilter : UriPartFilter( | ||||||
|  |         "Order by", | ||||||
|  |         "orderBy", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("Last updated", "update"), | ||||||
|  |             Pair("Recently added", "create"), | ||||||
|  |             Pair("Most popular today", "dailyCount"), | ||||||
|  |             Pair("Most popular this week", "weeklyCount"), | ||||||
|  |             Pair("Most popular this month", "monthlyCount"), | ||||||
|  |         ), | ||||||
|  |         2, | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     private class CategoryFilter : UriPartFilter( | ||||||
|  |         "Genre", | ||||||
|  |         "mainCategoryId", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("All", ""), | ||||||
|  |             Pair("Romance", "10008"), | ||||||
|  |             Pair("Drama", "10005"), | ||||||
|  |             Pair("Comedy", "10004"), | ||||||
|  |             Pair("Fantasy", "10006"), | ||||||
|  |             Pair("Action", "10002"), | ||||||
|  |             Pair("CEO", "10142"), | ||||||
|  |             Pair("Webtoons", "10012"), | ||||||
|  |             Pair("Historical", "10021"), | ||||||
|  |             Pair("Adventure", "10003"), | ||||||
|  |             Pair("Josei", "10059"), | ||||||
|  |             Pair("Smut", "10047"), | ||||||
|  |             Pair("Supernatural", "10018"), | ||||||
|  |             Pair("School life", "10017"), | ||||||
|  |             Pair("Completed", "10423"), | ||||||
|  |             Pair("Possessive", "10284"), | ||||||
|  |             Pair("Manhua", "10010"), | ||||||
|  |             Pair("Sweet", "10282"), | ||||||
|  |             Pair("Harem", "10007"), | ||||||
|  |             Pair("Slice of life", "10026"), | ||||||
|  |             Pair("Girl Power", "10144"), | ||||||
|  |             Pair("Martial arts", "10013"), | ||||||
|  |             Pair("Chinese Classic", "10243"), | ||||||
|  |             Pair("BL", "10262"), | ||||||
|  |             Pair("Manhwa", "10039"), | ||||||
|  |             Pair("Adult", "10030"), | ||||||
|  |             Pair("Shounen", "10009"), | ||||||
|  |             Pair("TimeTravel", "10143"), | ||||||
|  |             Pair("Shoujo", "10054"), | ||||||
|  |             Pair("Ecchi", "10027"), | ||||||
|  |             Pair("Revenge", "10556"), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     private class CharFilter : UriPartFilter( | ||||||
|  |         "Alphabet", | ||||||
|  |         "charCategoryId", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("All", ""), | ||||||
|  |             Pair("A", "10015"), | ||||||
|  |             Pair("B", "10028"), | ||||||
|  |             Pair("C", "10055"), | ||||||
|  |             Pair("D", "10034"), | ||||||
|  |             Pair("E", "10049"), | ||||||
|  |             Pair("F", "10056"), | ||||||
|  |             Pair("G", "10023"), | ||||||
|  |             Pair("H", "10037"), | ||||||
|  |             Pair("I", "10035"), | ||||||
|  |             Pair("J", "10060"), | ||||||
|  |             Pair("K", "10022"), | ||||||
|  |             Pair("L", "10046"), | ||||||
|  |             Pair("M", "10020"), | ||||||
|  |             Pair("N", "10044"), | ||||||
|  |             Pair("O", "10024"), | ||||||
|  |             Pair("P", "10048"), | ||||||
|  |             Pair("Q", "10051"), | ||||||
|  |             Pair("R", "10025"), | ||||||
|  |             Pair("S", "10011"), | ||||||
|  |             Pair("T", "10001"), | ||||||
|  |             Pair("U", "10058"), | ||||||
|  |             Pair("V", "10016"), | ||||||
|  |             Pair("W", "10052"), | ||||||
|  |             Pair("X", "10061"), | ||||||
|  |             Pair("Y", "10036"), | ||||||
|  |             Pair("Z", "10101"), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 3.4 KiB | 
| After Width: | Height: | Size: 6.2 KiB | 
| After Width: | Height: | Size: 8.6 KiB | 
							
								
								
									
										120
									
								
								multisrc/overrides/colamanga/onemanhua/src/Onemanhua.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,120 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.zh.onemanhua | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.colamanga.ColaManga | ||||||
|  | import eu.kanade.tachiyomi.multisrc.colamanga.UriPartFilter | ||||||
|  | import eu.kanade.tachiyomi.source.model.FilterList | ||||||
|  | 
 | ||||||
|  | class Onemanhua : ColaManga("COLAMANGA", "https://www.colamanga.com", "zh") { | ||||||
|  |     override val id = 8252565807829914103 // name used to be "One漫画" | ||||||
|  | 
 | ||||||
|  |     override fun popularMangaNextPageSelector() = "a:contains(下页):not(.fed-btns-disad)" | ||||||
|  | 
 | ||||||
|  |     override val statusTitle = "状态" | ||||||
|  |     override val authorTitle = "作者" | ||||||
|  |     override val genreTitle = "类别" | ||||||
|  |     override val statusOngoing = "连载中" | ||||||
|  |     override val statusCompleted = "已完结" | ||||||
|  | 
 | ||||||
|  |     override fun getFilterList(): FilterList { | ||||||
|  |         val filters = buildList { | ||||||
|  |             addAll(super.getFilterList().list) | ||||||
|  |             add(SortFilter()) | ||||||
|  |             add(CategoryFilter()) | ||||||
|  |             add(CharFilter()) | ||||||
|  |             add(StatusFilter()) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return FilterList(filters) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private class StatusFilter : UriPartFilter( | ||||||
|  |         "状态", | ||||||
|  |         "status", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("全部", ""), | ||||||
|  |             Pair("连载中", "1"), | ||||||
|  |             Pair("已完结", "2"), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  |     private class SortFilter : UriPartFilter( | ||||||
|  |         "排序", | ||||||
|  |         "orderBy", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("更新日", "update"), | ||||||
|  |             Pair("日点击", "dailyCount"), | ||||||
|  |             Pair("周点击", "weeklyCount"), | ||||||
|  |             Pair("月点击", "monthlyCount"), | ||||||
|  |         ), | ||||||
|  |         1, | ||||||
|  |     ) | ||||||
|  |     private class CategoryFilter : UriPartFilter( | ||||||
|  |         "类型", | ||||||
|  |         "mainCategoryId", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("全部", ""), | ||||||
|  |             Pair("热血", "10023"), | ||||||
|  |             Pair("玄幻", "10024"), | ||||||
|  |             Pair("恋爱", "10126"), | ||||||
|  |             Pair("冒险", "10210"), | ||||||
|  |             Pair("古风", "10143"), | ||||||
|  |             Pair("都市", "10124"), | ||||||
|  |             Pair("穿越", "10129"), | ||||||
|  |             Pair("奇幻", "10242"), | ||||||
|  |             Pair("其他", "10560"), | ||||||
|  |             Pair("少男", "10641"), | ||||||
|  |             Pair("搞笑", "10122"), | ||||||
|  |             Pair("战斗", "10309"), | ||||||
|  |             Pair("冒险热血", "11224"), | ||||||
|  |             Pair("重生", "10461"), | ||||||
|  |             Pair("爆笑", "10201"), | ||||||
|  |             Pair("逆袭", "10943"), | ||||||
|  |             Pair("后宫", "10138"), | ||||||
|  |             Pair("少年", "10321"), | ||||||
|  |             Pair("少女", "10301"), | ||||||
|  |             Pair("熱血", "12044"), | ||||||
|  |             Pair("系统", "10722"), | ||||||
|  |             Pair("动作", "10125"), | ||||||
|  |             Pair("校园", "10131"), | ||||||
|  |             Pair("冒險", "12123"), | ||||||
|  |             Pair("修真", "10133"), | ||||||
|  |             Pair("修仙", "10453"), | ||||||
|  |             Pair("剧情", "10480"), | ||||||
|  |             Pair("霸总", "10127"), | ||||||
|  |             Pair("大女主", "10706"), | ||||||
|  |             Pair("生活", "10142"), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  |     private class CharFilter : UriPartFilter( | ||||||
|  |         "字母", | ||||||
|  |         "charCategoryId", | ||||||
|  |         arrayOf( | ||||||
|  |             Pair("全部", ""), | ||||||
|  |             Pair("A", "10182"), | ||||||
|  |             Pair("B", "10081"), | ||||||
|  |             Pair("C", "10134"), | ||||||
|  |             Pair("D", "10001"), | ||||||
|  |             Pair("E", "10238"), | ||||||
|  |             Pair("F", "10161"), | ||||||
|  |             Pair("G", "10225"), | ||||||
|  |             Pair("H", "10137"), | ||||||
|  |             Pair("I", "10284"), | ||||||
|  |             Pair("J", "10141"), | ||||||
|  |             Pair("K", "10283"), | ||||||
|  |             Pair("L", "10132"), | ||||||
|  |             Pair("M", "10136"), | ||||||
|  |             Pair("N", "10130"), | ||||||
|  |             Pair("O", "10282"), | ||||||
|  |             Pair("P", "10262"), | ||||||
|  |             Pair("Q", "10164"), | ||||||
|  |             Pair("R", "10240"), | ||||||
|  |             Pair("S", "10121"), | ||||||
|  |             Pair("T", "10123"), | ||||||
|  |             Pair("U", "11184"), | ||||||
|  |             Pair("V", "11483"), | ||||||
|  |             Pair("W", "10135"), | ||||||
|  |             Pair("X", "10061"), | ||||||
|  |             Pair("Y", "10082"), | ||||||
|  |             Pair("Z", "10128"), | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  | } | ||||||
| @ -13,6 +13,9 @@ import rx.Observable | |||||||
| import java.util.Calendar | import java.util.Calendar | ||||||
| 
 | 
 | ||||||
| class Manga1000 : FMReader("Manga1000", "https://manga1000.top", "ja") { | class Manga1000 : FMReader("Manga1000", "https://manga1000.top", "ja") { | ||||||
|  | 
 | ||||||
|  |     override val infoElementSelector = "div.row div.row" | ||||||
|  | 
 | ||||||
|     // source is picky about URL format |     // source is picky about URL format | ||||||
|     private fun mangaRequest(sortBy: String, page: Int): Request { |     private fun mangaRequest(sortBy: String, page: Int): Request { | ||||||
|         return GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&ungenre=&magazine=&sort=$sortBy&sort_type=DESC", headers) |         return GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&ungenre=&magazine=&sort=$sortBy&sort_type=DESC", headers) | ||||||
| @ -25,7 +28,7 @@ class Manga1000 : FMReader("Manga1000", "https://manga1000.top", "ja") { | |||||||
|     override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { |     override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { | ||||||
|         val slug = manga.url.substringAfter("manga-").substringBefore(".html") |         val slug = manga.url.substringAfter("manga-").substringBefore(".html") | ||||||
| 
 | 
 | ||||||
|         return client.newCall(GET("$baseUrl/app/manga/controllers/cont.Listchapterapi.php?slug=$slug", headers)) |         return client.newCall(GET("$baseUrl/app/manga/controllers/cont.Listchapter.php?slug=$slug", headers)) | ||||||
|             .asObservableSuccess() |             .asObservableSuccess() | ||||||
|             .map { res -> |             .map { res -> | ||||||
|                 res.asJsoup().select(".at-series a").map { |                 res.asJsoup().select(".at-series a").map { | ||||||
|  | |||||||
| After Width: | Height: | Size: 3.1 KiB | 
| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 3.4 KiB | 
| After Width: | Height: | Size: 6.3 KiB | 
| After Width: | Height: | Size: 8.6 KiB | 
| @ -0,0 +1,96 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.ja.idolgravureprincessdate | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.gravureblogger.GravureBlogger | ||||||
|  | 
 | ||||||
|  | class IdolGravureprincessDate : GravureBlogger( | ||||||
|  |     "Idol. gravureprincess .date", | ||||||
|  |     "https://idol.gravureprincess.date", | ||||||
|  |     "ja", | ||||||
|  | ) { | ||||||
|  |     override val labelFilters = buildMap { | ||||||
|  |         put("Idol", getIdols()) | ||||||
|  |         put("Magazines", getMagazine()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun getIdols() = listOf( | ||||||
|  |         "Nogizaka46", | ||||||
|  |         "AKB48", | ||||||
|  |         "NMB48", | ||||||
|  |         "Keyakizaka46", | ||||||
|  |         "HKT48", | ||||||
|  |         "SKE48", | ||||||
|  |         "NGT48", | ||||||
|  |         "SUPER☆GiRLS", | ||||||
|  |         "Morning Musume", | ||||||
|  |         "Dempagumi.inc", | ||||||
|  |         "Angerme", | ||||||
|  |         "Juice=Juice", | ||||||
|  |         "NijiCon-虹コン", | ||||||
|  |         "Houkago Princess", | ||||||
|  |         "Magical Punchline", | ||||||
|  |         "Idoling!!!", | ||||||
|  |         "Rev. from DVL", | ||||||
|  |         "Link STAR`s", | ||||||
|  |         "LADYBABY", | ||||||
|  |         "℃-ute", | ||||||
|  |         "Country Girls", | ||||||
|  |         "Up Up Girls (Kakko Kari)", | ||||||
|  |         "Yumemiru Adolescence", | ||||||
|  |         "Shiritsu Ebisu Chugaku", | ||||||
|  |         "Tenkoushoujo Kagekidan", | ||||||
|  |         "Drop", | ||||||
|  |         "Steam Girls", | ||||||
|  |         "Kamen Joshi's", | ||||||
|  |         "LinQ", | ||||||
|  |         "Doll☆Element", | ||||||
|  |         "TrySail", | ||||||
|  |         "Akihabara Backstage Pass", | ||||||
|  |         "Palet", | ||||||
|  |         "Passport☆", | ||||||
|  |         "Ange☆Reve", | ||||||
|  |         "BiSH", | ||||||
|  |         "Ciao Bella Cinquetti", | ||||||
|  |         "Gekidanherbest", | ||||||
|  |         "Haraeki Stage Ace", | ||||||
|  |         "Ru:Run", | ||||||
|  |         "SDN48", | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     private fun getMagazine() = listOf( | ||||||
|  |         "FLASH", | ||||||
|  |         "Weekly Playboy", | ||||||
|  |         "FRIDAY Magazine", | ||||||
|  |         "Young Jump", | ||||||
|  |         "Young Magazine", | ||||||
|  |         "BLT", | ||||||
|  |         "ENTAME", | ||||||
|  |         "EX-Taishu", | ||||||
|  |         "SPA! Magazine", | ||||||
|  |         "Young Gangan", | ||||||
|  |         "UTB", | ||||||
|  |         "Young Animal", | ||||||
|  |         "Young Champion", | ||||||
|  |         "Big Comic Spirtis", | ||||||
|  |         "Shonen Magazine", | ||||||
|  |         "BUBKA", | ||||||
|  |         "BOMB", | ||||||
|  |         "Shonen Champion", | ||||||
|  |         "Manga Action", | ||||||
|  |         "Weekly Shonen Sunday", | ||||||
|  |         "Photobooks", | ||||||
|  |         "BRODY", | ||||||
|  |         "Hustle Press", | ||||||
|  |         "ANAN Magazine", | ||||||
|  |         "SMART Magazine", | ||||||
|  |         "Young Sunday", | ||||||
|  |         "Gravure The Television", | ||||||
|  |         "CD&DL My Girl", | ||||||
|  |         "Daily LoGiRL", | ||||||
|  |         "Shukan Taishu", | ||||||
|  |         "Girls! Magazine", | ||||||
|  |         "Soccer Game King", | ||||||
|  |         "Weekly Georgia", | ||||||
|  |         "Sunday Magazine", | ||||||
|  |         "Mery Magazine", | ||||||
|  |     ) | ||||||
|  | } | ||||||
| Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB | 
| Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB | 
| Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB | 
| Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB | 
| Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB | 
| @ -0,0 +1,62 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.ja.micmicidol | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.gravureblogger.GravureBlogger | ||||||
|  | 
 | ||||||
|  | class MicMicIdol : GravureBlogger("MIC MIC IDOL", "https://www.micmicidol.club", "ja") { | ||||||
|  |     override val labelFilters = buildMap { | ||||||
|  |         put("Type", getTypes()) | ||||||
|  |         put("Japan Magazine", getJapanMagazines()) | ||||||
|  |         put("Japan Fashion", getJapanFashion()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun getJapanMagazines() = listOf( | ||||||
|  |         "cyzo", | ||||||
|  |         "EnTame", | ||||||
|  |         "EX大衆", | ||||||
|  |         "Friday", | ||||||
|  |         "Flash", | ||||||
|  |         "Shonen Magazine", | ||||||
|  |         "Shonen Sunday", | ||||||
|  |         "Weekly Shonen Champion", | ||||||
|  |         "Weekly Big Comic Spirits", | ||||||
|  |         "Weekly Jitsuwa", | ||||||
|  |         "Weekly Playboy", | ||||||
|  |         "Weekly SPA!", | ||||||
|  |         "Young Animal", | ||||||
|  |         "Young Champion", | ||||||
|  |         "Young Gangan", | ||||||
|  |         "Young Jump", | ||||||
|  |         "Young Magazine", | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     private fun getJapanFashion() = listOf( | ||||||
|  |         "andGIRL", | ||||||
|  |         "aR", | ||||||
|  |         "Baila", | ||||||
|  |         "Biteki", | ||||||
|  |         "CanCam", | ||||||
|  |         "Classy", | ||||||
|  |         "ELLE Japan", | ||||||
|  |         "Ginger", | ||||||
|  |         "JJ", | ||||||
|  |         "Maquia", | ||||||
|  |         "Mina", | ||||||
|  |         "MORE", | ||||||
|  |         "Non-no", | ||||||
|  |         "Oggi", | ||||||
|  |         "Ray", | ||||||
|  |         "Scawaii", | ||||||
|  |         "Steady", | ||||||
|  |         "ViVi", | ||||||
|  |         "VoCE", | ||||||
|  |         "With", | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  |     private fun getTypes() = listOf( | ||||||
|  |         "- Cover", | ||||||
|  |         "- Japan Magazine", | ||||||
|  |         "- Japan Fashion Magazine", | ||||||
|  |         "- Japan Idol Photobook", | ||||||
|  |         "- Asia Idol", | ||||||
|  |     ) | ||||||
|  | } | ||||||
| @ -1,62 +0,0 @@ | |||||||
| package eu.kanade.tachiyomi.extension.es.atlantisscan |  | ||||||
| 
 |  | ||||||
| import eu.kanade.tachiyomi.multisrc.madara.Madara |  | ||||||
| import eu.kanade.tachiyomi.network.POST |  | ||||||
| import eu.kanade.tachiyomi.network.interceptor.rateLimit |  | ||||||
| import okhttp3.FormBody |  | ||||||
| import okhttp3.OkHttpClient |  | ||||||
| import okhttp3.Request |  | ||||||
| import java.text.SimpleDateFormat |  | ||||||
| import java.util.Locale |  | ||||||
| import java.util.concurrent.TimeUnit |  | ||||||
| 
 |  | ||||||
| class AtlantisScan : Madara( |  | ||||||
|     "Atlantis Scan", |  | ||||||
|     "https://scansatlanticos.com", |  | ||||||
|     "es", |  | ||||||
|     dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.US), |  | ||||||
| ) { |  | ||||||
|     override val id: Long = 2237642340381856331 |  | ||||||
| 
 |  | ||||||
|     override val client: OkHttpClient = super.client.newBuilder() |  | ||||||
|         .rateLimit(2, 1, TimeUnit.SECONDS) |  | ||||||
|         .build() |  | ||||||
| 
 |  | ||||||
|     override val useNewChapterEndpoint = true |  | ||||||
| 
 |  | ||||||
|     override fun popularMangaNextPageSelector() = "body:not(:has(.no-posts))" |  | ||||||
| 
 |  | ||||||
|     private fun loadMoreRequest(page: Int, metaKey: String): Request { |  | ||||||
|         val formBody = FormBody.Builder().apply { |  | ||||||
|             add("action", "madara_load_more") |  | ||||||
|             add("page", page.toString()) |  | ||||||
|             add("template", "madara-core/content/content-archive") |  | ||||||
|             add("vars[paged]", "1") |  | ||||||
|             add("vars[orderby]", "meta_value_num") |  | ||||||
|             add("vars[template]", "archive") |  | ||||||
|             add("vars[sidebar]", "full") |  | ||||||
|             add("vars[post_type]", "wp-manga") |  | ||||||
|             add("vars[post_status]", "publish") |  | ||||||
|             add("vars[meta_key]", metaKey) |  | ||||||
|             add("vars[order]", "desc") |  | ||||||
|             add("vars[meta_query][relation]", "AND") |  | ||||||
|             add("vars[manga_archives_item_layout]", "big_thumbnail") |  | ||||||
|         }.build() |  | ||||||
| 
 |  | ||||||
|         val xhrHeaders = headersBuilder() |  | ||||||
|             .add("Content-Length", formBody.contentLength().toString()) |  | ||||||
|             .add("Content-Type", formBody.contentType().toString()) |  | ||||||
|             .add("X-Requested-With", "XMLHttpRequest") |  | ||||||
|             .build() |  | ||||||
| 
 |  | ||||||
|         return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun popularMangaRequest(page: Int): Request { |  | ||||||
|         return loadMoreRequest(page - 1, "_wp_manga_views") |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     override fun latestUpdatesRequest(page: Int): Request { |  | ||||||
|         return loadMoreRequest(page - 1, "_latest_update") |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -8,7 +8,7 @@ import java.util.concurrent.TimeUnit | |||||||
| 
 | 
 | ||||||
| class Jiangzaitoon : Madara( | class Jiangzaitoon : Madara( | ||||||
|     "Jiangzaitoon", |     "Jiangzaitoon", | ||||||
|     "https://jiangzaitoon.cc", |     "https://jiangzaitoon.info", | ||||||
|     "tr", |     "tr", | ||||||
|     SimpleDateFormat("d MMM yyy", Locale("tr")), |     SimpleDateFormat("d MMM yyy", Locale("tr")), | ||||||
| ) { | ) { | ||||||
|  | |||||||
| After Width: | Height: | Size: 6.7 KiB | 
| After Width: | Height: | Size: 3.5 KiB | 
| After Width: | Height: | Size: 9.7 KiB | 
| After Width: | Height: | Size: 19 KiB | 
| After Width: | Height: | Size: 28 KiB | 
							
								
								
									
										30
									
								
								multisrc/overrides/madara/mangagezgini/src/MangaGezgini.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,30 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.tr.mangagezgini | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||||
|  | import eu.kanade.tachiyomi.source.model.SChapter | ||||||
|  | import org.jsoup.nodes.Element | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | class MangaGezgini : Madara( | ||||||
|  |     "MangaGezgini", | ||||||
|  |     "https://mangagezgini.com", | ||||||
|  |     "tr", | ||||||
|  |     SimpleDateFormat("dd/MM/yyy", Locale("tr")), | ||||||
|  | ) { | ||||||
|  |     override fun chapterFromElement(element: Element): SChapter { | ||||||
|  |         val chapter = SChapter.create() | ||||||
|  |         with(element) { | ||||||
|  |             select(chapterUrlSelector).first()?.let { urlElement -> | ||||||
|  |                 chapter.url = urlElement.attr("abs:href").let { | ||||||
|  |                     it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else "" | ||||||
|  |                 } | ||||||
|  |                 chapter.name = element.select("li.wp-manga-chapter.has-thumb a").text() | ||||||
|  |             } | ||||||
|  |             chapter.date_upload = select("img:not(.thumb)").firstOrNull()?.attr("alt")?.let { parseRelativeDate(it) } | ||||||
|  |                 ?: select("span a").firstOrNull()?.attr("title")?.let { parseRelativeDate(it) } | ||||||
|  |                 ?: parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text()) | ||||||
|  |         } | ||||||
|  |         return chapter | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -11,11 +11,11 @@ import uy.kohesive.injekt.api.get | |||||||
| import java.text.SimpleDateFormat | import java.text.SimpleDateFormat | ||||||
| import java.util.Locale | import java.util.Locale | ||||||
| 
 | 
 | ||||||
| class Mangalink : Madara("مانجا لينك", "https://manga-link.net", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) { | class Mangalink : Madara("مانجا لينك", "https://manga-link.com", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) { | ||||||
| 
 | 
 | ||||||
|     override val chapterUrlSuffix = "" |     override val chapterUrlSuffix = "" | ||||||
| 
 | 
 | ||||||
|     private val defaultBaseUrl = "https://manga-link.net" |     private val defaultBaseUrl = "https://manga-link.com" | ||||||
|     override val baseUrl by lazy { getPrefBaseUrl() } |     override val baseUrl by lazy { getPrefBaseUrl() } | ||||||
| 
 | 
 | ||||||
|     private val preferences: SharedPreferences by lazy { |     private val preferences: SharedPreferences by lazy { | ||||||
|  | |||||||
| After Width: | Height: | Size: 7.5 KiB | 
| After Width: | Height: | Size: 3.8 KiB | 
| After Width: | Height: | Size: 11 KiB | 
| After Width: | Height: | Size: 22 KiB | 
| After Width: | Height: | Size: 36 KiB | 
							
								
								
									
										12
									
								
								multisrc/overrides/madara/mangawow/src/MangaWOW.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,12 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.tr.mangawow | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | class MangaWOW : Madara( | ||||||
|  |     "MangaWOW", | ||||||
|  |     "https://mangawow.org", | ||||||
|  |     "tr", | ||||||
|  |     SimpleDateFormat("MMMM dd, yyyy", Locale("tr")), | ||||||
|  | ) | ||||||
| After Width: | Height: | Size: 4.6 KiB | 
| After Width: | Height: | Size: 2.7 KiB | 
| After Width: | Height: | Size: 7.0 KiB | 
| After Width: | Height: | Size: 13 KiB | 
| After Width: | Height: | Size: 20 KiB | 
							
								
								
									
										21
									
								
								multisrc/overrides/madara/ninjascan/src/NinjaScan.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.pt.ninjascan | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||||
|  | import eu.kanade.tachiyomi.network.interceptor.rateLimit | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | class NinjaScan : Madara( | ||||||
|  |     "Ninja Scan", | ||||||
|  |     "https://ninjascan.site", | ||||||
|  |     "pt-BR", | ||||||
|  |     SimpleDateFormat("dd 'de' MMMMM 'de' yyyy", Locale("pt", "BR")), | ||||||
|  | ) { | ||||||
|  |     override val client = super.client.newBuilder() | ||||||
|  |         .rateLimit(2) | ||||||
|  |         .build() | ||||||
|  | 
 | ||||||
|  |     override val useNewChapterEndpoint = true | ||||||
|  | 
 | ||||||
|  |     override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/" | ||||||
|  | } | ||||||
| @ -6,10 +6,12 @@ import java.util.Locale | |||||||
| 
 | 
 | ||||||
| class SamuraiScan : Madara( | class SamuraiScan : Madara( | ||||||
|     "SamuraiScan", |     "SamuraiScan", | ||||||
|     "https://samuraiscan.com", |     "https://samuraiscan.org", | ||||||
|     "es", |     "es", | ||||||
|     SimpleDateFormat("MMMM d, yyyy", Locale("es")), |     SimpleDateFormat("d MMMM, yyyy", Locale("es")), | ||||||
| ) { | ) { | ||||||
|  | 
 | ||||||
|  |     override val mangaSubString = "l" | ||||||
|     override val useNewChapterEndpoint = true |     override val useNewChapterEndpoint = true | ||||||
| 
 | 
 | ||||||
|     override val mangaDetailsSelectorDescription = "div.summary_content div.manga-summary" |     override val mangaDetailsSelectorDescription = "div.summary_content div.manga-summary" | ||||||
|  | |||||||
| After Width: | Height: | Size: 7.0 KiB | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 11 KiB | 
| After Width: | Height: | Size: 22 KiB | 
| After Width: | Height: | Size: 35 KiB | 
							
								
								
									
										15
									
								
								multisrc/overrides/madara/stonescape/src/StoneScape.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,15 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.en.stonescape | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | class StoneScape : Madara( | ||||||
|  |     "StoneScape", | ||||||
|  |     "https://stonescape.xyz", | ||||||
|  |     "en", | ||||||
|  |     SimpleDateFormat("MMMM dd, yyyy", Locale("en")), | ||||||
|  | ) { | ||||||
|  |     override val mangaSubString = "series" | ||||||
|  |     override val chapterUrlSelector = "div + a" | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 5.7 KiB | 
| After Width: | Height: | Size: 3.0 KiB | 
| After Width: | Height: | Size: 8.7 KiB | 
| After Width: | Height: | Size: 17 KiB | 
| After Width: | Height: | Size: 28 KiB | 
							
								
								
									
										21
									
								
								multisrc/overrides/madara/sussyscan/src/SussyScan.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.pt.sussyscan | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||||
|  | import eu.kanade.tachiyomi.network.interceptor.rateLimit | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | class SussyScan : Madara( | ||||||
|  |     "Sussy Scan", | ||||||
|  |     "https://sussyscan.com", | ||||||
|  |     "pt-BR", | ||||||
|  |     SimpleDateFormat("MMMMM dd, yyyy", Locale("pt", "BR")), | ||||||
|  | ) { | ||||||
|  |     override val client = super.client.newBuilder() | ||||||
|  |         .rateLimit(2) | ||||||
|  |         .build() | ||||||
|  | 
 | ||||||
|  |     override val useNewChapterEndpoint = true | ||||||
|  | 
 | ||||||
|  |     override val mangaSubString = "sus" | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 6.2 KiB | 
| After Width: | Height: | Size: 3.4 KiB | 
| After Width: | Height: | Size: 9.9 KiB | 
| After Width: | Height: | Size: 19 KiB | 
| After Width: | Height: | Size: 29 KiB | 
							
								
								
									
										8
									
								
								multisrc/overrides/manga18/hanman18/src/HANMAN18.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,8 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.zh.hanman18 | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.manga18.Manga18 | ||||||
|  | 
 | ||||||
|  | class HANMAN18 : Manga18("HANMAN18", "https://hanman18.com", "zh") { | ||||||
|  |     // tag filter doesn't work on site | ||||||
|  |     override val getAvailableTags = false | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 9.6 KiB | 
| After Width: | Height: | Size: 4.6 KiB | 
| After Width: | Height: | Size: 16 KiB | 
| After Width: | Height: | Size: 32 KiB | 
| After Width: | Height: | Size: 53 KiB | 
							
								
								
									
										16
									
								
								multisrc/overrides/manga18/hentai3zcc/src/Hentai3zCC.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,16 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.en.hentai3zcc | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.manga18.Manga18 | ||||||
|  | import eu.kanade.tachiyomi.source.model.SManga | ||||||
|  | import org.jsoup.nodes.Element | ||||||
|  | 
 | ||||||
|  | class Hentai3zCC : Manga18("Hentai3z.CC", "https://hentai3z.cc", "en") { | ||||||
|  | 
 | ||||||
|  |     override fun popularMangaFromElement(element: Element) = SManga.create().apply { | ||||||
|  |         setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href")) | ||||||
|  |         title = element.selectFirst("div.mg_info > div.mg_name a")!!.text() | ||||||
|  |         thumbnail_url = element.selectFirst("img")?.absUrl("src") | ||||||
|  |             ?.replace("cover_thumb_2.webp", "cover_250x350.jpg") | ||||||
|  |             ?.replace("admin.manga18.us", "bk.18porncomic.com") | ||||||
|  |     } | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 5.4 KiB | 
| After Width: | Height: | Size: 3.0 KiB | 
| After Width: | Height: | Size: 7.1 KiB | 
| After Width: | Height: | Size: 13 KiB | 
| After Width: | Height: | Size: 18 KiB | 
							
								
								
									
										251
									
								
								multisrc/overrides/mangareader/rawotaku/src/RawOtaku.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,251 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.ja.rawotaku | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.mangareader.MangaReader | ||||||
|  | import eu.kanade.tachiyomi.network.GET | ||||||
|  | import eu.kanade.tachiyomi.network.asObservableSuccess | ||||||
|  | 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.util.asJsoup | ||||||
|  | import kotlinx.serialization.json.Json | ||||||
|  | import kotlinx.serialization.json.jsonObject | ||||||
|  | import kotlinx.serialization.json.jsonPrimitive | ||||||
|  | import okhttp3.HttpUrl.Companion.toHttpUrl | ||||||
|  | import okhttp3.Request | ||||||
|  | import okhttp3.Response | ||||||
|  | import org.jsoup.Jsoup | ||||||
|  | import org.jsoup.nodes.Document | ||||||
|  | import org.jsoup.nodes.Element | ||||||
|  | import org.jsoup.nodes.TextNode | ||||||
|  | import org.jsoup.select.Evaluator | ||||||
|  | import rx.Observable | ||||||
|  | import java.net.URLEncoder | ||||||
|  | 
 | ||||||
|  | class RawOtaku : MangaReader() { | ||||||
|  | 
 | ||||||
|  |     override val name = "Raw Otaku" | ||||||
|  | 
 | ||||||
|  |     override val lang = "ja" | ||||||
|  | 
 | ||||||
|  |     override val baseUrl = "https://rawotaku.com" | ||||||
|  | 
 | ||||||
|  |     override val client = network.cloudflareClient.newBuilder() | ||||||
|  |         .rateLimit(2) | ||||||
|  |         .build() | ||||||
|  | 
 | ||||||
|  |     override fun headersBuilder() = super.headersBuilder() | ||||||
|  |         .add("Referer", "$baseUrl/") | ||||||
|  | 
 | ||||||
|  |     // ============================== Popular =============================== | ||||||
|  | 
 | ||||||
|  |     override fun popularMangaRequest(page: Int) = | ||||||
|  |         GET("$baseUrl/filter/?type=all&status=all&language=all&sort=most-viewed&p=$page", headers) | ||||||
|  | 
 | ||||||
|  |     // =============================== Latest =============================== | ||||||
|  | 
 | ||||||
|  |     override fun latestUpdatesRequest(page: Int) = | ||||||
|  |         GET("$baseUrl/filter/?type=all&status=all&language=all&sort=latest-updated&p=$page", headers) | ||||||
|  | 
 | ||||||
|  |     // =============================== Search =============================== | ||||||
|  | 
 | ||||||
|  |     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { | ||||||
|  |         val url = baseUrl.toHttpUrl().newBuilder().apply { | ||||||
|  |             if (query.isNotBlank()) { | ||||||
|  |                 addQueryParameter("q", query) | ||||||
|  |             } else { | ||||||
|  |                 addPathSegment("filter") | ||||||
|  |                 addPathSegment("") | ||||||
|  | 
 | ||||||
|  |                 filters.ifEmpty(::getFilterList).forEach { filter -> | ||||||
|  |                     when (filter) { | ||||||
|  |                         is TypeFilter -> { | ||||||
|  |                             addQueryParameter(filter.param, filter.selection) | ||||||
|  |                         } | ||||||
|  |                         is StatusFilter -> { | ||||||
|  |                             addQueryParameter(filter.param, filter.selection) | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         is LanguageFilter -> { | ||||||
|  |                             addQueryParameter(filter.param, filter.selection) | ||||||
|  |                         } | ||||||
|  |                         is SortFilter -> { | ||||||
|  |                             addQueryParameter(filter.param, filter.selection) | ||||||
|  |                         } | ||||||
|  |                         is GenresFilter -> { | ||||||
|  |                             filter.state.forEach { | ||||||
|  |                                 if (it.state) { | ||||||
|  |                                     addQueryParameter(filter.param, it.id) | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         else -> { } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             addQueryParameter("p", page.toString()) | ||||||
|  |         }.build() | ||||||
|  | 
 | ||||||
|  |         return GET(url, headers) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun searchMangaSelector() = ".manga_list-sbs .manga-poster" | ||||||
|  | 
 | ||||||
|  |     override fun searchMangaFromElement(element: Element) = | ||||||
|  |         SManga.create().apply { | ||||||
|  |             setUrlWithoutDomain(element.attr("href")) | ||||||
|  |             element.selectFirst(Evaluator.Tag("img"))!!.let { | ||||||
|  |                 title = it.attr("alt") | ||||||
|  |                 thumbnail_url = it.imgAttr() | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     override fun searchMangaNextPageSelector() = "ul.pagination > li.active + li" | ||||||
|  | 
 | ||||||
|  |     // =============================== Filters ============================== | ||||||
|  | 
 | ||||||
|  |     override fun getFilterList() = | ||||||
|  |         FilterList( | ||||||
|  |             Note, | ||||||
|  |             Filter.Separator(), | ||||||
|  |             TypeFilter(), | ||||||
|  |             StatusFilter(), | ||||||
|  |             LanguageFilter(), | ||||||
|  |             SortFilter(), | ||||||
|  |             GenresFilter(), | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     // =========================== Manga Details ============================ | ||||||
|  | 
 | ||||||
|  |     override fun mangaDetailsParse(document: Document) = SManga.create().apply { | ||||||
|  |         val root = document.selectFirst(Evaluator.Id("ani_detail"))!! | ||||||
|  |         val mangaTitle = root.selectFirst(Evaluator.Class("manga-name"))!!.ownText() | ||||||
|  |         title = mangaTitle | ||||||
|  |         description = buildString { | ||||||
|  |             root.selectFirst(".description")?.ownText()?.let { append(it) } | ||||||
|  |             append("\n\n") | ||||||
|  |             root.selectFirst(".manga-name-or")?.ownText()?.let { | ||||||
|  |                 if (it.isNotEmpty() && it != mangaTitle) { | ||||||
|  |                     append("Alternative Title: ") | ||||||
|  |                     append(it) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }.trim() | ||||||
|  |         thumbnail_url = root.selectFirst(Evaluator.Tag("img"))!!.imgAttr() | ||||||
|  |         genre = root.selectFirst(Evaluator.Class("genres"))!!.children().joinToString { it.ownText() } | ||||||
|  |         for (item in root.selectFirst(Evaluator.Class("anisc-info"))!!.children()) { | ||||||
|  |             if (item.hasClass("item").not()) continue | ||||||
|  |             when (item.selectFirst(Evaluator.Class("item-head"))!!.ownText()) { | ||||||
|  |                 "著者:" -> item.parseAuthorsTo(this) | ||||||
|  |                 "地位:" -> status = when (item.selectFirst(Evaluator.Class("name"))!!.ownText().lowercase()) { | ||||||
|  |                     "ongoing" -> SManga.ONGOING | ||||||
|  |                     "completed" -> SManga.COMPLETED | ||||||
|  |                     "on-hold" -> SManga.ON_HIATUS | ||||||
|  |                     "canceled" -> SManga.CANCELLED | ||||||
|  |                     else -> SManga.UNKNOWN | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun Element.parseAuthorsTo(manga: SManga) { | ||||||
|  |         val authors = select(Evaluator.Tag("a")) | ||||||
|  |         val text = authors.map { it.ownText().replace(",", "") } | ||||||
|  |         val count = authors.size | ||||||
|  |         when (count) { | ||||||
|  |             0 -> return | ||||||
|  |             1 -> { | ||||||
|  |                 manga.author = text[0] | ||||||
|  |                 return | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         val authorList = ArrayList<String>(count) | ||||||
|  |         val artistList = ArrayList<String>(count) | ||||||
|  |         for ((index, author) in authors.withIndex()) { | ||||||
|  |             val textNode = author.nextSibling() as? TextNode | ||||||
|  |             val list = if (textNode != null && "(Art)" in textNode.wholeText) artistList else authorList | ||||||
|  |             list.add(text[index]) | ||||||
|  |         } | ||||||
|  |         if (authorList.isEmpty().not()) manga.author = authorList.joinToString() | ||||||
|  |         if (artistList.isEmpty().not()) manga.artist = artistList.joinToString() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // ============================== Chapters ============================== | ||||||
|  | 
 | ||||||
|  |     override fun chapterListRequest(mangaUrl: String, type: String): Request = | ||||||
|  |         GET(baseUrl + mangaUrl, headers) | ||||||
|  | 
 | ||||||
|  |     override fun parseChapterElements(response: Response, isVolume: Boolean): List<Element> { | ||||||
|  |         TODO("Not yet implemented") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override val chapterType = "" | ||||||
|  |     override val volumeType = "" | ||||||
|  | 
 | ||||||
|  |     override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { | ||||||
|  |         return client.newCall(chapterListRequest(manga)) | ||||||
|  |             .asObservableSuccess() | ||||||
|  |             .map(::parseChapterList) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun parseChapterList(response: Response): List<SChapter> { | ||||||
|  |         val document = response.use { it.asJsoup() } | ||||||
|  | 
 | ||||||
|  |         return document.select(chapterListSelector()) | ||||||
|  |             .map(::chapterFromElement) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun chapterListSelector(): String = "#ja-chaps > .chapter-item" | ||||||
|  | 
 | ||||||
|  |     private fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { | ||||||
|  |         val id = element.attr("data-id") | ||||||
|  |         element.selectFirst("a")!!.run { | ||||||
|  |             setUrlWithoutDomain(attr("href") + "#$id") | ||||||
|  |             name = selectFirst(".name")?.text() ?: text() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // =============================== Pages ================================ | ||||||
|  | 
 | ||||||
|  |     override fun fetchPageList(chapter: SChapter): Observable<List<Page>> = Observable.fromCallable { | ||||||
|  |         val id = chapter.url.substringAfterLast("#") | ||||||
|  | 
 | ||||||
|  |         val ajaxHeaders = super.headersBuilder().apply { | ||||||
|  |             add("Accept", "application/json, text/javascript, */*; q=0.01") | ||||||
|  |             add("Referer", URLEncoder.encode(baseUrl + chapter.url.substringBeforeLast("#"), "utf-8")) | ||||||
|  |             add("X-Requested-With", "XMLHttpRequest") | ||||||
|  |         }.build() | ||||||
|  | 
 | ||||||
|  |         val ajaxUrl = "$baseUrl/json/chapter?mode=vertical&id=$id" | ||||||
|  |         client.newCall(GET(ajaxUrl, ajaxHeaders)).execute().let(::pageListParse) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun pageListParse(response: Response): List<Page> { | ||||||
|  |         val document = response.use { it.parseHtmlProperty() } | ||||||
|  | 
 | ||||||
|  |         val pageList = document.select(".container-reader-chapter > div > img").map { | ||||||
|  |             val index = it.attr("alt").toInt() | ||||||
|  |             val imgUrl = it.imgAttr() | ||||||
|  | 
 | ||||||
|  |             Page(index, imageUrl = imgUrl) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return pageList | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // ============================= Utilities ============================== | ||||||
|  | 
 | ||||||
|  |     private fun Element.imgAttr(): String = when { | ||||||
|  |         hasAttr("data-lazy-src") -> attr("abs:data-lazy-src") | ||||||
|  |         hasAttr("data-src") -> attr("abs:data-src") | ||||||
|  |         else -> attr("abs:src") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun Response.parseHtmlProperty(): Document { | ||||||
|  |         val html = Json.parseToJsonElement(body.string()).jsonObject["html"]!!.jsonPrimitive.content | ||||||
|  |         return Jsoup.parseBodyFragment(html) | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										110
									
								
								multisrc/overrides/mangareader/rawotaku/src/RawOtakuFilters.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,110 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.ja.rawotaku | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.source.model.Filter | ||||||
|  | 
 | ||||||
|  | object Note : Filter.Header("NOTE: Ignored if using text search!") | ||||||
|  | 
 | ||||||
|  | sealed class Select( | ||||||
|  |     name: String, | ||||||
|  |     val param: String, | ||||||
|  |     values: Array<String>, | ||||||
|  | ) : Filter.Select<String>(name, values) { | ||||||
|  |     open val selection: String | ||||||
|  |         get() = if (state == 0) "" else state.toString() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class TypeFilter( | ||||||
|  |     values: Array<String> = types.keys.toTypedArray(), | ||||||
|  | ) : Select("タイプ", "type", values) { | ||||||
|  |     override val selection: String | ||||||
|  |         get() = types[values[state]]!! | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private val types = mapOf( | ||||||
|  |             "全て" to "all", | ||||||
|  |             "Raw Manga" to "Raw Manga", | ||||||
|  |             "BLコミック" to "BLコミック", | ||||||
|  |             "TLコミック" to "TLコミック", | ||||||
|  |             "オトナコミック" to "オトナコミック", | ||||||
|  |             "女性マンガ" to "女性マンガ", | ||||||
|  |             "少女マンガ" to "少女マンガ", | ||||||
|  |             "少年マンガ" to "少年マンガ", | ||||||
|  |             "青年マンガ" to "青年マンガ", | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class StatusFilter( | ||||||
|  |     values: Array<String> = statuses.keys.toTypedArray(), | ||||||
|  | ) : Select("地位", "status", values) { | ||||||
|  |     override val selection: String | ||||||
|  |         get() = statuses[values[state]]!! | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private val statuses = mapOf( | ||||||
|  |             "全て" to "all", | ||||||
|  |             "Publishing" to "Publishing", | ||||||
|  |             "Finished" to "Finished", | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class LanguageFilter( | ||||||
|  |     values: Array<String> = languages.keys.toTypedArray(), | ||||||
|  | ) : Select("言語", "language", values) { | ||||||
|  |     override val selection: String | ||||||
|  |         get() = languages[values[state]]!! | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private val languages = mapOf( | ||||||
|  |             "全て" to "all", | ||||||
|  |             "Japanese" to "ja", | ||||||
|  |             "English" to "en", | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class SortFilter( | ||||||
|  |     values: Array<String> = sort.keys.toTypedArray(), | ||||||
|  | ) : Select("選別", "sort", values) { | ||||||
|  |     override val selection: String | ||||||
|  |         get() = sort[values[state]]!! | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private val sort = mapOf( | ||||||
|  |             "デフォルト" to "default", | ||||||
|  |             "最新の更新" to "latest-updated", | ||||||
|  |             "最も見られました" to "most-viewed", | ||||||
|  |             "Title [A-Z]" to "title-az", | ||||||
|  |             "Title [Z-A]" to "title-za", | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Genre(name: String, val id: String) : Filter.CheckBox(name) | ||||||
|  | 
 | ||||||
|  | class GenresFilter( | ||||||
|  |     values: List<Genre> = genres, | ||||||
|  | ) : Filter.Group<Genre>("ジャンル", values) { | ||||||
|  |     val param = "genre[]" | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private val genres: List<Genre> | ||||||
|  |             get() = listOf( | ||||||
|  |                 Genre("アクション", "55"), | ||||||
|  |                 Genre("エッチ", "15706"), | ||||||
|  |                 Genre("コメディ", "91"), | ||||||
|  |                 Genre("ドラマ", "56"), | ||||||
|  |                 Genre("ハーレム", "20"), | ||||||
|  |                 Genre("ファンタジー", "1"), | ||||||
|  |                 Genre("冒険", "54"), | ||||||
|  |                 Genre("悪魔", "6820"), | ||||||
|  |                 Genre("武道", "1064"), | ||||||
|  |                 Genre("歴史的", "9600"), | ||||||
|  |                 Genre("警察・特殊部隊", "6089"), | ||||||
|  |                 Genre("車・バイク", "4329"), | ||||||
|  |                 Genre("音楽", "473"), | ||||||
|  |                 Genre("魔法", "1416"), | ||||||
|  |             ) | ||||||
|  |     } | ||||||
|  | } | ||||||
| Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB | 
| Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB | 
| Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB | 
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB | 
| @ -0,0 +1,22 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.es.atlantisscan | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia | ||||||
|  | import eu.kanade.tachiyomi.network.interceptor.rateLimit | ||||||
|  | import okhttp3.OkHttpClient | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | import java.util.concurrent.TimeUnit | ||||||
|  | 
 | ||||||
|  | class AtlantisScan : MangaThemesia( | ||||||
|  |     "Atlantis Scan", | ||||||
|  |     "https://scansatlanticos.com", | ||||||
|  |     "es", | ||||||
|  |     dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US), | ||||||
|  | ) { | ||||||
|  |     // Site moved from Madara to MangaThemesia | ||||||
|  |     override val versionId = 2 | ||||||
|  | 
 | ||||||
|  |     override val client: OkHttpClient = super.client.newBuilder() | ||||||
|  |         .rateLimit(2, 1, TimeUnit.SECONDS) | ||||||
|  |         .build() | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 2.9 KiB | 
| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 3.9 KiB | 
| After Width: | Height: | Size: 6.7 KiB | 
| After Width: | Height: | Size: 9.4 KiB | 
							
								
								
									
										12
									
								
								multisrc/overrides/mangathemesia/comicaso/src/Comicaso.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,12 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.id.comicaso | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | class Comicaso : MangaThemesia( | ||||||
|  |     "Comicaso", | ||||||
|  |     "https://comicaso.com", | ||||||
|  |     "id", | ||||||
|  |     dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("id")), | ||||||
|  | ) | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.id.comicsekai | ||||||
|  | 
 | ||||||
|  | import android.util.Base64 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia | ||||||
|  | import eu.kanade.tachiyomi.source.model.Page | ||||||
|  | import kotlinx.serialization.json.jsonArray | ||||||
|  | import kotlinx.serialization.json.jsonPrimitive | ||||||
|  | import org.jsoup.nodes.Document | ||||||
|  | 
 | ||||||
|  | class Comicsekai : MangaThemesia("Comicsekai", "http://www.comicsekai.com", "id") { | ||||||
|  |     override fun pageListParse(document: Document): List<Page> { | ||||||
|  |         // "ts_reader.run({" in base64 | ||||||
|  |         val script = document.selectFirst("script[src^=data:text/javascript;base64,dHNfcmVhZGVyLnJ1bih7]") | ||||||
|  |             ?: return super.pageListParse(document) | ||||||
|  |         val data = Base64.decode(script.attr("src").substringAfter("base64,"), Base64.DEFAULT).toString(Charsets.UTF_8) | ||||||
|  |         val imageListJson = JSON_IMAGE_LIST_REGEX.find(data)?.destructured?.toList()?.get(0).orEmpty() | ||||||
|  |         val imageList = try { | ||||||
|  |             json.parseToJsonElement(imageListJson).jsonArray | ||||||
|  |         } catch (_: IllegalArgumentException) { | ||||||
|  |             emptyList() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return imageList.mapIndexed { i, jsonEl -> | ||||||
|  |             Page(i, imageUrl = jsonEl.jsonPrimitive.content) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package eu.kanade.tachiyomi.extension.th.dragonmanga | ||||||
|  | 
 | ||||||
|  | import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia | ||||||
|  | import java.text.SimpleDateFormat | ||||||
|  | import java.util.Locale | ||||||
|  | 
 | ||||||
|  | class DragonManga : MangaThemesia( | ||||||
|  |     "DragonManga", | ||||||
|  |     "https://www.dragon-manga.com", | ||||||
|  |     "th", | ||||||
|  |     dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("th")), | ||||||
|  | ) | ||||||
| @ -8,7 +8,7 @@ import java.util.Locale | |||||||
| 
 | 
 | ||||||
| class InariManga : MangaThemesia( | class InariManga : MangaThemesia( | ||||||
|     "InariManga", |     "InariManga", | ||||||
|     "https://inarimanga.com", |     "https://inarimanga.net", | ||||||
|     "es", |     "es", | ||||||
|     dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("en")), |     dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("en")), | ||||||
| ) { | ) { | ||||||
|  | |||||||
| After Width: | Height: | Size: 1.8 KiB | 
| After Width: | Height: | Size: 978 B | 
| After Width: | Height: | Size: 2.3 KiB |