77 lines
2.6 KiB
Python
77 lines
2.6 KiB
Python
"""Timestamp parsing and resolution."""
|
|
|
|
from .utils import parse_timestamp
|
|
|
|
|
|
def parse_track_timestamps(tracks):
|
|
"""
|
|
Parse timestamps from each track.
|
|
|
|
Args:
|
|
tracks: List of dicts from tracklist parsing.
|
|
|
|
Returns:
|
|
List of (start_seconds, end_seconds_or_None) for each track.
|
|
|
|
Raises:
|
|
ValueError: If timestamp is invalid or range is malformed.
|
|
"""
|
|
track_times = []
|
|
for idx, track in enumerate(tracks, 1):
|
|
ts_str = track.get('ts', '').strip()
|
|
if not ts_str:
|
|
raise ValueError(f"Track {idx}: timestamp is empty")
|
|
|
|
# Detect range: contains a dash.
|
|
if '-' in ts_str:
|
|
parts = ts_str.split('-', 1)
|
|
start_str = parts[0].strip()
|
|
end_str = parts[1].strip()
|
|
if not start_str or not end_str:
|
|
raise ValueError(f"Track {idx}: invalid range format '{ts_str}'. Expected 'start-end'.")
|
|
try:
|
|
start_sec = parse_timestamp(start_str)
|
|
end_sec = parse_timestamp(end_str)
|
|
except ValueError as e:
|
|
raise ValueError(f"Track {idx}: invalid timestamp in range '{ts_str}': {e}")
|
|
if end_sec <= start_sec:
|
|
raise ValueError(f"Track {idx}: end time ({end_str}) must be after start time ({start_str})")
|
|
track_times.append((start_sec, end_sec))
|
|
else:
|
|
# Start-only: we will compute end later.
|
|
try:
|
|
start_sec = parse_timestamp(ts_str)
|
|
except ValueError as e:
|
|
raise ValueError(f"Track {idx}: invalid timestamp '{ts_str}': {e}")
|
|
track_times.append((start_sec, None))
|
|
|
|
return track_times
|
|
|
|
|
|
def resolve_end_times(track_times, total_duration):
|
|
"""
|
|
Resolve None ends to next start or total duration.
|
|
|
|
Args:
|
|
track_times: List of (start_sec, end_sec_or_None).
|
|
total_duration: Total duration of the input file.
|
|
|
|
Returns:
|
|
List of (start_sec, end_sec) with all ends resolved.
|
|
|
|
Raises:
|
|
ValueError: If end time is not after start time.
|
|
"""
|
|
resolved = []
|
|
for idx, (start_sec, end_sec) in enumerate(track_times):
|
|
if end_sec is None:
|
|
if idx + 1 < len(track_times):
|
|
next_start = track_times[idx + 1][0]
|
|
end_sec = next_start
|
|
else:
|
|
end_sec = int(total_duration)
|
|
if end_sec <= start_sec:
|
|
raise ValueError(f"Track {idx+1}: end time ({end_sec}) is not after start ({start_sec})")
|
|
resolved.append((start_sec, end_sec))
|
|
return resolved
|