more work on utils/ with glm
Dependencies
- [2]
LQLC7S3Atrying gemini: Inconsistent Standards in @utils/ refactoring - [3]
KZKLAINJrun out of space on nest, cleaned out - [4]
P6HBSK3Wme - [5]
LBWQJEDHminor refactor and more tests for utils/
Change contents
- replacement in utils/filename_parser.go at line 44
// ParseFilenameTimestamps parses timestamps from a batch of filenames.// ParseFilenameTimestamps extracts timestamps from a batch of filenames using variance-based format detection. - edit in utils/filename_parser.go at line 47
// ParseFilenameTimestamps extracts timestamps from filenames using variance-based format detection - replacement in utils/filename_parser.go at line 75
// ApplyTimezoneOffset applies a fixed timezone offset to timestamps// Uses the EARLIEST (chronologically) timestamp to determine the offset, then applies it to all// This matches AudioMoth behavior (no DST adjustment during deployment)// ApplyTimezoneOffset converts local timestamps to location timezone with DST handling// ApplyTimezoneOffset converts local timestamps to a location timezone with DST handling.// Uses the EARLIEST (chronologically) timestamp to determine the offset, then applies it to all.// This matches AudioMoth behavior (no DST adjustment during deployment). - replacement in utils/filename_parser.go at line 258
// HasTimestampFilename checks if a filename matches the timestamp pattern// HasTimestampFilename checks if filename contains a timestamp pattern// HasTimestampFilename checks if a filename contains a timestamp pattern - edit in utils/file_import.go at line 10
// FileImportError records errors encountered during file processingtype FileImportError struct {FileName string `json:"file_name"`Error string `json:"error"`Stage string `json:"stage"` // "scan", "hash", "parse", "validate", "insert"} - replacement in utils/data_file.go at line 319
func ParseSpeciesCallType(s string) (species, callType string) {if s == "" {func ParseSpeciesCallType(label string) (species, callType string) {if label == "" { - replacement in utils/data_file.go at line 323
if before, after, ok := strings.Cut(s, "+"); ok {if before, after, ok := strings.Cut(label, "+"); ok { - replacement in utils/data_file.go at line 326
return s, ""return label, "" - edit in utils/cluster_import.go at line 14
// FileImportError records errors encountered during file processingtype FileImportError struct {FileName string `json:"file_name"`Error string `json:"error"`Stage string `json:"stage"` // "scan", "hash", "parse", "validate", "insert"} - replacement in utils/cluster_import.go at line 379
"SELECT EXISTS(SELECT 1 FROM file WHERE xxh64_hash = ?)","SELECT EXISTS(SELECT 1 FROM file WHERE xxh64_hash = ? AND active = true)", - replacement in utils/audiomoth_parser.go at line 36
// IsAudioMoth checks if the comment or artist field indicates an AudioMoth recording// IsAudioMoth detects if WAV file is from AudioMoth recorder// IsAudioMoth detects if a WAV file is from an AudioMoth recorder by checking comment and artist fields - replacement in utils/audiomoth_parser.go at line 41
// ParseAudioMothComment parses structured AudioMoth comment field// Returns parsed data or error if parsing fails// ParseAudioMothComment extracts timestamp, gain, battery, and temperature from AudioMoth comment// ParseAudioMothComment extracts timestamp, gain, battery, and temperature from an AudioMoth comment. - replacement in utils/audiomoth_parser.go at line 101
// parseLegacyComment parses older AudioMoth comment format (space-separated)// parseLegacyComment parses older AudioMoth comment format (space-separated). - replacement in utils/audio_player.go at line 84
// Close stops playback and releases the oto context.func (ap *AudioPlayer) Close() {ap.Stop()}[3.216198]// Close stops playback. The oto context is released by the garbage collector// (oto v3 does not expose a context close method). - edit in me.txt at line 561
Here is a brief report based on a comprehensive review of the utils directory.### 1. Duplicated Functionality- Audio Processing (Float64 to 16-bit PCM): wav_writer.go and audio_player.go contain identical,duplicated logic for converting float64 arrays into int16 LittleEndian bytes (including the [-1.0,1.0] bounds clamping and * 32767 scaling).- Timestamp Resolution Strategy: cluster_import.go (batchProcessFiles) manually reimplements theentire fallback chain for timestamp resolution (AudioMoth → Filename → File Modification Time). Thisexact logic is already neatly abstracted in file_import.go as ResolveTimestamp().- Directory Scanning: cluster_import.go implements its own scanClusterFiles to find .wav files, whiledata_file.go implements FindDataFiles to find .data files. These could be consolidated into ageneric, reusable directory walker. - edit in me.txt at line 562
### 2. Untested Code - edit in me.txt at line 563
Overall statement coverage for utils is at 46.5%. The following areas are completely untested (0%coverage):- Files with 0% coverage:- audio_player.go (Audio playback and context management)- config.go (JSON config file loading/parsing)- cluster_import.go (The core batch import logic and database transactions)- spectrogram.go (FFT operations, windowing, and image rendering)- wav_writer.go (WAV encoding logic)- Untested Critical Functions in otherwise tested files:- file_import.go: ProcessSingleFile, CheckDuplicateHash- mapping.go: ValidateMappingAgainstDB, Classify, ValidateCoversSpecies, Classes, Placeholders- validation.go: GetDatasetType, ValidateDatasetTypeForImport, ValidateDatasetTypeUnstructured,ValidateLocationBelongsToDataset