2

Good day.

I wrote a little Python program to help me easily create .cbc files for Calibre, which is just a renamed .zip file with a text file called comics.txt for TOC purposes. Each chapter is another zip file.

The issue is that the last zip file zipped always has the error "Unexpected end of data". The file itself is not corrupt, if I unzip it and rezip it it works perfectly. Playing around it seems that the problem is that Python doesn't close the last zip file after zipping it, since I can't delete the last zip while the program is still running since it's still open in Python. Needless to say, Calibre doesn't like the file and fails to convert it unless I manually rezip the affected chapters.

The code is as follows, checking the folders for not-image files, zipping the folders, zipping the zips while creating the text file, and "changing" extension.


import re, glob, os, zipfile, shutil, pathlib, gzip, itertools

Folders = glob.glob("*/")
items = len(Folders)
cn_list = []
cn_list_filtered = []
dirs_filtered = []
ch_id = ["c", "Ch. "]
subdir_im = []
total = 0
Dirs = next(os.walk('.'))[1]

for i in range(0, len(Dirs)):
    for items in os.listdir("./" + Dirs[i]):
        if items.__contains__('.png') or items.__contains__('.jpg'):
            total+=1
        else:
            print(items + " not an accepted format.")
    subdir_im.append(total)
    total = 0

for fname in Folders:
    if re.search(ch_id[0] + r'\d+' + r'[\S]' + r'\d+', fname):
        cn = re.findall(ch_id[0] + "(\d+[\S]\d+)", fname)[0]
        cn_list.append(cn)
    elif re.search(ch_id[0] + r'\d+', fname):
        cn = re.findall(ch_id[0] + "(\d+)", fname)[0]
        cn_list.append(cn)
    elif re.search(ch_id[1] + r'\d+' + '[\S]' + r'\d+', fname):
        cn = re.findall(ch_id[1] + "(\d+[\S]\d+)", fname)[0]
        cn_list.append(cn)
    elif re.search(ch_id[1] + r'\d+', fname):
        cn = re.findall(ch_id[1] + "(\d+)", fname)[0]
        cn_list.append(cn)
    else:
        print('Warning: File found without proper filename format.')

cn_list_filtered = set(cn_list)
cn_list_filtered = sorted(cn_list_filtered)

cwd = os.getcwd()
Dirs = Folders
subdir_zi = []
total = 0

for i in range(0, len(cn_list_filtered)):
    for folders in Dirs:
        if folders.__contains__(ch_id[0] + cn_list_filtered[i] + " ")\
         or folders.__contains__(ch_id[1] + cn_list_filtered[i] + " "):
            print('Zipping folder ', folders)
            namezip = "Chapter " + cn_list_filtered[i] + ".zip"
            current_zip = zipfile.ZipFile(namezip, "a")
            for items in os.listdir(folders):
                if items.__contains__('.png') or items.__contains__('.jpg'):
                    current_zip.write(folders + "/" + items, items)
                    total+=1
    subdir_zi.append(total)
    total = 0

print('Folder contents in order:', subdir_im, ' Total:', sum(subdir_im))
print("Number of items per zip: ", subdir_zi, ' Total:', sum(subdir_zi))

if subdir_im == subdir_zi:
    print("All items in folders have been successfully zipped")
else:
    print("Warning: File count in folders and zips do not match. Please check the affected chapters")

zips = glob.glob("*.zip")

namezip2 = os.path.basename(os.getcwd()) + ".zip"
zipfinal = zipfile.ZipFile(namezip2, "a")

for i in range(0, len(zips), 1):
    zipfinal.write(zips[i],zips[i])

Data = []

for i in range (0,len(cn_list_filtered),1):
    Datai = ("Chapter " + cn_list_filtered[i] + ".zip" + ":Chapter " + cn_list_filtered[i] + "\r\n")
    Data.append(Datai)

Dataok = ''.join(Data)

with zipfile.ZipFile(namezip2, 'a') as myzip:
    myzip.writestr("comics.txt", Dataok)

zipfinal.close()

os.rename(namezip2, namezip2 + ".cbc")

os.system("pause")

I am by no means a programmer, that is just a Frankenstein monster code I eventually managed to put together by checking threads, but this last issue has me stumped.

Some solutions I tried are:

for i in range(0, len(zips), 1):
    zipfinal.write(zips[i],zips[i])
    zips[i].close()

Fails with:

zips[i].close()
AttributeError: 'str' object has no attribute 'close'

and:

for i in range(0, len(zips), 1):
    zipfinal.write(zips[i],zips[i])

zips[len(zips)].close()

Fails with:

    zips[len(zips)].close()
IndexError: list index out of range

Thanks for the help.

  • Calibre fails with a "not a zip file" error. The error is always on the last zip added to the .cbc. If I unpack the failing zip file and rezip it works perfectly, file is not corrupted. Thanks for the syntax tips. Edit: The "Unexpected end of data" is a 7zip error. – user12221095 Oct 17 '19 at 14:38
  • Something else I just realized, the "original" .zip shows no errors. Only the unpacked one does. – user12221095 Oct 17 '19 at 15:01

1 Answers1

0

This solved my issue:

def generate_zip(file_list, file_name=None):
    zip_buffer = io.BytesIO()
    zf = zipfile.ZipFile(zip_buffer, mode="w", compression=zipfile.ZIP_DEFLATED)
    for file in file_list:
        print(f"Filename: {file[0]}\nData: {file[1]}")
        zf.writestr(file[0], file[1])
    **zf.close()**
    with open(file_name, 'wb') as f:
        f.write(zip_buffer.getvalue())
        f.close()