mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-22 09:41:51 +01:00
Clean up ComicInfo stuff a bit
This commit is contained in:
parent
4e628fe6de
commit
6ada3c90ff
@ -1,89 +1,145 @@
|
|||||||
package eu.kanade.domain.manga.model
|
package eu.kanade.domain.manga.model
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import nl.adaptivity.xmlutil.serialization.XmlElement
|
import nl.adaptivity.xmlutil.serialization.XmlElement
|
||||||
import nl.adaptivity.xmlutil.serialization.XmlSerialName
|
import nl.adaptivity.xmlutil.serialization.XmlSerialName
|
||||||
import nl.adaptivity.xmlutil.serialization.XmlValue
|
import nl.adaptivity.xmlutil.serialization.XmlValue
|
||||||
|
|
||||||
|
const val COMIC_INFO_FILE = "ComicInfo.xml"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ComicInfo instance based on the manga and chapter metadata.
|
||||||
|
*/
|
||||||
|
fun getComicInfo(manga: Manga, chapter: Chapter): ComicInfo {
|
||||||
|
return ComicInfo(
|
||||||
|
title = ComicInfo.Title(chapter.name),
|
||||||
|
series = ComicInfo.Series(manga.title),
|
||||||
|
web = ComicInfo.Web(manga.url),
|
||||||
|
summary = manga.description?.let { ComicInfo.Summary(it) },
|
||||||
|
writer = manga.author?.let { ComicInfo.Writer(it) },
|
||||||
|
penciller = manga.artist?.let { ComicInfo.Penciller(it) },
|
||||||
|
translator = chapter.scanlator?.let { ComicInfo.Translator(it) },
|
||||||
|
genre = manga.genre?.let { ComicInfo.Genre(it.joinToString()) },
|
||||||
|
publishingStatusTachiyomi = ComicInfo.PublishingStatusTachiyomi(
|
||||||
|
ComicInfoPublishingStatusMap.toComicInfoValue(manga.status),
|
||||||
|
),
|
||||||
|
inker = null,
|
||||||
|
colorist = null,
|
||||||
|
letterer = null,
|
||||||
|
coverArtist = null,
|
||||||
|
tags = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("ComicInfo", "", "")
|
@XmlSerialName("ComicInfo", "", "")
|
||||||
data class ComicInfo(
|
data class ComicInfo(
|
||||||
val title: ComicInfoTitle?,
|
val title: Title?,
|
||||||
val series: ComicInfoSeries?,
|
val series: Series?,
|
||||||
val summary: ComicInfoSummary?,
|
val summary: Summary?,
|
||||||
val writer: ComicInfoWriter?,
|
val writer: Writer?,
|
||||||
val penciller: ComicInfoPenciller?,
|
val penciller: Penciller?,
|
||||||
val inker: ComicInfoInker?,
|
val inker: Inker?,
|
||||||
val colorist: ComicInfoColorist?,
|
val colorist: Colorist?,
|
||||||
val letterer: ComicInfoLetterer?,
|
val letterer: Letterer?,
|
||||||
val coverArtist: ComicInfoCoverArtist?,
|
val coverArtist: CoverArtist?,
|
||||||
val translator: ComicInfoTranslator?,
|
val translator: Translator?,
|
||||||
val genre: ComicInfoGenre?,
|
val genre: Genre?,
|
||||||
val tags: ComicInfoTags?,
|
val tags: Tags?,
|
||||||
val web: ComicInfoWeb?,
|
val web: Web?,
|
||||||
val publishingStatusTachiyomi: ComicInfoPublishingStatusTachiyomi?,
|
val publishingStatusTachiyomi: PublishingStatusTachiyomi?,
|
||||||
) {
|
) {
|
||||||
|
@Suppress("UNUSED")
|
||||||
@XmlElement(false)
|
@XmlElement(false)
|
||||||
@XmlSerialName("xmlns:xsd", "", "")
|
@XmlSerialName("xmlns:xsd", "", "")
|
||||||
val xmlSchema: String = "http://www.w3.org/2001/XMLSchema"
|
val xmlSchema: String = "http://www.w3.org/2001/XMLSchema"
|
||||||
|
|
||||||
|
@Suppress("UNUSED")
|
||||||
@XmlElement(false)
|
@XmlElement(false)
|
||||||
@XmlSerialName("xmlns:xsi", "", "")
|
@XmlSerialName("xmlns:xsi", "", "")
|
||||||
val xmlSchemaInstance: String = "http://www.w3.org/2001/XMLSchema-instance"
|
val xmlSchemaInstance: String = "http://www.w3.org/2001/XMLSchema-instance"
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Title", "", "")
|
@XmlSerialName("Title", "", "")
|
||||||
data class ComicInfoTitle(@XmlValue(true) val value: String = "")
|
data class Title(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Series", "", "")
|
@XmlSerialName("Series", "", "")
|
||||||
data class ComicInfoSeries(@XmlValue(true) val value: String = "")
|
data class Series(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Summary", "", "")
|
@XmlSerialName("Summary", "", "")
|
||||||
data class ComicInfoSummary(@XmlValue(true) val value: String = "")
|
data class Summary(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Writer", "", "")
|
@XmlSerialName("Writer", "", "")
|
||||||
data class ComicInfoWriter(@XmlValue(true) val value: String = "")
|
data class Writer(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Penciller", "", "")
|
@XmlSerialName("Penciller", "", "")
|
||||||
data class ComicInfoPenciller(@XmlValue(true) val value: String = "")
|
data class Penciller(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Inker", "", "")
|
@XmlSerialName("Inker", "", "")
|
||||||
data class ComicInfoInker(@XmlValue(true) val value: String = "")
|
data class Inker(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Colorist", "", "")
|
@XmlSerialName("Colorist", "", "")
|
||||||
data class ComicInfoColorist(@XmlValue(true) val value: String = "")
|
data class Colorist(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Letterer", "", "")
|
@XmlSerialName("Letterer", "", "")
|
||||||
data class ComicInfoLetterer(@XmlValue(true) val value: String = "")
|
data class Letterer(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("CoverArtist", "", "")
|
@XmlSerialName("CoverArtist", "", "")
|
||||||
data class ComicInfoCoverArtist(@XmlValue(true) val value: String = "")
|
data class CoverArtist(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Translator", "", "")
|
@XmlSerialName("Translator", "", "")
|
||||||
data class ComicInfoTranslator(@XmlValue(true) val value: String = "")
|
data class Translator(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Genre", "", "")
|
@XmlSerialName("Genre", "", "")
|
||||||
data class ComicInfoGenre(@XmlValue(true) val value: String = "")
|
data class Genre(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Tags", "", "")
|
@XmlSerialName("Tags", "", "")
|
||||||
data class ComicInfoTags(@XmlValue(true) val value: String = "")
|
data class Tags(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("Web", "", "")
|
@XmlSerialName("Web", "", "")
|
||||||
data class ComicInfoWeb(@XmlValue(true) val value: String = "")
|
data class Web(@XmlValue(true) val value: String = "")
|
||||||
|
|
||||||
|
// The spec doesn't have a good field for this
|
||||||
@Serializable
|
@Serializable
|
||||||
@XmlSerialName("PublishingStatusTachiyomi", "http://www.w3.org/2001/XMLSchema", "ty")
|
@XmlSerialName("PublishingStatusTachiyomi", "http://www.w3.org/2001/XMLSchema", "ty")
|
||||||
data class ComicInfoPublishingStatusTachiyomi(@XmlValue(true) val value: String = "")
|
data class PublishingStatusTachiyomi(@XmlValue(true) val value: String = "")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ComicInfoPublishingStatusMap(
|
||||||
|
val comicInfoValue: String,
|
||||||
|
val sMangaModelValue: Int,
|
||||||
|
) {
|
||||||
|
ONGOING("Ongoing", SManga.ONGOING),
|
||||||
|
COMPLETED("Completed", SManga.COMPLETED),
|
||||||
|
LICENSED("Licensed", SManga.LICENSED),
|
||||||
|
PUBLISHING_FINISHED("Publishing finished", SManga.PUBLISHING_FINISHED),
|
||||||
|
CANCELLED("Cancelled", SManga.CANCELLED),
|
||||||
|
ON_HIATUS("On hiatus", SManga.ON_HIATUS),
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun toComicInfoValue(value: Long): String {
|
||||||
|
return values().firstOrNull { it.sMangaModelValue == value.toInt() }?.comicInfoValue
|
||||||
|
?: "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toSMangaValue(value: String?): Int {
|
||||||
|
return values().firstOrNull { it.comicInfoValue == value }?.sMangaModelValue
|
||||||
|
?: SManga.UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,21 +6,14 @@ import com.jakewharton.rxrelay.PublishRelay
|
|||||||
import eu.kanade.domain.chapter.model.Chapter
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
import eu.kanade.domain.chapter.model.toDbChapter
|
import eu.kanade.domain.chapter.model.toDbChapter
|
||||||
import eu.kanade.domain.download.service.DownloadPreferences
|
import eu.kanade.domain.download.service.DownloadPreferences
|
||||||
|
import eu.kanade.domain.manga.model.COMIC_INFO_FILE
|
||||||
import eu.kanade.domain.manga.model.ComicInfo
|
import eu.kanade.domain.manga.model.ComicInfo
|
||||||
import eu.kanade.domain.manga.model.ComicInfoGenre
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoPenciller
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoPublishingStatusTachiyomi
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoSeries
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoSummary
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoTitle
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoTranslator
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoWeb
|
|
||||||
import eu.kanade.domain.manga.model.ComicInfoWriter
|
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
|
import eu.kanade.domain.manga.model.getComicInfo
|
||||||
import eu.kanade.domain.track.interactor.GetTracks
|
import eu.kanade.domain.track.interactor.GetTracks
|
||||||
import eu.kanade.domain.track.model.Track
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
|
||||||
@ -28,8 +21,6 @@ import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
|||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.UnmeteredSource
|
import eu.kanade.tachiyomi.source.UnmeteredSource
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
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 eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.source.online.fetchAllImageUrlsFromPageList
|
import eu.kanade.tachiyomi.source.online.fetchAllImageUrlsFromPageList
|
||||||
import eu.kanade.tachiyomi.util.lang.RetryWithDelay
|
import eu.kanade.tachiyomi.util.lang.RetryWithDelay
|
||||||
@ -42,7 +33,6 @@ import eu.kanade.tachiyomi.util.storage.saveTo
|
|||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import nl.adaptivity.xmlutil.serialization.XML
|
import nl.adaptivity.xmlutil.serialization.XML
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
@ -537,8 +527,6 @@ class Downloader(
|
|||||||
// Ensure that the chapter folder has all the images.
|
// Ensure that the chapter folder has all the images.
|
||||||
val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") || (it.name!!.contains("__") && !it.name!!.contains("__001.jpg")) }
|
val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") || (it.name!!.contains("__") && !it.name!!.contains("__001.jpg")) }
|
||||||
|
|
||||||
createComicInfoFile(tmpDir, download.manga, download.chapter)
|
|
||||||
|
|
||||||
download.status = if (downloadedImages.size == download.pages!!.size) {
|
download.status = if (downloadedImages.size == download.pages!!.size) {
|
||||||
// Only rename the directory if it's downloaded.
|
// Only rename the directory if it's downloaded.
|
||||||
if (downloadPreferences.saveChaptersAsCBZ().get()) {
|
if (downloadPreferences.saveChaptersAsCBZ().get()) {
|
||||||
@ -549,8 +537,7 @@ class Downloader(
|
|||||||
cache.addChapter(dirname, mangaDir, download.manga)
|
cache.addChapter(dirname, mangaDir, download.manga)
|
||||||
|
|
||||||
DiskUtil.createNoMediaFile(tmpDir, context)
|
DiskUtil.createNoMediaFile(tmpDir, context)
|
||||||
|
createComicInfoFile(mangaDir, download.manga, download.chapter.toDomainChapter()!!)
|
||||||
createComicInfoFile(mangaDir, download.manga, download.chapter)
|
|
||||||
|
|
||||||
Download.State.DOWNLOADED
|
Download.State.DOWNLOADED
|
||||||
} else {
|
} else {
|
||||||
@ -602,47 +589,15 @@ class Downloader(
|
|||||||
private fun createComicInfoFile(
|
private fun createComicInfoFile(
|
||||||
dir: UniFile,
|
dir: UniFile,
|
||||||
manga: Manga,
|
manga: Manga,
|
||||||
chapter: SChapter,
|
chapter: Chapter,
|
||||||
) {
|
) {
|
||||||
File("${dir.filePath}/ComicInfo.xml").outputStream().also {
|
File("${dir.filePath}/$COMIC_INFO_FILE").outputStream().also {
|
||||||
// Force overwrite old file
|
// Force overwrite old file
|
||||||
(it as? FileOutputStream)?.channel?.truncate(0)
|
(it as? FileOutputStream)?.channel?.truncate(0)
|
||||||
}.use { it.write(getComicInfo(manga, chapter)) }
|
}.use {
|
||||||
|
val comicInfo = getComicInfo(manga, chapter)
|
||||||
|
it.write(xml.encodeToString(ComicInfo.serializer(), comicInfo).toByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* returns a ByteArray containing the Manga Metadata of the chapter to download in ComicInfo.xml format
|
|
||||||
*
|
|
||||||
* @param manga the manga of the chapter to download.
|
|
||||||
* @param chapter the name of the chapter to download
|
|
||||||
*/
|
|
||||||
private fun getComicInfo(manga: Manga, chapter: SChapter): ByteArray {
|
|
||||||
val track: Track? = runBlocking { getTracks.await(manga.id).firstOrNull() }
|
|
||||||
val comicInfo = ComicInfo(
|
|
||||||
title = ComicInfoTitle(chapter.name),
|
|
||||||
series = ComicInfoSeries(manga.title),
|
|
||||||
summary = manga.description?.let { ComicInfoSummary(it) },
|
|
||||||
writer = manga.author?.let { ComicInfoWriter(it) },
|
|
||||||
penciller = manga.artist?.let { ComicInfoPenciller(it) },
|
|
||||||
translator = chapter.scanlator?.let { ComicInfoTranslator(it) },
|
|
||||||
genre = manga.genre?.let { ComicInfoGenre(it.joinToString()) },
|
|
||||||
web = track?.remoteUrl?.let { ComicInfoWeb(it) },
|
|
||||||
publishingStatusTachiyomi = when (manga.status) {
|
|
||||||
SManga.ONGOING.toLong() -> ComicInfoPublishingStatusTachiyomi("Ongoing")
|
|
||||||
SManga.COMPLETED.toLong() -> ComicInfoPublishingStatusTachiyomi("Completed")
|
|
||||||
SManga.LICENSED.toLong() -> ComicInfoPublishingStatusTachiyomi("Licensed")
|
|
||||||
SManga.PUBLISHING_FINISHED.toLong() -> ComicInfoPublishingStatusTachiyomi("Publishing finished")
|
|
||||||
SManga.CANCELLED.toLong() -> ComicInfoPublishingStatusTachiyomi("Cancelled")
|
|
||||||
SManga.ON_HIATUS.toLong() -> ComicInfoPublishingStatusTachiyomi("On hiatus")
|
|
||||||
else -> ComicInfoPublishingStatusTachiyomi("Unknown")
|
|
||||||
},
|
|
||||||
inker = null,
|
|
||||||
colorist = null,
|
|
||||||
letterer = null,
|
|
||||||
coverArtist = null,
|
|
||||||
tags = null,
|
|
||||||
)
|
|
||||||
return xml.encodeToString(ComicInfo.serializer(), comicInfo).toByteArray()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.source
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.github.junrar.Archive
|
import com.github.junrar.Archive
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
|
import eu.kanade.domain.manga.model.COMIC_INFO_FILE
|
||||||
import eu.kanade.domain.manga.model.ComicInfo
|
import eu.kanade.domain.manga.model.ComicInfo
|
||||||
|
import eu.kanade.domain.manga.model.ComicInfoPublishingStatusMap
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
@ -270,15 +272,7 @@ class LocalSource(
|
|||||||
.takeIf { it.isNotEmpty() }
|
.takeIf { it.isNotEmpty() }
|
||||||
?.let { manga.artist = it }
|
?.let { manga.artist = it }
|
||||||
|
|
||||||
manga.status = when (comicInfo.publishingStatusTachiyomi?.value) {
|
manga.status = ComicInfoPublishingStatusMap.toSMangaValue(comicInfo.publishingStatusTachiyomi?.value)
|
||||||
"Ongoing" -> SManga.ONGOING
|
|
||||||
"Completed" -> SManga.COMPLETED
|
|
||||||
"Licensed" -> SManga.LICENSED
|
|
||||||
"Publishing finished" -> SManga.PUBLISHING_FINISHED
|
|
||||||
"Cancelled" -> SManga.CANCELLED
|
|
||||||
"On hiatus" -> SManga.ON_HIATUS
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -492,4 +486,3 @@ class LocalSource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "epub")
|
private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "epub")
|
||||||
private val COMIC_INFO_FILE = "ComicInfo.xml"
|
|
||||||
|
Loading…
Reference in New Issue
Block a user