GoScrobble/internal/goscrobble/ingress_jellyfin.go
2022-01-31 17:33:08 +13:00

111 lines
3.8 KiB
Go

package goscrobble
import (
"database/sql"
"errors"
"fmt"
"log"
"net"
"time"
)
type JellyfinRequest struct {
Album string `json:"Album"`
Artist string `json:"Artist"`
ClientName string `json:"ClientName"`
DeviceID string `json:"DeviceId"`
DeviceName string `json:"DeviceName"`
IsAutomated bool `json:"IsAutomated"`
IsPaused bool `json:"IsPaused"`
ItemID string `json:"ItemId"`
ItemType string `json:"ItemType"`
MediaSourceID string `json:"MediaSourceId"`
Name string `json:"Name"`
NotificationType string `json:"NotificationType"`
Overview string `json:"Overview"`
PlaybackPosition string `json:"PlaybackPosition"`
PlaybackPositionTicks int64 `json:"PlaybackPositionTicks"`
ProviderMusicbrainzalbum string `json:"Provider_musicbrainzalbum"`
ProviderMusicbrainzalbumartist string `json:"Provider_musicbrainzalbumartist"`
ProviderMusicbrainzartist string `json:"Provider_musicbrainzartist"`
ProviderMusicbrainzreleasegroup string `json:"Provider_musicbrainzreleasegroup"`
ProviderMusicbrainztrack string `json:"Provider_musicbrainztrack"`
RunTime string `json:"RunTime"`
RunTimeTicks int64 `json:"RunTimeTicks"`
ServerID string `json:"ServerId"`
ServerName string `json:"ServerName"`
ServerURL string `json:"ServerUrl"`
ServerVersion string `json:"ServerVersion"`
Timestamp string `json:"Timestamp"`
UserID string `json:"UserId"`
Username string `json:"Username"`
UtcTimestamp string `json:"UtcTimestamp"`
Year int64 `json:"Year"`
}
// ParseJellyfinInput - Transform API data into a common struct. Uses MusicBrainzID primarily
func ParseJellyfinInput(userUUID string, jf JellyfinRequest, ip net.IP, tx *sql.Tx) error {
// Debugging
// fmt.Printf("%+v", jf)
// Custom cache key - never log the same song twice in a row for now... (:
lastPlayedTitle := getUserLastPlayed(userUUID + fmt.Sprintf(":%s", jf.DeviceID))
if lastPlayedTitle == jf.Name+":"+jf.Album {
// If it matches last played song, skip it
return nil
}
if jf.ItemType != "Audio" {
return errors.New("Media type not audio")
}
// Safety Checks
if jf.Artist == "" {
return errors.New("Missing artist data")
}
if jf.Album == "" {
return errors.New("Missing album data")
}
if jf.Name == "" {
return errors.New("Missing track data")
}
// Insert artist if not exist
artist, err := insertArtist(jf.Artist, jf.ProviderMusicbrainzartist, "", "", tx)
if err != nil {
log.Printf("%+v", err)
return errors.New("Failed to map artist")
}
// Insert album if not exist
artists := []string{artist.UUID}
album, err := insertAlbum(jf.Album, jf.ProviderMusicbrainzalbum, "", artists, "", tx)
if err != nil {
log.Printf("%+v", err)
return errors.New("Failed to map album")
}
// Insert track if not exist
length := timestampToSeconds(jf.RunTime)
track, err := insertTrack(jf.Name, length, jf.ProviderMusicbrainztrack, "", album.UUID, artists, tx)
if err != nil {
log.Printf("%+v", err)
return errors.New("Failed to map track")
}
// Insert scrobble if not exist
timestamp := time.Now()
err = insertScrobble(userUUID, track.UUID, "jellyfin", timestamp, ip, tx)
if err != nil {
log.Printf("%+v", err)
return errors.New("Failed to map track")
}
// Add cache key!
setUserLastPlayed(userUUID+fmt.Sprintf(":%s", jf.DeviceID), jf.Name+":"+jf.Album)
return nil
}