From 589f5dc14164f01b6e01d4dd11c4621624dc30bb Mon Sep 17 00:00:00 2001
From: Neshura <neshura@neshweb.net>
Date: Sun, 2 Mar 2025 00:24:36 +0100
Subject: [PATCH] Support for Local Novels. Adjusted Metadata File Finding to
 not rely on File order.

---
 jnc/jnc.go |  17 ++
 main.go    | 453 ++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 308 insertions(+), 162 deletions(-)

diff --git a/jnc/jnc.go b/jnc/jnc.go
index e89aa71..0306bfa 100644
--- a/jnc/jnc.go
+++ b/jnc/jnc.go
@@ -125,6 +125,14 @@ func (creators Creators) Get(role string) *Creator {
 	return &(creators)[idx]
 }
 
+func (creators Creators) TryGetName(role string) string {
+	if creators.Contains(role) {
+		return creators.Get(role).Name
+	} else {
+		return ""
+	}
+}
+
 type VolumeAugmented struct {
 	Info       Volume
 	Downloads  []Download
@@ -199,6 +207,15 @@ type Pagination struct {
 	LastPage bool `json:"lastPage"`
 }
 
+type ProviderSettings struct {
+	Domain    string
+	Series    string
+	Directory string
+	Username  string
+	Password  string
+	Language  string
+}
+
 func NewJNC(domain string) Api {
 	baseUrl := fmt.Sprintf("https://%s/", domain)
 	jncApi := Api{
diff --git a/main.go b/main.go
index 5fc732a..8724fc9 100644
--- a/main.go
+++ b/main.go
@@ -13,6 +13,7 @@ import (
 	"kavita-helper-go/jnc"
 	"os"
 	"os/exec"
+	"path/filepath"
 	"regexp"
 	"slices"
 	"strconv"
@@ -30,19 +31,6 @@ type Chapter struct {
 	pages      []string
 }
 
-type FileWrapper struct {
-	fileName string
-	file     zip.File
-	fileSet  bool
-}
-
-func NewFileWrapper() FileWrapper {
-	newFileWrapper := FileWrapper{}
-	newFileWrapper.fileSet = false
-	newFileWrapper.fileName = ""
-	return newFileWrapper
-}
-
 // TODO's
 // [ ] Create Chapter .cbz's based on given Information (no ComicInfo.xml yet)
 // 		[ ] Sort Into Volume Folders (requires following step)
@@ -76,57 +64,150 @@ func GetArg(argKey string) (string, error) {
 	return "", errors.New("arg " + argKey + " not found")
 }
 
+// Arguments:
+// -I: Interactive Mode, prompts user for required info when needed
+// -D: Domain. Only required if -P jnc is set
+// -L: Language Suffix for Series Title
+// -S: Series Name. optional when using -I
+// -P: Provider
+// -d: download Directory or File Directory. Depends on set -P
+// -u: username. Only required if -P jnc is set
+// -p: password. Only required if -P jnc is set
+// -f: file. Only required when no -P is set. Specifies the file to be used
+// -n: number. Only required when no -P is set. Specifies the volume number
 func main() {
 	interactive := false
 	if slices.Contains(os.Args, "-I") {
 		interactive = true
 	}
 
-	if !interactive {
-		panic("automatic mode is not implemented yet")
-	}
+	provider, _ := GetArg("-P")
 
-	domain, err := GetArg("-D")
-	if err != nil {
-		panic(err)
-	}
-
-	serLan, err := GetArg("-L")
+	serLan, _ := GetArg("-L")
 	if serLan != "" {
 		serLan = " " + serLan
 	}
 
-	downloadDir, err := GetArg("-d")
-	if err != nil {
-		panic(err)
+	switch provider {
+	case "":
+		{
+			// figure out settings needed for series input
+			series, err := GetArg("-S")
+			if err != nil {
+				series = GetUserInput("Enter Series Name: ")
+			}
+
+			epubData := EpubInfo{
+				series: series,
+			}
+
+			dir, err := GetArg("-d")
+			if err != nil {
+				epubData.path, err = GetArg("-f")
+				if err != nil {
+					epubData.path = GetUserInput("Enter File Path: ")
+					epubData.title = filepath.Base(epubData.path)[0 : len(filepath.Base(epubData.path))-len(filepath.Ext(epubData.path))]
+
+					number, err := GetArg("-n")
+					if err != nil {
+						number = GetUserInput("Enter Volume Number: ")
+					}
+					epubData.number = number
+
+					epub, err := zip.OpenReader(epubData.path)
+					if err != nil {
+						fmt.Println(err)
+					}
+
+					epubData.format = DetermineEpubFormat(epub)
+					if epubData.format.fType == "manga" {
+						panic("Manga without provider not yet handled")
+					}
+					ProcessEpub(epub, epubData)
+				}
+			} else {
+				if strings.LastIndex(dir, "/") != len(dir)-1 {
+					dir = dir + "/"
+				}
+				files, err := os.ReadDir(dir)
+				if err != nil {
+					panic(err)
+				}
+				for fIdx := range files {
+					epubData.path = dir + files[fIdx].Name()
+					epubData.title = files[fIdx].Name()
+
+					epubData.number = GetUserInput(fmt.Sprintf("Enter Volume Number for '%s':", files[fIdx].Name()))
+
+					epub, err := zip.OpenReader(epubData.path)
+					if err != nil {
+						fmt.Println(err)
+					}
+
+					epubData.format = DetermineEpubFormat(epub)
+					if epubData.format.fType == "manga" {
+						panic("Manga without provider not yet handled")
+					}
+					ProcessEpub(epub, epubData)
+				}
+			}
+		}
+	case "jnc":
+		{
+			if !interactive {
+				panic("automatic mode for JNC is not implemented yet")
+			}
+			settings := jnc.ProviderSettings{
+				Language: serLan,
+			}
+
+			domain, err := GetArg("-D")
+			if err != nil {
+				panic(err)
+			}
+			settings.Domain = domain
+
+			downloadDir, err := GetArg("-d")
+			if err != nil {
+				panic(err)
+			}
+			if strings.LastIndex(downloadDir, "/") != len(downloadDir)-1 {
+				downloadDir = downloadDir + "/"
+			}
+			settings.Directory = downloadDir
+
+			series, err := GetArg("-S")
+			if err == nil {
+				settings.Series = series
+			}
+
+			if slices.Contains(os.Args, "-u") {
+				idx := slices.Index(os.Args, "-u")
+				settings.Username = os.Args[idx+1]
+			} else {
+				settings.Username = GetUserInput("Enter Username: ")
+			}
+
+			if slices.Contains(os.Args, "-p") {
+				idx := slices.Index(os.Args, "-p")
+				settings.Password = os.Args[idx+1]
+			} else {
+				settings.Password = GetUserInput("Enter Password: ")
+			}
+
+			RunJNCProvider(settings)
+		}
 	}
 
-	if strings.LastIndex(downloadDir, "/") != len(downloadDir)-1 {
-		downloadDir = downloadDir + "/"
-	}
+}
 
+func RunJNCProvider(settings jnc.ProviderSettings) {
 	// initialize the J-Novel Club Instance
-	jnovel := jnc.NewJNC(domain)
+	jnovel := jnc.NewJNC(settings.Domain)
+	jnovel.SetUsername(settings.Username)
+	jnovel.SetPassword(settings.Password)
 
-	var username string
-	if slices.Contains(os.Args, "-u") {
-		idx := slices.Index(os.Args, "-u")
-		username = os.Args[idx+1]
-	} else {
-		username = GetUserInput("Enter Username: ")
-	}
-	jnovel.SetUsername(username)
-
-	var password string
-	if slices.Contains(os.Args, "-p") {
-		idx := slices.Index(os.Args, "-p")
-		password = os.Args[idx+1]
-	} else {
-		password = GetUserInput("Enter Password: ")
-	}
-	jnovel.SetPassword(password)
-
-	err = jnovel.Login()
+	err := jnovel.Login()
 	if err != nil {
 		panic(err)
 	}
@@ -170,12 +251,12 @@ func main() {
 			serie := seriesList[s]
 			if mode == "3" || mode == "4" {
 				if serie.Info.Type == "MANGA" {
-					HandleSeries(jnovel, serie, downloadDir, updatedOnly == "Y" || updatedOnly == "y", serLan)
+					HandleSeries(jnovel, serie, settings.Directory, updatedOnly == "Y" || updatedOnly == "y", settings.Language)
 				}
 			}
 			if mode == "3" || mode == "5" {
 				if serie.Info.Type == "NOVEL" {
-					HandleSeries(jnovel, serie, downloadDir, updatedOnly == "Y" || updatedOnly == "y", serLan)
+					HandleSeries(jnovel, serie, settings.Directory, updatedOnly == "Y" || updatedOnly == "y", settings.Language)
 				}
 			}
 		}
@@ -202,7 +283,7 @@ func main() {
 		serie := seriesList[seriesNumber-1]
 
 		if mode == "2" {
-			HandleSeries(jnovel, serie, downloadDir, false, serLan)
+			HandleSeries(jnovel, serie, settings.Directory, false, settings.Language)
 		} else {
 			ClearScreen()
 			fmt.Println("\n###[Volume Selection]###")
@@ -223,7 +304,7 @@ func main() {
 			}
 
 			volume := serie.Volumes[volumeNumber-1]
-			HandleVolume(jnovel, serie, volume, downloadDir, serLan)
+			HandleVolume(jnovel, serie, volume, settings.Directory, settings.Language)
 		}
 	}
 }
@@ -287,89 +368,159 @@ func HandleVolume(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc.VolumeAug
 		downloadLink = volume.Downloads[0].Link
 	}
 
-	DownloadAndProcessEpub(jnovel, serie, volume, downloadLink, downloadDir, titleSuffix)
-}
-
-func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc.VolumeAugmented, downloadLink string, downloadDirectory string, titleSuffix string) {
-	FormatNavigationFile := map[string]string{
-		"manga": "item/nav.ncx",
-		"novel": "OEBPS/toc.ncx",
-	}
-
-	FormatMetadataName := map[string]string{
-		"item/comic.opf":    "manga",
-		"OEBPS/content.opf": "novel",
-	}
-
-	MetaInf := "META-INF/container.xml"
-	file, err := jnovel.Download(downloadLink, downloadDirectory)
+	file, err := jnovel.Download(downloadLink, downloadDir)
 	if err != nil {
 		panic(err)
 	}
+	volume.Info, err = jnovel.FetchVolumeInfo(volume.Info)
+	if err != nil {
+		fmt.Printf("Error fetching volume info: %s\n", err)
+	}
+
+	var title string
+	var number string
+	if serie.Info.Title == "Ascendance of a Bookworm" {
+		splits := strings.Split(volume.Info.ShortTitle, " ")
+		title = serie.Info.Title + " " + splits[0] + " " + splits[1] + titleSuffix
+		number = splits[3]
+	} else {
+		title = serie.Info.Title + titleSuffix
+		number = strconv.Itoa(volume.Info.Number)
+	}
+
+	epubData := EpubInfo{
+		path:   file,
+		title:  volume.Info.Title,
+		series: title,
+		number: number,
+		info: ComicInfo{
+			Publisher:  "J-Novel Club",
+			Tags:       strings.Join(serie.Info.Tags, ","),
+			Series:     serie.Info.Title,
+			Volume:     volume.Info.Number,
+			Summary:    volume.Info.Description,
+			Writer:     volume.Info.Creators.TryGetName("AUTHOR"),
+			Translator: volume.Info.Creators.TryGetName("TRANSLATOR"),
+			Editor:     volume.Info.Creators.TryGetName("EDITOR"),
+		},
+	}
+
+	if volume.Info.Creators.Contains("ARTIST") {
+		epubData.info.CoverArtist = volume.Info.Creators.Get("ARTIST").Name
+	} else if volume.Info.Creators.Contains("ILLUSTRATOR") {
+		epubData.info.CoverArtist = volume.Info.Creators.Get("ILLUSTRATOR").Name
+	}
+
+	if volume.Info.Creators.Contains("LETTERER") {
+		epubData.info.Letterer = volume.Info.Creators.Get("LETTERER").Name
+	} else if volume.Info.Creators.Contains("ILLUSTRATOR") {
+		epubData.info.Letterer = volume.Info.Creators.Get("ILLUSTRATOR").Name
+	}
+
+	publishingTime, err := time.Parse(time.RFC3339, volume.Info.Publishing)
+	if err != nil {
+		panic(err)
+	}
+	epubData.info.Year = publishingTime.Year()
+	epubData.info.Month = int(publishingTime.Month())
+	epubData.info.Day = publishingTime.Day()
 
 	epub, err := zip.OpenReader(file)
 	if err != nil {
 		fmt.Println(err)
 	}
 
-	metadata := NewFileWrapper()
-	navigation := NewFileWrapper()
+	epubData.format = DetermineEpubFormat(epub)
+	ProcessEpub(epub, epubData)
+}
 
-	for i := range epub.Reader.File {
-		file := epub.Reader.File[i]
+type EpubInfo struct {
+	path   string
+	title  string
+	series string
+	number string
+	info   ComicInfo
+	format FormatInfo
+}
 
-		if file.Name == MetaInf {
-			doc := etree.NewDocument()
-			reader, err := file.Open()
-			if err != nil {
-				fmt.Println(err)
-			}
+type FormatInfo struct {
+	fType      string
+	metadata   zip.File
+	navigation zip.File
+}
 
-			if _, err := doc.ReadFrom(reader); err != nil {
-				_ = reader.Close()
-				panic(err)
-			}
+func DetermineEpubFormat(epub *zip.ReadCloser) FormatInfo {
+	FormatNavigationFile := map[string]string{
+		"manga": "item/nav.ncx",
+		"novel": "OEBPS/toc.ncx",
+	}
+	FormatMetadataName := map[string]string{
+		"item/comic.opf":    "manga",
+		"OEBPS/content.opf": "novel",
+	}
+	MetaInf := "META-INF/container.xml"
 
-			metadata.fileName = doc.FindElement("//container/rootfiles/rootfile").SelectAttr("full-path").Value
-			navigation.fileName = FormatNavigationFile[FormatMetadataName[metadata.fileName]]
+	metaInfFileIdx := slices.IndexFunc(epub.Reader.File, func(f *zip.File) bool {
+		if f.Name == MetaInf {
+			return true
 		}
+		return false
+	})
 
-		if len(metadata.fileName) != 0 && file.Name == metadata.fileName {
-			metadata.file = *file
-			metadata.fileSet = true
-		}
-
-		if len(navigation.fileName) != 0 && file.Name == navigation.fileName {
-			navigation.file = *file
-			navigation.fileSet = true
-		}
-
-		if metadata.fileSet && navigation.fileSet {
-			break
-		}
+	metaInfFile := epub.Reader.File[metaInfFileIdx]
+	doc := etree.NewDocument()
+	reader, err := metaInfFile.Open()
+	if err != nil {
+		fmt.Println(err)
 	}
 
-	// Switch based on metadata file
+	if _, err := doc.ReadFrom(reader); err != nil {
+		_ = reader.Close()
+		panic(err)
+	}
 
-	switch FormatMetadataName[metadata.fileName] {
+	metadataFileName := doc.FindElement("//container/rootfiles/rootfile").SelectAttr("full-path").Value
+	metaFileIdx := slices.IndexFunc(epub.Reader.File, func(f *zip.File) bool {
+		if f.Name == metadataFileName {
+			return true
+		}
+		return false
+	})
+	metadata := *epub.Reader.File[metaFileIdx]
+
+	navigationFileName := FormatNavigationFile[FormatMetadataName[metadataFileName]]
+	navigationFileIdx := slices.IndexFunc(epub.Reader.File, func(f *zip.File) bool {
+		if f.Name == navigationFileName {
+			return true
+		}
+		return false
+	})
+	navigation := *epub.Reader.File[navigationFileIdx]
+
+	return FormatInfo{
+		fType:      FormatMetadataName[metadataFileName],
+		metadata:   metadata,
+		navigation: navigation,
+	}
+}
+
+func ProcessEpub(epub *zip.ReadCloser, epubData EpubInfo) {
+	// Switch based on metadata file
+	switch epubData.format.fType {
 	case "manga":
 		{
 			comicInfoName := "ComicInfo.xml"
-			chapterList := GenerateMangaChapterList(navigation)
+			chapterList := GenerateMangaChapterList(epubData.format.navigation)
 
 			if chapterList.Len() == 0 {
 				fmt.Println("No chapters found, chapter name likely not supported")
 			}
 
-			basePath := downloadDirectory + volume.Info.Title + titleSuffix + "/"
+			basePath := filepath.Dir(epubData.path) + "/" + epubData.title
 			PrepareVolumeDirectory(basePath)
-			volume.Info, err = jnovel.FetchVolumeInfo(volume.Info)
-			if err != nil {
-				fmt.Println(err)
-			}
 
 			doc := etree.NewDocument()
-			reader, err := metadata.file.Open()
+			reader, err := epubData.format.metadata.Open()
 			if err != nil {
 				fmt.Println(err)
 			}
@@ -384,7 +535,7 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 			for ch := chapterList.Front(); ch != nil; ch = ch.Next() {
 				chap := ch.Value.(Chapter)
 
-				zipPath := basePath + volume.Info.Title + " Chapter " + chap.chDisplay + ".cbz"
+				zipPath := basePath + "/" + epubData.title + " Chapter " + chap.chDisplay + ".cbz"
 
 				if _, err = os.Stat(zipPath); err == nil {
 					err := os.Remove(zipPath)
@@ -444,7 +595,7 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 					}
 				}
 
-				comicInfo, err := GenerateChapterMetadata(volume, serie, len(chap.pages), language, chap.chDisplay, titleSuffix)
+				comicInfo, err := GenerateChapterMetadata(epubData, len(chap.pages), language, chap.chDisplay)
 				if err != nil {
 					fmt.Println(err)
 				}
@@ -459,7 +610,7 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 			}
 
 			epub.Close()
-			os.Remove(file)
+			os.Remove(epubData.path)
 		}
 	case "novel":
 		{
@@ -467,7 +618,7 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 			CalibreSeriesIndexAttr := "calibre:series_index"
 			EpubTitleTag := "//package/metadata"
 
-			metafile, err := metadata.file.Open()
+			metafile, err := epubData.format.metadata.Open()
 			if err != nil {
 				fmt.Println(err)
 			}
@@ -481,29 +632,18 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 
 			seriesTitle := etree.NewElement("meta")
 			seriesTitle.CreateAttr("name", CalibreSeriesAttr)
-			var title string
-			var number string
-			if serie.Info.Title == "Ascendance of a Bookworm" {
-				splits := strings.Split(volume.Info.ShortTitle, " ")
-				title = serie.Info.Title + " " + splits[0] + " " + splits[1] + titleSuffix
-				number = splits[3]
-			} else {
-				title = serie.Info.Title + titleSuffix
-				number = strconv.Itoa(volume.Info.Number)
-			}
-
-			seriesTitle.CreateAttr("content", title)
+			seriesTitle.CreateAttr("content", epubData.series)
 
 			seriesNumber := etree.NewElement("meta")
 			seriesNumber.CreateAttr("name", CalibreSeriesIndexAttr)
-			seriesNumber.CreateAttr("content", number)
+			seriesNumber.CreateAttr("content", epubData.number)
 
 			doc.FindElement(EpubTitleTag).InsertChildAt(idx+1, seriesTitle)
 			doc.FindElement(EpubTitleTag).InsertChildAt(idx+2, seriesNumber)
 			doc.Indent(2)
 
 			// Open the zip file for writing
-			zipfile, err := os.OpenFile(file+".new", os.O_RDWR|os.O_CREATE, 0644)
+			zipfile, err := os.OpenFile(epubData.path+".new", os.O_RDWR|os.O_CREATE, 0644)
 			if err != nil {
 				panic(err)
 			}
@@ -521,7 +661,7 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 				panic(err)
 			}
 
-			metawriter, err := zipWriter.Create(metadata.fileName)
+			metawriter, err := zipWriter.Create(epubData.format.metadata.Name)
 			if err != nil {
 				panic(err)
 			}
@@ -532,7 +672,7 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 			}
 
 			for _, f := range epub.File {
-				if f.Name != metadata.fileName {
+				if f.Name != epubData.format.metadata.Name {
 					writer, err := zipWriter.Create(f.Name)
 					if err != nil {
 						panic(err)
@@ -552,68 +692,57 @@ func DownloadAndProcessEpub(jnovel jnc.Api, serie jnc.SerieAugmented, volume jnc
 
 			epub.Close()
 			zipWriter.Close()
-			source, _ := os.Open(file + ".new")
-			dest, _ := os.Create(file)
+			source, _ := os.Open(epubData.path + ".new")
+			dest, _ := os.Create(epubData.path)
 			io.Copy(dest, source)
-			os.Remove(file + ".new")
+			os.Remove(epubData.path + ".new")
 		}
 	}
 }
 
-func GenerateChapterMetadata(volume jnc.VolumeAugmented, serie jnc.SerieAugmented, pageCount int, language string, chapterNumber string, titleSuffix string) ([]byte, error) {
+func GenerateChapterMetadata(epubData EpubInfo, pageCount int, language string, chapterNumber string) ([]byte, error) {
 	comicInfo := ComicInfo{
 		XMLName: "ComicInfo",
 		XMLNS:   "http://www.w3.org/2001/XMLSchema-instance",
 		XSI:     "ComicInfo.xsd",
 	}
 
-	vInfo := volume.Info
-	sInfo := serie.Info
-
-	comicInfo.Series = sInfo.Title
-	comicInfo.Title = vInfo.Title + titleSuffix
+	comicInfo.Series = epubData.info.Series
+	comicInfo.Title = epubData.title
 	comicInfo.Number = chapterNumber
-	comicInfo.Volume = vInfo.Number
+	comicInfo.Volume = epubData.info.Volume
 
 	comicInfo.Count = -1 // TODO somehow fetch actual completion status
 
-	comicInfo.Summary = vInfo.Description
+	comicInfo.Summary = epubData.info.Summary
 
-	publishingTime, err := time.Parse(time.RFC3339, vInfo.Publishing)
-	if err != nil {
-		return nil, err
-	}
-	comicInfo.Year = publishingTime.Year()
-	comicInfo.Month = int(publishingTime.Month())
-	comicInfo.Day = publishingTime.Day()
+	comicInfo.Year = epubData.info.Year
+	comicInfo.Month = epubData.info.Month
+	comicInfo.Day = epubData.info.Day
 
-	if vInfo.Creators.Contains("AUTHOR") {
-		comicInfo.Writer = vInfo.Creators.Get("AUTHOR").Name
+	if epubData.info.Writer != "" {
+		comicInfo.Writer = epubData.info.Writer
 	}
 
-	if vInfo.Creators.Contains("LETTERER") {
-		comicInfo.Letterer = vInfo.Creators.Get("LETTERER").Name
-	} else if vInfo.Creators.Contains("ILLUSTRATOR") {
-		comicInfo.Letterer = vInfo.Creators.Get("ILLUSTRATOR").Name
+	if epubData.info.Letterer != "" {
+		comicInfo.Letterer = epubData.info.Letterer
 	}
 
-	if vInfo.Creators.Contains("ARTIST") {
-		comicInfo.CoverArtist = vInfo.Creators.Get("ARTIST").Name
-	} else if vInfo.Creators.Contains("ILLUSTRATOR") {
-		comicInfo.CoverArtist = vInfo.Creators.Get("ILLUSTRATOR").Name
+	if epubData.info.CoverArtist != "" {
+		comicInfo.CoverArtist = epubData.info.CoverArtist
 	}
 
-	if vInfo.Creators.Contains("TRANSLATOR") {
-		comicInfo.Translator = vInfo.Creators.Get("TRANSLATOR").Name
+	if epubData.info.Translator != "" {
+		comicInfo.Translator = epubData.info.Translator
 	}
 
-	if vInfo.Creators.Contains("EDITOR") {
-		comicInfo.Editor = vInfo.Creators.Get("EDITOR").Name
+	if epubData.info.Editor != "" {
+		comicInfo.Editor = epubData.info.Editor
 	}
 
-	comicInfo.Publisher = "J-Novel Club"
+	comicInfo.Publisher = epubData.info.Publisher
 
-	comicInfo.Tags = strings.Join(sInfo.Tags, ",")
+	comicInfo.Tags = epubData.info.Tags
 	comicInfo.PageCount = pageCount
 	comicInfo.Language = language
 	comicInfo.Format = "Comic" // JNC reports this as type in the epub file
@@ -820,8 +949,8 @@ func GetLastValidChapterNumber(currentChapter *list.Element) Chapter {
 	return currentChapter.Value.(Chapter)
 }
 
-func GenerateMangaChapterList(navigation FileWrapper) *list.List {
-	reader, err := navigation.file.Open()
+func GenerateMangaChapterList(navigation zip.File) *list.List {
+	reader, err := navigation.Open()
 	if err != nil {
 		fmt.Println(err)
 	}