From 0231331209e6a79416ce87dce99a0d56f3503c48 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Sat, 24 May 2025 01:23:12 +0200 Subject: [PATCH] Implemented listenrbainz.ExportArchive.IterFeedback --- internal/listenbrainz/archive.go | 55 +++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/internal/listenbrainz/archive.go b/internal/listenbrainz/archive.go index 1d3efa3..eb7677c 100644 --- a/internal/listenbrainz/archive.go +++ b/internal/listenbrainz/archive.go @@ -23,6 +23,7 @@ package listenbrainz import ( "encoding/json" + "errors" "io" "iter" "regexp" @@ -54,6 +55,9 @@ func OpenExportArchive(path string) (*ExportArchive, error) { // Close the archive and release any resources. func (a *ExportArchive) Close() error { + if a.backend == nil { + return nil + } return a.backend.Close() } @@ -126,8 +130,8 @@ func (a *ExportArchive) IterListens(minTimestamp time.Time) iter.Seq2[Listen, er continue } - f := NewExportFile(file.f) - for l, err := range f.IterListens() { + f := JSONLFile[Listen]{file: file.f} + for l, err := range f.IterItems() { if err != nil { yield(Listen{}, err) return @@ -144,6 +148,36 @@ func (a *ExportArchive) IterListens(minTimestamp time.Time) iter.Seq2[Listen, er } } +// Yields all feedbacks from the archive that are newer than the given timestamp. +// The feedbacks are yielded in ascending order of their Created timestamp. +func (a *ExportArchive) IterFeedback(minTimestamp time.Time) iter.Seq2[Feedback, error] { + return func(yield func(Feedback, error) bool) { + files, err := a.backend.Glob("feedback.jsonl") + if err != nil { + yield(Feedback{}, err) + return + } else if len(files) == 0 { + yield(Feedback{}, errors.New("no feedback.jsonl file found in archive")) + return + } + + j := JSONLFile[Feedback]{file: files[0].File} + for l, err := range j.IterItems() { + if err != nil { + yield(Feedback{}, err) + return + } + + if !time.Unix(l.Created, 0).After(minTimestamp) { + continue + } + if !yield(l, nil) { + break + } + } + } +} + type UserInfo struct { ID string `json:"user_id"` Name string `json:"username"` @@ -160,15 +194,11 @@ type ListenExportFileInfo struct { f archive.OpenableFile } -type ListenExportFile struct { +type JSONLFile[T any] struct { file archive.OpenableFile } -func NewExportFile(f archive.OpenableFile) ListenExportFile { - return ListenExportFile{file: f} -} - -func (f *ListenExportFile) openReader() (*jsonl.Reader, error) { +func (f *JSONLFile[T]) openReader() (*jsonl.Reader, error) { fio, err := f.file.Open() if err != nil { return nil, err @@ -177,17 +207,18 @@ func (f *ListenExportFile) openReader() (*jsonl.Reader, error) { return &reader, nil } -func (f *ListenExportFile) IterListens() iter.Seq2[Listen, error] { - return func(yield func(Listen, error) bool) { +func (f *JSONLFile[T]) IterItems() iter.Seq2[T, error] { + return func(yield func(T, error) bool) { reader, err := f.openReader() if err != nil { - yield(Listen{}, err) + var listen T + yield(listen, err) return } defer reader.Close() for { - listen := Listen{} + var listen T err := reader.ReadSingleLine(&listen) if err != nil { break