diff --git a/go.mod b/go.mod index 11f1804..d43815e 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module code.fmartingr.dev/fmartingr/mangadex2cbr go 1.15 require ( - code.fmartingr.dev/fmartingr/go-mangadex v0.0.0-20210206105358-8cfcb7a013b8 + code.fmartingr.dev/fmartingr/go-mangadex v0.0.0-20210209223856-e7c5b4489931 github.com/sirupsen/logrus v1.7.0 + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect ) diff --git a/go.sum b/go.sum index 03e6074..4b3ce80 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -code.fmartingr.dev/fmartingr/go-mangadex v0.0.0-20210206105358-8cfcb7a013b8 h1:JS8C40VcGUO1WdaAQfofvu4ROzDSJ1YCG0ycswOPfyY= -code.fmartingr.dev/fmartingr/go-mangadex v0.0.0-20210206105358-8cfcb7a013b8/go.mod h1:C4HCcFpl4VDk4O5Huau2cdTAOuwqIP9NBXItWhaMZVo= +code.fmartingr.dev/fmartingr/go-mangadex v0.0.0-20210209223856-e7c5b4489931 h1:DqfEAJhJaP+DYVVrw9LjoDol4NLD14wLVyCe+8Cblsc= +code.fmartingr.dev/fmartingr/go-mangadex v0.0.0-20210209223856-e7c5b4489931/go.mod h1:kcfwcGVuiSu/dloZwo/G8FxDzNHA/zanIr8DC5VResQ= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -10,3 +10,5 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index dfc90f3..0721d7b 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -1,9 +1,11 @@ package cli import ( + "archive/zip" "errors" "flag" "fmt" + "io" "io/ioutil" "net/http" "os" @@ -66,7 +68,7 @@ func DownloadFile(url string, destinationPath string) error { _, errWrite := file.Write(body) if errWrite != nil { - logrus.Errorf("Error writting image: %s", errWrite) + return errWrite } return nil @@ -108,6 +110,8 @@ func Start() { panic(err) } + // TODO: Allow selecting a name from AlternativeNames + logrus.Infof("Found! %s", manga.Title) logrus.Infof("Getting chapter information...") @@ -181,10 +185,11 @@ func Start() { // Usually chapters are just 1, 2, 3... but in some ocassions the chapters are sorted like // 1, 1.1, 1.2, 2, ... and that make a mess when sorting. Making the "non-decimal" chapters // fake "decimals" solves this issue easily for us. + // TODO Delete me - if mangaChapters[chapter].Volume != "1" { - continue - } + // if mangaChapters[chapter].Volume != "1" { + // continue + // } if !strings.Contains(mangaChapters[chapter].Chapter, ".") { mangaChapters[chapter].Chapter += ".0" @@ -219,10 +224,10 @@ func Start() { var task tasks.Task task, downloadChaptersTasks = tasks.TaskPop(downloadChaptersTasks) - // TODO: remove me - if task.Arguments["volume"] != "1" { - continue - } + // TODO: Delete me + // if task.Arguments["volume"] != "1" { + // continue + // } chapter, errChapterDetail := manga.GetChapter(task.Arguments["chapterID"]) if errChapterDetail != nil { @@ -265,6 +270,8 @@ func Start() { logrus.Tracef("Downlading page to %s", destinationPath) errDownload := DownloadFile(task.Arguments["url"], destinationPath) if errDownload != nil { + // TODO: Distinguish between 420 errors (GONE -> Use fallback) and other errors to keep retrying on the + // original (potentially MangaDex@HOME) urls. _, exists := task.Arguments["urlFallback"] if exists { logrus.Warnf("Using fallback for page %s", task.Arguments["filename"]) @@ -279,29 +286,110 @@ func Start() { logrus.Errorf("Error downloading page: %s", errDownload) } } + time.Sleep(100 * time.Millisecond) } - time.Sleep(100 * time.Millisecond) } + logrus.Info("Downloading covers") covers, errCovers := manga.GetCovers() if errCovers != nil { logrus.Errorf("Error getting cover information: %s", errCovers) } for cover := range covers { - if covers[cover].Volume == "1" { - extension := path.Ext(covers[cover].URL) - coverOutputPath := filepath.Join(mangaOutputPath, fmt.Sprintf("%s - Volume %s", manga.Title, covers[cover].Volume), fmt.Sprintf("0000%s", extension)) - if !fileExists(coverOutputPath) { - logrus.Tracef("Downloading cover from %s", covers[cover].URL) - logrus.Tracef("Writting cover to: %s", coverOutputPath) - errDownload := DownloadFile(covers[cover].URL, coverOutputPath) - if errDownload != nil { - logrus.Errorf("Error downloading cover: %s", errDownload) - } + extension := path.Ext(covers[cover].URL) + coverOutputPath := filepath.Join(mangaOutputPath, fmt.Sprintf("%s - Volume %s", manga.Title, covers[cover].Volume), fmt.Sprintf("0000%s", extension)) + if !fileExists(coverOutputPath) { + logrus.Tracef("Downloading cover from %s", covers[cover].URL) + logrus.Tracef("Writting cover to: %s", coverOutputPath) + errDownload := DownloadFile(covers[cover].URL, coverOutputPath) + if errDownload != nil { + logrus.Errorf("Error downloading cover: %s", errDownload) } time.Sleep(100 * time.Millisecond) } } + // TODO: Zip folders into CBR files + logrus.Info("Compressing volumes") + + files, errReadVolumes := ioutil.ReadDir(mangaOutputPath) + if errReadVolumes != nil { + logrus.Errorf("Error reading path with volume files: %s", errReadVolumes) + } + + for file := range files { + if files[file].IsDir() { + destinationPath := filepath.Join(mangaOutputPath, files[file].Name()) + ".cbr" + if !fileExists(destinationPath) { + _, errZip := zipVolume(destinationPath) + if errZip != nil { + logrus.Errorf("Error packing CBR file: %s", errZip) + } + } + } + } + +} + +func zipVolume(destinationPath string) (string, error) { + logrus.Tracef("Packing volume %s", path.Base(destinationPath)) + pagesPath := strings.Replace(destinationPath, path.Ext(destinationPath), "", 1) + + newZipFile, errCreate := os.Create(destinationPath) + if errCreate != nil { + return "", errCreate + } + defer newZipFile.Close() + + zipWriter := zip.NewWriter(newZipFile) + defer zipWriter.Close() + + files, errReadFiles := ioutil.ReadDir(pagesPath) + if errReadFiles != nil { + return "", errReadFiles + } + + for _, file := range files { + if errAddFile := AddFileToZip(zipWriter, filepath.Join(pagesPath, file.Name())); errAddFile != nil { + return "", errAddFile + } + } + + return "", nil +} + +func AddFileToZip(zipWriter *zip.Writer, filename string) error { + + fileToZip, err := os.Open(filename) + if err != nil { + return err + } + defer fileToZip.Close() + + // Get the file information + info, err := fileToZip.Stat() + if err != nil { + return err + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // Using FileInfoHeader() above only uses the basename of the file. If we want + // to preserve the folder structure we can overwrite this with the full path. + header.Name = filename + + // Change to deflate to gain better compression + // see http://golang.org/pkg/archive/zip/#pkg-constants + header.Method = zip.Deflate + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + _, err = io.Copy(writer, fileToZip) + return err }