* lynxscans

* Update src/en/lynxscans/src/eu/kanade/tachiyomi/extension/en/lynxscans/LynxScans.kt

Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>

* Update src/en/lynxscans/build.gradle

Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>

* throw exception on search

* use better icon

---------

Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>
This commit is contained in:
Henrik 2023-04-04 17:38:27 +02:00 committed by GitHub
parent f07b951326
commit 373b9cf4ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 254 additions and 0 deletions

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension" />

View File

@ -0,0 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'LynxScans'
pkgNameSuffix = 'en.lynxscans'
extClass = '.LynxScans'
extVersionCode = 7
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -0,0 +1,130 @@
package eu.kanade.tachiyomi.extension.en.lynxscans
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.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
class LynxScans : HttpSource() {
override val baseUrl: String = "https://lynxscans.com"
private val apiUrl: String = "https://api.lynxscans.com/api"
override val lang: String = "en"
override val name: String = "LynxScans"
override val versionId = 2
override val supportsLatest: Boolean = true
private val json: Json by injectLazy()
// Popular
override fun popularMangaRequest(page: Int): Request {
return GET("$apiUrl/comics?page=$page", headers)
}
override fun popularMangaParse(response: Response): MangasPage {
val data = json.decodeFromString<Popular>(response.body.string())
val titles = data.comics.data.map(PopularComicsData::toSManga)
return MangasPage(titles, !data.comics.next_page_url.isNullOrEmpty())
}
// Latest
override fun latestUpdatesRequest(page: Int): Request {
return GET("$apiUrl/latest?page=$page", headers)
}
override fun latestUpdatesParse(response: Response): MangasPage {
val data = json.decodeFromString<Latest>(response.body.string())
val titles = data.chapters.data.distinctBy { it.comic_titleSlug }.map(LatestChaptersData::toSManga)
return MangasPage(titles, !data.chapters.next_page_url.isNullOrEmpty())
}
// Search
override fun searchMangaParse(response: Response): MangasPage {
throw UnsupportedOperationException("Not used")
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
throw Exception("Search is not supported")
}
// Details
override fun mangaDetailsParse(response: Response): SManga {
val data = json.decodeFromString<MangaDetails>(response.body.string())
return data.comic.toSManga()
}
override fun mangaDetailsRequest(manga: SManga): Request {
val titleId = manga.url.substringAfterLast("/")
return GET("$apiUrl/comics/$titleId", headers)
}
override fun getMangaUrl(manga: SManga): String {
val titleId = manga.url.substringAfterLast("/")
return "$baseUrl/comics/$titleId"
}
// Chapters
override fun chapterListRequest(manga: SManga): Request {
return mangaDetailsRequest(manga)
}
override fun chapterListParse(response: Response): List<SChapter> {
val data = json.decodeFromString<MangaDetails>(response.body.string())
val chapters: MutableList<SChapter> = mutableListOf()
data.comic.volumes.forEach { volume ->
volume.chapters.forEach { chapter ->
chapters.add(
SChapter.create().apply {
url = "/comics/${data.comic.titleSlug}/volume/${volume.number}/chapter/${chapter.number}"
name = volume.name + " " + (if (!chapter.name.contains("chapter", true)) "Chapter ${chapter.number} " else "") + chapter.name
},
)
}
}
return chapters
}
override fun getChapterUrl(chapter: SChapter): String {
val chapterPath = chapter.url.substringAfter("/")
return "$baseUrl/$chapterPath"
}
// Page
override fun pageListRequest(chapter: SChapter): Request {
val chapterPath = chapter.url.substringAfter("/")
return GET("$apiUrl/$chapterPath", headers)
}
override fun pageListParse(response: Response): List<Page> {
val data = json.decodeFromString<PageList>(response.body.string())
return data.pages.mapIndexed { idx, it ->
Page(idx, imageUrl = it.thumb)
}
}
// Unused
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not Used")
}

View File

@ -0,0 +1,110 @@
package eu.kanade.tachiyomi.extension.en.lynxscans
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.Serializable
@Serializable
data class Latest(
val chapters: LatestChapters,
)
@Serializable
data class LatestChapters(
val next_page_url: String?,
val data: List<LatestChaptersData>,
)
@Serializable
data class LatestChaptersData(
val comic_title: String,
val comic_thumb: String,
val comic_titleSlug: String,
) {
fun toSManga(): SManga = SManga.create().apply {
title = this@LatestChaptersData.comic_title
thumbnail_url = this@LatestChaptersData.comic_thumb
url = "/comics/" + this@LatestChaptersData.comic_titleSlug
}
}
@Serializable
data class Popular(
val comics: PopularComics,
)
@Serializable
data class PopularComics(
val next_page_url: String?,
val data: List<PopularComicsData>,
)
@Serializable
data class PopularComicsData(
val title: String,
val thumb: String,
val titleSlug: String,
) {
fun toSManga(): SManga = SManga.create().apply {
title = this@PopularComicsData.title
thumbnail_url = this@PopularComicsData.thumb
url = "/comics/" + this@PopularComicsData.titleSlug
}
}
@Serializable
data class MangaDetails(
val comic: MangaDetailsComicData,
)
@Serializable
data class MangaDetailsComicData(
val title: String,
val thumb: String,
val titleSlug: String,
val artist: String,
val author: String,
val description: String,
val tags: List<MangaDetailsTag>,
val volumes: List<MangaDetailsVolume>,
) {
fun toSManga(): SManga = SManga.create().apply {
title = this@MangaDetailsComicData.title
thumbnail_url = this@MangaDetailsComicData.thumb
url = "/comics/" + this@MangaDetailsComicData.titleSlug
author = if (this@MangaDetailsComicData.author != "blank") this@MangaDetailsComicData.author else null
artist = if (this@MangaDetailsComicData.artist != "blank") this@MangaDetailsComicData.artist else null
description = this@MangaDetailsComicData.description
genre = this@MangaDetailsComicData.tags.joinToString { it.name }
status = SManga.UNKNOWN
}
}
@Serializable
data class MangaDetailsTag(
val name: String,
)
@Serializable
data class MangaDetailsVolume(
val chapters: List<MangaDetailsChapter>,
val name: String,
val number: Int,
)
@Serializable
data class MangaDetailsChapter(
val name: String,
val number: Int,
)
@Serializable
data class PageList(
val pages: List<Page>,
)
@Serializable
data class Page(
val thumb: String,
)