/* Copyright © 2023 Philipp Wolfer This file is part of Scotty. Scotty is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Scotty is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Scotty. If not, see . */ package scrobblerlog import ( "bufio" "os" "sort" "time" "github.com/spf13/viper" "go.uploadedlobster.com/scotty/models" ) type ScrobblerLogBackend struct { filePath string includeSkipped bool append bool file *os.File log ScrobblerLog } func (b *ScrobblerLogBackend) Name() string { return "scrobbler-log" } func (b *ScrobblerLogBackend) FromConfig(config *viper.Viper) models.Backend { b.filePath = config.GetString("file-path") b.includeSkipped = config.GetBool("include-skipped") b.append = true if config.IsSet("append") { b.append = config.GetBool("append") } b.log = ScrobblerLog{ Timezone: "UNKNOWN", Client: "Rockbox unknown $Revision$", } return b } func (b *ScrobblerLogBackend) StartImport() error { flags := os.O_RDWR | os.O_CREATE if !b.append { flags |= os.O_TRUNC } file, err := os.OpenFile(b.filePath, flags, 0666) if err != nil { return err } if b.append { stat, err := file.Stat() if err != nil { file.Close() return err } if stat.Size() == 0 { // Zero length file, treat as a new file b.append = false } else { // Verify existing file is a scrobbler log reader := bufio.NewReader(file) err = ReadHeader(reader, &b.log) if err != nil { file.Close() return err } file.Seek(0, 2) } } if !b.append { err = WriteHeader(file, &b.log) if err != nil { file.Close() return err } } b.file = file return nil } func (b *ScrobblerLogBackend) FinishImport() error { return b.file.Close() } func (b *ScrobblerLogBackend) ExportListens(oldestTimestamp time.Time, results chan models.ListensResult, progress chan models.Progress) { defer close(results) file, err := os.Open(b.filePath) if err != nil { progress <- models.Progress{}.Complete() results <- models.ListensResult{Error: err} return } defer file.Close() log, err := Parse(file, b.includeSkipped) if err != nil { progress <- models.Progress{}.Complete() results <- models.ListensResult{Error: err} return } listens := log.Listens.NewerThan(oldestTimestamp) sort.Sort(listens) progress <- models.Progress{Elapsed: int64(len(listens))}.Complete() results <- models.ListensResult{Listens: listens} } func (b *ScrobblerLogBackend) ImportListens(export models.ListensResult, importResult models.ImportResult, progress chan models.Progress) (models.ImportResult, error) { lastTimestamp, err := Write(b.file, export.Listens) if err != nil { return importResult, err } importResult.UpdateTimestamp(lastTimestamp) importResult.ImportCount += len(export.Listens) progress <- models.Progress{}.FromImportResult(importResult) return importResult, nil }