Skip to content

Instantly share code, notes, and snippets.

@kompowiec
Last active March 20, 2025 16:35
Show Gist options
  • Save kompowiec/9a3faa242e6c13bae87a9a83f7a23162 to your computer and use it in GitHub Desktop.
Save kompowiec/9a3faa242e6c13bae87a9a83f7a23162 to your computer and use it in GitHub Desktop.
implementation feature for linux: https://cdburnerxp.se/help/Data/disc-spanning
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()
@kompowiec
Copy link
Author

kompowiec commented Mar 14, 2025

screenshot:
disc spanning

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment