diff --git a/src/en/solarandsundry/AndroidManifest.xml b/src/en/solarandsundry/AndroidManifest.xml new file mode 100644 index 000000000..30deb7f79 --- /dev/null +++ b/src/en/solarandsundry/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/src/en/solarandsundry/build.gradle b/src/en/solarandsundry/build.gradle new file mode 100644 index 000000000..c323274de --- /dev/null +++ b/src/en/solarandsundry/build.gradle @@ -0,0 +1,11 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + extName = 'Solar and Sundry' + pkgNameSuffix = 'en.solarandsundry' + extClass = '.SolarAndSundry' + extVersionCode = 1 +} + +apply from: "$rootDir/common.gradle" diff --git a/src/en/solarandsundry/res/mipmap-hdpi/ic_launcher.png b/src/en/solarandsundry/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..3511d702d Binary files /dev/null and b/src/en/solarandsundry/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/en/solarandsundry/res/mipmap-mdpi/ic_launcher.png b/src/en/solarandsundry/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..4234086c5 Binary files /dev/null and b/src/en/solarandsundry/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/en/solarandsundry/res/mipmap-xhdpi/ic_launcher.png b/src/en/solarandsundry/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..50ccc5191 Binary files /dev/null and b/src/en/solarandsundry/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/en/solarandsundry/res/mipmap-xxhdpi/ic_launcher.png b/src/en/solarandsundry/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..8ea09c2f0 Binary files /dev/null and b/src/en/solarandsundry/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/en/solarandsundry/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/solarandsundry/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..0a098cfa9 Binary files /dev/null and b/src/en/solarandsundry/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/en/solarandsundry/res/web_hi_res_512.png b/src/en/solarandsundry/res/web_hi_res_512.png new file mode 100644 index 000000000..ef027088e Binary files /dev/null and b/src/en/solarandsundry/res/web_hi_res_512.png differ diff --git a/src/en/solarandsundry/src/eu/kanade/tachiyomi/extension/en/solarandsundry/SolarAndSundry.kt b/src/en/solarandsundry/src/eu/kanade/tachiyomi/extension/en/solarandsundry/SolarAndSundry.kt new file mode 100644 index 000000000..894c27e09 --- /dev/null +++ b/src/en/solarandsundry/src/eu/kanade/tachiyomi/extension/en/solarandsundry/SolarAndSundry.kt @@ -0,0 +1,134 @@ +package eu.kanade.tachiyomi.extension.en.solarandsundry + +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 okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import org.json.JSONArray +import org.json.JSONObject +import rx.Observable +import java.text.SimpleDateFormat +import java.util.Locale + +private const val ACCEPT_IMAGE = "image/avif,image/webp,image/*,*/*" + +private const val ARCHIVE_URL = "https://sas.ewanb.me" + +class SolarAndSundry : HttpSource() { + + override val name = "Solar and Sundry" + + override val baseUrl = "https://solar-and-sundry-worker.giraugh.workers.dev" + + override val lang = "en" + + override val supportsLatest = false + + override val client: OkHttpClient = network.cloudflareClient + + private fun createManga(): SManga { + return SManga.create().apply { + title = "Solar and Sundry" + url = "/chapter" + author = "Ewan Breakey" + artist = author + status = SManga.ONGOING + description = "a sci-fi webcomic about creating an ecosystem where there shouldn't be one" + thumbnail_url = "https://imagedelivery.net/zthi1l8fKrUGB5ig08mq-Q/4b15df30-85c7-429e-d062-bf1d19f0fd00/public" + } + } + + private val imgHeaders by lazy { + headersBuilder().set("Accept", ACCEPT_IMAGE).build() + } + + private fun parseDate(dateStr: String): Long { + return runCatching { DATE_FORMATTER.parse(dateStr)?.time } + .getOrNull() ?: 0L + } + + companion object { + private val DATE_FORMATTER by lazy { + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH) + } + } + + // Popular + + override fun fetchPopularManga(page: Int): Observable { + return Observable.just(MangasPage(listOf(createManga()), false)) + } + + override fun popularMangaRequest(page: Int): Request = throw UnsupportedOperationException("Not used") + + override fun popularMangaParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used") + + // Latest + + override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException("Not used") + + override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used") + + // Search + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable = Observable.just(MangasPage(emptyList(), false)) + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException("Not used") + + override fun searchMangaParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used") + + // Details + + override fun fetchMangaDetails(manga: SManga): Observable { + return Observable.just(createManga().apply { initialized = true }) + } + + override fun mangaDetailsParse(response: Response): SManga = throw UnsupportedOperationException("Not used") + + override fun getMangaUrl(manga: SManga): String { + return ARCHIVE_URL + } + + // Chapters + + override fun chapterListParse(response: Response): List { + val chapters = JSONArray(response.body.string()) + val pages = ArrayList() + for (i in 0 until chapters.length()) { + val chapterPages = chapters.getJSONObject(i).getJSONArray("pages") + for (j in 0 until chapterPages.length()) { + pages.add(chapterPages.getJSONObject(j)) + } + } + return pages.map { page -> + SChapter.create().apply { + name = page.getString("name") + setUrlWithoutDomain(baseUrl + "/page/" + page.getInt("page_number")) + chapter_number = page.getInt("page_number").toFloat() + date_upload = parseDate(page.getString("published_at")) + } + }.reversed() + } + + override fun getChapterUrl(chapter: SChapter): String { + return ARCHIVE_URL + "/comic/" + chapter.chapter_number + } + + // Pages + + override fun pageListParse(response: Response): List { + val page = JSONObject(response.body.string()) + + return listOf(Page(0, "", page.getString("image_url"))) + } + + override fun imageRequest(page: Page) = GET(page.imageUrl!!, imgHeaders) + + override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used") +}