mirror of
https://github.com/Belphemur/CBZOptimizer.git
synced 2026-01-11 16:17:04 +01:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea8fd55cc2 | ||
|
|
709c53d647 | ||
|
|
919a53fec7 | ||
|
|
d3b3a73b8f | ||
|
|
188211e26d | ||
|
|
f57a88eaf4 | ||
|
|
6e6b66b5eb | ||
|
|
1ff1bed3cc | ||
|
|
196938718c | ||
|
|
9972709d32 | ||
|
|
152fa85577 | ||
|
|
554fce5d1e | ||
|
|
25357e9ec6 | ||
|
|
ecc561263f | ||
|
|
fb1056e5e7 | ||
|
|
07bc88bb04 | ||
|
|
8c3665fa53 | ||
|
|
8dce346997 | ||
|
|
4646789e4e | ||
|
|
22ca56c98b | ||
|
|
f45a1d4ed0 | ||
|
|
ee53fddf02 | ||
|
|
f416f1ff32 | ||
|
|
969993161f | ||
|
|
f6b41f6391 | ||
|
|
0bb9e4320c | ||
|
|
35cfe41aa6 | ||
|
|
021c647a6e | ||
|
|
6217254305 | ||
|
|
0ad711a24d | ||
|
|
f24e4cc26e | ||
|
|
1d3a8396f2 | ||
|
|
497f206c50 | ||
|
|
9ade876952 | ||
|
|
103d38c74b | ||
|
|
80a1afe7c3 | ||
|
|
2de7bc7a04 | ||
|
|
bccf7a7029 | ||
|
|
4e80ddfb3a | ||
|
|
090bbac593 | ||
|
|
c8b0f11784 | ||
|
|
449b57b14e | ||
|
|
0dcb55f06d | ||
|
|
33ae460caf | ||
|
|
1af484aea8 | ||
|
|
e798a59a43 | ||
|
|
72086d658e | ||
|
|
a7bca7ee05 | ||
|
|
ba82003b53 | ||
|
|
5f7e7de644 | ||
|
|
5b183cca29 | ||
|
|
d901be14fa | ||
|
|
a80997835a | ||
|
|
37bb12fd61 | ||
|
|
c19afb9f40 | ||
|
|
911e1041ff | ||
|
|
a10d589b67 | ||
|
|
da508fcb3f | ||
|
|
57f5282032 | ||
|
|
d4f8d8b5ff | ||
|
|
1b026b9dbd | ||
|
|
12cc8d4e25 | ||
|
|
3442b2a845 | ||
|
|
b9a1fb213a | ||
|
|
278ee130e3 | ||
|
|
5357ece2b7 | ||
|
|
dbef43d376 | ||
|
|
7c63ea49c0 | ||
|
|
8a067939af | ||
|
|
9e61ff4634 |
23
.github/workflows/qodana.yml
vendored
Normal file
23
.github/workflows/qodana.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Qodana
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
|
||||
jobs:
|
||||
qodana:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
|
||||
fetch-depth: 0 # a full history is required for pull request analysis
|
||||
- name: 'Qodana Scan'
|
||||
uses: JetBrains/qodana-action@v2024.1
|
||||
env:
|
||||
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -22,12 +22,14 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # this is important, otherwise it won't checkout the full tree (i.e. no previous tags)
|
||||
- name: Install libwebp-dev
|
||||
run: sudo apt-get install -y libwebp-dev
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.23
|
||||
cache: true
|
||||
- uses: sigstore/cosign-installer@v3.6.0 # installs cosign
|
||||
- uses: anchore/sbom-action/download-syft@v0.17.2 # installs syft
|
||||
- uses: sigstore/cosign-installer@v3.7.0 # installs cosign
|
||||
- uses: anchore/sbom-action/download-syft@v0.18.0 # installs syft
|
||||
- uses: docker/login-action@v3 # login to ghcr
|
||||
with:
|
||||
registry: ghcr.io
|
||||
|
||||
15
.github/workflows/test.yml
vendored
15
.github/workflows/test.yml
vendored
@@ -17,6 +17,9 @@ jobs:
|
||||
with:
|
||||
go-version: '1.23'
|
||||
|
||||
- name: Install libwebp-dev
|
||||
run: sudo apt-get install -y libwebp-dev
|
||||
|
||||
- name: Install dependencies
|
||||
run: go mod tidy
|
||||
|
||||
@@ -32,15 +35,19 @@ jobs:
|
||||
set -o pipefail
|
||||
go test -v 2>&1 ./... -coverprofile=coverage.txt | tee test-results.txt
|
||||
- name: Analyse test results
|
||||
run: go-junit-report < test-results.txt > report.xml
|
||||
if: ${{ !cancelled() }}
|
||||
run: go-junit-report < test-results.txt > junit.xml
|
||||
- name: Upload test result artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results.txt
|
||||
path: |
|
||||
test-results.txt
|
||||
junit.xml
|
||||
retention-days: 7
|
||||
- name: Upload results to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
- name: Upload test results to Codecov
|
||||
|
||||
@@ -29,7 +29,6 @@ builds:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
# ensures mod timestamp to be the commit timestamp
|
||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||
flags:
|
||||
@@ -38,7 +37,7 @@ builds:
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }}
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- CGO_ENABLED=1
|
||||
# config the checksum filename
|
||||
# https://goreleaser.com/customization/checksum
|
||||
checksum:
|
||||
|
||||
33
Dockerfile
33
Dockerfile
@@ -1,21 +1,30 @@
|
||||
FROM alpine:latest
|
||||
FROM debian:sid-slim
|
||||
LABEL authors="Belphemur"
|
||||
ARG APP_PATH=/usr/local/bin/CBZOptimizer
|
||||
ENV USER=abc
|
||||
ENV CONFIG_FOLDER=/config
|
||||
ENV PUID=99
|
||||
RUN mkdir -p "${CONFIG_FOLDER}" && adduser \
|
||||
--disabled-password \
|
||||
--gecos "" \
|
||||
--home "$(pwd)" \
|
||||
--ingroup "users" \
|
||||
--no-create-home \
|
||||
--uid "${PUID}" \
|
||||
"${USER}" && \
|
||||
chown ${PUID}:${GUID} "${CONFIG_FOLDER}"
|
||||
|
||||
COPY CBZOptimizer /usr/local/bin/CBZOptimizer
|
||||
RUN mkdir -p "${CONFIG_FOLDER}" && \
|
||||
useradd \
|
||||
--system \
|
||||
--no-create-home \
|
||||
--home-dir "${CONFIG_FOLDER}" \
|
||||
--gid "users" \
|
||||
--uid "${PUID}" \
|
||||
"${USER}" && \
|
||||
chown ${PUID}:users "${CONFIG_FOLDER}"
|
||||
|
||||
RUN apk add --no-cache inotify-tools bash-completion && chmod +x /usr/local/bin/CBZOptimizer && /usr/local/bin/CBZOptimizer completion bash > /etc/bash_completion.d/CBZOptimizer
|
||||
COPY CBZOptimizer ${APP_PATH}
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get full-upgrade -y && \
|
||||
apt-get install -y inotify-tools bash-completion libwebp7 && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
chmod +x ${APP_PATH} && \
|
||||
${APP_PATH} completion bash > /etc/bash_completion.d/CBZOptimizer
|
||||
|
||||
VOLUME ${CONFIG_FOLDER}
|
||||
USER ${USER}
|
||||
ENTRYPOINT ["/usr/local/bin/CBZOptimizer"]
|
||||
36
README.md
36
README.md
@@ -1,3 +1,4 @@
|
||||
|
||||
# CBZOptimizer
|
||||
|
||||
CBZOptimizer is a Go-based tool designed to optimize CBZ (Comic Book Zip) files by converting images to a specified format and quality. This tool is useful for reducing the size of comic book archives while maintaining acceptable image quality.
|
||||
@@ -8,14 +9,15 @@ CBZOptimizer is a Go-based tool designed to optimize CBZ (Comic Book Zip) files
|
||||
- Adjust the quality of the converted images.
|
||||
- Process multiple chapters in parallel.
|
||||
- Option to override the original CBZ files.
|
||||
- Watch a folder for new CBZ files and optimize them automatically.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone the repository:
|
||||
```sh
|
||||
git clone https://github.com/belphemur/CBZOptimizer.git
|
||||
cd CBZOptimizer
|
||||
```
|
||||
```sh
|
||||
git clone https://github.com/belphemur/CBZOptimizer.git
|
||||
cd CBZOptimizer
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```sh
|
||||
@@ -26,10 +28,22 @@ CBZOptimizer is a Go-based tool designed to optimize CBZ (Comic Book Zip) files
|
||||
|
||||
### Command Line Interface
|
||||
|
||||
The tool provides a CLI command to optimize CBZ files. Below is an example of how to use it:
|
||||
The tool provides CLI commands to optimize and watch CBZ files. Below are examples of how to use them:
|
||||
|
||||
#### Optimize Command
|
||||
|
||||
Optimize all CBZ files in a folder recursively:
|
||||
|
||||
```sh
|
||||
go run main.go optimize --quality 85 --parallelism 2 --override /path/to/cbz/files
|
||||
go run main.go optimize [folder] --quality 85 --parallelism 2 --override --format webp --split
|
||||
```
|
||||
|
||||
#### Watch Command
|
||||
|
||||
Watch a folder for new CBZ files and optimize them automatically:
|
||||
|
||||
```sh
|
||||
go run main.go watch [folder] --quality 85 --override --format webp --split
|
||||
```
|
||||
|
||||
### Flags
|
||||
@@ -37,6 +51,8 @@ go run main.go optimize --quality 85 --parallelism 2 --override /path/to/cbz/fil
|
||||
- `--quality`, `-q`: Quality for conversion (0-100). Default is 85.
|
||||
- `--parallelism`, `-n`: Number of chapters to convert in parallel. Default is 2.
|
||||
- `--override`, `-o`: Override the original CBZ files. Default is false.
|
||||
- `--split`, `-s`: Split long pages into smaller chunks. Default is false.
|
||||
- `--format`, `-f`: Format to convert the images to (e.g., webp). Default is webp.
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -46,6 +62,12 @@ To run the tests, use the following command:
|
||||
go test ./... -v
|
||||
```
|
||||
|
||||
## Requirement
|
||||
Needs to have libwep installed on the machine if you're not using the docker image
|
||||
|
||||
## Docker
|
||||
`ghcr.io/belphemur/cbzoptimizer:latest`
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
The project includes a GitHub Actions workflow to run tests on every push and pull request to the `main` branch. The workflow is defined in `.github/workflows/go.yml`.
|
||||
@@ -60,4 +82,4 @@ The project includes a GitHub Actions workflow to run tests on every push and pu
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the `LICENSE` file for details.
|
||||
This project is licensed under the MIT License. See the `LICENSE` file for details.
|
||||
@@ -3,7 +3,8 @@ package cbz
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"github.com/belphemur/CBZOptimizer/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/utils/errs"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
@@ -14,15 +15,14 @@ func WriteChapterToCBZ(chapter *manga.Chapter, outputFilePath string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create .cbz file: %w", err)
|
||||
}
|
||||
defer zipFile.Close()
|
||||
defer errs.Capture(&err, zipFile.Close, "failed to close .cbz file")
|
||||
|
||||
// Create a new ZIP writer
|
||||
zipWriter := zip.NewWriter(zipFile)
|
||||
err = zipWriter.SetComment("Created by CBZOptimizer")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer zipWriter.Close()
|
||||
defer errs.Capture(&err, zipWriter.Close, "failed to close .cbz writer")
|
||||
|
||||
// Write each page to the ZIP archive
|
||||
for _, page := range chapter.Pages {
|
||||
@@ -71,18 +71,11 @@ func WriteChapterToCBZ(chapter *manga.Chapter, outputFilePath string) error {
|
||||
}
|
||||
|
||||
if chapter.IsConverted {
|
||||
convertedWriter, err := zipWriter.CreateHeader(&zip.FileHeader{
|
||||
Name: "Converted.txt",
|
||||
Method: zip.Deflate,
|
||||
Modified: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create Converted.txt in .cbz: %w", err)
|
||||
}
|
||||
|
||||
_, err = convertedWriter.Write([]byte(fmt.Sprintf("%s\nThis chapter has been converted by CBZOptimizer.", chapter.ConvertedTime)))
|
||||
convertedString := fmt.Sprintf("%s\nThis chapter has been converted by CBZOptimizer.", chapter.ConvertedTime)
|
||||
err = zipWriter.SetComment(convertedString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write Converted.txt contents: %w", err)
|
||||
return fmt.Errorf("failed to write comment: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,23 @@ package cbz
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"github.com/belphemur/CBZOptimizer/manga"
|
||||
"fmt"
|
||||
"github.com/belphemur/CBZOptimizer/v2/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/utils/errs"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWriteChapterToCBZ(t *testing.T) {
|
||||
currentTime := time.Now()
|
||||
|
||||
// Define test cases
|
||||
testCases := []struct {
|
||||
name string
|
||||
chapter *manga.Chapter
|
||||
expectedFiles []string
|
||||
name string
|
||||
chapter *manga.Chapter
|
||||
expectedFiles []string
|
||||
expectedComment string
|
||||
}{
|
||||
//test case where there is only one page and ComicInfo and the chapter is converted
|
||||
{
|
||||
@@ -29,9 +34,10 @@ func TestWriteChapterToCBZ(t *testing.T) {
|
||||
},
|
||||
ComicInfoXml: "<Series>Boundless Necromancer</Series>",
|
||||
IsConverted: true,
|
||||
ConvertedTime: time.Now(),
|
||||
ConvertedTime: currentTime,
|
||||
},
|
||||
expectedFiles: []string{"0000.jpg", "ComicInfo.xml", "Converted.txt"},
|
||||
expectedFiles: []string{"0000.jpg", "ComicInfo.xml"},
|
||||
expectedComment: fmt.Sprintf("%s\nThis chapter has been converted by CBZOptimizer.", currentTime),
|
||||
},
|
||||
//test case where there is only one page and no
|
||||
{
|
||||
@@ -90,7 +96,7 @@ func TestWriteChapterToCBZ(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temporary file: %v", err)
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
defer errs.CaptureGeneric(&err, os.Remove, tempFile.Name(), "failed to remove temporary file")
|
||||
|
||||
// Write the chapter to the .cbz file
|
||||
err = WriteChapterToCBZ(tc.chapter, tempFile.Name())
|
||||
@@ -103,7 +109,7 @@ func TestWriteChapterToCBZ(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to open CBZ file: %v", err)
|
||||
}
|
||||
defer r.Close()
|
||||
defer errs.Capture(&err, r.Close, "failed to close CBZ file")
|
||||
|
||||
// Collect the names of the files in the archive
|
||||
var filesInArchive []string
|
||||
@@ -125,6 +131,10 @@ func TestWriteChapterToCBZ(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if tc.expectedComment != "" && r.Comment != tc.expectedComment {
|
||||
t.Errorf("Expected comment %s, but found %s", tc.expectedComment, r.Comment)
|
||||
}
|
||||
|
||||
// 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))
|
||||
|
||||
@@ -6,7 +6,8 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/belphemur/CBZOptimizer/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/utils/errs"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -18,72 +19,85 @@ func LoadChapter(filePath string) (*manga.Chapter, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open .cbz file: %w", err)
|
||||
}
|
||||
defer r.Close()
|
||||
defer errs.Capture(&err, r.Close, "failed to close opened .cbz file")
|
||||
|
||||
chapter := &manga.Chapter{
|
||||
FilePath: filePath,
|
||||
}
|
||||
// Check for comment
|
||||
if r.Comment != "" {
|
||||
scanner := bufio.NewScanner(strings.NewReader(r.Comment))
|
||||
if scanner.Scan() {
|
||||
convertedTime := scanner.Text()
|
||||
chapter.ConvertedTime, err = dateparse.ParseAny(convertedTime)
|
||||
if err == nil {
|
||||
chapter.IsConverted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range r.File {
|
||||
if f.FileInfo().IsDir() {
|
||||
continue
|
||||
}
|
||||
// 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 := io.ReadAll(rc)
|
||||
err := func() error {
|
||||
// Open the file inside the zip
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
rc.Close()
|
||||
return nil, fmt.Errorf("failed to read ComicInfo.xml content: %w", err)
|
||||
return fmt.Errorf("failed to open file inside .cbz: %w", err)
|
||||
}
|
||||
chapter.ComicInfoXml = string(xmlContent)
|
||||
} else if ext == ".txt" && strings.ToLower(filepath.Base(f.Name)) == "converted.txt" {
|
||||
textContent, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
rc.Close()
|
||||
return nil, fmt.Errorf("failed to read Converted.xml content: %w", err)
|
||||
}
|
||||
scanner := bufio.NewScanner(bytes.NewReader(textContent))
|
||||
if scanner.Scan() {
|
||||
convertedTime := scanner.Text()
|
||||
chapter.ConvertedTime, err = dateparse.ParseAny(convertedTime)
|
||||
|
||||
defer errs.Capture(&err, rc.Close, "failed to close file inside .cbz")
|
||||
|
||||
// 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 := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
rc.Close()
|
||||
return nil, fmt.Errorf("failed to parse converted time: %w", err)
|
||||
return fmt.Errorf("failed to read ComicInfo.xml content: %w", err)
|
||||
}
|
||||
chapter.ComicInfoXml = string(xmlContent)
|
||||
} else if !chapter.IsConverted && ext == ".txt" && strings.ToLower(filepath.Base(f.Name)) == "converted.txt" {
|
||||
textContent, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read Converted.xml content: %w", err)
|
||||
}
|
||||
scanner := bufio.NewScanner(bytes.NewReader(textContent))
|
||||
if scanner.Scan() {
|
||||
convertedTime := scanner.Text()
|
||||
chapter.ConvertedTime, err = dateparse.ParseAny(convertedTime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse converted time: %w", err)
|
||||
}
|
||||
chapter.IsConverted = true
|
||||
}
|
||||
} else {
|
||||
// Read the file contents for page
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = io.Copy(buf, rc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read file contents: %w", err)
|
||||
}
|
||||
chapter.IsConverted = true
|
||||
}
|
||||
} 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 := &manga.Page{
|
||||
Index: uint16(len(chapter.Pages)), // Simple index based on order
|
||||
Extension: ext,
|
||||
Size: uint64(buf.Len()),
|
||||
Contents: buf,
|
||||
IsSplitted: false,
|
||||
}
|
||||
// Create a new Page object
|
||||
page := &manga.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)
|
||||
// Add the page to the chapter
|
||||
chapter.Pages = append(chapter.Pages, page)
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rc.Close()
|
||||
|
||||
}
|
||||
|
||||
return chapter, nil
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestLoadChapter(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Converted Chapter",
|
||||
filePath: "../testdata/Chapter 1_converted.cbz",
|
||||
filePath: "../testdata/Chapter 10_converted.cbz",
|
||||
expectedPages: 107,
|
||||
expectedSeries: "<Series>Boundless Necromancer</Series>",
|
||||
expectedConversion: true,
|
||||
|
||||
@@ -2,9 +2,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/belphemur/CBZOptimizer/converter"
|
||||
"github.com/belphemur/CBZOptimizer/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/utils"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/v2/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/thediveo/enumflag/v2"
|
||||
"os"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/belphemur/CBZOptimizer/cbz"
|
||||
"github.com/belphemur/CBZOptimizer/converter"
|
||||
"github.com/belphemur/CBZOptimizer/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/cbz"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/v2/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/utils/errs"
|
||||
"github.com/spf13/cobra"
|
||||
"log"
|
||||
"os"
|
||||
@@ -37,7 +38,7 @@ func TestConvertCbzCommand(t *testing.T) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir) // Clean up the temp directory when done
|
||||
defer errs.CaptureGeneric(&err, os.RemoveAll, tempDir, "failed to remove temporary directory")
|
||||
|
||||
// Locate the testdata directory
|
||||
testdataDir := filepath.Join("../testdata")
|
||||
|
||||
@@ -2,9 +2,9 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/belphemur/CBZOptimizer/converter"
|
||||
"github.com/belphemur/CBZOptimizer/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/utils"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/v2/utils"
|
||||
"github.com/pablodz/inotifywaitgo/inotifywaitgo"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -76,7 +76,7 @@ func WatchCommand(_ *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prepare converter: %v", err)
|
||||
}
|
||||
log.Printf("Watching [%s] with [override: %t, quality: %d, format: %s]", path, override, quality, converterType.String())
|
||||
log.Printf("Watching [%s] with [override: %t, quality: %d, format: %s, split: %t]", path, override, quality, converterType.String(), split)
|
||||
|
||||
events := make(chan inotifywaitgo.FileEvent)
|
||||
errors := make(chan error)
|
||||
@@ -116,7 +116,7 @@ func WatchCommand(_ *cobra.Command, args []string) error {
|
||||
case inotifywaitgo.CLOSE_WRITE, inotifywaitgo.MOVE:
|
||||
err := utils.Optimize(&utils.OptimizeOptions{
|
||||
ChapterConverter: chapterConverter,
|
||||
Path: path,
|
||||
Path: event.Filename,
|
||||
Quality: quality,
|
||||
Override: override,
|
||||
Split: split,
|
||||
|
||||
@@ -2,9 +2,9 @@ package converter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/belphemur/CBZOptimizer/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/converter/webp"
|
||||
"github.com/belphemur/CBZOptimizer/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter/webp"
|
||||
"github.com/belphemur/CBZOptimizer/v2/manga"
|
||||
"github.com/samber/lo"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -2,8 +2,9 @@ package converter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/belphemur/CBZOptimizer/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter/constant"
|
||||
"github.com/belphemur/CBZOptimizer/v2/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/utils/errs"
|
||||
"golang.org/x/exp/slices"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
@@ -62,7 +63,7 @@ func TestConvertChapter(t *testing.T) {
|
||||
t.Fatalf("failed to create temporary file: %v", err)
|
||||
|
||||
}
|
||||
defer os.Remove(temp.Name())
|
||||
defer errs.CaptureGeneric(&err, os.Remove, temp.Name(), "failed to remove temporary file")
|
||||
for _, converter := range Available() {
|
||||
converter, err := Get(converter)
|
||||
if err != nil {
|
||||
@@ -121,7 +122,7 @@ func genHugePage(path string) (*manga.Chapter, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
defer errs.Capture(&err, file.Close, "failed to close file")
|
||||
|
||||
var pages []*manga.Page
|
||||
for i := 0; i < 1; i++ { // Assuming there are 5 pages for the test
|
||||
@@ -150,7 +151,7 @@ func genSmallPages(path string) (*manga.Chapter, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
defer errs.Capture(&err, file.Close, "failed to close file")
|
||||
|
||||
var pages []*manga.Page
|
||||
for i := 0; i < 5; i++ { // Assuming there are 5 pages for the test
|
||||
@@ -179,7 +180,7 @@ func genMixSmallBig(path string) (*manga.Chapter, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
defer errs.Capture(&err, file.Close, "failed to close file")
|
||||
|
||||
var pages []*manga.Page
|
||||
for i := 0; i < 5; i++ { // Assuming there are 5 pages for the test
|
||||
@@ -208,7 +209,7 @@ func genMixSmallHuge(path string) (*manga.Chapter, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
defer errs.Capture(&err, file.Close, "failed to close file")
|
||||
|
||||
var pages []*manga.Page
|
||||
for i := 0; i < 10; i++ { // Assuming there are 5 pages for the test
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/belphemur/CBZOptimizer/converter/constant"
|
||||
converterrors "github.com/belphemur/CBZOptimizer/converter/errors"
|
||||
"github.com/belphemur/CBZOptimizer/manga"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter/constant"
|
||||
converterrors "github.com/belphemur/CBZOptimizer/v2/converter/errors"
|
||||
"github.com/belphemur/CBZOptimizer/v2/manga"
|
||||
"github.com/oliamb/cutter"
|
||||
"golang.org/x/exp/slices"
|
||||
_ "golang.org/x/image/webp"
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
package webp
|
||||
|
||||
import (
|
||||
"github.com/belphemur/go-webpbin/v2"
|
||||
"github.com/kolesa-team/go-webp/encoder"
|
||||
"github.com/kolesa-team/go-webp/webp"
|
||||
"image"
|
||||
"io"
|
||||
)
|
||||
|
||||
const libwebpVersion = "1.4.0"
|
||||
|
||||
func PrepareEncoder() error {
|
||||
webpbin.SetLibVersion(libwebpVersion)
|
||||
container := webpbin.NewCWebP()
|
||||
return container.BinWrapper.Run()
|
||||
return nil
|
||||
}
|
||||
func Encode(w io.Writer, m image.Image, quality uint) error {
|
||||
return webpbin.NewCWebP().
|
||||
Quality(quality).
|
||||
InputImage(m).
|
||||
Output(w).
|
||||
Run()
|
||||
options, err := encoder.NewLossyEncoderOptions(encoder.PresetDefault, float32(quality))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return webp.Encode(w, m, options)
|
||||
}
|
||||
|
||||
34
go.mod
34
go.mod
@@ -1,36 +1,30 @@
|
||||
module github.com/belphemur/CBZOptimizer
|
||||
module github.com/belphemur/CBZOptimizer/v2
|
||||
|
||||
go 1.23.0
|
||||
go 1.23.1
|
||||
|
||||
toolchain go1.23.5
|
||||
|
||||
require (
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
||||
github.com/belphemur/go-webpbin/v2 v2.0.0
|
||||
github.com/kolesa-team/go-webp v1.0.4
|
||||
github.com/oliamb/cutter v0.2.2
|
||||
github.com/pablodz/inotifywaitgo v0.0.7
|
||||
github.com/samber/lo v1.47.0
|
||||
github.com/pablodz/inotifywaitgo v0.0.9
|
||||
github.com/samber/lo v1.49.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/thediveo/enumflag/v2 v2.0.5
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
|
||||
golang.org/x/image v0.19.0
|
||||
github.com/thediveo/enumflag/v2 v2.0.7
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
|
||||
golang.org/x/image v0.23.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/belphemur/go-binwrapper v0.0.0-20240827152605-33977349b1f0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jfrog/archiver/v3 v3.6.1 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
@@ -38,12 +32,10 @@ require (
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
75
go.sum
75
go.sum
@@ -1,19 +1,10 @@
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
||||
github.com/belphemur/go-binwrapper v0.0.0-20240827152605-33977349b1f0 h1:EzKgPYK90TyAOmytK7bvapqlkG/m7KWKK28mOAdQEaM=
|
||||
github.com/belphemur/go-binwrapper v0.0.0-20240827152605-33977349b1f0/go.mod h1:s2Dv+CfgVbNM9ucqvE5qCCC0AkI1PE2OZb7N8PPlOh4=
|
||||
github.com/belphemur/go-webpbin/v2 v2.0.0 h1:Do0TTTJ6cS6lgi+R67De+jXRYe+ZOwxFqTiFggyX5p8=
|
||||
github.com/belphemur/go-webpbin/v2 v2.0.0/go.mod h1:VIHXZQaIwaIYDn08w0qeJFPj1MuYt5pyJnkQALPYc5g=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
@@ -22,9 +13,6 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
@@ -33,14 +21,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI=
|
||||
github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kolesa-team/go-webp v1.0.4 h1:wQvU4PLG/X7RS0vAeyhiivhLRoxfLVRlDq4I3frdxIQ=
|
||||
github.com/kolesa-team/go-webp v1.0.4/go.mod h1:oMvdivD6K+Q5qIIkVC2w4k2ZUnI1H+MyP7inwgWq9aA=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -50,8 +32,6 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
||||
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k=
|
||||
github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU=
|
||||
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
|
||||
@@ -60,10 +40,10 @@ github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA=
|
||||
github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/pablodz/inotifywaitgo v0.0.7 h1:1ii49dGBnRn0t1Sz7RGZS6/NberPEDQprwKHN49Bv6U=
|
||||
github.com/pablodz/inotifywaitgo v0.0.7/go.mod h1:OtzRCsYTJlIr+vAzlOtauTkfQ1c25ebFuXq8tbbf8cw=
|
||||
github.com/pablodz/inotifywaitgo v0.0.9 h1:njquRbBU7fuwIe5rEvtaniVBjwWzcpdUVptSgzFqZsw=
|
||||
github.com/pablodz/inotifywaitgo v0.0.9/go.mod h1:hAfx2oN+WKg8miwUKPs52trySpPignlRBRxWcXVHku0=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -77,6 +57,10 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
|
||||
github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
|
||||
github.com/samber/lo v1.48.0 h1:ELOfcaM7vdYPe0egBS2Nxa8LxkY4lR+9LBzj0l6cHJ0=
|
||||
github.com/samber/lo v1.48.0/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||
github.com/samber/lo v1.49.0 h1:AGnTnQrg1jpFuwECPUSoxZCfVH5W22b605kWSry3YxM=
|
||||
github.com/samber/lo v1.49.0/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
@@ -107,30 +91,45 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/thediveo/enumflag/v2 v2.0.5 h1:VJjvlAqUb6m6mxOrB/0tfBJI0Kvi9wJ8ulh38xK87i8=
|
||||
github.com/thediveo/enumflag/v2 v2.0.5/go.mod h1:0NcG67nYgwwFsAvoQCmezG0J0KaIxZ0f7skg9eLq1DA=
|
||||
github.com/thediveo/enumflag/v2 v2.0.7 h1:uxXDU+rTel7Hg4X0xdqICpG9rzuI/mzLAEYXWLflOfs=
|
||||
github.com/thediveo/enumflag/v2 v2.0.7/go.mod h1:bWlnNvTJuUK+huyzf3WECFLy557Ttlc+yk3o+BPs0EA=
|
||||
github.com/thediveo/success v1.0.1 h1:NVwUOwKUwaN8szjkJ+vsiM2L3sNBFscldoDJ2g2tAPg=
|
||||
github.com/thediveo/success v1.0.1/go.mod h1:AZ8oUArgbIsCuDEWrzWNQHdKnPbDOLQsWOFj9ynwLt0=
|
||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/image v0.19.0 h1:D9FX4QWkLfkeqaC62SonffIIuYdOk/UE2XKUBgRIBIQ=
|
||||
golang.org/x/image v0.19.0/go.mod h1:y0zrRqlQRWQ5PXaYCOMLTW2fpsxZ8Qh9I/ohnInJEys=
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
|
||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20241210172134-14434422244c h1:G0f8LmhCW7rzpybldgSjhhKDCwW7mYO0Qr6HZDb0HJA=
|
||||
golang.org/x/exp v0.0.0-20241210172134-14434422244c/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
|
||||
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20250103163809-dd03c70a0a45 h1:tHbTCyM7JD+jm5mShcnp+cl1Q6nJpFZe7kyALJCclHA=
|
||||
golang.org/x/exp v0.0.0-20250103163809-dd03c70a0a45/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329 h1:9kj3STMvgqy3YA4VQXBrN7925ICMxD5wzMRcgA30588=
|
||||
golang.org/x/exp v0.0.0-20250103183323-7d7fa50e5329/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68=
|
||||
golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
2
main.go
2
main.go
@@ -1,7 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/belphemur/CBZOptimizer/cmd"
|
||||
"github.com/belphemur/CBZOptimizer/v2/cmd"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package meta
|
||||
|
||||
var Version = "v0.0.0"
|
||||
var Commit = ""
|
||||
var Date = ""
|
||||
@@ -2,5 +2,16 @@
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchUpdateTypes": [
|
||||
"minor",
|
||||
"patch",
|
||||
"digest"
|
||||
],
|
||||
"matchCurrentVersion": "!/^0/",
|
||||
"automerge": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
25
utils/errs/errors_defer.go
Normal file
25
utils/errs/errors_defer.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package errs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Capture runs errFunc and assigns the error, if any, to *errPtr. Preserves the
|
||||
// original error by wrapping with errors.Join if the errFunc err is non-nil.
|
||||
func Capture(errPtr *error, errFunc func() error, msg string) {
|
||||
err := errFunc()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
*errPtr = errors.Join(*errPtr, fmt.Errorf("%s: %w", msg, err))
|
||||
}
|
||||
|
||||
// CaptureGeneric runs errFunc with a generic type K and assigns the error, if any, to *errPtr.
|
||||
func CaptureGeneric[K any](errPtr *error, errFunc func(value K) error, value K, msg string) {
|
||||
err := errFunc(value)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
*errPtr = errors.Join(*errPtr, fmt.Errorf("%s: %w", msg, err))
|
||||
}
|
||||
122
utils/errs/errors_defer_test.go
Normal file
122
utils/errs/errors_defer_test.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package errs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCapture(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
initial error
|
||||
errFunc func() error
|
||||
msg string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "No error from errFunc",
|
||||
initial: nil,
|
||||
errFunc: func() error { return nil },
|
||||
msg: "test message",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "Error from errFunc with no initial error",
|
||||
initial: nil,
|
||||
errFunc: func() error { return errors.New("error from func") },
|
||||
msg: "test message",
|
||||
expected: "test message: error from func",
|
||||
},
|
||||
{
|
||||
name: "Error from errFunc with initial error",
|
||||
initial: errors.New("initial error"),
|
||||
errFunc: func() error { return errors.New("error from func") },
|
||||
msg: "test message",
|
||||
expected: "initial error\ntest message: error from func",
|
||||
},
|
||||
{
|
||||
name: "Error from errFunc with initial wrapped error",
|
||||
initial: fmt.Errorf("wrapped error: %w", errors.New("initial error")),
|
||||
errFunc: func() error { return errors.New("error from func") },
|
||||
msg: "test message",
|
||||
expected: "wrapped error: initial error\ntest message: error from func",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var err error = tt.initial
|
||||
Capture(&err, tt.errFunc, tt.msg)
|
||||
if err != nil && err.Error() != tt.expected {
|
||||
t.Errorf("expected %q, got %q", tt.expected, err.Error())
|
||||
} else if err == nil && tt.expected != "" {
|
||||
t.Errorf("expected %q, got nil", tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCaptureGeneric(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
initial error
|
||||
errFunc func(int) error
|
||||
value int
|
||||
msg string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "No error from errFunc",
|
||||
initial: nil,
|
||||
errFunc: func(value int) error { return nil },
|
||||
value: 0,
|
||||
msg: "test message",
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "Error from errFunc with no initial error",
|
||||
initial: nil,
|
||||
errFunc: func(value int) error { return errors.New("error from func") },
|
||||
value: 0,
|
||||
msg: "test message",
|
||||
expected: "test message: error from func",
|
||||
},
|
||||
{
|
||||
name: "Error from errFunc with initial error",
|
||||
initial: errors.New("initial error"),
|
||||
errFunc: func(value int) error { return errors.New("error from func") },
|
||||
value: 0,
|
||||
msg: "test message",
|
||||
expected: "initial error\ntest message: error from func",
|
||||
},
|
||||
{
|
||||
name: "Error from errFunc with initial wrapped error",
|
||||
initial: fmt.Errorf("wrapped error: %w", errors.New("initial error")),
|
||||
errFunc: func(value int) error { return errors.New("error from func") },
|
||||
value: 0,
|
||||
msg: "test message",
|
||||
expected: "wrapped error: initial error\ntest message: error from func",
|
||||
},
|
||||
{
|
||||
name: "Error from errFunc with initial wrapped error and value",
|
||||
initial: fmt.Errorf("wrapped error: %w", errors.New("initial error")),
|
||||
errFunc: func(value int) error { return fmt.Errorf("hello error:%d", value) },
|
||||
value: 1,
|
||||
msg: "test message",
|
||||
expected: "wrapped error: initial error\ntest message: hello error:1",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var err error = tt.initial
|
||||
CaptureGeneric(&err, tt.errFunc, tt.value, tt.msg)
|
||||
if err != nil && err.Error() != tt.expected {
|
||||
t.Errorf("expected %q, got %q", tt.expected, err.Error())
|
||||
} else if err == nil && tt.expected != "" {
|
||||
t.Errorf("expected %q, got nil", tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ package utils
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/belphemur/CBZOptimizer/cbz"
|
||||
"github.com/belphemur/CBZOptimizer/converter"
|
||||
errors2 "github.com/belphemur/CBZOptimizer/converter/errors"
|
||||
"github.com/belphemur/CBZOptimizer/v2/cbz"
|
||||
"github.com/belphemur/CBZOptimizer/v2/converter"
|
||||
errors2 "github.com/belphemur/CBZOptimizer/v2/converter/errors"
|
||||
"log"
|
||||
"strings"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user