Files
audio_splitter/utils.py
T

172 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Generalpurpose helper functions."""
import re
def parse_timestamp(timestamp: str) -> int:
"""
Convert a timestamp in 'mm:ss' or 'HH:MM:SS' format to total seconds.
Args:
timestamp: String in the format 'mm:ss' or 'HH:MM:SS'.
Returns:
Total number of seconds.
Raises:
ValueError: If the format is unrecognized.
"""
parts = timestamp.strip().split(':')
if len(parts) == 2:
minutes, seconds = map(int, parts)
return minutes * 60 + seconds
elif len(parts) == 3:
hours, minutes, seconds = map(int, parts)
return hours * 3600 + minutes * 60 + seconds
else:
raise ValueError(f"Invalid timestamp format: {timestamp}")
def format_time(seconds: int) -> str:
"""
Convert seconds to 'HH:MM:SS' format for FFmpeg.
Args:
seconds: Total number of seconds.
Returns:
Time string in 'HH:MM:SS' format.
"""
hours = seconds // 3600
minutes = (seconds % 3600) // 60
secs = seconds % 60
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
def sanitize_filename(name: str) -> str:
"""
Remove characters that are problematic on common filesystems.
This is a fallback sanitizer; the main replacement is handled by
apply_replacement() when --replace-bad-chars is used.
Args:
name: Original filename candidate.
Returns:
Sanitized string with dangerous characters replaced by '_'.
"""
# Replace characters that are forbidden on Windows/Linux/macOS.
return re.sub(r'[<>:"/\\|?*]', '_', name).strip()
def apply_replacement(name: str, bad_chars: str, replacement_char: str) -> str:
"""
Replace every occurrence of any character in bad_chars with replacement_char.
Args:
name: The original string.
bad_chars: String containing all characters to replace.
replacement_char: The character to insert.
Returns:
The transformed string.
"""
if not bad_chars:
return name
# Build a translation table mapping each bad character to the replacement.
translation_table = str.maketrans({c: replacement_char for c in set(bad_chars)})
return name.translate(translation_table)
def cleanup_good_chars(name: str, good_char: str) -> str:
"""
Clean up the filename after replacement to avoid awkward sequences.
Steps performed:
1. Strip leading/trailing good_char characters.
2. Collapse consecutive good_char characters into a single one.
3. Remove good_char characters that are adjacent to a single nongood_char
(i.e., pattern good_char + X + good_char becomes just X),
and repeat this step until no more such patterns exist.
4. After each iteration, reapply stripping and collapsing.
This makes filenames more humanreadable, e.g.:
"author_-_song" -> "author-song"
"hello__world" -> "hello_world"
"_hello_" -> "hello"
Args:
name: The string to clean (after replacement).
good_char: The character used as replacement.
Returns:
The cleaned string.
"""
# Escape the good_char for regex usage.
escaped = re.escape(good_char)
# Helper to collapse consecutive good chars and strip edges.
def collapse_and_strip(s: str) -> str:
# Collapse multiple consecutive good chars into one.
s = re.sub(rf'{escaped}+', good_char, s)
# Remove leading/trailing good chars.
s = s.strip(good_char)
return s
# Apply stripping and collapsing initially.
name = collapse_and_strip(name)
# Remove patterns: good_char + X + good_char (where X is any char != good_char).
# Repeat until no further changes.
while True:
# Replace pattern: good_char (non-good-char) good_char -> just the non-good-char.
# The negative lookahead ensures X is not the good_char.
pattern = rf'{escaped}([^{escaped}]){escaped}'
new_name = re.sub(pattern, r'\1', name)
if new_name == name:
break
name = new_name
# Reapply stripping and collapsing after removal.
name = collapse_and_strip(name)
return name
def apply_template(template: str, placeholders: dict) -> str:
"""
Replace placeholders in a template string with values from a dict.
Placeholders are of the form %key (e.g., %tn, %an).
Use %% to escape a literal percent sign.
Args:
template: The template string.
placeholders: Dict mapping placeholder names to values.
Returns:
The rendered string.
"""
import re
result = []
i = 0
while i < len(template):
ch = template[i]
if ch == '%':
if i + 1 < len(template) and template[i + 1] == '%':
result.append('%')
i += 2
continue
match = re.match(r'%([a-zA-Z]+)', template[i:])
if match:
key = match.group(1)
value = placeholders.get(key, '')
result.append(value)
i += len(match.group(0))
else:
result.append(ch)
i += 1
else:
result.append(ch)
i += 1
return ''.join(result)