feat: name cut clips by wall-clock time; fix recording filename format
Cut downloads were named by byte offsets (`..._cut_740s-750s.flac`). They are now named by the actual recording time the slice covers, e.g. `20260523_22-31-30_22-32-30.flac` for a 22:31:30->22:32:30 cut of a recording started at 22:00:00. To make this reliable, the recording filename is now a fixed `%Y%m%d_%H%M%S` start-time format (`FILENAME_FORMAT`) shared by isr.py and web.py, replacing the user-configurable `filename_pattern` (web.py never reads config.ini, so a custom pattern could not be parsed back). web.py parses the start time out of the filename via `_recording_start()` and builds cut names with `_cut_filename()`. The DATE column now also comes from the filename (falling back to mtime only for non-standard names), since mtime is the last write, not the start. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,13 @@ except ImportError:
|
||||
SOUNDFILE_AVAILABLE = False
|
||||
|
||||
|
||||
# Fixed recording-filename timestamp format. This is the recording's *start*
|
||||
# time and is the single source of truth for the clock: web.py parses it back
|
||||
# out to derive the displayed date and to name cut clips with real wall-clock
|
||||
# times. It is intentionally not configurable — both files must agree on it.
|
||||
FILENAME_FORMAT = '%Y%m%d_%H%M%S'
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Audio Device & Backend System
|
||||
# =============================================================================
|
||||
@@ -329,7 +336,6 @@ class BaseRecorder(ABC):
|
||||
# Common settings
|
||||
self.split_duration = config.get('split_minutes', 60)
|
||||
self.output_dir = config.get('output_directory', 'recordings')
|
||||
self.filename_pattern = config.get('filename_pattern', '%Y%m%d_%H%M%S')
|
||||
self.max_retries = config.get('max_retries', 10)
|
||||
self.retry_delay = config.get('retry_delay_seconds', 5)
|
||||
self.file_format = config.get('format', 'auto')
|
||||
@@ -343,9 +349,9 @@ class BaseRecorder(ABC):
|
||||
return next_split.replace(second=0, microsecond=0)
|
||||
|
||||
def generate_filename(self, ext: str) -> str:
|
||||
"""Generate filename from pattern with strftime substitution."""
|
||||
"""Generate filename from the fixed start-time format (see FILENAME_FORMAT)."""
|
||||
now = self._clock()
|
||||
filename = now.strftime(self.filename_pattern) + f".{ext}"
|
||||
filename = now.strftime(FILENAME_FORMAT) + f".{ext}"
|
||||
full_path = os.path.join(self.output_dir, filename)
|
||||
Path(full_path).parent.mkdir(parents=True, exist_ok=True)
|
||||
return full_path
|
||||
@@ -806,7 +812,6 @@ class RecorderManager:
|
||||
general = {
|
||||
'output_directory': config.get('general', 'output_directory', fallback='recordings'),
|
||||
'split_minutes': config.getint('general', 'split_minutes', fallback=60),
|
||||
'filename_pattern': config.get('general', 'filename_pattern', fallback='%Y%m%d_%H%M%S', raw=True),
|
||||
'max_retries': config.getint('general', 'max_retries', fallback=10),
|
||||
'retry_delay_seconds': config.getint('general', 'retry_delay_seconds', fallback=5),
|
||||
'log_level': config.get('general', 'log_level', fallback='INFO').upper(),
|
||||
|
||||
Reference in New Issue
Block a user