comicbook 0.1.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 +7 -0
- data/.ruby-version +1 -0
- data/AGENT.md +110 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.md +21 -0
- data/README.md +65 -0
- data/Rakefile +8 -0
- data/SYSTEM.md +235 -0
- data/exe/comicbook +6 -0
- data/lib/comic_book/adapter.rb +26 -0
- data/lib/comic_book/cb7/archiver.rb +58 -0
- data/lib/comic_book/cb7/extractor.rb +65 -0
- data/lib/comic_book/cb7.rb +48 -0
- data/lib/comic_book/cbt/archiver.rb +72 -0
- data/lib/comic_book/cbt/extractor.rb +81 -0
- data/lib/comic_book/cbt.rb +48 -0
- data/lib/comic_book/cbz/archiver.rb +56 -0
- data/lib/comic_book/cbz/extractor.rb +70 -0
- data/lib/comic_book/cbz.rb +46 -0
- data/lib/comic_book/cli.rb +123 -0
- data/lib/comic_book/cli_helpers.rb +27 -0
- data/lib/comic_book/page.rb +10 -0
- data/lib/comic_book/vendor/linux/MPL-License-for-lsar-and-unar.txt +529 -0
- data/lib/comic_book/vendor/linux/lsar +0 -0
- data/lib/comic_book/vendor/linux/unar +0 -0
- data/lib/comic_book/vendor/macos/MPL-License-for-lsar-and-unar.txt +529 -0
- data/lib/comic_book/vendor/macos/lsar +0 -0
- data/lib/comic_book/vendor/macos/unar +0 -0
- data/lib/comic_book/vendor/windows/Foundation.1.0.dll +0 -0
- data/lib/comic_book/vendor/windows/MPL-License-for-lsar-unar-and-Foundation-dll.txt +529 -0
- data/lib/comic_book/vendor/windows/lsar.exe +0 -0
- data/lib/comic_book/vendor/windows/unar.exe +0 -0
- data/lib/comic_book/version.rb +3 -0
- data/lib/comicbook.rb +104 -0
- data/sig/comicbook.rbs +4 -0
- metadata +111 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class ComicBook
|
|
2
|
+
class CB7 < Adapter
|
|
3
|
+
class Extractor
|
|
4
|
+
def initialize archive_path
|
|
5
|
+
@archive_path = File.expand_path(archive_path)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def extract options = {}
|
|
9
|
+
extension = options.fetch :extension, :cb
|
|
10
|
+
delete_original = options.fetch :delete_original, false
|
|
11
|
+
destination_folder = options[:to]
|
|
12
|
+
|
|
13
|
+
destination = destination_folder || determine_extract_path(extension)
|
|
14
|
+
extract_7z_contents destination
|
|
15
|
+
cleanup_archive_file if delete_original
|
|
16
|
+
|
|
17
|
+
destination
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
attr_reader :archive_path
|
|
23
|
+
|
|
24
|
+
def determine_extract_path extension
|
|
25
|
+
base_name = File.basename archive_path, '.*'
|
|
26
|
+
dir_name = File.dirname archive_path
|
|
27
|
+
archive_name = base_name
|
|
28
|
+
|
|
29
|
+
archive_name << ".#{extension}" if extension
|
|
30
|
+
|
|
31
|
+
full_path = File.join dir_name, archive_name
|
|
32
|
+
File.expand_path full_path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def extract_7z_contents destination
|
|
36
|
+
FileUtils.mkdir_p destination
|
|
37
|
+
|
|
38
|
+
File.open(archive_path, 'rb') do |file|
|
|
39
|
+
SevenZipRuby::Reader.open(file) do |szr|
|
|
40
|
+
szr.entries.each do |entry|
|
|
41
|
+
next unless entry.file? && image_file?(entry.path)
|
|
42
|
+
|
|
43
|
+
extract_single_file entry, destination, szr
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def extract_single_file entry, destination, szr
|
|
50
|
+
file_path = File.join(destination, entry.path)
|
|
51
|
+
FileUtils.mkdir_p File.dirname(file_path)
|
|
52
|
+
|
|
53
|
+
File.binwrite(file_path, szr.extract_data(entry))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def cleanup_archive_file
|
|
57
|
+
File.delete archive_path
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def image_file? filename
|
|
61
|
+
ComicBook::IMAGE_EXTENSIONS.include? File.extname(filename.downcase)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'seven_zip_ruby'
|
|
2
|
+
require_relative 'adapter'
|
|
3
|
+
require_relative 'cb7/archiver'
|
|
4
|
+
require_relative 'cb7/extractor'
|
|
5
|
+
|
|
6
|
+
class ComicBook
|
|
7
|
+
class CB7 < Adapter
|
|
8
|
+
def archive options = {}
|
|
9
|
+
Archiver.new(path).archive options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def extract options = {}
|
|
13
|
+
Extractor.new(path).extract options
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def pages = collect_pages_from_7z
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def collect_pages_from_7z
|
|
21
|
+
pages = []
|
|
22
|
+
|
|
23
|
+
File.open(path, 'rb') do |file|
|
|
24
|
+
SevenZipRuby::Reader.open(file) do |szr|
|
|
25
|
+
szr.entries.each do |entry|
|
|
26
|
+
next unless entry.file? && image_file?(entry.path)
|
|
27
|
+
|
|
28
|
+
pages << create_page_from_entry(entry)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
pages.sort_by(&:name)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def create_page_from_entry entry
|
|
37
|
+
basename = File.basename(entry.path)
|
|
38
|
+
|
|
39
|
+
ComicBook::Page.new entry.path, basename
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def image_file? filename
|
|
43
|
+
extension = File.extname(filename.downcase)
|
|
44
|
+
|
|
45
|
+
ComicBook::IMAGE_EXTENSIONS.include? extension
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
class ComicBook
|
|
2
|
+
class CBT < Adapter
|
|
3
|
+
class Archiver
|
|
4
|
+
def initialize source_folder
|
|
5
|
+
@source_folder = File.expand_path source_folder
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def archive options = {}
|
|
9
|
+
extension = options.fetch :extension, :cbt
|
|
10
|
+
destination = options[:to] || determine_output_path(extension)
|
|
11
|
+
delete_original = options.fetch :delete_original, false
|
|
12
|
+
|
|
13
|
+
create_tar_file destination
|
|
14
|
+
cleanup_source_folder if delete_original
|
|
15
|
+
|
|
16
|
+
destination
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_reader :source_folder
|
|
22
|
+
|
|
23
|
+
def determine_output_path extension
|
|
24
|
+
base_name = File.basename source_folder, '.*'
|
|
25
|
+
dir_name = File.dirname source_folder
|
|
26
|
+
|
|
27
|
+
File.expand_path File.join(dir_name, "#{base_name}.#{extension}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def create_tar_file destination
|
|
31
|
+
File.open(destination, 'wb') do |file|
|
|
32
|
+
Gem::Package::TarWriter.new(file) do |tar|
|
|
33
|
+
add_files_to_tar tar, source_folder
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def add_files_to_tar tar, folder, prefix = ''
|
|
39
|
+
Dir.entries(folder).sort.each do |entry|
|
|
40
|
+
next if ['.', '..'].include?(entry)
|
|
41
|
+
|
|
42
|
+
full_path = File.join(folder, entry)
|
|
43
|
+
tar_path = prefix.empty? ? entry : File.join(prefix, entry)
|
|
44
|
+
|
|
45
|
+
if File.directory?(full_path)
|
|
46
|
+
add_files_to_tar tar, full_path, tar_path
|
|
47
|
+
elsif image_file?(entry)
|
|
48
|
+
add_file_to_tar tar, full_path, tar_path
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def add_file_to_tar tar, file_path, tar_path
|
|
54
|
+
stat = File.stat(file_path)
|
|
55
|
+
tar.add_file(tar_path, stat.mode) do |io|
|
|
56
|
+
File.open(file_path, 'rb') do |file|
|
|
57
|
+
io.write(file.read)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def image_file? filename
|
|
63
|
+
extension = File.extname(filename.downcase)
|
|
64
|
+
ComicBook::IMAGE_EXTENSIONS.include? extension
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def cleanup_source_folder
|
|
68
|
+
FileUtils.rm_rf source_folder
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'rubygems/package'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
class ComicBook
|
|
5
|
+
class CBT < Adapter
|
|
6
|
+
class Extractor
|
|
7
|
+
def initialize path
|
|
8
|
+
@path = File.expand_path path
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def extract options = {}
|
|
12
|
+
extension = options.fetch :extension, :cb
|
|
13
|
+
delete_original = options.fetch :delete_original, false
|
|
14
|
+
destination_folder = options[:to]
|
|
15
|
+
|
|
16
|
+
destination = destination_folder || determine_extract_path(extension)
|
|
17
|
+
create_destination_directory destination
|
|
18
|
+
extract_files destination, options
|
|
19
|
+
cleanup_original_archive if delete_original
|
|
20
|
+
|
|
21
|
+
destination
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
attr_reader :path
|
|
27
|
+
|
|
28
|
+
def determine_extract_path extension
|
|
29
|
+
base_name = File.basename path, '.*'
|
|
30
|
+
dir_name = File.dirname path
|
|
31
|
+
archive_name = base_name
|
|
32
|
+
|
|
33
|
+
if extension
|
|
34
|
+
extension_str = extension.to_s
|
|
35
|
+
extension_str = extension_str[1..] if extension_str.start_with?('.')
|
|
36
|
+
archive_name << ".#{extension_str}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
full_path = File.join dir_name, archive_name
|
|
40
|
+
File.expand_path full_path
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_destination_directory destination
|
|
44
|
+
FileUtils.mkdir_p destination
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def extract_files destination, options
|
|
48
|
+
File.open(path, 'rb') do |file|
|
|
49
|
+
Gem::Package::TarReader.new(file) do |tar|
|
|
50
|
+
tar.each do |entry|
|
|
51
|
+
next unless entry.file?
|
|
52
|
+
next unless options[:all] || image_file?(entry.full_name)
|
|
53
|
+
|
|
54
|
+
extract_entry entry, destination
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def extract_entry entry, destination
|
|
61
|
+
output_path = File.join destination, entry.full_name
|
|
62
|
+
create_parent_directory output_path
|
|
63
|
+
|
|
64
|
+
File.binwrite(output_path, entry.read)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def create_parent_directory file_path
|
|
68
|
+
parent_dir = File.dirname file_path
|
|
69
|
+
FileUtils.mkdir_p parent_dir
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def image_file? filename
|
|
73
|
+
ComicBook::IMAGE_EXTENSIONS.include? File.extname(filename.downcase)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def cleanup_original_archive
|
|
77
|
+
FileUtils.rm path
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'rubygems/package'
|
|
2
|
+
require_relative 'adapter'
|
|
3
|
+
require_relative 'cbt/archiver'
|
|
4
|
+
require_relative 'cbt/extractor'
|
|
5
|
+
|
|
6
|
+
class ComicBook
|
|
7
|
+
class CBT < Adapter
|
|
8
|
+
def archive options = {}
|
|
9
|
+
Archiver.new(path).archive options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def extract options = {}
|
|
13
|
+
Extractor.new(path).extract options
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def pages = collect_pages_from_tar
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def collect_pages_from_tar
|
|
21
|
+
pages = []
|
|
22
|
+
|
|
23
|
+
File.open(path, 'rb') do |file|
|
|
24
|
+
Gem::Package::TarReader.new(file) do |tar|
|
|
25
|
+
tar.each do |entry|
|
|
26
|
+
next unless entry.file? && image_file?(entry.full_name)
|
|
27
|
+
|
|
28
|
+
pages << create_page_from_entry(entry)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
pages.sort_by &:name
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def create_page_from_entry entry
|
|
37
|
+
basename = File.basename entry.full_name
|
|
38
|
+
|
|
39
|
+
ComicBook::Page.new entry.full_name, basename
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def image_file? filename
|
|
43
|
+
extension = File.extname filename.downcase
|
|
44
|
+
|
|
45
|
+
ComicBook::IMAGE_EXTENSIONS.include? extension
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class ComicBook
|
|
2
|
+
class CBZ < Adapter
|
|
3
|
+
class Archiver
|
|
4
|
+
def initialize source_folder
|
|
5
|
+
@source_folder = File.expand_path source_folder
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def archive options = {}
|
|
9
|
+
extension = options.fetch :extension, :cbz
|
|
10
|
+
delete_original = options.fetch :delete_original, false
|
|
11
|
+
|
|
12
|
+
output_path = options[:to] || determine_output_path(extension)
|
|
13
|
+
create_zip_archive output_path
|
|
14
|
+
cleanup_source_folder if delete_original
|
|
15
|
+
|
|
16
|
+
output_path
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
attr_reader :source_folder
|
|
22
|
+
|
|
23
|
+
def determine_output_path extension
|
|
24
|
+
base_name = File.basename source_folder, '.*'
|
|
25
|
+
dir_name = File.dirname source_folder
|
|
26
|
+
|
|
27
|
+
File.expand_path File.join(dir_name, "#{base_name}.#{extension}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def create_zip_archive output_path
|
|
31
|
+
Zip::File.open(output_path, create: true) do |zipfile|
|
|
32
|
+
find_image_files.each do |file|
|
|
33
|
+
add_file_to_zip zipfile, file
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def find_image_files
|
|
39
|
+
pattern = File.join(source_folder, '**', ComicBook::IMAGE_GLOB_PATTERN)
|
|
40
|
+
Dir.glob(pattern, File::FNM_CASEFOLD).sort
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def add_file_to_zip zipfile, file
|
|
44
|
+
file_path = Pathname.new file
|
|
45
|
+
source_path = Pathname.new source_folder
|
|
46
|
+
relative_path = file_path.relative_path_from source_path
|
|
47
|
+
|
|
48
|
+
zipfile.add relative_path.to_s, file
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def cleanup_source_folder
|
|
52
|
+
FileUtils.rm_rf source_folder
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
class ComicBook
|
|
2
|
+
class CBZ < Adapter
|
|
3
|
+
class Extractor
|
|
4
|
+
def initialize archive_path
|
|
5
|
+
@archive_path = File.expand_path(archive_path)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def extract options = {}
|
|
9
|
+
extension = options.fetch :extension, :cb
|
|
10
|
+
delete_original = options.fetch :delete_original, false
|
|
11
|
+
destination_folder = options[:to]
|
|
12
|
+
|
|
13
|
+
destination = destination_folder || determine_extract_path(extension)
|
|
14
|
+
extract_zip_contents destination
|
|
15
|
+
cleanup_archive_file if delete_original
|
|
16
|
+
|
|
17
|
+
destination
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
attr_reader :archive_path
|
|
23
|
+
|
|
24
|
+
def determine_extract_path extension
|
|
25
|
+
base_name = File.basename archive_path, '.*'
|
|
26
|
+
dir_name = File.dirname archive_path
|
|
27
|
+
archive_name = base_name
|
|
28
|
+
|
|
29
|
+
archive_name << ".#{extension}" if extension
|
|
30
|
+
|
|
31
|
+
full_path = File.join dir_name, archive_name
|
|
32
|
+
File.expand_path full_path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def extract_zip_contents destination
|
|
36
|
+
FileUtils.mkdir_p destination
|
|
37
|
+
|
|
38
|
+
Dir.chdir(File.dirname(destination)) do
|
|
39
|
+
destination_basename = File.basename destination
|
|
40
|
+
extract_files_from_zip destination_basename
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def extract_files_from_zip destination_basename
|
|
45
|
+
Zip::File.open(archive_path) do |zipfile|
|
|
46
|
+
zipfile.each do |entry|
|
|
47
|
+
next unless image_file?(entry.name)
|
|
48
|
+
|
|
49
|
+
extract_single_file entry, destination_basename
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def extract_single_file entry, destination_basename
|
|
55
|
+
file_path = File.join(destination_basename, entry.name)
|
|
56
|
+
FileUtils.mkdir_p File.dirname(file_path)
|
|
57
|
+
|
|
58
|
+
entry.extract(file_path) { true }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def cleanup_archive_file
|
|
62
|
+
File.delete archive_path
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def image_file? filename
|
|
66
|
+
ComicBook::IMAGE_EXTENSIONS.include? File.extname(filename.downcase)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'zip'
|
|
2
|
+
require_relative 'adapter'
|
|
3
|
+
require_relative 'cbz/archiver'
|
|
4
|
+
require_relative 'cbz/extractor'
|
|
5
|
+
|
|
6
|
+
class ComicBook
|
|
7
|
+
class CBZ < Adapter
|
|
8
|
+
def archive options = {}
|
|
9
|
+
Archiver.new(path).archive options
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def extract options = {}
|
|
13
|
+
Extractor.new(path).extract options
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def pages = collect_pages_from_zip
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def collect_pages_from_zip
|
|
21
|
+
pages = []
|
|
22
|
+
|
|
23
|
+
Zip::File.open(path) do |zipfile|
|
|
24
|
+
zipfile.each do |entry|
|
|
25
|
+
next unless image_file?(entry.name)
|
|
26
|
+
|
|
27
|
+
pages << create_page_from_entry(entry)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
pages.sort_by &:name
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_page_from_entry entry
|
|
35
|
+
basename = File.basename entry.name
|
|
36
|
+
|
|
37
|
+
ComicBook::Page.new entry.name, basename
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def image_file? filename
|
|
41
|
+
extension = File.extname filename.downcase
|
|
42
|
+
|
|
43
|
+
ComicBook::IMAGE_EXTENSIONS.include? extension
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
|
|
3
|
+
class ComicBook
|
|
4
|
+
class CLI
|
|
5
|
+
SUPPORTED_FORMATS = %w[.cb7 .cbt .cbz].freeze
|
|
6
|
+
UNSUPPORTED_FORMATS = %w[.cbr .cba].freeze
|
|
7
|
+
|
|
8
|
+
def self.start argv
|
|
9
|
+
new.start Array(argv)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def start argv
|
|
13
|
+
argv = Array argv
|
|
14
|
+
|
|
15
|
+
if argv.empty? || argv.include?('-h') || argv.include?('--help')
|
|
16
|
+
show_help
|
|
17
|
+
return
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
case command = argv.shift
|
|
21
|
+
when 'extract' then extract(argv)
|
|
22
|
+
when 'archive' then archive(argv)
|
|
23
|
+
else
|
|
24
|
+
puts "Unknown command: #{command}"
|
|
25
|
+
show_help
|
|
26
|
+
exit 1
|
|
27
|
+
end
|
|
28
|
+
rescue ComicBook::Error, StandardError => e
|
|
29
|
+
puts "Error: #{e.message}"
|
|
30
|
+
exit 1
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def show_help
|
|
36
|
+
puts <<~HELP
|
|
37
|
+
ComicBook CLI
|
|
38
|
+
|
|
39
|
+
Usage:
|
|
40
|
+
comicbook extract <file> [--to <path>]
|
|
41
|
+
comicbook archive <folder> [--to <path>]
|
|
42
|
+
comicbook -h, --help
|
|
43
|
+
|
|
44
|
+
Commands:
|
|
45
|
+
extract Extract comic book archive
|
|
46
|
+
archive Create comic book archive
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
--from Source path (optional, first arg is default)
|
|
50
|
+
--to Destination path
|
|
51
|
+
--help, -h Show this help
|
|
52
|
+
HELP
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def extract argv
|
|
56
|
+
from_path = nil
|
|
57
|
+
to_path = nil
|
|
58
|
+
|
|
59
|
+
parser = OptionParser.new do |opts|
|
|
60
|
+
opts.on('--from PATH', 'Source file path') { from_path = it }
|
|
61
|
+
opts.on('--to PATH', 'Destination path') { to_path = it }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
remaining = parser.parse argv
|
|
65
|
+
from_path ||= remaining.first
|
|
66
|
+
|
|
67
|
+
validate_extract_args! from_path, to_path
|
|
68
|
+
ComicBook.extract from_path, { to: to_path }.compact
|
|
69
|
+
|
|
70
|
+
puts "Extracted #{from_path}#{" to #{to_path}" if to_path}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def archive argv
|
|
74
|
+
from_path = nil
|
|
75
|
+
to_path = nil
|
|
76
|
+
|
|
77
|
+
parser = OptionParser.new do |opts|
|
|
78
|
+
opts.on('--from PATH', 'Source folder path') { from_path = it }
|
|
79
|
+
opts.on('--to PATH', 'Destination path') { to_path = it }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
remaining = parser.parse argv
|
|
83
|
+
from_path ||= remaining.first
|
|
84
|
+
|
|
85
|
+
validate_archive_args! from_path, to_path
|
|
86
|
+
|
|
87
|
+
cb = ComicBook.new from_path
|
|
88
|
+
|
|
89
|
+
if to_path
|
|
90
|
+
cb.archive to: to_path
|
|
91
|
+
else
|
|
92
|
+
cb.archive
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
puts "Archived #{from_path}#{" to #{to_path}" if to_path}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def validate_extract_args! from_path, to_path
|
|
99
|
+
# from
|
|
100
|
+
raise ComicBook::Error, 'Source file required' unless from_path
|
|
101
|
+
raise ComicBook::Error, "Source file not found: #{from_path}" unless File.exist?(from_path)
|
|
102
|
+
# to
|
|
103
|
+
raise ComicBook::Error, "Destination already exists: #{to_path}" if to_path && File.exist?(to_path)
|
|
104
|
+
|
|
105
|
+
# formats
|
|
106
|
+
ext = File.extname(from_path).downcase
|
|
107
|
+
raise ComicBook::Error, "Unsupported format: #{ext} (not yet implemented)" unless SUPPORTED_FORMATS.include?(ext)
|
|
108
|
+
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def validate_archive_args! from_path, to_path
|
|
113
|
+
# from
|
|
114
|
+
raise ComicBook::Error, 'Source folder required' unless from_path
|
|
115
|
+
raise ComicBook::Error, "Source folder not found: #{from_path}" unless File.exist?(from_path)
|
|
116
|
+
raise ComicBook::Error, "Source must be a directory: #{from_path}" unless File.directory?(from_path)
|
|
117
|
+
# to
|
|
118
|
+
raise ComicBook::Error, "Destination already exists: #{to_path}" if to_path && File.exist?(to_path)
|
|
119
|
+
|
|
120
|
+
nil
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class ComicBook
|
|
2
|
+
class CLIHelpers
|
|
3
|
+
class << self
|
|
4
|
+
def platform_dir
|
|
5
|
+
case RUBY_PLATFORM
|
|
6
|
+
when /darwin/ then 'macos'
|
|
7
|
+
when /linux/ then 'linux'
|
|
8
|
+
when /mingw/ then 'windows'
|
|
9
|
+
else
|
|
10
|
+
raise "Unsupported platform: #{RUBY_PLATFORM}"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def binary_path name
|
|
15
|
+
File.expand_path("../vendor/#{platform_dir}/#{name}", __FILE__)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def run_lsar(*)
|
|
19
|
+
system(binary_path('lsar'), *)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_unar(*)
|
|
23
|
+
system(binary_path('unar'), *)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|