mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Clean up ComicInfo stuff a bit
This commit is contained in:
		@@ -1,89 +1,145 @@
 | 
			
		||||
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 nl.adaptivity.xmlutil.serialization.XmlElement
 | 
			
		||||
import nl.adaptivity.xmlutil.serialization.XmlSerialName
 | 
			
		||||
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
 | 
			
		||||
@XmlSerialName("ComicInfo", "", "")
 | 
			
		||||
data class ComicInfo(
 | 
			
		||||
    val title: ComicInfoTitle?,
 | 
			
		||||
    val series: ComicInfoSeries?,
 | 
			
		||||
    val summary: ComicInfoSummary?,
 | 
			
		||||
    val writer: ComicInfoWriter?,
 | 
			
		||||
    val penciller: ComicInfoPenciller?,
 | 
			
		||||
    val inker: ComicInfoInker?,
 | 
			
		||||
    val colorist: ComicInfoColorist?,
 | 
			
		||||
    val letterer: ComicInfoLetterer?,
 | 
			
		||||
    val coverArtist: ComicInfoCoverArtist?,
 | 
			
		||||
    val translator: ComicInfoTranslator?,
 | 
			
		||||
    val genre: ComicInfoGenre?,
 | 
			
		||||
    val tags: ComicInfoTags?,
 | 
			
		||||
    val web: ComicInfoWeb?,
 | 
			
		||||
    val publishingStatusTachiyomi: ComicInfoPublishingStatusTachiyomi?,
 | 
			
		||||
    val title: Title?,
 | 
			
		||||
    val series: Series?,
 | 
			
		||||
    val summary: Summary?,
 | 
			
		||||
    val writer: Writer?,
 | 
			
		||||
    val penciller: Penciller?,
 | 
			
		||||
    val inker: Inker?,
 | 
			
		||||
    val colorist: Colorist?,
 | 
			
		||||
    val letterer: Letterer?,
 | 
			
		||||
    val coverArtist: CoverArtist?,
 | 
			
		||||
    val translator: Translator?,
 | 
			
		||||
    val genre: Genre?,
 | 
			
		||||
    val tags: Tags?,
 | 
			
		||||
    val web: Web?,
 | 
			
		||||
    val publishingStatusTachiyomi: PublishingStatusTachiyomi?,
 | 
			
		||||
) {
 | 
			
		||||
    @Suppress("UNUSED")
 | 
			
		||||
    @XmlElement(false)
 | 
			
		||||
    @XmlSerialName("xmlns:xsd", "", "")
 | 
			
		||||
    val xmlSchema: String = "http://www.w3.org/2001/XMLSchema"
 | 
			
		||||
 | 
			
		||||
    @Suppress("UNUSED")
 | 
			
		||||
    @XmlElement(false)
 | 
			
		||||
    @XmlSerialName("xmlns:xsi", "", "")
 | 
			
		||||
    val xmlSchemaInstance: String = "http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Title", "", "")
 | 
			
		||||
    data class Title(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Series", "", "")
 | 
			
		||||
    data class Series(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Summary", "", "")
 | 
			
		||||
    data class Summary(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Writer", "", "")
 | 
			
		||||
    data class Writer(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Penciller", "", "")
 | 
			
		||||
    data class Penciller(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Inker", "", "")
 | 
			
		||||
    data class Inker(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Colorist", "", "")
 | 
			
		||||
    data class Colorist(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Letterer", "", "")
 | 
			
		||||
    data class Letterer(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("CoverArtist", "", "")
 | 
			
		||||
    data class CoverArtist(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Translator", "", "")
 | 
			
		||||
    data class Translator(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Genre", "", "")
 | 
			
		||||
    data class Genre(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Tags", "", "")
 | 
			
		||||
    data class Tags(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("Web", "", "")
 | 
			
		||||
    data class Web(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
    // The spec doesn't have a good field for this
 | 
			
		||||
    @Serializable
 | 
			
		||||
    @XmlSerialName("PublishingStatusTachiyomi", "http://www.w3.org/2001/XMLSchema", "ty")
 | 
			
		||||
    data class PublishingStatusTachiyomi(@XmlValue(true) val value: String = "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Title", "", "")
 | 
			
		||||
data class ComicInfoTitle(@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),
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Series", "", "")
 | 
			
		||||
data class ComicInfoSeries(@XmlValue(true) val value: String = "")
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun toComicInfoValue(value: Long): String {
 | 
			
		||||
            return values().firstOrNull { it.sMangaModelValue == value.toInt() }?.comicInfoValue
 | 
			
		||||
                ?: "Unknown"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Summary", "", "")
 | 
			
		||||
data class ComicInfoSummary(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Writer", "", "")
 | 
			
		||||
data class ComicInfoWriter(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Penciller", "", "")
 | 
			
		||||
data class ComicInfoPenciller(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Inker", "", "")
 | 
			
		||||
data class ComicInfoInker(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Colorist", "", "")
 | 
			
		||||
data class ComicInfoColorist(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Letterer", "", "")
 | 
			
		||||
data class ComicInfoLetterer(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("CoverArtist", "", "")
 | 
			
		||||
data class ComicInfoCoverArtist(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Translator", "", "")
 | 
			
		||||
data class ComicInfoTranslator(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Genre", "", "")
 | 
			
		||||
data class ComicInfoGenre(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Tags", "", "")
 | 
			
		||||
data class ComicInfoTags(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("Web", "", "")
 | 
			
		||||
data class ComicInfoWeb(@XmlValue(true) val value: String = "")
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
@XmlSerialName("PublishingStatusTachiyomi", "http://www.w3.org/2001/XMLSchema", "ty")
 | 
			
		||||
data class ComicInfoPublishingStatusTachiyomi(@XmlValue(true) val value: String = "")
 | 
			
		||||
        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.toDbChapter
 | 
			
		||||
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.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.getComicInfo
 | 
			
		||||
import eu.kanade.domain.track.interactor.GetTracks
 | 
			
		||||
import eu.kanade.domain.track.model.Track
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
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.DownloadQueue
 | 
			
		||||
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.UnmeteredSource
 | 
			
		||||
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.fetchAllImageUrlsFromPageList
 | 
			
		||||
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.logcat
 | 
			
		||||
import kotlinx.coroutines.async
 | 
			
		||||
import kotlinx.coroutines.runBlocking
 | 
			
		||||
import logcat.LogPriority
 | 
			
		||||
import nl.adaptivity.xmlutil.serialization.XML
 | 
			
		||||
import okhttp3.Response
 | 
			
		||||
@@ -537,8 +527,6 @@ class Downloader(
 | 
			
		||||
        // 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")) }
 | 
			
		||||
 | 
			
		||||
        createComicInfoFile(tmpDir, download.manga, download.chapter)
 | 
			
		||||
 | 
			
		||||
        download.status = if (downloadedImages.size == download.pages!!.size) {
 | 
			
		||||
            // Only rename the directory if it's downloaded.
 | 
			
		||||
            if (downloadPreferences.saveChaptersAsCBZ().get()) {
 | 
			
		||||
@@ -549,8 +537,7 @@ class Downloader(
 | 
			
		||||
            cache.addChapter(dirname, mangaDir, download.manga)
 | 
			
		||||
 | 
			
		||||
            DiskUtil.createNoMediaFile(tmpDir, context)
 | 
			
		||||
 | 
			
		||||
            createComicInfoFile(mangaDir, download.manga, download.chapter)
 | 
			
		||||
            createComicInfoFile(mangaDir, download.manga, download.chapter.toDomainChapter()!!)
 | 
			
		||||
 | 
			
		||||
            Download.State.DOWNLOADED
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -602,47 +589,15 @@ class Downloader(
 | 
			
		||||
    private fun createComicInfoFile(
 | 
			
		||||
        dir: UniFile,
 | 
			
		||||
        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
 | 
			
		||||
            (it as? FileOutputStream)?.channel?.truncate(0)
 | 
			
		||||
        }.use { it.write(getComicInfo(manga, chapter)) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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()
 | 
			
		||||
        }.use {
 | 
			
		||||
            val comicInfo = getComicInfo(manga, chapter)
 | 
			
		||||
            it.write(xml.encodeToString(ComicInfo.serializer(), comicInfo).toByteArray())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,9 @@ package eu.kanade.tachiyomi.source
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import com.github.junrar.Archive
 | 
			
		||||
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.ComicInfoPublishingStatusMap
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.Filter
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.FilterList
 | 
			
		||||
@@ -270,15 +272,7 @@ class LocalSource(
 | 
			
		||||
            .takeIf { it.isNotEmpty() }
 | 
			
		||||
            ?.let { manga.artist = it }
 | 
			
		||||
 | 
			
		||||
        manga.status = when (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
 | 
			
		||||
        }
 | 
			
		||||
        manga.status = ComicInfoPublishingStatusMap.toSMangaValue(comicInfo.publishingStatusTachiyomi?.value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Serializable
 | 
			
		||||
@@ -492,4 +486,3 @@ class LocalSource(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private val SUPPORTED_ARCHIVE_TYPES = listOf("zip", "cbz", "rar", "cbr", "epub")
 | 
			
		||||
private val COMIC_INFO_FILE = "ComicInfo.xml"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user