Sandraandwoo (#12949)

* Add Sandra and Woo source

* Simplify numbering in chapter titles

* Override mangaDetailsParse to prevent the exception being thrown

* Make source class abstract, have English source derive from it

* Change cover art to one I like a little more

* Update publication status based on comments on the most recent chapter

Co-authored-by: Khuldraeseth <khuldraeseth@gmail.com>
This commit is contained in:
khuldraeseth 2022-08-15 09:53:47 -07:00 committed by GitHub
parent 17e9e56d79
commit 10dccd46b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 198 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 = 'Sandra and Woo'
pkgNameSuffix = 'all.sandraandwoo'
extClass = '.SandraAndWooFactory'
extVersionCode = 1
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 KiB

View File

@ -0,0 +1,142 @@
package eu.kanade.tachiyomi.extension.all.sandraandwoo
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.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.net.URI
import java.text.SimpleDateFormat
import java.util.Locale
import kotlin.math.floor
abstract class SandraAndWoo(
final override val baseUrl: String = "http://www.sandraandwoo.com",
final override val lang: String,
) : ParsedHttpSource() {
override val supportsLatest = false
protected abstract val writer: String
protected abstract val illustrator: String
protected abstract val synopsis: String
protected abstract val genres: String
protected abstract val state: Int
protected abstract val thumbnail: String
protected abstract val archive: String
private val manga: SManga
get() = SManga.create().apply {
title = name
artist = illustrator
author = writer
description = synopsis
genre = genres
status = state
thumbnail_url = thumbnail
setUrlWithoutDomain(archive)
}
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
val mangasPage = MangasPage(listOf(manga), false)
return Observable.just(mangasPage)
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
Observable.just(MangasPage(emptyList(), false))!!
override fun chapterListSelector() = "#column a"
private fun roundHalfwayUp(x: Float) = (x + floor(x + 1)) / 2
private fun chapterParse(element: Element, lastChapterNumber: Float): Pair<Float, SChapter> {
val path = URI(element.attr("href")).path
val dateMatch = CHAPTER_DATE_REGEX.matchEntire(path)!!
val (_, year, month, day) = dateMatch.groupValues
val date = "$year-$month-$day".timestamp()
val hover = element.attr("title")
val titleMatch = CHAPTER_TITLE_REGEX.matchEntire(hover)!!
val (_, title, number, backupNumber) = titleMatch.groupValues
val chapterNumber =
if (number.isNotEmpty()) number.toFloat()
else if (backupNumber.isNotEmpty()) backupNumber.toFloat()
else roundHalfwayUp(lastChapterNumber)
val chapter = SChapter.create().apply {
url = path
name = title
chapter_number = chapterNumber
date_upload = date
}
return Pair(chapterNumber, chapter)
}
private fun chapterListParse(document: Document): List<SChapter> {
val elements = document.select(chapterListSelector()).reversed()
val initial = Pair(0f, SChapter.create())
return elements.runningFold(initial) { previous, element ->
chapterParse(element, previous.first)
}.drop(1).map { it.second }.reversed()
}
override fun chapterListParse(response: Response) = chapterListParse(response.asJsoup())
private fun pageImageSelector() = "#comic img"
override fun pageListParse(document: Document): List<Page> {
val img = document.selectFirst(pageImageSelector())
val path = img.attr("src")
return listOf(Page(0, "", "${baseUrl}$path"))
}
override fun mangaDetailsParse(document: Document) = manga
// <editor-fold desc="not used">
override fun chapterFromElement(element: Element) = throw Exception("Not used")
override fun imageUrlParse(document: Document) = throw Exception("Not used")
override fun latestUpdatesFromElement(element: Element) = throw Exception("Not used")
override fun latestUpdatesNextPageSelector() = throw Exception("Not used")
override fun latestUpdatesRequest(page: Int) = throw Exception("Not used")
override fun latestUpdatesSelector() = throw Exception("Not used")
override fun popularMangaFromElement(element: Element) = throw Exception("Not used")
override fun popularMangaNextPageSelector() = throw Exception("Not used")
override fun popularMangaRequest(page: Int) = throw Exception("Not used")
override fun popularMangaSelector() = throw Exception("Not used")
override fun searchMangaFromElement(element: Element) = throw Exception("Not used")
override fun searchMangaNextPageSelector() = throw Exception("Not used")
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw Exception("Not used")
override fun searchMangaSelector() = throw Exception("Not used")
// </editor-fold>
private fun String.timestamp() = DATE_FORMAT.parse(this)?.time ?: 0L
companion object {
private val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
private val CHAPTER_DATE_REGEX = Regex(""".*/(\d+)/(\d+)/(\d+)/[^/]*/""")
private val CHAPTER_TITLE_REGEX = Regex("""Permanent Link:\s*((?:\[(\d{4})])?\s*(?:\[[^]]*(\d{4})])?.*)""")
}
}

View File

@ -0,0 +1,12 @@
package eu.kanade.tachiyomi.extension.all.sandraandwoo
import eu.kanade.tachiyomi.extension.all.sandraandwoo.translations.SandraAndWooDE
import eu.kanade.tachiyomi.extension.all.sandraandwoo.translations.SandraAndWooEN
import eu.kanade.tachiyomi.source.SourceFactory
class SandraAndWooFactory : SourceFactory {
override fun createSources() = listOf(
SandraAndWooDE(),
SandraAndWooEN(),
)
}

View File

@ -0,0 +1,15 @@
package eu.kanade.tachiyomi.extension.all.sandraandwoo.translations
import eu.kanade.tachiyomi.extension.all.sandraandwoo.SandraAndWoo
import eu.kanade.tachiyomi.source.model.SManga
class SandraAndWooDE : SandraAndWoo(lang = "de") {
override val name = "Sandra und Woo"
override val writer = "Oliver Knörzer"
override val illustrator = "Powree"
override val synopsis = "Sandra und Woo ist ein Comedy-Webcomic mit dem zwölfjährigen Mädchen Sandra North und ihrem Waschbären Woo in den Hauptrollen. Zwar sollen die meisten Strips einfach nur lustig oder gewitzt sein, gelegentlich werden aber auch ernste Themen wie die Missachtung von Menschenrechten in Burma oder die Zerstörung der Natur angesprochen. Wir wollen außerdem zeigen, was es für Sandra und ihre Schulfreunde Cloud und Larisa bedeutet, erwachsen zu werden. Nicht vergessen werden sollten außerdem Woos Ausflüge in den nahen Wald um dort seine tierischen Freunde Shadow, ein Fuchs, und Sid, ein Eichhörnchen, zu treffen. Als weiteres Alleinstellungsmerkmal des Comics darf gelten, dass sich immer wieder einzelne Strips oder sogar längere Geschichten um die Nebenfiguren drehen."
override val genres = "Comedy"
override val state = SManga.ON_HIATUS
override val thumbnail = "http://www.sandraandwoo.com/images/fanart/fanart-contest-2014/pictures/zheng-qu-01-color-corrected.jpg"
override val archive = "/woode/archiv"
}

View File

@ -0,0 +1,15 @@
package eu.kanade.tachiyomi.extension.all.sandraandwoo.translations
import eu.kanade.tachiyomi.extension.all.sandraandwoo.SandraAndWoo
import eu.kanade.tachiyomi.source.model.SManga
class SandraAndWooEN : SandraAndWoo(lang = "en") {
override val name = "Sandra and Woo"
override val writer = "Oliver Knörzer"
override val illustrator = "Powree"
override val synopsis = "Sandra and Woo is a comedy comic strip featuring the 13-year-old girl Sandra North and her mischievous pet raccoon Woo. While most strips are just supposed to be funny or tell an exciting story, some also deal with more serious topics. We also want to show what growing up means for Sandra and her best friends in middle school, Cloud and Larisa. Another regular feature of the comic are Woos trips to the forest to meet his furry friends Shadow (a fox) and Sid (a squirrel) and his love interest Lily."
override val genres = "Comedy"
override val state = SManga.ON_HIATUS
override val thumbnail = "http://www.sandraandwoo.com/images/fanart/fanart-contest-2014/pictures/zheng-qu-01-color-corrected.jpg"
override val archive = "/archive"
}