package modelimport ("errors""fmt""strconv""strings""time")type Kind struct {prefix stringname string}func (k Kind) String() string {return k.name}var (KindMediaFileArtwork = Kind{"mf", "media_file"}KindArtistArtwork = Kind{"ar", "artist"}KindAlbumArtwork = Kind{"al", "album"}KindPlaylistArtwork = Kind{"pl", "playlist"}KindDiscArtwork = Kind{"dc", "disc"}KindRadioArtwork = Kind{"ra", "radio"})var artworkKindMap = map[string]Kind{KindMediaFileArtwork.prefix: KindMediaFileArtwork,KindArtistArtwork.prefix: KindArtistArtwork,KindAlbumArtwork.prefix: KindAlbumArtwork,KindPlaylistArtwork.prefix: KindPlaylistArtwork,KindDiscArtwork.prefix: KindDiscArtwork,KindRadioArtwork.prefix: KindRadioArtwork,}type ArtworkID struct {Kind KindID stringLastUpdate time.Time}func (id ArtworkID) String() string {if id.ID == "" {return ""}s := fmt.Sprintf("%s-%s", id.Kind.prefix, id.ID)if lu := id.LastUpdate.Unix(); lu > 0 {return fmt.Sprintf("%s_%x", s, lu)}return s + "_0"}func NewArtworkID(kind Kind, id string, lastUpdate *time.Time) ArtworkID {artID := ArtworkID{kind, id, time.Time{}}if lastUpdate != nil {artID.LastUpdate = *lastUpdate}return artID}func ParseArtworkID(id string) (ArtworkID, error) {parts := strings.SplitN(id, "-", 2)if len(parts) != 2 {return ArtworkID{}, errors.New("invalid artwork id")}kind, ok := artworkKindMap[parts[0]]if !ok {return ArtworkID{}, errors.New("invalid artwork kind")}parsedID := ArtworkID{Kind: kind,ID: parts[1],}parts = strings.SplitN(parts[1], "_", 2)if len(parts) == 2 {if parts[1] != "0" {lastUpdate, err := strconv.ParseInt(parts[1], 16, 64)if err != nil {return ArtworkID{}, err}parsedID.LastUpdate = time.Unix(lastUpdate, 0)}parsedID.ID = parts[0]}return parsedID, nil}func MustParseArtworkID(id string) ArtworkID {artID, err := ParseArtworkID(id)if err != nil {panic(artID)}return artID}func DiscArtworkID(albumID string, discNumber int) string {return fmt.Sprintf("%s:%d", albumID, discNumber)}func ParseDiscArtworkID(id string) (albumID string, discNumber int, err error) {parts := strings.SplitN(id, ":", 2)if len(parts) != 2 || parts[1] == "" {return "", 0, errors.New("invalid disc artwork id")}num, err := strconv.Atoi(parts[1])if err != nil {return "", 0, fmt.Errorf("invalid disc number in artwork id: %w", err)}return parts[0], num, nil}func artworkIDFromAlbum(al Album) ArtworkID {return ArtworkID{Kind: KindAlbumArtwork,ID: al.ID,LastUpdate: al.UpdatedAt,}}func artworkIDFromMediaFile(mf MediaFile) ArtworkID {return ArtworkID{Kind: KindMediaFileArtwork,ID: mf.ID,LastUpdate: mf.UpdatedAt,}}func artworkIDFromPlaylist(pls Playlist) ArtworkID {return ArtworkID{Kind: KindPlaylistArtwork,ID: pls.ID,LastUpdate: pls.UpdatedAt,}}func artworkIDFromArtist(ar Artist) ArtworkID {return ArtworkID{Kind: KindArtistArtwork,ID: ar.ID,}}func artworkIDFromRadio(r Radio) ArtworkID {return ArtworkID{Kind: KindRadioArtwork,ID: r.ID,LastUpdate: r.UpdatedAt,}}