|
|
|
|
@ -1,10 +1,11 @@
|
|
|
|
|
package org.koitharu.kotatsu.parsers.model
|
|
|
|
|
|
|
|
|
|
import androidx.collection.ArrayMap
|
|
|
|
|
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
|
|
|
|
import org.koitharu.kotatsu.parsers.util.findById
|
|
|
|
|
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
|
|
|
|
|
|
|
|
|
public class Manga(
|
|
|
|
|
@ExposedCopyVisibility
|
|
|
|
|
public data class Manga private constructor(
|
|
|
|
|
/**
|
|
|
|
|
* Unique identifier for manga
|
|
|
|
|
*/
|
|
|
|
|
@ -34,12 +35,12 @@ public class Manga(
|
|
|
|
|
/**
|
|
|
|
|
* Indicates that manga may contain sensitive information (18+, NSFW)
|
|
|
|
|
*/
|
|
|
|
|
@JvmField public val isNsfw: Boolean,
|
|
|
|
|
@JvmField public val contentRating: ContentRating?,
|
|
|
|
|
/**
|
|
|
|
|
* Absolute link to the cover
|
|
|
|
|
* @see largeCoverUrl
|
|
|
|
|
*/
|
|
|
|
|
@JvmField public val coverUrl: String,
|
|
|
|
|
@JvmField public val coverUrl: String?,
|
|
|
|
|
/**
|
|
|
|
|
* Tags (genres) of the manga
|
|
|
|
|
*/
|
|
|
|
|
@ -78,15 +79,17 @@ public class Manga(
|
|
|
|
|
public val hasRating: Boolean
|
|
|
|
|
get() = rating > 0f && rating <= 1f
|
|
|
|
|
|
|
|
|
|
public val isNsfw: Boolean
|
|
|
|
|
get() = contentRating == ContentRating.ADULT
|
|
|
|
|
|
|
|
|
|
public fun getChapters(branch: String?): List<MangaChapter> {
|
|
|
|
|
return chapters?.filter { x -> x.branch == branch }.orEmpty()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public fun findChapterById(id: Long): MangaChapter? = chapters?.findById(id)
|
|
|
|
|
|
|
|
|
|
public fun requireChapterById(id: Long): MangaChapter = requireNotNull(findChapterById(id)) {
|
|
|
|
|
"Chapter with id $id not found"
|
|
|
|
|
}
|
|
|
|
|
public fun requireChapterById(id: Long): MangaChapter = findChapterById(id)
|
|
|
|
|
?: throw NoSuchElementException("Chapter with id $id not found")
|
|
|
|
|
|
|
|
|
|
public fun getBranches(): Map<String?, Int> {
|
|
|
|
|
if (chapters.isNullOrEmpty()) {
|
|
|
|
|
@ -100,30 +103,82 @@ public class Manga(
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@InternalParsersApi
|
|
|
|
|
public fun copy(
|
|
|
|
|
url: String = this.url,
|
|
|
|
|
title: String = this.title,
|
|
|
|
|
altTitle: String? = this.altTitle,
|
|
|
|
|
publicUrl: String = this.publicUrl,
|
|
|
|
|
rating: Float = this.rating,
|
|
|
|
|
isNsfw: Boolean = this.isNsfw,
|
|
|
|
|
coverUrl: String = this.coverUrl,
|
|
|
|
|
tags: Set<MangaTag> = this.tags,
|
|
|
|
|
state: MangaState? = this.state,
|
|
|
|
|
author: String? = this.author,
|
|
|
|
|
largeCoverUrl: String? = this.largeCoverUrl,
|
|
|
|
|
description: String? = this.description,
|
|
|
|
|
chapters: List<MangaChapter>? = this.chapters,
|
|
|
|
|
source: MangaSource = this.source,
|
|
|
|
|
): Manga = Manga(
|
|
|
|
|
public companion object {
|
|
|
|
|
|
|
|
|
|
@Deprecated("")
|
|
|
|
|
public operator fun invoke(
|
|
|
|
|
/**
|
|
|
|
|
* Unique identifier for manga
|
|
|
|
|
*/
|
|
|
|
|
id: Long,
|
|
|
|
|
/**
|
|
|
|
|
* Manga title, human-readable
|
|
|
|
|
*/
|
|
|
|
|
title: String,
|
|
|
|
|
/**
|
|
|
|
|
* Alternative title (for example on other language), may be null
|
|
|
|
|
*/
|
|
|
|
|
altTitle: String?,
|
|
|
|
|
/**
|
|
|
|
|
* Relative url to manga (**without** a domain) or any other uri.
|
|
|
|
|
* Used principally in parsers
|
|
|
|
|
*/
|
|
|
|
|
url: String,
|
|
|
|
|
/**
|
|
|
|
|
* Absolute url to manga, must be ready to open in browser
|
|
|
|
|
*/
|
|
|
|
|
publicUrl: String,
|
|
|
|
|
/**
|
|
|
|
|
* Normalized manga rating, must be in range of 0..1 or [RATING_UNKNOWN] if rating s unknown
|
|
|
|
|
* @see hasRating
|
|
|
|
|
*/
|
|
|
|
|
rating: Float,
|
|
|
|
|
/**
|
|
|
|
|
* Indicates that manga may contain sensitive information (18+, NSFW)
|
|
|
|
|
*/
|
|
|
|
|
isNsfw: Boolean,
|
|
|
|
|
/**
|
|
|
|
|
* Absolute link to the cover
|
|
|
|
|
* @see largeCoverUrl
|
|
|
|
|
*/
|
|
|
|
|
coverUrl: String?,
|
|
|
|
|
/**
|
|
|
|
|
* Tags (genres) of the manga
|
|
|
|
|
*/
|
|
|
|
|
tags: Set<MangaTag>,
|
|
|
|
|
/**
|
|
|
|
|
* Manga status (ongoing, finished) or null if unknown
|
|
|
|
|
*/
|
|
|
|
|
state: MangaState?,
|
|
|
|
|
/**
|
|
|
|
|
* Author of the manga, may be null
|
|
|
|
|
*/
|
|
|
|
|
author: String?,
|
|
|
|
|
/**
|
|
|
|
|
* Large cover url (absolute), null if is no large cover
|
|
|
|
|
* @see coverUrl
|
|
|
|
|
*/
|
|
|
|
|
largeCoverUrl: String? = null,
|
|
|
|
|
/**
|
|
|
|
|
* Manga description, may be html or null
|
|
|
|
|
*/
|
|
|
|
|
description: String? = null,
|
|
|
|
|
/**
|
|
|
|
|
* List of chapters
|
|
|
|
|
*/
|
|
|
|
|
chapters: List<MangaChapter>? = null,
|
|
|
|
|
/**
|
|
|
|
|
* Manga source
|
|
|
|
|
*/
|
|
|
|
|
source: MangaSource,
|
|
|
|
|
): Manga = invoke(
|
|
|
|
|
id = id,
|
|
|
|
|
title = title,
|
|
|
|
|
altTitle = altTitle,
|
|
|
|
|
url = url,
|
|
|
|
|
publicUrl = publicUrl,
|
|
|
|
|
rating = rating,
|
|
|
|
|
isNsfw = isNsfw,
|
|
|
|
|
contentRating = if (isNsfw) ContentRating.ADULT else ContentRating.SAFE,
|
|
|
|
|
coverUrl = coverUrl,
|
|
|
|
|
tags = tags,
|
|
|
|
|
state = state,
|
|
|
|
|
@ -134,51 +189,87 @@ public class Manga(
|
|
|
|
|
source = source,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
override fun equals(other: Any?): Boolean {
|
|
|
|
|
if (this === other) return true
|
|
|
|
|
if (javaClass != other?.javaClass) return false
|
|
|
|
|
|
|
|
|
|
other as Manga
|
|
|
|
|
|
|
|
|
|
if (id != other.id) return false
|
|
|
|
|
if (title != other.title) return false
|
|
|
|
|
if (altTitle != other.altTitle) return false
|
|
|
|
|
if (url != other.url) return false
|
|
|
|
|
if (publicUrl != other.publicUrl) return false
|
|
|
|
|
if (rating != other.rating) return false
|
|
|
|
|
if (isNsfw != other.isNsfw) return false
|
|
|
|
|
if (coverUrl != other.coverUrl) return false
|
|
|
|
|
if (tags != other.tags) return false
|
|
|
|
|
if (state != other.state) return false
|
|
|
|
|
if (author != other.author) return false
|
|
|
|
|
if (largeCoverUrl != other.largeCoverUrl) return false
|
|
|
|
|
if (description != other.description) return false
|
|
|
|
|
if (chapters != other.chapters) return false
|
|
|
|
|
if (source != other.source) return false
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun hashCode(): Int {
|
|
|
|
|
var result = id.hashCode()
|
|
|
|
|
result = 31 * result + title.hashCode()
|
|
|
|
|
result = 31 * result + (altTitle?.hashCode() ?: 0)
|
|
|
|
|
result = 31 * result + url.hashCode()
|
|
|
|
|
result = 31 * result + publicUrl.hashCode()
|
|
|
|
|
result = 31 * result + rating.hashCode()
|
|
|
|
|
result = 31 * result + isNsfw.hashCode()
|
|
|
|
|
result = 31 * result + coverUrl.hashCode()
|
|
|
|
|
result = 31 * result + tags.hashCode()
|
|
|
|
|
result = 31 * result + (state?.hashCode() ?: 0)
|
|
|
|
|
result = 31 * result + (author?.hashCode() ?: 0)
|
|
|
|
|
result = 31 * result + (largeCoverUrl?.hashCode() ?: 0)
|
|
|
|
|
result = 31 * result + (description?.hashCode() ?: 0)
|
|
|
|
|
result = 31 * result + (chapters?.hashCode() ?: 0)
|
|
|
|
|
result = 31 * result + source.hashCode()
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun toString(): String {
|
|
|
|
|
return "Manga($id - \"$title\" [$url] - $source)"
|
|
|
|
|
public operator fun invoke(
|
|
|
|
|
/**
|
|
|
|
|
* Unique identifier for manga
|
|
|
|
|
*/
|
|
|
|
|
id: Long,
|
|
|
|
|
/**
|
|
|
|
|
* Manga title, human-readable
|
|
|
|
|
*/
|
|
|
|
|
title: String,
|
|
|
|
|
/**
|
|
|
|
|
* Alternative title (for example on other language), may be null
|
|
|
|
|
*/
|
|
|
|
|
altTitle: String?,
|
|
|
|
|
/**
|
|
|
|
|
* Relative url to manga (**without** a domain) or any other uri.
|
|
|
|
|
* Used principally in parsers
|
|
|
|
|
*/
|
|
|
|
|
url: String,
|
|
|
|
|
/**
|
|
|
|
|
* Absolute url to manga, must be ready to open in browser
|
|
|
|
|
*/
|
|
|
|
|
publicUrl: String,
|
|
|
|
|
/**
|
|
|
|
|
* Normalized manga rating, must be in range of 0..1 or [RATING_UNKNOWN] if rating s unknown
|
|
|
|
|
* @see hasRating
|
|
|
|
|
*/
|
|
|
|
|
rating: Float,
|
|
|
|
|
/**
|
|
|
|
|
* Indicates that manga may contain sensitive information (18+, NSFW)
|
|
|
|
|
*/
|
|
|
|
|
contentRating: ContentRating?,
|
|
|
|
|
/**
|
|
|
|
|
* Absolute link to the cover
|
|
|
|
|
* @see largeCoverUrl
|
|
|
|
|
*/
|
|
|
|
|
coverUrl: String?,
|
|
|
|
|
/**
|
|
|
|
|
* Tags (genres) of the manga
|
|
|
|
|
*/
|
|
|
|
|
tags: Set<MangaTag>,
|
|
|
|
|
/**
|
|
|
|
|
* Manga status (ongoing, finished) or null if unknown
|
|
|
|
|
*/
|
|
|
|
|
state: MangaState?,
|
|
|
|
|
/**
|
|
|
|
|
* Author of the manga, may be null
|
|
|
|
|
*/
|
|
|
|
|
author: String?,
|
|
|
|
|
/**
|
|
|
|
|
* Large cover url (absolute), null if is no large cover
|
|
|
|
|
* @see coverUrl
|
|
|
|
|
*/
|
|
|
|
|
largeCoverUrl: String? = null,
|
|
|
|
|
/**
|
|
|
|
|
* Manga description, may be html or null
|
|
|
|
|
*/
|
|
|
|
|
description: String? = null,
|
|
|
|
|
/**
|
|
|
|
|
* List of chapters
|
|
|
|
|
*/
|
|
|
|
|
chapters: List<MangaChapter>? = null,
|
|
|
|
|
/**
|
|
|
|
|
* Manga source
|
|
|
|
|
*/
|
|
|
|
|
source: MangaSource,
|
|
|
|
|
): Manga = Manga(
|
|
|
|
|
id = id,
|
|
|
|
|
title = title,
|
|
|
|
|
altTitle = altTitle?.nullIfEmpty(),
|
|
|
|
|
url = url,
|
|
|
|
|
publicUrl = publicUrl,
|
|
|
|
|
rating = rating,
|
|
|
|
|
contentRating = contentRating,
|
|
|
|
|
coverUrl = coverUrl?.nullIfEmpty(),
|
|
|
|
|
tags = tags,
|
|
|
|
|
state = state,
|
|
|
|
|
author = author?.nullIfEmpty(),
|
|
|
|
|
largeCoverUrl = largeCoverUrl?.nullIfEmpty(),
|
|
|
|
|
description = description?.nullIfEmpty(),
|
|
|
|
|
chapters = chapters,
|
|
|
|
|
source = source,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|