{"id":31823857,"url":"https://github.com/veganstraightedge/comicinfo","last_synced_at":"2026-01-20T17:30:32.460Z","repository":{"id":318113973,"uuid":"1070058287","full_name":"veganstraightedge/comicinfo","owner":"veganstraightedge","description":"Ruby gem for working with ComicInfo.xml files, often used in .cbr/.cbz/etc for comic book metadata","archived":false,"fork":false,"pushed_at":"2025-10-05T07:54:13.000Z","size":84,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-05T08:25:23.754Z","etag":null,"topics":["cbr","cbz","comic-reader","comicinfo","comics-reader"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/veganstraightedge.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-05T07:09:14.000Z","updated_at":"2025-10-05T07:53:21.000Z","dependencies_parsed_at":"2025-10-05T08:25:32.785Z","dependency_job_id":"d4cdf7a9-c3c9-4b7e-b658-476c36f19d22","html_url":"https://github.com/veganstraightedge/comicinfo","commit_stats":null,"previous_names":["veganstraightedge/comicinfo"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/veganstraightedge/comicinfo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veganstraightedge%2Fcomicinfo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veganstraightedge%2Fcomicinfo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veganstraightedge%2Fcomicinfo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veganstraightedge%2Fcomicinfo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/veganstraightedge","download_url":"https://codeload.github.com/veganstraightedge/comicinfo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veganstraightedge%2Fcomicinfo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001766,"owners_count":26083171,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cbr","cbz","comic-reader","comicinfo","comics-reader"],"created_at":"2025-10-11T14:59:13.680Z","updated_at":"2026-01-20T17:30:32.373Z","avatar_url":"https://github.com/veganstraightedge.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ComicInfo Ruby Gem\n\nA Ruby gem that provides an idiomatic interface for reading and writing ComicInfo.xml files,\nfollowing the official ComicInfo schema specifications from the\n[Anansi Project](https://github.com/anansi-project/comicinfo).\n\n![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.4.6-ruby.svg)\n![Gem Version](https://badge.fury.io/rb/comicinfo.svg)\n![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)\n\n## Features\n\n- 📚 **Complete Schema Support**: Full ComicInfo v2.0 schema implementation\n- 🔧 **Idiomatic Ruby API**: Ruby-style interface with proper method naming\n- 📁 **Flexible Loading**: Load from file paths or XML strings\n- 🌍 **Unicode Support**: Full Unicode and special character handling\n- 📖 **Manga Support**: Right-to-left reading direction and manga-specific fields\n- ✅ **Comprehensive Validation**: Schema-compliant enum validation and type coercion\n- 🚨 **Detailed Error Handling**: Custom exception classes with helpful error messages\n- 📊 **Export Support**: JSON, YAML, and XML serialization with hash representation\n- ✍️ **XML Generation**: Complete ComicInfo.xml writing with round-trip consistency\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'comicinfo'\n```\n\nAnd then execute:\n\n```sh\nbundle install\n```\n\nOr install it yourself as:\n\n```sh\ngem install comicinfo\n```\n\n## Usage\n\n### Loading ComicInfo Files\n\n```ruby\nrequire 'comicinfo'\n\n# Load from file path\ncomic = ComicInfo.load 'path/to/ComicInfo.xml'\n\n# Load from XML string\nxml_content = File.read 'ComicInfo.xml'\ncomic       = ComicInfo.load xml_content\n```\n\n### Accessing Comic Information\n\n```ruby\n# Basic information\nputs comic.title  #=\u003e \"The Amazing Spider-Man\"\nputs comic.series #=\u003e \"The Amazing Spider-Man\"\nputs comic.number #=\u003e \"1\"\nputs comic.count  #=\u003e 600\nputs comic.volume #=\u003e 3\n\n# Publication details\nputs comic.publisher #=\u003e \"Marvel Comics\"\nputs comic.year      #=\u003e 2018\nputs comic.month     #=\u003e 3\nputs comic.day       #=\u003e 15\n\n# Creator information\nputs comic.writer       #=\u003e \"Dan Slott, Christos Gage\"\nputs comic.penciller    #=\u003e \"Ryan Ottley\"\nputs comic.cover_artist #=\u003e \"Ryan Ottley\"\n\n# Content details\nputs comic.page_count   #=\u003e 20\nputs comic.genre        #=\u003e \"Superhero, Action, Adventure\"\nputs comic.language_iso #=\u003e \"en-US\"\nputs comic.format       #=\u003e \"Digital\"\n\n# Ratings and reviews\nputs comic.age_rating       #=\u003e \"Teen\"\nputs comic.community_rating #=\u003e 4.25\n```\n\n### Convenience Methods\n\n```ruby\n# Boolean helpers\nputs comic.manga?           #=\u003e false\nputs comic.right_to_left?   #=\u003e false\nputs comic.black_and_white? #=\u003e false\n\n# Page information\nputs comic.pages?       #=\u003e true\nputs comic.pages.length #=\u003e 12\n\n# Get specific page types\ncovers  = comic.cover_pages\nstories = comic.story_pages\n\n# Multi-value fields as arrays\ncharacters = comic.characters #=\u003e [\"Spider-Man\", \"Peter Parker\", ...]\nteams      = comic.teams      #=\u003e [\"Avengers\"]\nlocations  = comic.locations  #=\u003e [\"New York City\", \"Manhattan\", ...]\ngenres     = comic.genres     #=\u003e [\"Superhero\", \"Action\", \"Adventure\"]\nweb_urls   = comic.web_urls   #=\u003e [\"https://marvel.com/...\", \"https://comicvine.com/...\"]\n\n# Raw data methods for original comma-separated strings\ngenres_raw     = comic.genres_raw_data     #=\u003e \"Superhero, Action, Adventure\"\ncharacters_raw = comic.characters_raw_data #=\u003e \"Spider-Man, Peter Parker, J. Jonah Jameson, Aunt May\"\nstory_arcs_raw = comic.story_arcs_raw_data #=\u003e \"Brand New Day, Spider-Island\"\n\n# Singular schema elements alias to plural arrays\ngenre          = comic.genre          #=\u003e [\"Superhero\", \"Action\", \"Adventure\"] (same as genres)\nstory_arc      = comic.story_arc      #=\u003e [\"Brand New Day\", \"Spider-Island\"] (same as story_arcs)\nstory_arc_num  = comic.story_arc_number #=\u003e [\"1\", \"5\"] (same as story_arc_numbers)\n```\n\n### Working with Pages\n\n```ruby\ncomic.pages.each do |page|\n  puts \"Page #{page.image}: #{page.type}\"\n  puts \"  Double page: #{page.double_page?}\"                    if page.double_page?\n  puts \"  Bookmark: #{page.bookmark}\"                           if page.bookmarked?\n  puts \"  Dimensions: #{page.image_width}x#{page.image_height}\" if page.dimensions_available?\nend\n\n# Page type checks\npage = comic.pages.first\nputs page.cover?   #=\u003e true for FrontCover, BackCover, InnerCover\nputs page.story?   #=\u003e true for Story pages\nputs page.deleted? #=\u003e true for Deleted pages\n```\n\n### Manga Support\n\n```ruby\n# Load a manga ComicInfo file\nmanga = ComicInfo.load 'path/to/manga/ComicInfo.xml'\n\nputs manga.title            #=\u003e \"進撃の巨人\"\nputs manga.series           #=\u003e \"Attack on Titan\"\nputs manga.manga            #=\u003e \"YesAndRightToLeft\"\nputs manga.right_to_left?   #=\u003e true\nputs manga.language_iso     #=\u003e \"ja-JP\"\nputs manga.black_and_white? #=\u003e true\nputs manga.black_and_white  #=\u003e \"Yes\"\n```\n\n### Error Handling\n\n```ruby\nbegin\n  comic = ComicInfo.load('nonexistent.xml')\nrescue ComicInfo::Errors::FileError =\u003e e\n  puts \"File error: #{e.message}\"\nrescue ComicInfo::Errors::ParseError =\u003e e\n  puts \"Parse error: #{e.message}\"\nrescue ComicInfo::Errors::InvalidEnumError =\u003e e\n  puts \"Invalid enum: #{e.field} = '#{e.value}', valid: #{e.valid_values}\"\nrescue ComicInfo::Errors::RangeError =\u003e e\n  puts \"Out of range: #{e.field} = #{e.value}, range: #{e.min}..#{e.max}\"\nrescue ComicInfo::Errors::TypeCoercionError =\u003e e\n  puts \"Type coercion error: #{e.message}\"\nend\n```\n\n## Schema Support\n\nThis gem fully supports the ComicInfo v2.0 XSD schema with all field types:\n\n### String Fields\n- Title, Series, Number, Summary, Notes\n- Creator fields (Writer, Penciller, Inker, Colorist, Letterer, CoverArtist, Editor, Translator)\n- Publication fields (Publisher, Imprint, Web, LanguageISO, Format)\n- Character/Location fields (MainCharacterOrTeam)\n- Story fields (SeriesGroup, ScanInformation, Review)\n\n### Multi-value Fields (String + Array Access)\n- Genre/Genres: Raw comma-separated string + parsed array\n- Characters: Raw comma-separated string + parsed array\n- Teams: Raw comma-separated string + parsed array\n- Locations: Raw comma-separated string + parsed array\n- StoryArc/StoryArcs: Raw comma-separated string + parsed array\n- StoryArcNumber/StoryArcNumbers: Raw comma-separated string + parsed array\n\n### Integer Fields\n- Count, Volume, AlternateCount, PageCount\n- Date fields (Year, Month, Day)\n\n### Enum Fields\n- BlackAndWhite: \"Unknown\", \"No\", \"Yes\"\n- Manga: \"Unknown\", \"No\", \"Yes\", \"YesAndRightToLeft\"\n- AgeRating: Various ESRB and international ratings\n\n### Decimal Fields\n- CommunityRating: 0.0 to 5.0 range with validation\n\n### Complex Fields\n- Pages: Array of ComicPageInfo objects with full attribute support\n- Page types: FrontCover, BackCover, InnerCover, Roundup, Story, Advertisement, Editorial, Letters, Preview, Other, Deleted\n\n### Export Formats\n- **JSON**: Complete serialization with all fields\n- **YAML**: Human-readable format with array structures\n- **XML**: Valid ComicInfo v2.0 compliant XML generation\n- **Hash**: Ruby hash representation with symbol keys\n\n### Data Export \u0026 XML Generation\n\n```ruby\ncomic = ComicInfo.load 'path/to/ComicInfo.xml'\n\n# Export as JSON\njson_string = comic.to_json\nputs JSON.pretty_generate(JSON.parse(json_string))\n\n# Export as YAML\nyaml_string = comic.to_yaml\nputs yaml_string\n\n# Generate XML\nxml_string = comic.to_xml\nputs xml_string\n\n# Save to file\ncomic.save 'path/to/new/ComicInfo.xml'\n\n# Save to IO object\nFile.open('path/to/new/ComicInfo.xml', 'w') do |file|\n  comic.save file\nend\n\n# Export as Hash\nhash = comic.to_h\nputs hash[:title]                   #=\u003e \"The Amazing Spider-Man\"\nputs hash[:genre]                   #=\u003e \"Superhero, Action, Adventure\" (raw data)\nputs hash[:genres]                  #=\u003e [\"Superhero\", \"Action\", \"Adventure\"] (parsed array)\nputs hash[:genres_raw_data]         #=\u003e \"Superhero, Action, Adventure\" (same as :genre)\nputs hash[:characters]              #=\u003e [\"Spider-Man\", \"Peter Parker\", ...]\nputs hash[:characters_raw_data]     #=\u003e \"Spider-Man, Peter Parker, J. Jonah Jameson, Aunt May\"\nputs hash[:pages].length            #=\u003e 12\n```\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies.\nThen, run `rake spec` to run the tests.\nYou can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`.\nTo release a new version, update the version number in `version.rb`,\nand then run `bundle exec rake release`,\nwhich will create a git tag for the version,\npush git commits and the created tag,\nand push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n### Running Tests\n\n```sh\n# Run all tests\nbundle exec rspec\n\n# Run with documentation format\nbundle exec rspec --format documentation\n\n# Run specific test file\nbundle exec rspec spec/comic_info_spec.rb\n```\n\n### Code Quality\n\n```sh\n# Run RuboCop linter\nbundle exec rubocop\n\n# Auto-fix correctable issues\nbundle exec rubocop --autocorrect\n```\n\n## Implementation Status\n\n### Current Features ✅\n- **Core Reading**: Complete ComicInfo.xml parsing\n- **XML Writing**: Full ComicInfo.xml generation with round-trip consistency\n- **Schema Compliance**: Full ComicInfo v2.0 support\n- **Field Types**: String, Integer, Decimal, Enum, Boolean, Arrays\n- **Multi-value Fields**: Both string and array access methods\n- **Issue \u0026Page Support**: Complete Issue and nested Page objects\n- **Error Handling**: Custom exceptions with detailed messages\n- **Data Export**: JSON, YAML, and XML serialization\n- **Validation**: Enum values, ranges, type coercion\n- **Unicode Support**: International characters and special symbols\n- **Test Coverage**: 178 comprehensive test cases\n\n### Planned Features 🚧\n- **CLI Tool**: Command-line interface for file manipulation\n- **Schema Migration**: Support for multiple ComicInfo versions\n\n### Schema Versions\n- ✅ **ComicInfo v2.0**: Full support (current)\n- 🚧 **ComicInfo v2.1**: Planned\n- 🚧 **ComicInfo v1.0**: Planned\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/veganstraightedge/comicinfo.\nThis project is intended to be a safe, welcoming space for collaboration,\nand contributors are expected to adhere to the\n[code of conduct](https://github.com/veganstraightedge/comicinfo/blob/main/CODE_OF_CONDUCT.md).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the ComicInfo project's codebases,\nissue trackers, chat rooms and mailing lists is expected to follow the\n[code of conduct](https://github.com/veganstraightedge/comicinfo/blob/main/CODE_OF_CONDUCT.md).\n\n## Acknowledgments\n\n- [Anansi Project](https://github.com/anansi-project/comicinfo) for the ComicInfo schema specification\n- [Nokogiri](https://nokogiri.org/) for XML parsing capabilities\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fveganstraightedge%2Fcomicinfo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fveganstraightedge%2Fcomicinfo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fveganstraightedge%2Fcomicinfo/lists"}