Resumable Analysis
When you analyze a directory of audio files, BirdNET-Analyzer keeps a crash-safe journal of its progress. If the run is interrupted (by a crash, a power loss, a closed window, or the Pause button in the GUI), you can continue it later instead of starting over: files that were already analyzed are skipped, and their stored detections are combined with the fresh results as if the run had never stopped.
How to resume a run
Progress is stored in a hidden .birdnet-resume folder inside the output
directory (or inside the input directory, if no separate output directory was
chosen). To continue an interrupted run, simply start the same analysis again:
CLI: re-run the same
birdnet_analyzer.analyzecommand with the same arguments and output folder.GUI: in the batch analysis tab, select the same input and output folders. A status line shows how many files were already completed and the start button changes to Continue analysis.
Files that were already analyzed are skipped, the remaining files are processed, and the output files are written for the complete set. After a successful run the journal folder is deleted, so a finished analysis leaves nothing behind.
Which settings have to match
The journal records a fingerprint of every setting that affects which detections are produced: the input directory, the model and its version, a custom classifier, minimum confidence, top-N, sensitivity, overlap, the bandpass frequencies, audio speed, latitude/longitude/week, a custom species list, the species filter threshold, and the species-name language.
A run only continues if all of these match the interrupted run. If any of them changed, the stored progress is discarded and the analysis starts from the beginning — results produced with different settings are never mixed.
Attention
The GUI does not restore the settings of the interrupted run when you click
Continue analysis — it uses whatever is currently set in the interface. If
you changed one of the settings listed above in the meantime, the saved progress
is discarded and the analysis silently starts over. Loading the *-params.csv
file written next to the results restores the original settings.
Settings that only affect how results are formatted may change freely between the interrupted run and its resume: the output formats, additional columns, table splitting, merging of consecutive detections, batch size, and the number of workers and producers. The journal stores raw detections, so the outputs are always written with the settings of the resuming run.
Changed and added files
Each stored result is keyed on the input file’s path and its size and modification time. A file that changed on disk since it was first analyzed — edited, regenerated, or merely touched — is re-analyzed instead of reusing the stale result. Files added to the input directory are picked up and analyzed; stored results for files that no longer exist are ignored.
How it works internally
The implementation lives in birdnet_analyzer/analyze/resume.py. The journal
directory contains:
manifest.json— the parameter fingerprint (a hash over the detection-relevant settings), a human-readable snapshot of those settings, the total file count, and the model metadata needed to write outputs when a resume finds no work left.results/<key>.parquet— one file per completed input file, holding that file’s detections.<key>hashes the input path plus its size and modification time. Files the inference library reported as unprocessable are stored with an.invalid.parquetsuffix so a resume does not retry them.
While an analysis runs, the birdnet library invokes an on_file_complete
callback after each finished file, off the inference hot path. The callback writes
the file’s detections to a temporary name and moves it into place atomically, so a
result file’s presence is the “this file is done” marker — a crash can never leave
a half-written result that a resume would trust. The callback never raises: a
persistence problem (a full disk, say) costs the resumability of that one file, not
the running analysis.
On the next run, analyze() opens the journal before inference starts. A journal
whose fingerprint does not match the current settings is wiped and replaced. With a
matching fingerprint, the completed files are removed from the inference input, the
remaining files are analyzed (journaled the same way), and the stored detections are
merged with the fresh ones in input order — so outputs that accumulate offsets
across files, like the combined Raven table, come out exactly as they would from an
uninterrupted run. If every file was already completed, no inference happens at all
and the outputs are rebuilt from the journal alone, using the model metadata saved
in the manifest. Once the outputs are written, the journal is deleted.
The GUI builds on the same mechanism: Pause cancels the running inference
session while leaving the journal in place, and selecting the input/output folders
calls ResumeJournal.inspect() to display the paused progress and relabel the
start button.