mirror of
https://git.sr.ht/~phw/scotty
synced 2025-04-30 05:37:05 +02:00
scrobblerlog: Use specific Record type
This makes the interface more generic and easier to reuse in other projects.
This commit is contained in:
parent
aeb3a56982
commit
aad542850a
3 changed files with 132 additions and 76 deletions
|
@ -37,7 +37,6 @@ import (
|
|||
"time"
|
||||
|
||||
"go.uploadedlobster.com/mbtypes"
|
||||
"go.uploadedlobster.com/scotty/internal/models"
|
||||
)
|
||||
|
||||
// TZInfo is the timezone information in the header of the scrobbler log file.
|
||||
|
@ -50,16 +49,36 @@ const (
|
|||
TZ_UTC TZInfo = "UTC"
|
||||
)
|
||||
|
||||
// L if listened at least 50% or S if skipped
|
||||
type Rating string
|
||||
|
||||
const (
|
||||
RATING_LISTENED Rating = "L"
|
||||
RATING_SKIPPED Rating = "S"
|
||||
)
|
||||
|
||||
// A single entry of a track in the scrobbler log file.
|
||||
type Record struct {
|
||||
ArtistName string
|
||||
AlbumName string
|
||||
TrackName string
|
||||
TrackNumber int
|
||||
Duration time.Duration
|
||||
Rating Rating
|
||||
Timestamp time.Time
|
||||
MusicBrainzRecordingID mbtypes.MBID
|
||||
}
|
||||
|
||||
// Represents a scrobbler log file.
|
||||
type ScrobblerLog struct {
|
||||
TZ TZInfo
|
||||
Client string
|
||||
Listens models.ListensList
|
||||
Records []Record
|
||||
location *time.Location
|
||||
}
|
||||
|
||||
func (l *ScrobblerLog) Parse(data io.Reader, includeSkipped bool) error {
|
||||
l.Listens = make(models.ListensList, 0)
|
||||
l.Records = make([]Record, 0)
|
||||
|
||||
reader := bufio.NewReader(data)
|
||||
err := l.ReadHeader(reader)
|
||||
|
@ -95,41 +114,37 @@ func (l *ScrobblerLog) Parse(data io.Reader, includeSkipped bool) error {
|
|||
continue
|
||||
}
|
||||
|
||||
listen, err := l.rowToListen(row)
|
||||
record, err := l.rowToRecord(row)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.Listens = append(l.Listens, listen)
|
||||
l.Records = append(l.Records, record)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *ScrobblerLog) Append(data io.Writer, listens models.ListensList) (lastTimestamp time.Time, err error) {
|
||||
func (l *ScrobblerLog) Append(data io.Writer, records []Record) (lastTimestamp time.Time, err error) {
|
||||
tsvWriter := csv.NewWriter(data)
|
||||
tsvWriter.Comma = '\t'
|
||||
|
||||
for _, listen := range listens {
|
||||
if listen.ListenedAt.Unix() > lastTimestamp.Unix() {
|
||||
lastTimestamp = listen.ListenedAt
|
||||
for _, record := range records {
|
||||
if record.Timestamp.After(lastTimestamp) {
|
||||
lastTimestamp = record.Timestamp
|
||||
}
|
||||
|
||||
// A row is:
|
||||
// artistName releaseName trackName trackNumber duration rating timestamp recordingMBID
|
||||
rating, ok := listen.AdditionalInfo["rockbox_rating"].(string)
|
||||
if !ok || rating == "" {
|
||||
rating = "L"
|
||||
}
|
||||
err = 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),
|
||||
record.ArtistName,
|
||||
record.AlbumName,
|
||||
record.TrackName,
|
||||
strconv.Itoa(record.TrackNumber),
|
||||
strconv.Itoa(int(record.Duration.Seconds())),
|
||||
string(record.Rating),
|
||||
strconv.FormatInt(record.Timestamp.Unix(), 10),
|
||||
string(record.MusicBrainzRecordingID),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -191,44 +206,38 @@ func (l *ScrobblerLog) WriteHeader(writer io.Writer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (l ScrobblerLog) rowToListen(row []string) (models.Listen, error) {
|
||||
var listen models.Listen
|
||||
func (l ScrobblerLog) rowToRecord(row []string) (Record, error) {
|
||||
var record Record
|
||||
trackNumber, err := strconv.Atoi(row[3])
|
||||
if err != nil {
|
||||
return listen, err
|
||||
return record, err
|
||||
}
|
||||
|
||||
duration, err := strconv.Atoi(row[4])
|
||||
if err != nil {
|
||||
return listen, err
|
||||
return record, err
|
||||
}
|
||||
|
||||
timestamp, err := strconv.ParseInt(row[6], 10, 64)
|
||||
if err != nil {
|
||||
return listen, err
|
||||
return record, err
|
||||
}
|
||||
|
||||
client := strings.Split(l.Client, " ")[0]
|
||||
listen = models.Listen{
|
||||
Track: models.Track{
|
||||
ArtistNames: []string{row[0]},
|
||||
ReleaseName: row[1],
|
||||
TrackName: row[2],
|
||||
TrackNumber: trackNumber,
|
||||
Duration: time.Duration(duration * int(time.Second)),
|
||||
AdditionalInfo: models.AdditionalInfo{
|
||||
"rockbox_rating": row[5],
|
||||
"media_player": client,
|
||||
},
|
||||
},
|
||||
ListenedAt: timeFromLocalTimestamp(timestamp, l.location),
|
||||
record = Record{
|
||||
ArtistName: row[0],
|
||||
AlbumName: row[1],
|
||||
TrackName: row[2],
|
||||
TrackNumber: trackNumber,
|
||||
Duration: time.Duration(duration) * time.Second,
|
||||
Rating: Rating(row[5]),
|
||||
Timestamp: timeFromLocalTimestamp(timestamp, l.location),
|
||||
}
|
||||
|
||||
if len(row) > 7 {
|
||||
listen.Track.RecordingMBID = mbtypes.MBID(row[7])
|
||||
record.MusicBrainzRecordingID = mbtypes.MBID(row[7])
|
||||
}
|
||||
|
||||
return listen, nil
|
||||
return record, nil
|
||||
}
|
||||
|
||||
// Convert the timezone string from the header to a time.Location.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue