cbz_tools 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.vscode/settings.json +1 -1
- data/CHANGELOG.md +6 -0
- data/README.md +5 -25
- data/lib/cbz_tools/cbr_converter.rb +26 -56
- data/lib/cbz_tools/system_dependencies.rb +29 -0
- data/lib/cbz_tools/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30f58af31425d78057d97105cfe21164b6ec05263f0b86d2b2a0dca150792d5d
|
|
4
|
+
data.tar.gz: edd397b9588670cd49a3bcfe517f684ae9f684f4469a9725d1ac440f00da0fbe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57e09be8a89fec63e2cb22b140c6500afa29a0363a1f0e7b1b6d5ef75b9a137e4f6da4b1012031d18b2875db856e73145ded2fabf8532a6080d9f80d9ff98894
|
|
7
|
+
data.tar.gz: 73deffc4ac234b2288b2b8c5898cd12dc005561b79a7b5941cfb052ace8766fef6227bf935b6835226381f679d0bfb5fd2f9553fc68fd8cb2bc5ce309e7bfd45
|
data/.vscode/settings.json
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-08-04
|
|
4
|
+
|
|
5
|
+
- `CbzTools::CbrConverter` now uses `unrar` directly — no extractor param required.
|
|
6
|
+
- **Breaking**: Removed `extractor:` param, `ExtractionError`, and `extractor` attribute.
|
|
7
|
+
- Runtime check raises `ArchiveError` if `unrar` is not in PATH.
|
|
8
|
+
|
|
3
9
|
## [0.4.0] - 2026-08-03
|
|
4
10
|
|
|
5
11
|
- Add `CbzTools::CbrConverter` for converting CBR archives to CBZ. The gem ships the orchestration (extract → repack → error model) but no default extractor — callers pass `extractor:` (anything responding to `call(cbr_path, destination_dir)` and raising `ExtractionError` on failure).
|
data/README.md
CHANGED
|
@@ -38,37 +38,17 @@ end
|
|
|
38
38
|
|
|
39
39
|
### Converting CBR to CBZ
|
|
40
40
|
|
|
41
|
-
`CbzTools::CbrConverter`
|
|
42
|
-
|
|
43
|
-
`call(cbr_path, destination_dir)` (and that raises `ExtractionError`
|
|
44
|
-
on failure):
|
|
41
|
+
`CbzTools::CbrConverter` converts CBR archives to CBZ using the `unrar`
|
|
42
|
+
command-line tool (which must be installed on your system).
|
|
45
43
|
|
|
46
44
|
```ruby
|
|
47
|
-
|
|
48
|
-
CbzTools::CbrConverter.convert("path/to/comic.cbr",
|
|
49
|
-
to: "path/to/comic.cbz",
|
|
50
|
-
extractor: extractor)
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Reuse one extractor across many conversions with `work_in:` to pool
|
|
54
|
-
the tmpdir:
|
|
55
|
-
|
|
56
|
-
```ruby
|
|
57
|
-
extractor = MyApp::UnrarExtractor.new
|
|
58
|
-
work_in = Dir.mktmpdir("batch")
|
|
59
|
-
converter = CbzTools::CbrConverter.new(extractor: extractor)
|
|
60
|
-
|
|
61
|
-
paths.each do |cbr|
|
|
62
|
-
converter.convert(cbr, to: cbr.sub(/\.cbr\z/i, ".cbz"), work_in: work_in)
|
|
63
|
-
end
|
|
45
|
+
CbzTools::CbrConverter.convert("path/to/comic.cbr", to: "path/to/comic.cbz")
|
|
64
46
|
```
|
|
65
47
|
|
|
66
48
|
Errors inherit from `CbzTools::Error`:
|
|
67
49
|
|
|
68
|
-
- `CbzTools::CbrConverter::
|
|
69
|
-
|
|
70
|
-
the destination couldn't be written, or `overwrite: false` and the
|
|
71
|
-
destination already exists.
|
|
50
|
+
- `CbzTools::CbrConverter::ArchiveError` — the destination couldn't be written,
|
|
51
|
+
`overwrite: false` and the destination already exists, or `unrar` is not installed.
|
|
72
52
|
|
|
73
53
|
## Development
|
|
74
54
|
|
|
@@ -4,45 +4,28 @@ require "tmpdir"
|
|
|
4
4
|
require "fileutils"
|
|
5
5
|
require "zip"
|
|
6
6
|
require "pathname"
|
|
7
|
+
require "open3"
|
|
8
|
+
|
|
9
|
+
require_relative "system_dependencies"
|
|
7
10
|
|
|
8
11
|
module CbzTools
|
|
9
12
|
# Converts a CBR (Comic Book RAR) archive into a CBZ (Comic Book ZIP)
|
|
10
13
|
# archive.
|
|
11
14
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# extractor; this class is deliberately agnostic about which binary,
|
|
16
|
-
# library, or pure-Ruby implementation is used to expand the source.
|
|
15
|
+
# Extraction is handled internally using the +unrar+ command-line tool,
|
|
16
|
+
# which must be installed on the system. Consumers do not need to
|
|
17
|
+
# install or configure any extraction backend.
|
|
17
18
|
#
|
|
18
|
-
# @example Single-shot conversion
|
|
19
|
-
#
|
|
20
|
-
# CbzTools::CbrConverter.convert("path/to/comic.cbr",
|
|
21
|
-
# to: "path/to/comic.cbz",
|
|
22
|
-
# extractor: extractor)
|
|
19
|
+
# @example Single-shot conversion
|
|
20
|
+
# CbzTools::CbrConverter.convert("path/to/comic.cbr", to: "path/to/comic.cbz")
|
|
23
21
|
#
|
|
24
|
-
# @example Reusing one
|
|
25
|
-
#
|
|
26
|
-
# converter = CbzTools::CbrConverter.new(extractor: extractor)
|
|
22
|
+
# @example Reusing one converter across many conversions
|
|
23
|
+
# converter = CbzTools::CbrConverter.new
|
|
27
24
|
# paths.each { |p| converter.convert(p, to: p.sub(/\.cbr\z/i, ".cbz")) }
|
|
28
25
|
class CbrConverter
|
|
29
|
-
# Raised when the underlying extractor fails to expand the source
|
|
30
|
-
# CBR into a directory. Propagated untouched so callers can rescue
|
|
31
|
-
# it without unwrapping.
|
|
32
|
-
class ExtractionError < Error
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Raised when the resulting CBZ cannot be written, when the
|
|
36
|
-
# destination already exists and +overwrite:+ is false, or when no
|
|
37
|
-
# +extractor:+ was supplied. Propagated untouched from the
|
|
38
|
-
# relevant step.
|
|
39
26
|
class ArchiveError < Error
|
|
40
27
|
end
|
|
41
28
|
|
|
42
|
-
# @return [#call, nil] the configured extractor, or +nil+ if none
|
|
43
|
-
# was supplied. Read-only; there is no corresponding writer.
|
|
44
|
-
attr_reader :extractor
|
|
45
|
-
|
|
46
29
|
# @see #convert
|
|
47
30
|
#
|
|
48
31
|
# @param cbr_path [String] source CBR path
|
|
@@ -53,39 +36,18 @@ module CbzTools
|
|
|
53
36
|
# a fresh +Dir.mktmpdir+ is created and cleaned up. When set, the
|
|
54
37
|
# converter uses that directory and leaves cleanup to the caller
|
|
55
38
|
# (useful when batching many conversions).
|
|
56
|
-
# @param extractor [#call] extractor backend; required.
|
|
57
39
|
# @return [String] the destination CBZ path
|
|
58
|
-
# @raise [ArchiveError] when
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
new(extractor: extractor).convert(cbr_path, to: to, overwrite: overwrite, work_in: work_in)
|
|
40
|
+
# @raise [ArchiveError] when target cannot be written or unrar is unavailable
|
|
41
|
+
def self.convert(cbr_path, to:, overwrite: true, work_in: nil)
|
|
42
|
+
new.convert(cbr_path, to: to, overwrite: overwrite, work_in: work_in)
|
|
62
43
|
end
|
|
63
44
|
|
|
64
|
-
# @param extractor [#call, nil] anything responding to
|
|
65
|
-
# +call(cbr_path, destination_dir)+ that raises {ExtractionError}
|
|
66
|
-
# on failure. Required — {#convert} raises {ArchiveError} if left
|
|
67
|
-
# as +nil+.
|
|
68
|
-
def initialize(extractor: nil)
|
|
69
|
-
@extractor = extractor
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# @see .convert
|
|
73
|
-
#
|
|
74
|
-
# @param cbr_path [String] source CBR path
|
|
75
|
-
# @param to [String] destination CBZ path
|
|
76
|
-
# @param overwrite [Boolean] when false, raise {ArchiveError} if
|
|
77
|
-
# +to+ already exists; default true
|
|
78
|
-
# @param work_in [String, nil] see {.convert}
|
|
79
|
-
# @return [String] the destination CBZ path
|
|
80
|
-
# @raise [ArchiveError] when no extractor was configured or target cannot be written
|
|
81
|
-
# @raise [ExtractionError] when the extractor fails
|
|
82
45
|
def convert(cbr_path, to:, overwrite: true, work_in: nil)
|
|
83
|
-
ensure_extractor!
|
|
84
46
|
ensure_target_slot!(to, overwrite: overwrite)
|
|
85
47
|
File.delete(to) if overwrite && File.exist?(to)
|
|
86
48
|
|
|
87
49
|
in_workdir(work_in) do |temp_dir|
|
|
88
|
-
|
|
50
|
+
extract(cbr_path, temp_dir)
|
|
89
51
|
repack(temp_dir, to)
|
|
90
52
|
end
|
|
91
53
|
|
|
@@ -94,9 +56,17 @@ module CbzTools
|
|
|
94
56
|
|
|
95
57
|
private
|
|
96
58
|
|
|
97
|
-
def
|
|
98
|
-
|
|
99
|
-
|
|
59
|
+
def extract(cbr_path, destination)
|
|
60
|
+
unrar = SystemDependencies.unrar!
|
|
61
|
+
_, stderr, status = Open3.capture3(unrar, "x", "-o+", cbr_path, "#{destination}/")
|
|
62
|
+
|
|
63
|
+
unless status.success?
|
|
64
|
+
raise ArchiveError, "unrar failed: #{stderr}"
|
|
65
|
+
end
|
|
66
|
+
rescue SystemDependencies::MissingExecutableError => e
|
|
67
|
+
raise ArchiveError, e.message
|
|
68
|
+
rescue => e
|
|
69
|
+
raise ArchiveError, "Failed to extract CBR: #{e.message}"
|
|
100
70
|
end
|
|
101
71
|
|
|
102
72
|
def ensure_target_slot!(to, overwrite:)
|
|
@@ -133,4 +103,4 @@ module CbzTools
|
|
|
133
103
|
zipfile.add(relative, file_path)
|
|
134
104
|
end
|
|
135
105
|
end
|
|
136
|
-
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CbzTools
|
|
4
|
+
module SystemDependencies
|
|
5
|
+
class MissingExecutableError < StandardError; end
|
|
6
|
+
|
|
7
|
+
def self.find_executable(name)
|
|
8
|
+
extensions = Gem.win_platform? ? ENV.fetch("PATHEXT", "").split(";") : [""]
|
|
9
|
+
|
|
10
|
+
ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).each do |directory|
|
|
11
|
+
extensions.each do |extension|
|
|
12
|
+
path = File.join(directory, "#{name}#{extension}")
|
|
13
|
+
return path if File.file?(path) && File.executable?(path)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.unrar!
|
|
21
|
+
find_executable("unrar") ||
|
|
22
|
+
raise(
|
|
23
|
+
MissingExecutableError,
|
|
24
|
+
"`unrar` is required for CBR conversion but was not found in PATH. " \
|
|
25
|
+
"Install unrar using your system's package manager."
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/cbz_tools/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cbz_tools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Figueroa
|
|
@@ -55,6 +55,7 @@ files:
|
|
|
55
55
|
- lib/cbz_tools/comic_info.rb
|
|
56
56
|
- lib/cbz_tools/error.rb
|
|
57
57
|
- lib/cbz_tools/reader.rb
|
|
58
|
+
- lib/cbz_tools/system_dependencies.rb
|
|
58
59
|
- lib/cbz_tools/version.rb
|
|
59
60
|
- sig/cbz_tools.rbs
|
|
60
61
|
homepage: https://github.com/dmfigueroa/cbz_tools
|
|
@@ -78,7 +79,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
78
79
|
- - ">="
|
|
79
80
|
- !ruby/object:Gem::Version
|
|
80
81
|
version: '0'
|
|
81
|
-
requirements:
|
|
82
|
+
requirements:
|
|
83
|
+
- unrar executable available in PATH (for CBR conversion)
|
|
82
84
|
rubygems_version: 4.0.17
|
|
83
85
|
specification_version: 4
|
|
84
86
|
summary: Read, extract, and edit metadata of CBZ comic archives, and convert CBR to
|