Initial commit. Basic featues are implemented
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user