Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- import os
- import shutil
- import unicodedata
- import re
- from pathlib import Path
- import sys
- # Copy a directory (~/Masic/RythmBox) to a FAT32 formated
- # flash drive, named MUSIC, converting all filenames
- # This was written with GPT-5 Mini via duck.ai as a bash script,
- # Some manual changes and it was fed into Google Gemini
- # Gemini then made further optimizations and rewrote it in python
- # --- CONFIGURATION ---
- HOME = Path.home()
- SOURCE_DIR = HOME / "Music/RythmBox"
- DEST_DIR = Path("/media") / HOME.name / "MUSIC"
- MAX_BYTES = 255
- # --- PROGRESS BAR SETUP ---
- # Try to import tqdm. If missing, create a dummy fallback.
- try:
- from tqdm import tqdm
- HAS_TQDM = True
- except ImportError:
- HAS_TQDM = False
- print("Tip: Run 'pip3 install tqdm' for a nicer progress bar with ETA.")
- # Fallback class to mimic tqdm if library is missing
- class tqdm:
- def __init__(self, total=0, unit='files', **kwargs):
- self.total = total
- self.n = 0
- def update(self, n=1):
- self.n += n
- sys.stdout.write(f"\rProcessed: {self.n}/{self.total}")
- sys.stdout.flush()
- def close(self):
- print("")
- def write(self, msg):
- sys.stdout.write(f"\r{msg}\n")
- def __enter__(self): return self
- def __exit__(self, *args): self.close()
- def sanitize_component(name):
- """
- Makes a filename FAT32 safe.
- """
- # 1. Transliterate Unicode to ASCII
- norm = unicodedata.normalize('NFKD', name)
- name = norm.encode('ASCII', 'ignore').decode('ASCII')
- # 2. Replace forbidden characters and spaces
- name = re.sub(r'[<>:"/\\|?*]', '-', name)
- name = re.sub(r'[\000-\037]', '', name)
- name = re.sub(r'\s+', '_', name)
- # 3. Trim leading/trailing dots and spaces
- name = name.strip('. ')
- # 4. Ensure not empty
- if not name:
- name = "_"
- # 5. Truncate to MAX_BYTES
- encoded = name.encode('utf-8')
- if len(encoded) > MAX_BYTES:
- name = encoded[:MAX_BYTES].decode('utf-8', 'ignore')
- return name
- def main():
- src_path = Path(SOURCE_DIR)
- dst_path = Path(DEST_DIR)
- if not src_path.exists():
- print(f"Error: Source directory not found: {src_path}")
- return
- print(f"Source: {src_path}")
- print(f"Dest: {dst_path}")
- # 1. Count total files for the progress bar
- print("Scanning source directory to count files...")
- total_files = sum(len(files) for _, _, files in os.walk(src_path))
- print(f"Total files found: {total_files}")
- print("-" * 40)
- # 2. Start the copy process
- with tqdm(total=total_files, unit='file') as pbar:
- for root, dirs, files in os.walk(src_path):
- rel_path = Path(root).relative_to(src_path)
- # Sanitize directory path
- safe_parts = [sanitize_component(p) for p in rel_path.parts if p != '.']
- current_dst_dir = dst_path.joinpath(*safe_parts)
- if not current_dst_dir.exists():
- try:
- current_dst_dir.mkdir(parents=True, exist_ok=True)
- except OSError as e:
- pbar.write(f"Error creating dir {rel_path}: {e}")
- continue
- for filename in files:
- safe_filename = sanitize_component(filename)
- src_file = Path(root) / filename
- dst_file = current_dst_dir / safe_filename
- # Logic: Copy if dest missing OR src is newer
- should_copy = False
- if not dst_file.exists():
- should_copy = True
- elif src_file.stat().st_mtime > dst_file.stat().st_mtime:
- should_copy = True
- if should_copy:
- try:
- # Update description to show current file being copied
- # (Only do this if using real tqdm to avoid clutter in fallback)
- if HAS_TQDM:
- pbar.set_description(f"Copying {safe_filename[:20]}...")
- shutil.copy2(src_file, dst_file)
- except Exception as e:
- pbar.write(f"Failed to copy {filename}: {e}")
- # Advance progress bar
- pbar.update(1)
- print("Operation complete.")
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment