First step for a config file

This commit is contained in:
Roncero Blanco, Edgar
2025-05-26 15:33:07 +02:00
parent dfe237d3ea
commit 63953f45e8
3 changed files with 110 additions and 66 deletions

2
.gitignore vendored
View File

@@ -180,3 +180,5 @@ cython_debug/
.cursorignore .cursorignore
.cursorindexingignore .cursorindexingignore
# ed1337x
config.ini

View File

@@ -4,26 +4,38 @@ from pathlib import Path
from mutagen.id3 import ID3 from mutagen.id3 import ID3
from datetime import datetime from datetime import datetime
from collections import defaultdict from collections import defaultdict
import configparser
import sys
CD_SIZE = 695 * 1024 * 1024 # 695 MB
GROUP_SIZE = 5 GROUP_SIZE = 5
# Store the current date def load_config():
run_date = datetime.now().strftime("%Y-%m-%d_%H%M%S") config_path = Path("config.ini")
default_config_path = Path("def_config.ini")
# Ask for source path, strip quotes if pasted # If config.ini missing, copy def_config.ini
source_input = input("Drag and drop your music folder here, then press Enter: ").strip().strip('"') if not config_path.exists():
source_media_path = Path(source_input) if default_config_path.exists():
shutil.copy(default_config_path, config_path)
print("config.ini created from def_config.ini with default settings.")
else:
print("Error: def_config.ini not found! Please create it and rerun.")
sys.exit(1)
if not source_media_path.exists() or not source_media_path.is_dir(): # Read default config
print(f"Error: {source_media_path} is not a valid directory.") default_config = configparser.ConfigParser()
exit(1) default_config.read(default_config_path)
# Build destination path # Read user config (overrides default)
parent = source_media_path.parent user_config = configparser.ConfigParser()
folder_name = source_media_path.name user_config.read(config_path)
dest_media_path = parent / f"[CDs-{run_date}]{folder_name}"
dest_media_path.mkdir(parents=True, exist_ok=True) # Merge configs: start with defaults, update with user settings
merged_config = configparser.ConfigParser()
merged_config.read_dict(default_config)
merged_config.read_dict(user_config)
return merged_config
def get_bpm(file_path): def get_bpm(file_path):
try: try:
@@ -35,64 +47,90 @@ def get_bpm(file_path):
print(f"Skipping {file_path.name} (no BPM): {e}") print(f"Skipping {file_path.name} (no BPM): {e}")
return None return None
# Collect all tracks recursively, grouping unknown BPM separately
all_tracks = []
for file in source_media_path.rglob("*.mp3"): # <-- recursive glob
bpm = get_bpm(file)
size = file.stat().st_size
if bpm is None:
bpm_range = "[Unknown BPM]"
else:
bpm_range = f"{(bpm // GROUP_SIZE) * GROUP_SIZE}-to-{((bpm // GROUP_SIZE) * GROUP_SIZE) + GROUP_SIZE - 1}"
all_tracks.append({"file": file, "size": size, "bpm_range": bpm_range})
if not all_tracks:
print("No MP3 files found.")
exit(0)
# Calculate total size and number of CDs needed
total_size = sum(t["size"] for t in all_tracks)
num_cds = max(1, (total_size + CD_SIZE - 1) // CD_SIZE)
print(f"Total size: {total_size / 1024**2:.2f} MB, splitting into {num_cds} CDs")
# Group tracks by BPM range
bpm_groups = defaultdict(list)
for track in all_tracks:
bpm_groups[track["bpm_range"]].append(track)
# Sort each bpm group
for bpm_range in bpm_groups:
bpm_groups[bpm_range].sort(key=lambda x: x["file"].name)
# Split each BPM group evenly into num_cds parts
def split_evenly(lst, n): def split_evenly(lst, n):
k, m = divmod(len(lst), n) k, m = divmod(len(lst), n)
return [lst[i*k + min(i, m):(i+1)*k + min(i+1, m)] for i in range(n)] return [lst[i*k + min(i, m):(i+1)*k + min(i+1, m)] for i in range(n)]
bpm_chunks = {} def main():
for bpm_range, tracks in bpm_groups.items(): config = load_config()
bpm_chunks[bpm_range] = split_evenly(tracks, num_cds)
# Prepare CDs # Use SplitFolderMB from config, convert MB to bytes
cd_contents = [[] for _ in range(num_cds)] CD_SIZE = config.getint("Settings", "SplitFolderMB") * 1024 * 1024
# Fill CDs with balanced BPM chunks # Store the current date for folder naming
for bpm_range in bpm_chunks: run_date = datetime.now().strftime("%Y-%m-%d_%H%M%S")
for i, chunk in enumerate(bpm_chunks[bpm_range]):
cd_contents[i].extend(chunk)
# Write CDs with BPM subfolders # Ask for source path, strip quotes if pasted
for i, tracks in enumerate(cd_contents, start=1): source_input = input("Drag and drop your music folder here, then press Enter: ").strip().strip('"')
cd_folder = dest_media_path / f"CD-{i:02}" source_media_path = Path(source_input)
cd_folder.mkdir(parents=True, exist_ok=True)
size_accum = 0
for track in tracks:
bpm_subfolder = cd_folder / track["bpm_range"]
bpm_subfolder.mkdir(parents=True, exist_ok=True)
shutil.copy(track["file"], bpm_subfolder / track["file"].name)
size_accum += track["size"]
print(f"[WRITE] CD-{i:02}: {len(tracks)} tracks, approx {size_accum/1024**2:.2f} MB")
print("\n✅ Done!") if not source_media_path.exists() or not source_media_path.is_dir():
print(f"Error: {source_media_path} is not a valid directory.")
sys.exit(1)
# Build destination path
parent = source_media_path.parent
folder_name = source_media_path.name
dest_media_path = parent / f"[CDs-{run_date}]{folder_name}"
dest_media_path.mkdir(parents=True, exist_ok=True)
# Collect all tracks recursively, group unknown BPM separately
all_tracks = []
for file in source_media_path.rglob("*.mp3"):
bpm = get_bpm(file)
size = file.stat().st_size
if bpm is None:
bpm_range = "[Unknown BPM]"
else:
bpm_range = f"{(bpm // GROUP_SIZE) * GROUP_SIZE}-to-{((bpm // GROUP_SIZE) * GROUP_SIZE) + GROUP_SIZE - 1}"
all_tracks.append({"file": file, "size": size, "bpm_range": bpm_range})
if not all_tracks:
print("No MP3 files found.")
sys.exit(0)
# Calculate total size and number of CDs needed
total_size = sum(t["size"] for t in all_tracks)
num_cds = max(1, (total_size + CD_SIZE - 1) // CD_SIZE)
print(f"Total size: {total_size / 1024**2:.2f} MB, splitting into {num_cds} CDs")
# Group tracks by BPM range
bpm_groups = defaultdict(list)
for track in all_tracks:
bpm_groups[track["bpm_range"]].append(track)
# Sort each bpm group
for bpm_range in bpm_groups:
bpm_groups[bpm_range].sort(key=lambda x: x["file"].name)
# Split each BPM group evenly into num_cds parts
bpm_chunks = {}
for bpm_range, tracks in bpm_groups.items():
bpm_chunks[bpm_range] = split_evenly(tracks, num_cds)
# Prepare CDs
cd_contents = [[] for _ in range(num_cds)]
# Fill CDs with balanced BPM chunks
for bpm_range in bpm_chunks:
for i, chunk in enumerate(bpm_chunks[bpm_range]):
cd_contents[i].extend(chunk)
# Write CDs with BPM subfolders
for i, tracks in enumerate(cd_contents, start=1):
cd_folder = dest_media_path / f"CD-{i:02}"
cd_folder.mkdir(parents=True, exist_ok=True)
size_accum = 0
for track in tracks:
bpm_subfolder = cd_folder / track["bpm_range"]
bpm_subfolder.mkdir(parents=True, exist_ok=True)
shutil.copy(track["file"], bpm_subfolder / track["file"].name)
size_accum += track["size"]
print(f"[WRITE] CD-{i:02}: {len(tracks)} tracks, approx {size_accum/1024**2:.2f} MB")
print("\n✅ Done!")
if __name__ == "__main__":
main()

4
src/def_config.ini Normal file
View File

@@ -0,0 +1,4 @@
[Settings]
bCheckNonPresentBPM = False
bReCheckPresentBPM = False
SplitFolderMB = 695