From e9b7aabc0afeb9926b57f006da71186cac333736 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Thu, 9 Nov 2023 17:31:02 +0100 Subject: [PATCH] Implemented scrobbler.log writer --- backends/scrobblerlog.go | 77 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/backends/scrobblerlog.go b/backends/scrobblerlog.go index 3724df6..c1c5585 100644 --- a/backends/scrobblerlog.go +++ b/backends/scrobblerlog.go @@ -60,16 +60,16 @@ func (b ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time) ([]Listen, return nil, err } - csvReader := csv.NewReader(reader) - csvReader.Comma = '\t' + tsvReader := csv.NewReader(reader) + tsvReader.Comma = '\t' // Row length is often flexible - csvReader.FieldsPerRecord = -1 + tsvReader.FieldsPerRecord = -1 listens := make([]Listen, 0) for { // A row is: // artistName releaseName trackName trackNumber duration rating timestamp recordingMbid - row, err := csvReader.Read() + row, err := tsvReader.Read() if err == io.EOF { break } else if err != nil { @@ -80,7 +80,7 @@ func (b ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time) ([]Listen, // We consider only the last field (recording MBID) optional if len(row) < 7 { - line, _ := csvReader.FieldPos(0) + line, _ := tsvReader.FieldPos(0) return nil, errors.New(fmt.Sprintf( "Invalid record in %s line %v", b.filePath, line)) } @@ -101,6 +101,56 @@ func (b ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time) ([]Listen, return listens, nil } +func (b ScrobblerLogBackend) ImportListens(listens []Listen, oldestTimestamp time.Time) (ImportResult, error) { + result := ImportResult{ + Count: 0, + LastTimestamp: oldestTimestamp, + } + + file, err := os.Create(b.filePath) + if err != nil { + return result, err + } + + defer file.Close() + + err = writeHeader(file) + if err != nil { + return result, err + } + + tsvWriter := csv.NewWriter(file) + tsvWriter.Comma = '\t' + + for _, listen := range listens { + result.Count += 1 + if listen.ListenedAt.Unix() > result.LastTimestamp.Unix() { + result.LastTimestamp = listen.ListenedAt + } + + // A row is: + // artistName releaseName trackName trackNumber duration rating timestamp recordingMbid + rating := listen.AdditionalInfo["rockbox_rating"] + if rating == "" { + rating = "L" + } + tsvWriter.Write([]string{ + listen.ArtistName(), + listen.ReleaseName, + listen.TrackName, + strconv.Itoa(listen.TrackNumber), + strconv.Itoa(int(listen.Duration.Seconds())), + rating, + strconv.Itoa(int(listen.ListenedAt.Unix())), + string(listen.RecordingMbid), + }) + } + + tsvWriter.Flush() + + return result, nil +} + func readHeader(reader *bufio.Reader) (client string, err error) { // Skip header for i := 0; i < 3; i++ { @@ -130,6 +180,21 @@ func readHeader(reader *bufio.Reader) (client string, err error) { return client, nil } +func writeHeader(writer io.Writer) error { + headers := []string{ + "#AUDIOSCROBBLER/1.1\n", + "#TZ/UNKNOWN\n", + "#CLIENT/Rockbox sansaclipplus $Revision$\n", + } + for _, line := range headers { + _, err := writer.Write([]byte(line)) + if err != nil { + return err + } + } + return nil +} + func rowToListen(row []string, client string) (Listen, error) { var listen Listen trackNumber, err := strconv.Atoi(row[3]) @@ -153,7 +218,7 @@ func rowToListen(row []string, client string) (Listen, error) { ReleaseName: row[1], TrackName: row[2], TrackNumber: trackNumber, - Duration: time.Duration(duration), + Duration: time.Duration(duration * int(time.Second)), AdditionalInfo: AdditionalInfo{ "rockbox_rating": row[5], "media_player": client,