Init CBZ Volume Combiner v0.2.0

This commit is contained in:
Ben
2025-03-21 23:04:35 +00:00
commit 9fa11aea72
11 changed files with 1076 additions and 0 deletions

129
bin/cbz-volume-combiner Executable file
View File

@@ -0,0 +1,129 @@
#!/usr/bin/env python
# File: /home/code/projects/manga-organizer-1/cbz-volume-combiner/bin/cbz-volume-combiner
import os
import sys
import argparse
from cbz_volume_combiner.file_utils import find_cbz_files
from cbz_volume_combiner.core import organize_by_volume
from cbz_volume_combiner.volume import create_volume_cbz
def main():
parser = argparse.ArgumentParser(description='Combine individual CBZ chapters into volume CBZ files')
parser.add_argument('folder', help='Folder containing CBZ chapter files')
parser.add_argument('-r', '--recursive', action='store_true', help='Search for CBZ files recursively')
parser.add_argument('-o', '--output', help='Output folder for volume CBZ files (defaults to same location as chapters)')
parser.add_argument('-f', '--force', action='store_true', help='Force creation even if volume CBZ already exists')
parser.add_argument('-v', '--verbose', action='store_true', help='Show detailed progress')
parser.add_argument('-vv', '--extra-verbose', action='store_true', help='Show extremely detailed debugging information')
parser.add_argument('-m', '--min-chapters', type=int, default=2,
help='Minimum number of chapters required to create a volume (default: 2)')
args = parser.parse_args()
# If extra-verbose is enabled, automatically enable verbose too
if args.extra_verbose:
args.verbose = True
if not os.path.isdir(args.folder):
print(f"Error: '{args.folder}' is not a valid directory")
return 1
cbz_files = find_cbz_files(args.folder, args.recursive, args.extra_verbose)
if not cbz_files:
print(f"No CBZ files found in '{args.folder}'")
return 0
print(f"Found {len(cbz_files)} CBZ file(s)")
# Organize files by manga and volume
volumes = organize_by_volume(cbz_files, args.extra_verbose)
total_manga = len(volumes)
total_volumes = sum(len(volumes[manga]) for manga in volumes)
print(f"Found {total_manga} manga series with {total_volumes} volume(s) to process")
# Print detailed manga and volume information in extra verbose mode
if args.extra_verbose:
print("\nDetailed manga and volume breakdown:")
for manga_name in volumes:
try:
first_volume = min(volumes[manga_name].keys())
manga_display_name = volumes[manga_name][first_volume][0]['manga_name']
print(f"\n{manga_display_name}:")
for volume_num in sorted(volumes[manga_name].keys()):
chapters = volumes[manga_name][volume_num]
print(f" Volume {volume_num}: {len(chapters)} chapters")
if args.extra_verbose:
for chapter in chapters:
print(f" - Chapter {chapter['chapter_str']}: {os.path.basename(chapter['filename'])}")
print(f" Exists: {os.path.exists(chapter['filename'])}")
except (ValueError, IndexError):
pass
success_count = 0
skip_count = 0
fail_count = 0
ignored_count = 0
# Process each manga and volume
for manga_name in volumes:
# Get a proper display name from the first volume's first chapter
try:
first_volume = min(volumes[manga_name].keys())
manga_display_name = volumes[manga_name][first_volume][0]['manga_name']
except (ValueError, IndexError, KeyError):
# Fallback if we can't get proper name
manga_display_name = manga_name
if args.verbose:
print(f"\nProcessing manga: {manga_display_name}")
for volume_num in sorted(volumes[manga_name].keys()):
chapters = volumes[manga_name][volume_num]
# Skip volumes with too few chapters
if len(chapters) < args.min_chapters:
if args.verbose:
print(f"Skipping Volume {volume_num} - only has {len(chapters)} chapter(s) (minimum is {args.min_chapters})")
ignored_count += 1
continue
# List all chapters for debugging
if args.extra_verbose:
print(f"\nChapters for {manga_display_name} Volume {volume_num}:")
for chapter in chapters:
print(f" - Chapter {chapter['chapter_str']}: {os.path.basename(chapter['filename'])}")
print(f" Exists: {os.path.exists(chapter['filename'])}")
success, message = create_volume_cbz(
manga_display_name,
volume_num,
chapters,
args.output,
args.force,
args.verbose,
args.extra_verbose
)
if success:
if message == "Skipped (already exists)":
skip_count += 1
else:
success_count += 1
else:
fail_count += 1
print(f"Error creating Volume {volume_num} for {manga_display_name}: {message}")
print(f"\nVolume creation complete:")
print(f" - {success_count} volumes created successfully")
print(f" - {skip_count} volumes skipped (already exist)")
print(f" - {ignored_count} volumes ignored (too few chapters)")
print(f" - {fail_count} volumes failed")
return 0
if __name__ == '__main__':
sys.exit(main())