Last active
March 20, 2025 16:35
-
-
Save kompowiec/9a3faa242e6c13bae87a9a83f7a23162 to your computer and use it in GitHub Desktop.
implementation feature for linux: https://cdburnerxp.se/help/Data/disc-spanning
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import shutil | |
import subprocess | |
import tkinter as tk | |
from tkinter import filedialog, messagebox | |
from collections import defaultdict | |
def get_file_sizes(directory): | |
files = [] | |
for root, _, filenames in os.walk(directory): | |
for filename in filenames: | |
filepath = os.path.join(root, filename) | |
files.append((filepath, os.path.getsize(filepath))) | |
return sorted(files, key=lambda x: x[1], reverse=True) | |
def span_discs(files, disc_size, method="fewest_discs"): | |
discs = [] | |
current_disc = [] | |
current_size = 0 | |
if method == "fewest_discs": | |
for file, size in files: | |
if current_size + size > disc_size: | |
discs.append(current_disc) | |
current_disc = [] | |
current_size = 0 | |
current_disc.append(file) | |
current_size += size | |
if current_disc: | |
discs.append(current_disc) | |
elif method == "keep_folders": | |
folder_groups = defaultdict(list) | |
for file, size in files: | |
folder = os.path.dirname(file) | |
folder_groups[folder].append((file, size)) | |
for folder, file_list in folder_groups.items(): | |
folder_size = sum(size for _, size in file_list) | |
if folder_size > disc_size: | |
for file, size in file_list: | |
if current_size + size > disc_size: | |
discs.append(current_disc) | |
current_disc = [] | |
current_size = 0 | |
current_disc.append(file) | |
current_size += size | |
else: | |
if current_size + folder_size > disc_size: | |
discs.append(current_disc) | |
current_disc = [] | |
current_size = 0 | |
current_disc.extend([file for file, _ in file_list]) | |
current_size += folder_size | |
if current_disc: | |
discs.append(current_disc) | |
return discs | |
def save_table_of_contents(discs, output_dir): | |
for i, disc in enumerate(discs, start=1): | |
disc_folder = os.path.join(output_dir, f"Disc_{i}") | |
os.makedirs(disc_folder, exist_ok=True) | |
toc_path = os.path.join(disc_folder, "table_of_contents.txt") | |
with open(toc_path, "w") as toc: | |
toc.write(f"Disc {i}:\n") | |
for file in disc: | |
toc.write(f" {file}\n") | |
toc.write("\n") | |
print(f"Table of contents saved to {toc_path}") | |
def copy_files_to_output(discs, output_dir, input_dir): | |
for i, disc in enumerate(discs, start=1): | |
disc_folder = os.path.join(output_dir, f"Disc_{i}") | |
os.makedirs(disc_folder, exist_ok=True) | |
for file in disc: | |
relative_path = os.path.relpath(file, input_dir) | |
dest_dir = os.path.join(disc_folder, os.path.dirname(relative_path)) | |
os.makedirs(dest_dir, exist_ok=True) | |
dest = os.path.join(dest_dir, os.path.basename(file)) | |
shutil.copy2(file, dest) | |
print(f"Disc {i} files copied to {disc_folder}") | |
def create_iso(discs, output_dir): | |
for i, _ in enumerate(discs, start=1): | |
disc_folder = os.path.join(output_dir, f"Disc_{i}") | |
iso_path = os.path.join(output_dir, f"Disc_{i}.iso") | |
try: | |
subprocess.run([ | |
"mkisofs", "-o", iso_path, "-J", "-R", disc_folder | |
], check=True) | |
print(f"ISO created: {iso_path}") | |
shutil.rmtree(disc_folder) | |
print(f"Deleted folder: {disc_folder}") | |
except FileNotFoundError: | |
print("Error: mkisofs command not found. Please install cdrkit (Linux) or use an equivalent tool.") | |
except subprocess.CalledProcessError as e: | |
print(f"Error creating ISO for {disc_folder}: {e}") | |
def run_gui(): | |
root = tk.Tk() | |
root.title("Disc Spanning and ISO Creator") | |
def browse_input(): | |
input_path.set(filedialog.askdirectory()) | |
def browse_output(): | |
output_path.set(filedialog.askdirectory()) | |
def update_custom_entry(*args): | |
if disc_size.get() == "Custom": | |
custom_size_entry.config(state="normal") | |
else: | |
custom_size_entry.config(state="disabled") | |
disc_size_value.set(disc_size.get().split()[0]) | |
def start_process(): | |
input_dir = input_path.get() | |
output_dir = output_path.get() | |
disc_size_mb = float(disc_size_value.get()) | |
ecc_option = ecc_var.get() | |
if ecc_option == "Normal": | |
disc_size_mb *= (1 - 0.143) | |
elif ecc_option == "High": | |
disc_size_mb *= (1 - 0.335) | |
disc_size_bytes = disc_size_mb * 1024 * 1024 | |
method_choice = method_var.get() | |
files = get_file_sizes(input_dir) | |
discs = span_discs(files, disc_size_bytes, method_choice) | |
save_table_of_contents(discs, output_dir) | |
copy_files_to_output(discs, output_dir, input_dir) | |
create_iso(discs, output_dir) | |
messagebox.showinfo("Success", "Disc spanning and ISO creation complete!") | |
input_path = tk.StringVar() | |
output_path = tk.StringVar() | |
disc_size = tk.StringVar(value="700 (CD)") | |
disc_size_value = tk.StringVar(value="700") | |
ecc_var = tk.StringVar(value="None") | |
method_var = tk.StringVar(value="fewest_discs") | |
tk.Label(root, text="Input Directory:").pack() | |
tk.Entry(root, textvariable=input_path, width=50).pack() | |
tk.Button(root, text="Browse", command=browse_input).pack() | |
tk.Label(root, text="Output Directory:").pack() | |
tk.Entry(root, textvariable=output_path, width=50).pack() | |
tk.Button(root, text="Browse", command=browse_output).pack() | |
tk.Label(root, text="Disc Size (MiB):").pack() | |
sizes = ["1.2 (Floppy 1.2 MB)", | |
"1.44 (Floppy 1.4 MB)", | |
"100 (Zip Drive)", | |
"185 (CD 21 min)", | |
"250 (Zip Drive)", | |
"553 (CD 63 min)", | |
"650 (CD 74 min)", | |
"700 (CD 80 min)", | |
"750 (Zip Drive)", | |
"790 (CD 90 min)", | |
"870 (CD 99 min)", | |
"1392.36 (DVD-1)", | |
"2527.23 (DVD-2 DL)", | |
"4489.25 (DVD-5)", | |
"4482.625 (DVD+5)", | |
"8147.875 (DVD-9 DL)", | |
"8152 (DVD+9 DL)", | |
"14378.12 (HD DVD)", | |
"31846.49 (HD DVD-DL)", | |
"25600 (BD)", | |
"51200 (BD-DL)", | |
"102400 (BD-XL)", | |
"131072 (BD-XL)", | |
"Custom"] | |
disc_size_menu = tk.OptionMenu(root, disc_size, *sizes, command=update_custom_entry) | |
disc_size_menu.pack() | |
custom_size_entry = tk.Entry(root, textvariable=disc_size_value, state="disabled") | |
custom_size_entry.pack() | |
tk.Label(root, text="Error Correction Code:").pack() | |
tk.OptionMenu(root, ecc_var, "None", "Normal", "High").pack() | |
tk.Label(root, text="Method:").pack() | |
tk.OptionMenu(root, method_var, "fewest_discs", "keep_folders").pack() | |
tk.Button(root, text="Start", command=start_process).pack() | |
root.mainloop() | |
if __name__ == "__main__": | |
run_gui() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
screenshot:
