diff --git a/src/all/lanraragi/build.gradle b/src/all/lanraragi/build.gradle new file mode 100644 index 000000000..25a6f2a75 --- /dev/null +++ b/src/all/lanraragi/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + appName = 'Tachiyomi: LANraragi' + pkgNameSuffix = 'all.lanraragi' + extClass = '.LANraragi' + extVersionCode = 1 + libVersion = '1.2' +} + +dependencies { + compileOnly project(':preference-stub') + + compileOnly 'com.github.inorichi.injekt:injekt-core:65b0440' + + compileOnly 'com.google.code.gson:gson:2.8.2' + compileOnly 'com.github.salomonbrys.kotson:kotson:2.5.0' +} + +apply from: "$rootDir/common.gradle" diff --git a/src/all/lanraragi/res/mipmap-hdpi/ic_launcher.png b/src/all/lanraragi/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..fd5da2645 Binary files /dev/null and b/src/all/lanraragi/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/all/lanraragi/res/mipmap-mdpi/ic_launcher.png b/src/all/lanraragi/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..d6c4ff69b Binary files /dev/null and b/src/all/lanraragi/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/all/lanraragi/res/mipmap-xhdpi/ic_launcher.png b/src/all/lanraragi/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..8e4b170b5 Binary files /dev/null and b/src/all/lanraragi/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/all/lanraragi/res/mipmap-xxhdpi/ic_launcher.png b/src/all/lanraragi/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..083804647 Binary files /dev/null and b/src/all/lanraragi/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/all/lanraragi/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/lanraragi/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..fae8e4285 Binary files /dev/null and b/src/all/lanraragi/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/all/lanraragi/res/web_hi_res_512.png b/src/all/lanraragi/res/web_hi_res_512.png new file mode 100644 index 000000000..0ddd28e9b Binary files /dev/null and b/src/all/lanraragi/res/web_hi_res_512.png differ diff --git a/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/LANraragi.kt b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/LANraragi.kt new file mode 100644 index 000000000..d5c2fdd27 --- /dev/null +++ b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/LANraragi.kt @@ -0,0 +1,257 @@ +package eu.kanade.tachiyomi.extension.all.lanraragi + +import android.app.Application +import android.content.SharedPreferences +import android.net.Uri +import android.support.v7.preference.EditTextPreference +import android.support.v7.preference.PreferenceScreen +import com.github.salomonbrys.kotson.fromJson +import com.google.gson.Gson +import eu.kanade.tachiyomi.extension.all.lanraragi.model.ArchivePage +import eu.kanade.tachiyomi.extension.all.lanraragi.model.ArchiveSearchResult +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.ConfigurableSource +import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.online.HttpSource +import okhttp3.Request +import okhttp3.Response +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +open class LANraragi : ConfigurableSource, HttpSource() { + + override val baseUrl: String + get() = preferences.getString("hostname", "http://127.0.0.1:3000")!! + + override val lang = "all" + + override val name = "LANraragi" + + override val supportsLatest = true + + private val apiKey: String + get() = preferences.getString("apiKey", "")!! + + private val gson: Gson = Gson() + + override fun mangaDetailsParse(response: Response): SManga { + val id = getId(response) + + return SManga.create().apply { + thumbnail_url = getThumbnailUri(id) + } + } + + override fun chapterListParse(response: Response): List { + val id = getId(response) + + val uri = getApiUriBuilder("/api/extract") + uri.appendQueryParameter("id", id) + + return listOf( + SChapter.create().apply { + val uriBuild = uri.build() + + url = "${uriBuild.encodedPath}?${uriBuild.encodedQuery}" + chapter_number = 1F + name = "Chapter" + }) + } + + override fun pageListParse(response: Response): List { + val archivePage = gson.fromJson(response.body()!!.string()) + + return archivePage.pages.mapIndexed { index, url -> + val uri = Uri.parse("${baseUrl}${url.trimStart('.')}") + Page(index, uri.toString(), uri.toString(), uri) + } + } + + override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("imageUrlParse is unused") + + override fun popularMangaRequest(page: Int): Request { + return searchMangaRequest(page, "", FilterList()) + } + + override fun popularMangaParse(response: Response): MangasPage { + return searchMangaParse(response) + } + + override fun latestUpdatesRequest(page: Int): Request { + return searchMangaRequest(page, "", FilterList()) + } + + override fun latestUpdatesParse(response: Response): MangasPage { + return searchMangaParse(response) + } + + private var lastResultCount: Int = 100 + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val uri = getApiUriBuilder("/api/search") + uri.appendQueryParameter("start", ((page - 1) * lastResultCount).toString()) + + if (query.isNotEmpty()) { + uri.appendQueryParameter("filter", query) + } + + return GET(uri.toString()) + } + + override fun searchMangaParse(response: Response): MangasPage { + val jsonResult = gson.fromJson(response.body()!!.string()) + val currentStart = getStart(response) + + lastResultCount = jsonResult.data.size + + return MangasPage( + jsonResult.data.map { + SManga.create().apply { + url = "/reader?id=${it.arcid}" + title = it.title + thumbnail_url = getThumbnailUri(it.arcid) + genre = it.tags + artist = getArtist(it.tags) + author = artist + } + }, currentStart + jsonResult.data.size < jsonResult.recordsFiltered) + } + + // Preferences + private val preferences: SharedPreferences by lazy { + Injekt.get().getSharedPreferences("source_$id", 0x0000) + } + + override fun setupPreferenceScreen(screen: PreferenceScreen) { + val hostnamePref = EditTextPreference(screen.context).apply { + key = "Hostname" + title = "Hostname" + text = baseUrl + summary = baseUrl + dialogTitle = "Hostname" + + setOnPreferenceChangeListener { _, newValue -> + var hostname = newValue as String + if (!hostname.startsWith("http://") && !hostname.startsWith("https://")) { + hostname = "http://$hostname" + } + + this.apply { + text = hostname + summary = hostname + } + + preferences.edit().putString("hostname", hostname).commit() + } + } + + val apiKeyPref = EditTextPreference(screen.context).apply { + key = "API Key" + title = "API Key" + text = apiKey + summary = apiKey + dialogTitle = "API Key" + + setOnPreferenceChangeListener { _, newValue -> + val apiKey = newValue as String + + this.apply { + text = apiKey + summary = apiKey + } + + preferences.edit().putString("apiKey", newValue).commit() + } + } + + screen.addPreference(hostnamePref) + screen.addPreference(apiKeyPref) + } + + override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) { + val hostnamePref = androidx.preference.EditTextPreference(screen.context).apply { + key = "Hostname" + title = "Hostname" + text = baseUrl + summary = baseUrl + dialogTitle = "Hostname" + + setOnPreferenceChangeListener { _, newValue -> + var hostname = newValue as String + if (!hostname.startsWith("http://") && !hostname.startsWith("https://")) { + hostname = "http://$hostname" + } + + this.apply { + text = hostname + summary = hostname + } + + preferences.edit().putString("hostname", hostname).commit() + } + } + + val apiKeyPref = androidx.preference.EditTextPreference(screen.context).apply { + key = "API Key" + title = "API Key" + text = apiKey + summary = apiKey + dialogTitle = "API Key" + + setOnPreferenceChangeListener { _, newValue -> + val apiKey = newValue as String + + this.apply { + text = apiKey + summary = apiKey + } + + preferences.edit().putString("apiKey", newValue).commit() + } + } + + screen.addPreference(hostnamePref) + screen.addPreference(apiKeyPref) + } + + // Helper + private fun getApiUriBuilder(path: String): Uri.Builder { + val uri = Uri.parse("$baseUrl$path").buildUpon() + if (apiKey.isNotEmpty()) { + uri.appendQueryParameter("key", apiKey) + } + + return uri + } + + private fun getThumbnailUri(id: String): String { + val uri = getApiUriBuilder("/api/thumbnail") + uri.appendQueryParameter("id", id) + + return uri.toString() + } + + private fun getTopResponse(response: Response): Response { + return if (response.priorResponse() == null) response else getTopResponse(response.priorResponse()!!) + } + + private fun getId(response: Response): String { + return getTopResponse(response).request().url().queryParameter("id").toString() + } + + private fun getStart(response: Response): Int { + return getTopResponse(response).request().url().queryParameter("start")!!.toInt() + } + + private fun getArtist(tags: String): String { + tags.split(',').forEach { + if (it.contains(':')) { + val temp = it.trim().split(':') + + if (temp[0].equals("artist", true)) return temp[1] + } + } + + return "N/A" + } +} diff --git a/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/Archive.kt b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/Archive.kt new file mode 100644 index 000000000..4e507ba0e --- /dev/null +++ b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/Archive.kt @@ -0,0 +1,8 @@ +package eu.kanade.tachiyomi.extension.all.lanraragi.model + +data class Archive( + val arcid: String, + val isnew: String, + val tags: String, + val title: String +) diff --git a/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/ArchivePage.kt b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/ArchivePage.kt new file mode 100644 index 000000000..b620ca4e1 --- /dev/null +++ b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/ArchivePage.kt @@ -0,0 +1,5 @@ +package eu.kanade.tachiyomi.extension.all.lanraragi.model + +data class ArchivePage( + val pages: List +) diff --git a/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/ArchiveSearchResult.kt b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/ArchiveSearchResult.kt new file mode 100644 index 000000000..c9046f18f --- /dev/null +++ b/src/all/lanraragi/src/eu/kanade/tachiyomi/extension/all/lanraragi/model/ArchiveSearchResult.kt @@ -0,0 +1,8 @@ +package eu.kanade.tachiyomi.extension.all.lanraragi.model + +data class ArchiveSearchResult( + val data: List, + val draw: Int, + val recordsFiltered: Int, + val recordsTotal: Int +)