feat: implemented unified downloading
This commit is contained in:
60
utils.py
Normal file
60
utils.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""Shared utilities for file naming and organization."""
|
||||
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import mutagen
|
||||
|
||||
|
||||
def sanitize_filename(name):
|
||||
"""Remove characters prohibited in Windows filenames."""
|
||||
name = re.sub(r'[<>:"/\\|?*]', '_', name)
|
||||
return name.strip().strip('.')
|
||||
|
||||
|
||||
def rename_from_metadata(file_path):
|
||||
"""Rename an audio file to 'Title - Artist1, Artist2.ext' using embedded metadata.
|
||||
|
||||
Returns the new Path (or original if rename not possible).
|
||||
"""
|
||||
file_path = Path(file_path)
|
||||
audio = mutagen.File(str(file_path), easy=True)
|
||||
if audio is None:
|
||||
return file_path
|
||||
|
||||
try:
|
||||
title = audio.get("title", [None])[0]
|
||||
artist = audio.get("artist", [None])[0]
|
||||
except (IndexError, KeyError):
|
||||
return file_path
|
||||
|
||||
if not title or not artist:
|
||||
return file_path
|
||||
|
||||
new_name = sanitize_filename(f"{title} - {artist}{file_path.suffix}")
|
||||
new_path = file_path.parent / new_name
|
||||
|
||||
if new_path == file_path:
|
||||
return file_path
|
||||
|
||||
# Handle collisions
|
||||
counter = 2
|
||||
base_stem = new_path.stem
|
||||
while new_path.exists():
|
||||
new_path = new_path.with_stem(f"{base_stem} ({counter})")
|
||||
counter += 1
|
||||
|
||||
file_path.rename(new_path)
|
||||
return new_path
|
||||
|
||||
|
||||
def cleanup_empty_dirs(directory):
|
||||
"""Remove empty subdirectories (bottom-up)."""
|
||||
directory = Path(directory)
|
||||
for dirpath, dirnames, filenames in os.walk(str(directory), topdown=False):
|
||||
dirpath = Path(dirpath)
|
||||
if dirpath == directory:
|
||||
continue
|
||||
if not any(dirpath.iterdir()):
|
||||
dirpath.rmdir()
|
||||
Reference in New Issue
Block a user