itagger


Nameitagger JSON
Version 0.1.2 PyPI version JSON
download
home_pageNone
SummaryCLI tool to create and embed ComicInfo.xml metadata for manga using AniList API
upload_time2025-10-18 16:40:39
maintainerNone
docs_urlNone
authorNone
requires_python>=3.13
licenseNone
keywords anilist cbz comicinfo kavita komga manga metadata
VCS
bugtrack_url
requirements requests lxml click python-dateutil
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center" style="margin-top: 20px">
  <a href="https://github.com/FelixSiegel/itagger">
        <img src="assets/logos/logo.svg" alt="Logo" width="120" height="120" />
    </a>
    <h1 style="margin-top: 0">iTagger</h1>
</div>

[![Language: Python](https://img.shields.io/badge/Language-Python-green)](https://www.python.org/)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)

A Python tool for creating `ComicInfo.xml` files for manga using the AniList API. This tool follows the ComicInfo schema specifications from [The Anansi Project](https://anansi-project.github.io/docs/comicinfo/documentation).

## Features

- 🔍 **Search manga** by title using AniList's comprehensive database
- 📊 **Fetch detailed metadata** including authors, artists, genres, tags, and more
- 📄 **Generate ComicInfo.xml** files compliant with the ComicInfo v2.1 schema
- 🎯 **Volume/chapter-specific** metadata generation
- 🌐 **Multi-language support** with proper language ISO codes
- 📚 **Batch processing** for multiple volumes
- 🎨 **Rich metadata** including character information, reading direction, age ratings

## Installation

### Using uv (Recommended)

Install the tool using [uv](https://docs.astral.sh/uv/):

```bash
uv tool install itagger
```

### Using pip

Install from PyPI using pip:

```bash
pip install itagger
```

Or install in development mode from source:

```bash
git clone https://github.com/FelixSiegel/itagger
cd itagger
pip install -e .
```

### Manual Installation

1. Clone or download this repository
2. Install dependencies:

```bash
pip install requests lxml click python-dateutil
```

or using uv, just run:

```bash
uv sync
```

## Usage

### Command Line Interface

The tool provides a CLI with several commands:

```text
  batch     Generate ComicInfo.xml files for multiple volumes of a manga...
  embed     Embed ComicInfo.xml metadata directly into CBZ files.
  generate  Generate ComicInfo.xml for a specific manga.
  search    Search for manga on AniList.
```

You can get help for each command using the `--help` flag.

#### Search for manga

Syntax:

```sh
itagger search [OPTIONS] QUERY
```

Example:

```bash
itagger search --limit 5 "Attack on Titan"
```

The command returns a list of matching manga titles along with their AniList IDs and other basic information.

#### Generate ComicInfo.xml for a specific manga (requires AniList ID)

Syntax:

```sh
itagger generate [OPTIONS] MANGA_ID
```

Example:

```bash
itagger generate --volume 1 --scan-info "My Scanlation Group" 105778
```

This command generates a `ComicInfo.xml` file for volume 1 of the manga with AniList ID `105778` (Chainsaw Man) and includes the specified [scanlation group](https://anansi-project.github.io/docs/comicinfo/documentation#scaninformation) in the metadata.

You can find the AniList ID using the `search` command or by visiting the manga's page on AniList (the ID is in the URL).

#### Batch generate for multiple volumes

Syntax:

```sh
itagger batch [OPTIONS] QUERY
```

Example:

```bash
itagger batch --volumes "1-10" --output-dir "output/" "One Piece"
```

This command searches for "One Piece" on AniList, retrieves its AniList ID, and generates `ComicInfo.xml` files for volumes 1 to 10, saving them in the specified output directory.

#### Embed metadata directly into CBZ files

Syntax:

```sh
itagger embed [OPTIONS] CBZ_DIR MANGA_ID
```

Examples:

```bash
# Embed metadata (from Manga by ID) into existing CBZ files for Komga/Kavita
itagger embed /path/to/cbz/folder 30933

# For specific range of volumes/chapters
itagger embed --range "1-10" /path/to/cbz/folder 30933

# For volume-based CBZ files
itagger embed --metadata-type volumes --pattern "v{:02d}.cbz" /path/to/cbz/folder 30933

# Dry run to see what would be processed
itagger embed --dry-run /path/to/cbz/folder 30933
```

Also read the [KOMGA_KAVITA_GUIDE.md](KOMGA_KAVITA_GUIDE.md) for more details on embedding metadata into CBZ files.

### Programmatic Usage

```python
from itagger.anilist_client import AniListClient
from itagger.comicinfo_generator import ComicInfoGenerator

# Initialize clients
client = AniListClient()
generator = ComicInfoGenerator()

# Search for manga
results = client.search_manga("Naruto", limit=5)
print(f"Found {len(results)} results")

# Get detailed information
manga = client.get_manga_details(results[0].id)

# Generate ComicInfo.xml
comic_info = generator.generate_comic_info(
    manga=manga,
    volume=1,
    scan_info="Example Scanlation Group"
)

# Save to file
with open("ComicInfo.xml", "w", encoding="utf-8") as f:
    f.write(comic_info)
```

## ComicInfo.xml Fields

The tool maps AniList data to ComicInfo.xml fields according to the schema:

| ComicInfo Field | Source | Description |
|----------------|--------|-------------|
| `Title` | Manga title + volume/chapter | Full title including volume/chapter info |
| `Series` | Primary title | Series name (English preferred, fallback to Romaji) |
| `Number` | Volume/Chapter | Volume or chapter number |
| `Count` | Volume count | Total volumes in series |
| `Volume` | Volume number | Specific volume number |
| `Summary` | Description | Cleaned description without HTML |
| `Year/Month/Day` | Start date | Publication start date |
| `Writer` | Staff with "Story" role | Authors/writers |
| `Penciller` | Staff with "Art" role | Artists |
| `Publisher` | Studios | Publishing studios |
| `Genre` | Genres | Comma-separated genres |
| `Tags` | Tags (non-spoiler) | Comma-separated tags |
| `Web` | Site URL | AniList page URL |
| `LanguageISO` | Country of origin | Language code (ja, ko, zh, etc.) |
| `Manga` | Country + format | Reading direction (YesAndRightToLeft for JP) |
| `Characters` | Main characters | Main character names |
| `AgeRating` | Tags + adult flag | Age appropriateness rating |
| `CommunityRating` | Average score | Rating converted to 0-5 scale |

### Example Output

```xml
<?xml version='1.0' encoding='UTF-8'?>
<ComicInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ComicInfo.xsd">
  <Title>Attack on Titan Volume 1</Title>
  <Series>Attack on Titan</Series>
  <Number>1</Number>
  <Count>34</Count>
  <Volume>1</Volume>
  <Summary>Hundreds of years ago, horrifying creatures which resembled humans appeared...</Summary>
  <Notes>Generated from AniList ID: 53390</Notes>
  <Year>2009</Year>
  <Month>9</Month>
  <Day>9</Day>
  <Writer>Hajime Isayama</Writer>
  <Penciller>Hajime Isayama</Penciller>
  <CoverArtist>Hajime Isayama</CoverArtist>
  <Publisher>Kodansha</Publisher>
  <Genre>Action, Drama, Fantasy, Horror</Genre>
  <Tags>Survival, Military, Tragedy, Gore, War</Tags>
  <Web>https://anilist.co/manga/53390</Web>
  <LanguageISO>ja</LanguageISO>
  <Format>Digital</Format>
  <BlackAndWhite>Yes</BlackAndWhite>
  <Manga>YesAndRightToLeft</Manga>
  <Characters>Eren Yeager, Mikasa Ackerman, Armin Arlert</Characters>
  <MainCharacterOrTeam>Eren Yeager</MainCharacterOrTeam>
  <AgeRating>Mature 17+</AgeRating>
  <CommunityRating>4.3</CommunityRating>
</ComicInfo>
```

## AniList API Integration

The tool uses AniList's GraphQL API to fetch comprehensive manga metadata:

- **Search**: Finds manga by title with popularity and score sorting
- **Details**: Retrieves full metadata including staff, characters, tags, and more
- **No authentication required**: Uses public API endpoints
- **Rate limiting**: Respectful API usage with proper error handling

## Schema Compliance

Generated ComicInfo.xml files follow the [ComicInfo v2.1 schema](https://anansi-project.github.io/docs/comicinfo/schemas/v2.1) specifications:

- Proper XML structure and encoding
- Correct data types for numeric fields
- Enumerated values for specific fields (Manga, AgeRating, etc.)
- Optional field handling
- HTML entity escaping

## Dependencies

- `requests`: HTTP client for AniList API
- `lxml`: XML processing and generation
- `click`: Command-line interface framework
- `python-dateutil`: Date parsing utilities

## License

This project is open source and available under the [GNU General Public License v3.0](LICENSE).

## Contributing

Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.

## Acknowledgments

- [AniList](https://anilist.co/) for providing the comprehensive manga database API
- [The Anansi Project](https://anansi-project.github.io/) for ComicInfo schema documentation
- [uv](https://docs.astral.sh/uv/) for making the whole build and installation process easier
- The manga and digital comics community for standardization efforts

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "itagger",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.13",
    "maintainer_email": null,
    "keywords": "anilist, cbz, comicinfo, kavita, komga, manga, metadata",
    "author": null,
    "author_email": "InfinityCoding <infinitycoding@web.de>",
    "download_url": "https://files.pythonhosted.org/packages/5a/a9/86ec3ce1201ca3b281e3f59b32ecff2ae3b5b8a50581c7f7db52a673fc9f/itagger-0.1.2.tar.gz",
    "platform": null,
    "description": "<div align=\"center\" style=\"margin-top: 20px\">\n  <a href=\"https://github.com/FelixSiegel/itagger\">\n        <img src=\"assets/logos/logo.svg\" alt=\"Logo\" width=\"120\" height=\"120\" />\n    </a>\n    <h1 style=\"margin-top: 0\">iTagger</h1>\n</div>\n\n[![Language: Python](https://img.shields.io/badge/Language-Python-green)](https://www.python.org/)\n[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)\n\nA Python tool for creating `ComicInfo.xml` files for manga using the AniList API. This tool follows the ComicInfo schema specifications from [The Anansi Project](https://anansi-project.github.io/docs/comicinfo/documentation).\n\n## Features\n\n- \ud83d\udd0d **Search manga** by title using AniList's comprehensive database\n- \ud83d\udcca **Fetch detailed metadata** including authors, artists, genres, tags, and more\n- \ud83d\udcc4 **Generate ComicInfo.xml** files compliant with the ComicInfo v2.1 schema\n- \ud83c\udfaf **Volume/chapter-specific** metadata generation\n- \ud83c\udf10 **Multi-language support** with proper language ISO codes\n- \ud83d\udcda **Batch processing** for multiple volumes\n- \ud83c\udfa8 **Rich metadata** including character information, reading direction, age ratings\n\n## Installation\n\n### Using uv (Recommended)\n\nInstall the tool using [uv](https://docs.astral.sh/uv/):\n\n```bash\nuv tool install itagger\n```\n\n### Using pip\n\nInstall from PyPI using pip:\n\n```bash\npip install itagger\n```\n\nOr install in development mode from source:\n\n```bash\ngit clone https://github.com/FelixSiegel/itagger\ncd itagger\npip install -e .\n```\n\n### Manual Installation\n\n1. Clone or download this repository\n2. Install dependencies:\n\n```bash\npip install requests lxml click python-dateutil\n```\n\nor using uv, just run:\n\n```bash\nuv sync\n```\n\n## Usage\n\n### Command Line Interface\n\nThe tool provides a CLI with several commands:\n\n```text\n  batch     Generate ComicInfo.xml files for multiple volumes of a manga...\n  embed     Embed ComicInfo.xml metadata directly into CBZ files.\n  generate  Generate ComicInfo.xml for a specific manga.\n  search    Search for manga on AniList.\n```\n\nYou can get help for each command using the `--help` flag.\n\n#### Search for manga\n\nSyntax:\n\n```sh\nitagger search [OPTIONS] QUERY\n```\n\nExample:\n\n```bash\nitagger search --limit 5 \"Attack on Titan\"\n```\n\nThe command returns a list of matching manga titles along with their AniList IDs and other basic information.\n\n#### Generate ComicInfo.xml for a specific manga (requires AniList ID)\n\nSyntax:\n\n```sh\nitagger generate [OPTIONS] MANGA_ID\n```\n\nExample:\n\n```bash\nitagger generate --volume 1 --scan-info \"My Scanlation Group\" 105778\n```\n\nThis command generates a `ComicInfo.xml` file for volume 1 of the manga with AniList ID `105778` (Chainsaw Man) and includes the specified [scanlation group](https://anansi-project.github.io/docs/comicinfo/documentation#scaninformation) in the metadata.\n\nYou can find the AniList ID using the `search` command or by visiting the manga's page on AniList (the ID is in the URL).\n\n#### Batch generate for multiple volumes\n\nSyntax:\n\n```sh\nitagger batch [OPTIONS] QUERY\n```\n\nExample:\n\n```bash\nitagger batch --volumes \"1-10\" --output-dir \"output/\" \"One Piece\"\n```\n\nThis command searches for \"One Piece\" on AniList, retrieves its AniList ID, and generates `ComicInfo.xml` files for volumes 1 to 10, saving them in the specified output directory.\n\n#### Embed metadata directly into CBZ files\n\nSyntax:\n\n```sh\nitagger embed [OPTIONS] CBZ_DIR MANGA_ID\n```\n\nExamples:\n\n```bash\n# Embed metadata (from Manga by ID) into existing CBZ files for Komga/Kavita\nitagger embed /path/to/cbz/folder 30933\n\n# For specific range of volumes/chapters\nitagger embed --range \"1-10\" /path/to/cbz/folder 30933\n\n# For volume-based CBZ files\nitagger embed --metadata-type volumes --pattern \"v{:02d}.cbz\" /path/to/cbz/folder 30933\n\n# Dry run to see what would be processed\nitagger embed --dry-run /path/to/cbz/folder 30933\n```\n\nAlso read the [KOMGA_KAVITA_GUIDE.md](KOMGA_KAVITA_GUIDE.md) for more details on embedding metadata into CBZ files.\n\n### Programmatic Usage\n\n```python\nfrom itagger.anilist_client import AniListClient\nfrom itagger.comicinfo_generator import ComicInfoGenerator\n\n# Initialize clients\nclient = AniListClient()\ngenerator = ComicInfoGenerator()\n\n# Search for manga\nresults = client.search_manga(\"Naruto\", limit=5)\nprint(f\"Found {len(results)} results\")\n\n# Get detailed information\nmanga = client.get_manga_details(results[0].id)\n\n# Generate ComicInfo.xml\ncomic_info = generator.generate_comic_info(\n    manga=manga,\n    volume=1,\n    scan_info=\"Example Scanlation Group\"\n)\n\n# Save to file\nwith open(\"ComicInfo.xml\", \"w\", encoding=\"utf-8\") as f:\n    f.write(comic_info)\n```\n\n## ComicInfo.xml Fields\n\nThe tool maps AniList data to ComicInfo.xml fields according to the schema:\n\n| ComicInfo Field | Source | Description |\n|----------------|--------|-------------|\n| `Title` | Manga title + volume/chapter | Full title including volume/chapter info |\n| `Series` | Primary title | Series name (English preferred, fallback to Romaji) |\n| `Number` | Volume/Chapter | Volume or chapter number |\n| `Count` | Volume count | Total volumes in series |\n| `Volume` | Volume number | Specific volume number |\n| `Summary` | Description | Cleaned description without HTML |\n| `Year/Month/Day` | Start date | Publication start date |\n| `Writer` | Staff with \"Story\" role | Authors/writers |\n| `Penciller` | Staff with \"Art\" role | Artists |\n| `Publisher` | Studios | Publishing studios |\n| `Genre` | Genres | Comma-separated genres |\n| `Tags` | Tags (non-spoiler) | Comma-separated tags |\n| `Web` | Site URL | AniList page URL |\n| `LanguageISO` | Country of origin | Language code (ja, ko, zh, etc.) |\n| `Manga` | Country + format | Reading direction (YesAndRightToLeft for JP) |\n| `Characters` | Main characters | Main character names |\n| `AgeRating` | Tags + adult flag | Age appropriateness rating |\n| `CommunityRating` | Average score | Rating converted to 0-5 scale |\n\n### Example Output\n\n```xml\n<?xml version='1.0' encoding='UTF-8'?>\n<ComicInfo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"ComicInfo.xsd\">\n  <Title>Attack on Titan Volume 1</Title>\n  <Series>Attack on Titan</Series>\n  <Number>1</Number>\n  <Count>34</Count>\n  <Volume>1</Volume>\n  <Summary>Hundreds of years ago, horrifying creatures which resembled humans appeared...</Summary>\n  <Notes>Generated from AniList ID: 53390</Notes>\n  <Year>2009</Year>\n  <Month>9</Month>\n  <Day>9</Day>\n  <Writer>Hajime Isayama</Writer>\n  <Penciller>Hajime Isayama</Penciller>\n  <CoverArtist>Hajime Isayama</CoverArtist>\n  <Publisher>Kodansha</Publisher>\n  <Genre>Action, Drama, Fantasy, Horror</Genre>\n  <Tags>Survival, Military, Tragedy, Gore, War</Tags>\n  <Web>https://anilist.co/manga/53390</Web>\n  <LanguageISO>ja</LanguageISO>\n  <Format>Digital</Format>\n  <BlackAndWhite>Yes</BlackAndWhite>\n  <Manga>YesAndRightToLeft</Manga>\n  <Characters>Eren Yeager, Mikasa Ackerman, Armin Arlert</Characters>\n  <MainCharacterOrTeam>Eren Yeager</MainCharacterOrTeam>\n  <AgeRating>Mature 17+</AgeRating>\n  <CommunityRating>4.3</CommunityRating>\n</ComicInfo>\n```\n\n## AniList API Integration\n\nThe tool uses AniList's GraphQL API to fetch comprehensive manga metadata:\n\n- **Search**: Finds manga by title with popularity and score sorting\n- **Details**: Retrieves full metadata including staff, characters, tags, and more\n- **No authentication required**: Uses public API endpoints\n- **Rate limiting**: Respectful API usage with proper error handling\n\n## Schema Compliance\n\nGenerated ComicInfo.xml files follow the [ComicInfo v2.1 schema](https://anansi-project.github.io/docs/comicinfo/schemas/v2.1) specifications:\n\n- Proper XML structure and encoding\n- Correct data types for numeric fields\n- Enumerated values for specific fields (Manga, AgeRating, etc.)\n- Optional field handling\n- HTML entity escaping\n\n## Dependencies\n\n- `requests`: HTTP client for AniList API\n- `lxml`: XML processing and generation\n- `click`: Command-line interface framework\n- `python-dateutil`: Date parsing utilities\n\n## License\n\nThis project is open source and available under the [GNU General Public License v3.0](LICENSE).\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues, feature requests, or pull requests.\n\n## Acknowledgments\n\n- [AniList](https://anilist.co/) for providing the comprehensive manga database API\n- [The Anansi Project](https://anansi-project.github.io/) for ComicInfo schema documentation\n- [uv](https://docs.astral.sh/uv/) for making the whole build and installation process easier\n- The manga and digital comics community for standardization efforts\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "CLI tool to create and embed ComicInfo.xml metadata for manga using AniList API",
    "version": "0.1.2",
    "project_urls": {
        "Homepage": "https://github.com/FelixSiegel/itagger",
        "Issues": "https://github.com/FelixSiegel/itagger/issues",
        "Repository": "https://github.com/FelixSiegel/itagger"
    },
    "split_keywords": [
        "anilist",
        " cbz",
        " comicinfo",
        " kavita",
        " komga",
        " manga",
        " metadata"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d78b13271b214bea88e70944e61836937d1ce2d6a0426f2583b5478f7bdb2c29",
                "md5": "fea09294a9520c2b6adb8fcc37cf5c3e",
                "sha256": "fb4689c38de15263b0688357b09ec0477f336ca769cef8bfd7630c055beb1479"
            },
            "downloads": -1,
            "filename": "itagger-0.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "fea09294a9520c2b6adb8fcc37cf5c3e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.13",
            "size": 27668,
            "upload_time": "2025-10-18T16:40:38",
            "upload_time_iso_8601": "2025-10-18T16:40:38.064426Z",
            "url": "https://files.pythonhosted.org/packages/d7/8b/13271b214bea88e70944e61836937d1ce2d6a0426f2583b5478f7bdb2c29/itagger-0.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5aa986ec3ce1201ca3b281e3f59b32ecff2ae3b5b8a50581c7f7db52a673fc9f",
                "md5": "806299c2251e06c062517b67a1455c32",
                "sha256": "0bae8bcbc43f513213e126cb33cbb691ad6b08507ebd321ceaf1b03e7dee651d"
            },
            "downloads": -1,
            "filename": "itagger-0.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "806299c2251e06c062517b67a1455c32",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.13",
            "size": 36805,
            "upload_time": "2025-10-18T16:40:39",
            "upload_time_iso_8601": "2025-10-18T16:40:39.276366Z",
            "url": "https://files.pythonhosted.org/packages/5a/a9/86ec3ce1201ca3b281e3f59b32ecff2ae3b5b8a50581c7f7db52a673fc9f/itagger-0.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-18 16:40:39",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "FelixSiegel",
    "github_project": "itagger",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "requests",
            "specs": [
                [
                    ">=",
                    "2.31.0"
                ]
            ]
        },
        {
            "name": "lxml",
            "specs": [
                [
                    ">=",
                    "4.9.0"
                ]
            ]
        },
        {
            "name": "click",
            "specs": [
                [
                    ">=",
                    "8.1.0"
                ]
            ]
        },
        {
            "name": "python-dateutil",
            "specs": [
                [
                    ">=",
                    "2.8.0"
                ]
            ]
        }
    ],
    "lcname": "itagger"
}
        
Elapsed time: 1.47843s