Add BrasilHentai (#2918)
* Add BrasilHentai * Fix popularMangaNextPage * Fix popularMangaRequest and set rateLimit * Fix names * Fix filter * Fix intent pathSegment * Remove extra request and add Initilize in popularMangaFromElement * Update src/pt/brasilhentai/src/eu/kanade/tachiyomi/extension/pt/brasilhentai/BrasilHentai.kt * Update src/pt/brasilhentai/src/eu/kanade/tachiyomi/extension/pt/brasilhentai/BrasilHentai.kt --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									9fe6e06574
								
							
						
					
					
						commit
						1ef8153eca
					
				
							
								
								
									
										22
									
								
								src/pt/brasilhentai/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/pt/brasilhentai/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <application> | ||||
|         <activity | ||||
|             android:name=".pt.brasilhentai.BrasilHentaiUrlActivity" | ||||
|             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="brasilhentai.com" | ||||
|                     android:pathPattern="/..*" | ||||
|                     android:scheme="https" /> | ||||
|             </intent-filter> | ||||
|         </activity> | ||||
|     </application> | ||||
| </manifest> | ||||
							
								
								
									
										8
									
								
								src/pt/brasilhentai/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/pt/brasilhentai/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| ext { | ||||
|     extName = 'Brasil Hentai' | ||||
|     extClass = '.BrasilHentai' | ||||
|     extVersionCode = 1 | ||||
|     isNsfw = true | ||||
| } | ||||
| 
 | ||||
| apply from: "$rootDir/common.gradle" | ||||
							
								
								
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-hdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-hdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-mdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-mdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-xhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-xhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 8.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-xxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-xxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 17 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-xxxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/pt/brasilhentai/res/mipmap-xxxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 26 KiB | 
| @ -0,0 +1,173 @@ | ||||
| package eu.kanade.tachiyomi.extension.pt.brasilhentai | ||||
| 
 | ||||
| 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.MangasPage | ||||
| import eu.kanade.tachiyomi.source.model.Page | ||||
| import eu.kanade.tachiyomi.source.model.SChapter | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import eu.kanade.tachiyomi.source.online.ParsedHttpSource | ||||
| import eu.kanade.tachiyomi.util.asJsoup | ||||
| import okhttp3.HttpUrl.Companion.toHttpUrl | ||||
| import okhttp3.OkHttpClient | ||||
| import okhttp3.Request | ||||
| import okhttp3.Response | ||||
| import org.jsoup.nodes.Document | ||||
| import org.jsoup.nodes.Element | ||||
| import rx.Observable | ||||
| 
 | ||||
| class BrasilHentai : ParsedHttpSource() { | ||||
| 
 | ||||
|     override val name = "Brasil Hentai" | ||||
| 
 | ||||
|     override val baseUrl = "https://brasilhentai.com" | ||||
| 
 | ||||
|     override val lang = "pt-BR" | ||||
| 
 | ||||
|     override val supportsLatest: Boolean = false | ||||
| 
 | ||||
|     override val client: OkHttpClient = network.cloudflareClient.newBuilder() | ||||
|         .rateLimit(4) | ||||
|         .build() | ||||
| 
 | ||||
|     private var categoryFilterOptions: Array<Pair<String, String>> = emptyArray() | ||||
| 
 | ||||
|     override fun chapterFromElement(element: Element) = | ||||
|         throw UnsupportedOperationException() | ||||
| 
 | ||||
|     override fun chapterListSelector() = | ||||
|         throw UnsupportedOperationException() | ||||
| 
 | ||||
|     override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { | ||||
|         return Observable.just( | ||||
|             listOf( | ||||
|                 SChapter.create().apply { | ||||
|                     name = "Capítulo único" | ||||
|                     url = manga.url | ||||
|                 }, | ||||
|             ), | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun imageUrlParse(document: Document) = "" | ||||
| 
 | ||||
|     override fun latestUpdatesFromElement(element: Element) = | ||||
|         throw UnsupportedOperationException() | ||||
| 
 | ||||
|     override fun latestUpdatesNextPageSelector() = | ||||
|         throw UnsupportedOperationException() | ||||
| 
 | ||||
|     override fun latestUpdatesRequest(page: Int) = | ||||
|         throw UnsupportedOperationException() | ||||
| 
 | ||||
|     override fun latestUpdatesSelector() = | ||||
|         throw UnsupportedOperationException() | ||||
| 
 | ||||
|     override fun mangaDetailsParse(document: Document) = SManga.create().apply { | ||||
|         title = document.selectFirst("h1")!!.ownText() | ||||
|         thumbnail_url = document.selectFirst(".entry-content p a img")?.absUrl("src") | ||||
|     } | ||||
| 
 | ||||
|     override fun pageListParse(document: Document): List<Page> { | ||||
|         return document.select(".entry-content p > img").mapIndexed { index, element -> | ||||
|             Page(index, imageUrl = element.absUrl("src")) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun popularMangaFromElement(element: Element) = SManga.create().apply { | ||||
|         val anchor = element.selectFirst("a[title]") | ||||
|         title = anchor!!.attr("title") | ||||
|         thumbnail_url = element.selectFirst("img")?.absUrl("src") | ||||
|         initialized = true | ||||
|         setUrlWithoutDomain(anchor.absUrl("href")) | ||||
|     } | ||||
| 
 | ||||
|     override fun popularMangaNextPageSelector() = ".next.page-numbers" | ||||
| 
 | ||||
|     override fun popularMangaRequest(page: Int) = GET("$baseUrl/page/$page", headers) | ||||
| 
 | ||||
|     override fun popularMangaSelector() = ".content-area article" | ||||
| 
 | ||||
|     override fun popularMangaParse(response: Response): MangasPage { | ||||
|         val document = response.asJsoup() | ||||
|         if (categoryFilterOptions.isEmpty()) { | ||||
|             categoryFilterOptions = parseCategories(document) | ||||
|         } | ||||
|         return MangasPage( | ||||
|             mangas = document.select(popularMangaSelector()).map(::popularMangaFromElement), | ||||
|             hasNextPage = document.selectFirst(popularMangaNextPageSelector()) != null, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) | ||||
| 
 | ||||
|     override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() | ||||
| 
 | ||||
|     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { | ||||
|         val category = filters.filterIsInstance<CategoryFilter>().first() | ||||
|             .selectedValue() | ||||
| 
 | ||||
|         val url = if (category.isEmpty()) { | ||||
|             "$baseUrl/page/$page".toHttpUrl().newBuilder() | ||||
|                 .addQueryParameter("s", query) | ||||
|                 .build() | ||||
|         } else { | ||||
|             "$baseUrl/category/$category/page/$page/".toHttpUrl() | ||||
|         } | ||||
| 
 | ||||
|         return GET(url, headers) | ||||
|     } | ||||
| 
 | ||||
|     override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { | ||||
|         return if (query.startsWith(PREFIX_SEARCH)) { | ||||
|             client.newCall(GET("$baseUrl/${query.substringAfter(PREFIX_SEARCH)}", headers)) | ||||
|                 .asObservableSuccess() | ||||
|                 .map { MangasPage(listOf(searchMangaFromElement(it.asJsoup())), false) } | ||||
|         } else { | ||||
|             super.fetchSearchManga(page, query, filters) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun searchMangaSelector() = popularMangaSelector() | ||||
| 
 | ||||
|     override fun getFilterList(): FilterList { | ||||
|         val filters = mutableListOf<Filter<*>>() | ||||
| 
 | ||||
|         filters += if (categoryFilterOptions.isNotEmpty()) { | ||||
|             CategoryFilter("Categoria", categoryFilterOptions) | ||||
|         } else { | ||||
|             Filter.Header("Aperte 'Redefinir' para tentar mostrar as categorias") | ||||
|         } | ||||
| 
 | ||||
|         return FilterList(filters) | ||||
|     } | ||||
| 
 | ||||
|     private fun parseCategories(document: Document): Array<Pair<String, String>> { | ||||
|         return document.select("#categories-2 li a") | ||||
|             .map { element -> | ||||
|                 val url = element.absUrl("href") | ||||
|                 val category = url.split("/").filter { it.isNotBlank() }.last() | ||||
|                 Pair(element.ownText(), category) | ||||
|             }.toTypedArray() | ||||
|     } | ||||
| 
 | ||||
|     class CategoryFilter( | ||||
|         displayName: String, | ||||
|         private val vals: Array<Pair<String, String>>, | ||||
|     ) : Filter.Select<String>( | ||||
|         displayName, | ||||
|         vals.map { it.first }.toTypedArray(), | ||||
|         vals.indexOfFirst { it.second.isEmpty() }.takeIf { it != -1 } ?: 0, | ||||
|     ) { | ||||
|         fun selectedValue() = vals[state].second | ||||
|     } | ||||
| 
 | ||||
|     private fun categoriesRequest(): Request = GET(baseUrl, headers) | ||||
| 
 | ||||
|     companion object { | ||||
|         val PREFIX_SEARCH: String = "slug:" | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| package eu.kanade.tachiyomi.extension.pt.brasilhentai | ||||
| 
 | ||||
| import android.app.Activity | ||||
| import android.content.ActivityNotFoundException | ||||
| import android.content.Intent | ||||
| import android.os.Bundle | ||||
| import android.util.Log | ||||
| import kotlin.system.exitProcess | ||||
| 
 | ||||
| class BrasilHentaiUrlActivity : Activity() { | ||||
| 
 | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         super.onCreate(savedInstanceState) | ||||
|         val segment = intent?.data?.lastPathSegment | ||||
|         if (segment != null) { | ||||
|             val mainIntent = Intent().apply { | ||||
|                 action = "eu.kanade.tachiyomi.SEARCH" | ||||
|                 putExtra("query", "${BrasilHentai.PREFIX_SEARCH}$segment") | ||||
|                 putExtra("filter", packageName) | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 startActivity(mainIntent) | ||||
|             } catch (e: ActivityNotFoundException) { | ||||
|                 Log.e("BrasilHentaiUrlActivity", e.toString()) | ||||
|             } | ||||
|         } else { | ||||
|             Log.e("BrasilHentaiUrlActivity", "could not parse uri from intent $intent") | ||||
|         } | ||||
| 
 | ||||
|         finish() | ||||
|         exitProcess(0) | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Chopper
						Chopper