mirror of
https://git.sr.ht/~phw/scotty
synced 2025-04-18 19:19:28 +02:00
Rockbox scrobbler.log listen reader
This commit is contained in:
parent
8661075975
commit
0b3b3b768d
1 changed files with 128 additions and 1 deletions
|
@ -22,6 +22,14 @@ THE SOFTWARE.
|
||||||
package backends
|
package backends
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/csv"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -39,5 +47,124 @@ func (b ScrobblerLogBackend) FromConfig(config *viper.Viper) Backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time) ([]Listen, error) {
|
func (b ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time) ([]Listen, error) {
|
||||||
return nil, nil
|
file, err := os.Open(b.filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
reader := bufio.NewReader(file)
|
||||||
|
client, err := readHeader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
csvReader := csv.NewReader(reader)
|
||||||
|
csvReader.Comma = '\t'
|
||||||
|
// Row length is often flexible
|
||||||
|
csvReader.FieldsPerRecord = -1
|
||||||
|
|
||||||
|
listens := make([]Listen, 0)
|
||||||
|
for {
|
||||||
|
// A row is:
|
||||||
|
// artistName releaseName trackName trackNumber duration rating timestamp recordingMbid
|
||||||
|
row, err := csvReader.Read()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("row: %v\n", row)
|
||||||
|
|
||||||
|
// We consider only the last field (recording MBID) optional
|
||||||
|
if len(row) < 7 {
|
||||||
|
line, _ := csvReader.FieldPos(0)
|
||||||
|
return nil, errors.New(fmt.Sprintf(
|
||||||
|
"Invalid record in %s line %v", b.filePath, line))
|
||||||
|
}
|
||||||
|
|
||||||
|
rating := row[5]
|
||||||
|
if !b.includeSkipped && rating == "S" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
listen, err := rowToListen(row, client)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
listens = append(listens, listen)
|
||||||
|
}
|
||||||
|
|
||||||
|
return listens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readHeader(reader *bufio.Reader) (client string, err error) {
|
||||||
|
// Skip header
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
line, _, err := reader.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
return client, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(line) == 0 || line[0] != '#' {
|
||||||
|
err = errors.New(fmt.Sprintf("Unexpected header (line %v)", i))
|
||||||
|
} else {
|
||||||
|
text := string(line)
|
||||||
|
if i == 0 && !strings.HasPrefix(text, "#AUDIOSCROBBLER/1") {
|
||||||
|
err = errors.New(fmt.Sprintf("Not a scrobbler log file"))
|
||||||
|
}
|
||||||
|
|
||||||
|
after, found := strings.CutPrefix(text, "#CLIENT/")
|
||||||
|
if found {
|
||||||
|
client = strings.Split(after, " ")[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return client, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func rowToListen(row []string, client string) (Listen, error) {
|
||||||
|
var listen Listen
|
||||||
|
trackNumber, err := strconv.Atoi(row[3])
|
||||||
|
if err != nil {
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
|
|
||||||
|
duration, err := strconv.Atoi(row[4])
|
||||||
|
if err != nil {
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp, err := strconv.Atoi(row[6])
|
||||||
|
if err != nil {
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
|
|
||||||
|
listen = Listen{
|
||||||
|
Track: Track{
|
||||||
|
ArtistNames: []string{row[0]},
|
||||||
|
ReleaseName: row[1],
|
||||||
|
TrackName: row[2],
|
||||||
|
TrackNumber: trackNumber,
|
||||||
|
Duration: time.Duration(duration),
|
||||||
|
AdditionalInfo: AdditionalInfo{
|
||||||
|
"rockbox_rating": row[5],
|
||||||
|
"media_player": client,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ListenedAt: time.Unix(int64(timestamp), 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(row) > 7 {
|
||||||
|
listen.Track.RecordingMbid = MBID(row[7])
|
||||||
|
}
|
||||||
|
|
||||||
|
return listen, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue