Add ksp to generate MangaSource enum
parent
dd9ace35d1
commit
62e43c407a
@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id 'org.jetbrains.kotlin.jvm'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'com.google.devtools.ksp:symbol-processing-api:1.6.20-1.0.5'
|
||||||
|
}
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.ksp
|
||||||
|
|
||||||
|
import com.google.devtools.ksp.isAbstract
|
||||||
|
import com.google.devtools.ksp.processing.*
|
||||||
|
import com.google.devtools.ksp.symbol.ClassKind
|
||||||
|
import com.google.devtools.ksp.symbol.KSAnnotated
|
||||||
|
import com.google.devtools.ksp.symbol.KSClassDeclaration
|
||||||
|
import com.google.devtools.ksp.symbol.KSVisitorVoid
|
||||||
|
import com.google.devtools.ksp.validate
|
||||||
|
import java.io.Writer
|
||||||
|
|
||||||
|
class ParserProcessor(
|
||||||
|
private val codeGenerator: CodeGenerator,
|
||||||
|
private val logger: KSPLogger,
|
||||||
|
private val options: Map<String, String>,
|
||||||
|
) : SymbolProcessor {
|
||||||
|
|
||||||
|
override fun process(resolver: Resolver): List<KSAnnotated> {
|
||||||
|
val symbols = resolver
|
||||||
|
.getSymbolsWithAnnotation("org.koitharu.kotatsu.parsers.MangaSourceParser")
|
||||||
|
val ret = symbols.filterNot { it.validate() }.toList()
|
||||||
|
if (!symbols.iterator().hasNext()) {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
val dependencies = Dependencies.ALL_FILES
|
||||||
|
val factoryFile = try {
|
||||||
|
codeGenerator.createNewFile(
|
||||||
|
dependencies = dependencies,
|
||||||
|
packageName = "org.koitharu.kotatsu.parsers",
|
||||||
|
fileName = "MangaParserFactory",
|
||||||
|
)
|
||||||
|
} catch (e: FileAlreadyExistsException) {
|
||||||
|
logger.warn(e.toString(), null)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
val sourcesFile = try {
|
||||||
|
codeGenerator.createNewFile(
|
||||||
|
dependencies = dependencies,
|
||||||
|
packageName = "org.koitharu.kotatsu.parsers.model",
|
||||||
|
fileName = "MangaSource",
|
||||||
|
)
|
||||||
|
} catch (e: FileAlreadyExistsException) {
|
||||||
|
logger.warn(e.toString(), null)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
sourcesFile?.writer().use { sourcesWriter ->
|
||||||
|
factoryFile?.writer().use { factoryWriter ->
|
||||||
|
writeContent(sourcesWriter, factoryWriter, symbols)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeContent(
|
||||||
|
sourcesWriter: Writer?,
|
||||||
|
factoryWriter: Writer?,
|
||||||
|
symbols: Sequence<KSAnnotated>,
|
||||||
|
) {
|
||||||
|
if (sourcesWriter == null && factoryWriter == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
factoryWriter?.write(
|
||||||
|
"""
|
||||||
|
package org.koitharu.kotatsu.parsers
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
|
fun MangaSource.newParser(context: MangaLoaderContext): MangaParser = when (this) {
|
||||||
|
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
sourcesWriter?.write(
|
||||||
|
"""
|
||||||
|
package org.koitharu.kotatsu.parsers.model
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
|
enum class MangaSource(
|
||||||
|
val title: String,
|
||||||
|
val locale: String?,
|
||||||
|
) {
|
||||||
|
LOCAL("Local", null),
|
||||||
|
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
val visitor = ParserVisitor(sourcesWriter, factoryWriter)
|
||||||
|
symbols
|
||||||
|
.filter { it is KSClassDeclaration && it.validate() }
|
||||||
|
.forEach { it.accept(visitor, Unit) }
|
||||||
|
|
||||||
|
factoryWriter?.write(
|
||||||
|
"""
|
||||||
|
MangaSource.LOCAL -> throw NotImplementedError("Local manga parser is not supported")
|
||||||
|
}.also {
|
||||||
|
require(it.source == this) {
|
||||||
|
"Cannot instantiate manga parser: ${'$'}name mapped to ${'$'}{it.source}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
sourcesWriter?.write(
|
||||||
|
"""
|
||||||
|
;
|
||||||
|
}
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ParserVisitor(
|
||||||
|
private val sourcesWriter: Writer?,
|
||||||
|
private val factoryWriter: Writer?,
|
||||||
|
) : KSVisitorVoid() {
|
||||||
|
|
||||||
|
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
|
||||||
|
if (classDeclaration.classKind != ClassKind.CLASS || classDeclaration.isAbstract()) {
|
||||||
|
logger.error("Only non-abstract can be annotated with @MangaSourceParser", classDeclaration)
|
||||||
|
}
|
||||||
|
val annotation = classDeclaration.annotations.single { it.shortName.asString() == "MangaSourceParser" }
|
||||||
|
val name = annotation.arguments.single { it.name?.asString() == "name" }.value as String
|
||||||
|
val title = annotation.arguments.single { it.name?.asString() == "title" }.value as String
|
||||||
|
val locale = annotation.arguments.single { it.name?.asString() == "locale" }.value as String
|
||||||
|
val localeString = if (locale.isEmpty()) "null" else "\"$locale\""
|
||||||
|
|
||||||
|
if (name.any { it.isLowerCase() }) {
|
||||||
|
logger.error("Manga source name must be uppercase: $name")
|
||||||
|
}
|
||||||
|
|
||||||
|
val constructor = classDeclaration.primaryConstructor
|
||||||
|
if (constructor == null || constructor.parameters.count { !it.hasDefault } != 1) {
|
||||||
|
logger.error(
|
||||||
|
"Class with @MangaSourceParser must have a primary constructor with one parameter",
|
||||||
|
classDeclaration,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val className = classDeclaration.qualifiedName?.asString()
|
||||||
|
factoryWriter?.write("\tMangaSource.$name -> $className(context)\n")
|
||||||
|
sourcesWriter?.write("\t$name(\"$title\", $localeString),\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.ksp
|
||||||
|
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessor
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
|
||||||
|
import com.google.devtools.ksp.processing.SymbolProcessorProvider
|
||||||
|
|
||||||
|
class ParserProcessorProvider : SymbolProcessorProvider {
|
||||||
|
|
||||||
|
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
|
||||||
|
return ParserProcessor(
|
||||||
|
codeGenerator = environment.codeGenerator,
|
||||||
|
logger = environment.logger,
|
||||||
|
options = environment.options
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
org.koitharu.kotatsu.parsers.ksp.ParserProcessorProvider
|
||||||
@ -1,3 +1,22 @@
|
|||||||
|
pluginManagement {
|
||||||
|
plugins {
|
||||||
|
id 'com.google.devtools.ksp' version '1.6.21-1.0.5'
|
||||||
|
id 'org.jetbrains.kotlin.jvm' version '1.6.21'
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
google()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rootProject.name = 'kotatsu-parsers'
|
rootProject.name = 'kotatsu-parsers'
|
||||||
|
include 'kotatsu-parsers-ksp'
|
||||||
|
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.parsers
|
|
||||||
|
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
|
||||||
import org.koitharu.kotatsu.parsers.site.*
|
|
||||||
|
|
||||||
fun MangaSource.newParser(context: MangaLoaderContext): MangaParser = when (this) {
|
|
||||||
MangaSource.READMANGA_RU -> ReadmangaParser(context)
|
|
||||||
MangaSource.MINTMANGA -> MintMangaParser(context)
|
|
||||||
MangaSource.SELFMANGA -> SelfMangaParser(context)
|
|
||||||
MangaSource.MANGACHAN -> MangaChanParser(context)
|
|
||||||
MangaSource.DESUME -> DesuMeParser(context)
|
|
||||||
MangaSource.HENCHAN -> HenChanParser(context)
|
|
||||||
MangaSource.YAOICHAN -> YaoiChanParser(context)
|
|
||||||
MangaSource.MANGATOWN -> MangaTownParser(context)
|
|
||||||
MangaSource.MANGALIB -> MangaLibParser(context)
|
|
||||||
MangaSource.NUDEMOON -> NudeMoonParser(context)
|
|
||||||
MangaSource.MANGAREAD -> MangareadParser(context)
|
|
||||||
MangaSource.REMANGA -> RemangaParser(context)
|
|
||||||
MangaSource.HENTAILIB -> HentaiLibParser(context)
|
|
||||||
MangaSource.ANIBEL -> AnibelParser(context)
|
|
||||||
MangaSource.NINEMANGA_EN -> NineMangaParser.English(context)
|
|
||||||
MangaSource.NINEMANGA_ES -> NineMangaParser.Spanish(context)
|
|
||||||
MangaSource.NINEMANGA_RU -> NineMangaParser.Russian(context)
|
|
||||||
MangaSource.NINEMANGA_DE -> NineMangaParser.Deutsch(context)
|
|
||||||
MangaSource.NINEMANGA_IT -> NineMangaParser.Italiano(context)
|
|
||||||
MangaSource.NINEMANGA_BR -> NineMangaParser.Brazil(context)
|
|
||||||
MangaSource.NINEMANGA_FR -> NineMangaParser.Francais(context)
|
|
||||||
MangaSource.EXHENTAI -> ExHentaiParser(context)
|
|
||||||
MangaSource.MANGAOWL -> MangaOwlParser(context)
|
|
||||||
MangaSource.MANGADEX -> MangaDexParser(context)
|
|
||||||
MangaSource.BATOTO -> BatoToParser(context)
|
|
||||||
MangaSource.COMICK_FUN -> ComickFunParser(context)
|
|
||||||
MangaSource.LOCAL -> throw NotImplementedError("Local manga parser is not supported")
|
|
||||||
}.also {
|
|
||||||
require(it.source == this) {
|
|
||||||
"Cannot instantiate manga parser: $name mapped to ${it.source}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
annotation class MangaSourceParser(
|
||||||
|
val name: String,
|
||||||
|
val title: String,
|
||||||
|
val locale: String = "",
|
||||||
|
)
|
||||||
@ -1,36 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.parsers.model
|
|
||||||
|
|
||||||
@Suppress("SpellCheckingInspection")
|
|
||||||
enum class MangaSource(
|
|
||||||
val title: String,
|
|
||||||
val locale: String?,
|
|
||||||
) {
|
|
||||||
LOCAL("Local", null),
|
|
||||||
READMANGA_RU("ReadManga", "ru"),
|
|
||||||
MINTMANGA("MintManga", "ru"),
|
|
||||||
SELFMANGA("SelfManga", "ru"),
|
|
||||||
MANGACHAN("Манга-тян", "ru"),
|
|
||||||
DESUME("Desu.me", "ru"),
|
|
||||||
HENCHAN("Хентай-тян", "ru"),
|
|
||||||
YAOICHAN("Яой-тян", "ru"),
|
|
||||||
MANGATOWN("MangaTown", "en"),
|
|
||||||
MANGALIB("MangaLib", "ru"),
|
|
||||||
NUDEMOON("Nude-Moon", "ru"),
|
|
||||||
MANGAREAD("MangaRead", "en"),
|
|
||||||
REMANGA("Remanga", "ru"),
|
|
||||||
HENTAILIB("HentaiLib", "ru"),
|
|
||||||
ANIBEL("Anibel", "be"),
|
|
||||||
NINEMANGA_EN("NineManga English", "en"),
|
|
||||||
NINEMANGA_ES("NineManga Español", "es"),
|
|
||||||
NINEMANGA_RU("NineManga Русский", "ru"),
|
|
||||||
NINEMANGA_DE("NineManga Deutsch", "de"),
|
|
||||||
NINEMANGA_IT("NineManga Italiano", "it"),
|
|
||||||
NINEMANGA_BR("NineManga Brasil", "pt"),
|
|
||||||
NINEMANGA_FR("NineManga Français", "fr"),
|
|
||||||
EXHENTAI("ExHentai", null),
|
|
||||||
MANGAOWL("MangaOwl", "en"),
|
|
||||||
MANGADEX("MangaDex", null),
|
|
||||||
BATOTO("Bato.To", null),
|
|
||||||
COMICK_FUN("ComicK", null),
|
|
||||||
;
|
|
||||||
}
|
|
||||||
@ -1,9 +1,11 @@
|
|||||||
package org.koitharu.kotatsu.parsers.site
|
package org.koitharu.kotatsu.parsers.site
|
||||||
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
|
@MangaSourceParser("MANGACHAN", "Манга-тян", "ru")
|
||||||
internal class MangaChanParser(override val context: MangaLoaderContext) : ChanParser(MangaSource.MANGACHAN) {
|
internal class MangaChanParser(override val context: MangaLoaderContext) : ChanParser(MangaSource.MANGACHAN) {
|
||||||
|
|
||||||
override val configKeyDomain = ConfigKey.Domain("manga-chan.me", null)
|
override val configKeyDomain = ConfigKey.Domain("manga-chan.me", null)
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package org.koitharu.kotatsu.parsers.site
|
package org.koitharu.kotatsu.parsers.site
|
||||||
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
|
@MangaSourceParser("MINTMANGA", "MintManga", "ru")
|
||||||
internal class MintMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.MINTMANGA) {
|
internal class MintMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.MINTMANGA) {
|
||||||
|
|
||||||
override val configKeyDomain = ConfigKey.Domain("mintmanga.live", null)
|
override val configKeyDomain = ConfigKey.Domain("mintmanga.live", null)
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package org.koitharu.kotatsu.parsers.site
|
package org.koitharu.kotatsu.parsers.site
|
||||||
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
|
@MangaSourceParser("READMANGA_RU", "ReadManga", "ru")
|
||||||
internal class ReadmangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.READMANGA_RU) {
|
internal class ReadmangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.READMANGA_RU) {
|
||||||
|
|
||||||
override val configKeyDomain = ConfigKey.Domain("readmanga.io", null)
|
override val configKeyDomain = ConfigKey.Domain("readmanga.io", null)
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package org.koitharu.kotatsu.parsers.site
|
package org.koitharu.kotatsu.parsers.site
|
||||||
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
|
@MangaSourceParser("SELFMANGA", "SelfManga", "ru")
|
||||||
internal class SelfMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.SELFMANGA) {
|
internal class SelfMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.SELFMANGA) {
|
||||||
|
|
||||||
override val configKeyDomain = ConfigKey.Domain("selfmanga.live", null)
|
override val configKeyDomain = ConfigKey.Domain("selfmanga.live", null)
|
||||||
|
|||||||
Loading…
Reference in New Issue