Class: CbzTools::Reader

Inherits:
Object
  • Object
show all
Defined in:
lib/cbz_tools/reader.rb,
sig/cbz_tools.rbs

Overview

Reads the contents of a CBZ (Comic Book ZIP) archive.

The public surface is image access and parsed ComicInfo metadata; XML is an internal wire format and never appears on the API.

Examples:

Reading images and metadata

CbzTools::Reader.open("path/to/comic.cbz") do |reader|
  reader.image_names.first    # => "page_001.jpg"
  reader.first_image          # => "<image bytes>"
  reader.comic_info           # => {title: "The Amazing Spider-Man", page_count: "32"}
end

Defined Under Namespace

Classes: ImageNotFoundError

Constant Summary collapse

IMAGE_EXTENSIONS =

File extensions recognized as comic page images.

Returns:

  • (Array[String])
%w[.jpg .jpeg .png .webp].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Reader

Opens the archive at the given path. Prefer open unless you need to hold the reader open across multiple operations.

Parameters:

  • path (String)

    path to a CBZ file



43
44
45
46
# File 'lib/cbz_tools/reader.rb', line 43

def initialize(path)
  @path = path
  @zip = Zip::File.open(@path)
end

Class Method Details

.open(path) {|reader| ... } ⇒ void

This method returns an undefined value.

Opens a CBZ archive, yields a reader, and closes it when the block exits — including on exception.

Parameters:

  • path (String)

Yields:

Yield Parameters:

  • reader (Reader)

    the open reader

Yield Returns:

  • (void)


32
33
34
35
36
37
# File 'lib/cbz_tools/reader.rb', line 32

def self.open(path, &block)
  reader = new(path)
  block.call(reader)
ensure
  reader&.close
end

Instance Method Details

#closevoid

This method returns an undefined value.

Releases the underlying zip handle. Safe to call more than once.



51
52
53
54
# File 'lib/cbz_tools/reader.rb', line 51

def close
  @zip&.close
  @zip = nil
end

#comic_infoHash

Returns the parsed ComicInfo metadata as a symbol-keyed hash.

Returns an empty hash when the archive has no ComicInfo.xml. The lookup is case-insensitive (+comicinfo.xml+ is also recognized).

Returns:

  • (Hash)

    parsed metadata, keyed by SCHEMA symbols

Raises:



95
96
97
98
# File 'lib/cbz_tools/reader.rb', line 95

def comic_info
  xml = read("ComicInfo.xml") || read("comicinfo.xml")
  xml ? CbzTools::ComicInfo.parse(xml) : {}
end

#first_imageString?

Returns the bytes of the first image in the archive, or nil when there are no images.

Returns:

  • (String, nil)


71
72
73
# File 'lib/cbz_tools/reader.rb', line 71

def first_image
  read(image_names.first)
end

#image(name) ⇒ String

Returns the bytes of a specific image by name.

Parameters:

  • name (String)

    entry name within the archive

Returns:

  • (String)

Raises:



80
81
82
83
84
85
# File 'lib/cbz_tools/reader.rb', line 80

def image(name)
  data = read(name)
  raise ImageNotFoundError, "Image '#{name}' not found in #{@path}" unless data

  data
end

#image?(name) ⇒ Boolean

Parameters:

  • name (String)

Returns:

  • (Boolean)


124
125
126
# File 'lib/cbz_tools/reader.rb', line 124

def image?(name)
  IMAGE_EXTENSIONS.any? { |ext| name.downcase.end_with?(ext) }
end

#image_namesArray<String>

Returns the names of all image entries in the archive, sorted.

Returns:

  • (Array<String>)


59
60
61
62
63
64
65
# File 'lib/cbz_tools/reader.rb', line 59

def image_names
  @zip.entries
    .reject(&:directory?)
    .map(&:name)
    .select { |name| !name.include?("__macosx") && image?(name) }
    .sort
end

#read(name) ⇒ String?

Parameters:

  • name (String)

Returns:

  • (String, nil)


117
118
119
120
121
122
# File 'lib/cbz_tools/reader.rb', line 117

def read(name)
  entry = @zip.find_entry(name)
  return nil unless entry

  entry.get_input_stream.read
end

#update_comic_info(metadata) ⇒ void

This method returns an undefined value.

Writes the given metadata hash back into the archive as ComicInfo.xml, replacing any existing entry with that name.

Accepts symbol or string keys; non-SCHEMA keys are ignored.

Parameters:

  • metadata (Hash)

    field values keyed by SCHEMA symbols or strings

Raises:

  • (Zip::Error)

    when the archive cannot be opened for writing

  • (SystemCallError)

    when an underlying I/O operation fails



109
110
111
112
113
# File 'lib/cbz_tools/reader.rb', line 109

def update_comic_info()
  @zip.get_output_stream("ComicInfo.xml") do |f|
    f.write(CbzTools::ComicInfo.build())
  end
end