AralosBD: added new extension to add support for aralosbd.fr (#12581)
* AralosBD: added new extension to add support for aralosbd.fr * AralosBD: fixed pull request - Fixed icon format - Removed useless configuration file - Removed useless headers
							
								
								
									
										2
									
								
								src/fr/aralosbd/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,2 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<manifest package="eu.kanade.tachiyomi.extension" />
 | 
			
		||||
							
								
								
									
										12
									
								
								src/fr/aralosbd/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,12 @@
 | 
			
		||||
apply plugin: 'com.android.application'
 | 
			
		||||
apply plugin: 'kotlin-android'
 | 
			
		||||
apply plugin: 'kotlinx-serialization'
 | 
			
		||||
 | 
			
		||||
ext {
 | 
			
		||||
    extName = 'AralosBD'
 | 
			
		||||
    pkgNameSuffix = 'fr.aralosbd'
 | 
			
		||||
    extClass = '.AralosBD'
 | 
			
		||||
    extVersionCode = 4
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: "$rootDir/common.gradle"
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/fr/aralosbd/ic_launcher-playstore.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 55 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/fr/aralosbd/res/mipmap-hdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/fr/aralosbd/res/mipmap-mdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/fr/aralosbd/res/mipmap-xhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.9 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/fr/aralosbd/res/mipmap-xxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 13 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/fr/aralosbd/res/mipmap-xxxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 19 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/fr/aralosbd/res/web_hi_res_512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 43 KiB  | 
@ -0,0 +1,230 @@
 | 
			
		||||
package eu.kanade.tachiyomi.extension.fr.aralosbd
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.network.GET
 | 
			
		||||
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.HttpSource
 | 
			
		||||
import kotlinx.serialization.Serializable
 | 
			
		||||
import kotlinx.serialization.decodeFromString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import okhttp3.Request
 | 
			
		||||
import okhttp3.Response
 | 
			
		||||
import org.jsoup.parser.Parser
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import java.text.SimpleDateFormat
 | 
			
		||||
import java.util.Locale
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDSearchManga(
 | 
			
		||||
    val icon: String = "",
 | 
			
		||||
    val title: String = "",
 | 
			
		||||
    val id: String = "",
 | 
			
		||||
    val read_count: String = "",
 | 
			
		||||
    val chapter_count: String = "",
 | 
			
		||||
    val is_favorite: Boolean = false,
 | 
			
		||||
    val is_liked: Boolean = false,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDSearchResult(
 | 
			
		||||
    val error: Int = 0,
 | 
			
		||||
    val mangas: List<AralosBDSearchManga> = emptyList()
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDAlternativeTitle(
 | 
			
		||||
    val title: String = "",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDAuthor(
 | 
			
		||||
    val name: String = "",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDTranslator(
 | 
			
		||||
    val name: String = "",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDTag(
 | 
			
		||||
    val tag: String = "",
 | 
			
		||||
    val color: String = "",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDManga(
 | 
			
		||||
    val main_title: String = "",
 | 
			
		||||
    val fulldescription: String? = "",
 | 
			
		||||
    val description: String = "",
 | 
			
		||||
    val year: String = "",
 | 
			
		||||
    val id: Int = 0,
 | 
			
		||||
    val alternative_titles: List<AralosBDAlternativeTitle>? = emptyList(),
 | 
			
		||||
    val authors: List<AralosBDAuthor>? = emptyList(),
 | 
			
		||||
    val translators: List<AralosBDTranslator>? = emptyList(),
 | 
			
		||||
    val tags: List<AralosBDTag>? = emptyList(),
 | 
			
		||||
    val banner: String = "",
 | 
			
		||||
    val icon: String = "",
 | 
			
		||||
    val error: Int = 0,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDChapter(
 | 
			
		||||
    val chapter_number: String = "",
 | 
			
		||||
    val chapter_user: String = "",
 | 
			
		||||
    val chapter_title: String = "",
 | 
			
		||||
    val chapter_translator: String? = "",
 | 
			
		||||
    val chapter_view_count: String = "",
 | 
			
		||||
    val chapter_like_count: String = "",
 | 
			
		||||
    val chapter_date: String = "",
 | 
			
		||||
    val chapter_id: String = "",
 | 
			
		||||
    val chapter_read: Boolean = false,
 | 
			
		||||
    val chapter_released: String = "0",
 | 
			
		||||
    val chapter_release_time: String = "",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class AralosBDPages(
 | 
			
		||||
    val error: Int = 0,
 | 
			
		||||
    val links: List<String> = emptyList()
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
class AralosBD : HttpSource() {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.FRANCE)
 | 
			
		||||
 | 
			
		||||
        val LINK_REGEX = "\\[([^]]+)\\]\\(([^)]+)\\)".toRegex()
 | 
			
		||||
        val BOLD_REGEX = "\\*+\\s*([^\\*]*)\\s*\\*+".toRegex()
 | 
			
		||||
        val ITALIC_REGEX = "_+\\s*([^_]*)\\s*_+".toRegex()
 | 
			
		||||
        val ICON_REGEX = ":+[a-zA-Z]+:".toRegex()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun cleanString(string: String): String {
 | 
			
		||||
        return Parser.unescapeEntities(string, false)
 | 
			
		||||
            .substringBefore("---")
 | 
			
		||||
            .replace(LINK_REGEX, "$2")
 | 
			
		||||
            .replace(BOLD_REGEX, "$1")
 | 
			
		||||
            .replace(ITALIC_REGEX, "$1")
 | 
			
		||||
            .replace(ICON_REGEX, "")
 | 
			
		||||
            .trim()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val name = "AralosBD"
 | 
			
		||||
    override val baseUrl = "https://aralosbd.fr"
 | 
			
		||||
    override val lang = "fr"
 | 
			
		||||
    override val supportsLatest = true
 | 
			
		||||
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
 | 
			
		||||
    override fun popularMangaRequest(page: Int): Request {
 | 
			
		||||
        // This is the search query used for the 'recommandations' in the front page
 | 
			
		||||
        return GET("$baseUrl/manga/search?s=sort:allviews;limit:16;-id:3", headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun popularMangaParse(response: Response): MangasPage {
 | 
			
		||||
        val searchResult = json.decodeFromString<AralosBDSearchResult>(response.body!!.string())
 | 
			
		||||
 | 
			
		||||
        return MangasPage(searchResult.mangas.map(::searchMangaToSManga), false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException("Not used.")
 | 
			
		||||
    override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException("Not used.")
 | 
			
		||||
 | 
			
		||||
    override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
 | 
			
		||||
        // For a basic search, we call the appropriate endpoint
 | 
			
		||||
        return GET("$baseUrl/manga/search?s=text:$query", headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun searchMangaParse(response: Response): MangasPage {
 | 
			
		||||
        val searchResult = json.decodeFromString<AralosBDSearchResult>(response.body!!.string())
 | 
			
		||||
 | 
			
		||||
        return MangasPage(searchResult.mangas.map(::searchMangaToSManga), false)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun mangaDetailsRequest(manga: SManga): Request {
 | 
			
		||||
        // This is a needed call, so the Tachiyomi user behave like a regular user
 | 
			
		||||
        // return GET(manga.url.replace("display?", "api?get=manga&"), headers)
 | 
			
		||||
        return GET(manga.url, headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun mangaDetailsParse(response: Response): SManga {
 | 
			
		||||
        val responseBody = client.newCall(GET(response.request.url.toString().replace("display?", "api?get=manga&"), headers)).execute().body
 | 
			
		||||
 | 
			
		||||
        val manga = json.decodeFromString<AralosBDManga>(responseBody!!.string())
 | 
			
		||||
 | 
			
		||||
        return SManga.create().apply {
 | 
			
		||||
            url = "$baseUrl/manga/display?id=${manga.id}"
 | 
			
		||||
            title = manga.main_title
 | 
			
		||||
            artist = "" // manga.authors.joinToString(", ")
 | 
			
		||||
            author = manga.authors?.joinToString(", ", transform = ::authorToString)
 | 
			
		||||
            description = cleanString("${manga.description}\n\n" + (manga.fulldescription ?: ""))
 | 
			
		||||
            status = 0 // This is not on the website
 | 
			
		||||
            genre = manga.tags?.joinToString(", ", transform = ::tagToString)
 | 
			
		||||
            thumbnail_url = "$baseUrl/${manga.icon}"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun chapterListRequest(manga: SManga): Request {
 | 
			
		||||
        return GET(manga.url.replace("display?id", "api?get=chapters&manga"), headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun chapterListParse(response: Response): List<SChapter> {
 | 
			
		||||
        val searchResult = json.decodeFromString<List<AralosBDChapter>>(response.body!!.string())
 | 
			
		||||
 | 
			
		||||
        val validSearchResults = mutableListOf<AralosBDChapter>()
 | 
			
		||||
        searchResult.filterTo(validSearchResults) { it.chapter_released == "1" }
 | 
			
		||||
 | 
			
		||||
        return validSearchResults.map(::chapterToSChapter)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun pageListRequest(chapter: SChapter): Request {
 | 
			
		||||
        return GET(chapter.url, headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun pageListParse(response: Response): List<Page> {
 | 
			
		||||
        val responseBody = client.newCall(GET(response.request.url.toString().replace("chapter?id", "api?get=pages&chapter"), headers)).execute().body
 | 
			
		||||
 | 
			
		||||
        val pageResult = json.decodeFromString<AralosBDPages>(responseBody!!.string())
 | 
			
		||||
 | 
			
		||||
        return pageResult.links.mapIndexed { index, link ->
 | 
			
		||||
            Page(
 | 
			
		||||
                index,
 | 
			
		||||
                "$baseUrl/$link",
 | 
			
		||||
                "$baseUrl/$link"
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Not used.")
 | 
			
		||||
 | 
			
		||||
    private fun authorToString(author: AralosBDAuthor) = author.name
 | 
			
		||||
    private fun translatorToString(translator: AralosBDTranslator) = translator.name
 | 
			
		||||
    private fun tagToString(tag: AralosBDTag) = tag.tag
 | 
			
		||||
 | 
			
		||||
    private fun searchMangaToSManga(manga: AralosBDSearchManga): SManga {
 | 
			
		||||
        return SManga.create().apply {
 | 
			
		||||
            // No need to trim, it's already done by the server
 | 
			
		||||
            title = manga.title
 | 
			
		||||
 | 
			
		||||
            // Just need to append the base url to the relative link returned
 | 
			
		||||
            thumbnail_url = "$baseUrl/${manga.icon}"
 | 
			
		||||
 | 
			
		||||
            // The url of the manga is simply based on the manga ID for now
 | 
			
		||||
            url = "$baseUrl/manga/display?id=${manga.id}"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun chapterToSChapter(chapter: AralosBDChapter): SChapter {
 | 
			
		||||
        return SChapter.create().apply {
 | 
			
		||||
            url = "$baseUrl/manga/chapter?id=${chapter.chapter_id}"
 | 
			
		||||
            name = chapter.chapter_number + " - " + chapter.chapter_title
 | 
			
		||||
            date_upload = try { DATE_FORMAT.parse(chapter.chapter_release_time)!!.time } catch (e: Exception) { System.currentTimeMillis() }
 | 
			
		||||
            // chapter_number = // This is a string and it can be 2.5.1 for example
 | 
			
		||||
            scanlator = chapter.chapter_translator
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||