feat: init with converting cbz files

This commit is contained in:
Antoine Aflalo
2024-08-26 22:48:54 -04:00
parent d06653c503
commit 2aeecd363a
20 changed files with 930 additions and 0 deletions

61
cbz/cbz_creator.go Normal file
View File

@@ -0,0 +1,61 @@
package cbz
import (
"CBZOptimizer/packer"
"archive/zip"
"fmt"
"os"
)
func WriteChapterToCBZ(chapter *packer.Chapter, outputFilePath string) error {
// Create a new ZIP file
zipFile, err := os.Create(outputFilePath)
if err != nil {
return fmt.Errorf("failed to create .cbz file: %w", err)
}
defer zipFile.Close()
// Create a new ZIP writer
zipWriter := zip.NewWriter(zipFile)
defer zipWriter.Close()
// Write each page to the ZIP archive
for _, page := range chapter.Pages {
// Construct the file name for the page
var fileName string
if page.IsSplitted {
// Use the format page%03d-%02d for split pages
fileName = fmt.Sprintf("page_%03d-%02d%s", page.Index, page.SplitPartIndex, page.Extension)
} else {
// Use the format page%03d for non-split pages
fileName = fmt.Sprintf("page_%03d%s", page.Index, page.Extension)
}
// Create a new file in the ZIP archive
fileWriter, err := zipWriter.Create(fileName)
if err != nil {
return fmt.Errorf("failed to create file in .cbz: %w", err)
}
// Write the page contents to the file
_, err = fileWriter.Write(page.Contents.Bytes())
if err != nil {
return fmt.Errorf("failed to write page contents: %w", err)
}
}
// Optionally, write the ComicInfo.xml file if present
if chapter.ComicInfoXml != "" {
comicInfoWriter, err := zipWriter.Create("ComicInfo.xml")
if err != nil {
return fmt.Errorf("failed to create ComicInfo.xml in .cbz: %w", err)
}
_, err = comicInfoWriter.Write([]byte(chapter.ComicInfoXml))
if err != nil {
return fmt.Errorf("failed to write ComicInfo.xml contents: %w", err)
}
}
return nil
}

115
cbz/cbz_creator_test.go Normal file
View File

@@ -0,0 +1,115 @@
package cbz
import (
"CBZOptimizer/packer"
"archive/zip"
"bytes"
"os"
"testing"
)
func TestWriteChapterToCBZ(t *testing.T) {
// Define test cases
testCases := []struct {
name string
chapter *packer.Chapter
expectedFiles []string
}{
{
name: "Single page, no ComicInfo",
chapter: &packer.Chapter{
Pages: []*packer.Page{
{
Index: 0,
Extension: ".jpg",
Contents: bytes.NewBuffer([]byte("image data")),
},
},
},
expectedFiles: []string{"page_000.jpg"},
},
{
name: "Multiple pages with ComicInfo",
chapter: &packer.Chapter{
Pages: []*packer.Page{
{
Index: 0,
Extension: ".jpg",
Contents: bytes.NewBuffer([]byte("image data 1")),
},
{
Index: 1,
Extension: ".jpg",
Contents: bytes.NewBuffer([]byte("image data 2")),
},
},
ComicInfoXml: "<Series>Boundless Necromancer</Series>",
},
expectedFiles: []string{"page_000.jpg", "page_001.jpg", "ComicInfo.xml"},
},
{
name: "Split page",
chapter: &packer.Chapter{
Pages: []*packer.Page{
{
Index: 0,
Extension: ".jpg",
Contents: bytes.NewBuffer([]byte("split image data")),
IsSplitted: true,
SplitPartIndex: 1,
},
},
},
expectedFiles: []string{"page_000-01.jpg"},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Create a temporary file for the .cbz output
tempFile, err := os.CreateTemp("", "*.cbz")
if err != nil {
t.Fatalf("Failed to create temporary file: %v", err)
}
defer os.Remove(tempFile.Name())
// Write the chapter to the .cbz file
err = WriteChapterToCBZ(tc.chapter, tempFile.Name())
if err != nil {
t.Fatalf("Failed to write chapter to CBZ: %v", err)
}
// Open the .cbz file as a zip archive
r, err := zip.OpenReader(tempFile.Name())
if err != nil {
t.Fatalf("Failed to open CBZ file: %v", err)
}
defer r.Close()
// Collect the names of the files in the archive
var filesInArchive []string
for _, f := range r.File {
filesInArchive = append(filesInArchive, f.Name)
}
// Check if all expected files are present
for _, expectedFile := range tc.expectedFiles {
found := false
for _, actualFile := range filesInArchive {
if actualFile == expectedFile {
found = true
break
}
}
if !found {
t.Errorf("Expected file %s not found in archive", expectedFile)
}
}
// Check if there are no unexpected files
if len(filesInArchive) != len(tc.expectedFiles) {
t.Errorf("Expected %d files, but found %d", len(tc.expectedFiles), len(filesInArchive))
}
})
}
}

71
cbz/cbz_loader.go Normal file
View File

@@ -0,0 +1,71 @@
package cbz
import (
"CBZOptimizer/packer"
"archive/zip"
"bytes"
"fmt"
"io"
"io/ioutil"
"path/filepath"
"strings"
)
func LoadChapter(filePath string) (*packer.Chapter, error) {
// Open the .cbz file
r, err := zip.OpenReader(filePath)
if err != nil {
return nil, fmt.Errorf("failed to open .cbz file: %w", err)
}
defer r.Close()
chapter := &packer.Chapter{
FilePath: filePath,
}
for _, f := range r.File {
if !f.FileInfo().IsDir() {
// Open the file inside the zip
rc, err := f.Open()
if err != nil {
return nil, fmt.Errorf("failed to open file inside .cbz: %w", err)
}
// Determine the file extension
ext := strings.ToLower(filepath.Ext(f.Name))
if ext == ".xml" && strings.ToLower(filepath.Base(f.Name)) == "comicinfo.xml" {
// Read the ComicInfo.xml file content
xmlContent, err := ioutil.ReadAll(rc)
if err != nil {
rc.Close()
return nil, fmt.Errorf("failed to read ComicInfo.xml content: %w", err)
}
chapter.ComicInfoXml = string(xmlContent)
} else {
// Read the file contents for page
buf := new(bytes.Buffer)
_, err = io.Copy(buf, rc)
if err != nil {
rc.Close()
return nil, fmt.Errorf("failed to read file contents: %w", err)
}
// Create a new Page object
page := &packer.Page{
Index: uint16(len(chapter.Pages)), // Simple index based on order
Extension: ext,
Size: uint64(buf.Len()),
Contents: buf,
IsSplitted: false,
}
// Add the page to the chapter
chapter.Pages = append(chapter.Pages, page)
}
rc.Close()
}
}
return chapter, nil
}

30
cbz/cbz_loader_test.go Normal file
View File

@@ -0,0 +1,30 @@
package cbz
import (
"strings"
"testing"
)
func TestLoadChapter(t *testing.T) {
// Define the path to the .cbz file
chapterFilePath := "../testdata/Chapter 1.cbz"
// Load the chapter
chapter, err := LoadChapter(chapterFilePath)
if err != nil {
t.Fatalf("Failed to load chapter: %v", err)
}
// Check the number of pages
expectedPages := 16
actualPages := len(chapter.Pages)
if actualPages != expectedPages {
t.Errorf("Expected %d pages, but got %d", expectedPages, actualPages)
}
// Check if ComicInfoXml contains the expected series name
expectedSeries := "<Series>Boundless Necromancer</Series>"
if !strings.Contains(chapter.ComicInfoXml, expectedSeries) {
t.Errorf("ComicInfoXml does not contain the expected series: %s", expectedSeries)
}
}