Initial commit. Basic featues are implemented

This commit is contained in:
2026-07-28 16:25:11 +05:00
commit 842e3bf1b0
12 changed files with 1190 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
"""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)