diff --git a/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go b/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go index ea5586de..2315c429 100644 --- a/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go +++ b/backend/mediaprovider/jellyfin/jellyfinmediaprovider.go @@ -458,7 +458,7 @@ func fillAlbum(a *jellyfin.Album, album *mediaprovider.Album) { album.Duration = int(a.RunTimeTicks / runTimeTicksPerSecond) album.ArtistIDs = artistIDs album.ArtistNames = artistNames - album.Year = a.Year + album.Date.Year = &a.Year album.TrackCount = a.ChildCount album.Genres = a.Genres album.Favorite = a.UserData.IsFavorite diff --git a/backend/mediaprovider/mediaprovider.go b/backend/mediaprovider/mediaprovider.go index 9fb19517..a40db186 100644 --- a/backend/mediaprovider/mediaprovider.go +++ b/backend/mediaprovider/mediaprovider.go @@ -106,7 +106,7 @@ func (f albumFilter) Matches(album *Album) bool { if f.options.ExcludeUnfavorited && !album.Favorite { return false } - if y := album.Year; y < f.options.MinYear || (f.options.MaxYear > 0 && y > f.options.MaxYear) { + if y := album.YearOrZero(); y < f.options.MinYear || (f.options.MaxYear > 0 && y > f.options.MaxYear) { return false } if len(f.options.Genres) == 0 { diff --git a/backend/mediaprovider/model.go b/backend/mediaprovider/model.go index e83264ba..b2ec9d7e 100644 --- a/backend/mediaprovider/model.go +++ b/backend/mediaprovider/model.go @@ -32,6 +32,12 @@ const ( ReleaseTypeSpokenWord ReleaseType = 0x8000 ) +type ItemDate struct { + Year *int + Month *int + Day *int +} + type Album struct { ID string CoverArtID string @@ -39,14 +45,21 @@ type Album struct { Duration int ArtistIDs []string ArtistNames []string - Year int - ReissueYear int + Date ItemDate + ReissueDate ItemDate Genres []string TrackCount int Favorite bool ReleaseTypes ReleaseTypes } +func (a *Album) YearOrZero() int { + if a.Date.Year != nil { + return *a.Date.Year + } + return 0 +} + type AlbumWithTracks struct { Album Tracks []*Track diff --git a/backend/mediaprovider/subsonic/subsonicmediaprovider.go b/backend/mediaprovider/subsonic/subsonicmediaprovider.go index 9dc7df59..7c736615 100644 --- a/backend/mediaprovider/subsonic/subsonicmediaprovider.go +++ b/backend/mediaprovider/subsonic/subsonicmediaprovider.go @@ -581,14 +581,21 @@ func fillAlbum(subAlbum *subsonic.AlbumID3, album *mediaprovider.Album) { genres = append(genres, subAlbum.Genre) } - album.Year = subAlbum.Year - if subAlbum.OriginalReleaseDate != nil && - subAlbum.OriginalReleaseDate.Year != nil && - *subAlbum.OriginalReleaseDate.Year < subAlbum.Year { - album.Year = *subAlbum.OriginalReleaseDate.Year - } - if subAlbum.ReleaseDate != nil && subAlbum.ReleaseDate.Year != nil { - album.ReissueYear = *subAlbum.ReleaseDate.Year + if ord := subAlbum.OriginalReleaseDate; ord != nil && ord.Year != nil { + album.Date = mediaprovider.ItemDate{ + Year: ord.Year, + Month: ord.Month, + Day: ord.Date, + } + } else { + album.Date.Year = &subAlbum.Year + } + if rd := subAlbum.ReleaseDate; rd != nil && rd.Year != nil { + album.ReissueDate = mediaprovider.ItemDate{ + Year: rd.Year, + Month: rd.Month, + Day: rd.Date, + } } album.ID = subAlbum.ID diff --git a/ui/browsing/albumpage.go b/ui/browsing/albumpage.go index c8cd55e9..c2bb5534 100644 --- a/ui/browsing/albumpage.go +++ b/ui/browsing/albumpage.go @@ -3,7 +3,6 @@ package browsing import ( "fmt" "log" - "strconv" "github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend/mediaprovider" @@ -370,9 +369,9 @@ func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string { if a.TrackCount == 1 { tracks = lang.L("track") } - yearStr := strconv.Itoa(a.Year) - if a.ReissueYear > a.Year { - yearStr += fmt.Sprintf(" (%s %d)", lang.L("reissued"), a.ReissueYear) + yearStr := util.FormatItemDate(a.Date) + if y := a.ReissueDate.Year; y != nil && *y > a.YearOrZero() { + yearStr += fmt.Sprintf(" (%s %d)", lang.L("reissued"), util.FormatItemDate(a.ReissueDate)) } return fmt.Sprintf("%s · %d %s · %s%s", yearStr, a.TrackCount, tracks, discs, util.SecondsToTimeString(float64(a.Duration))) } diff --git a/ui/browsing/artistpage.go b/ui/browsing/artistpage.go index 42390d59..34d8c3b6 100644 --- a/ui/browsing/artistpage.go +++ b/ui/browsing/artistpage.go @@ -203,12 +203,12 @@ func (a *ArtistPage) getGridViewAlbumsModel() []widgets.GridViewItemModel { return nil } sortFunc := func(x, y int) bool { - return a.artistInfo.Albums[x].Year < a.artistInfo.Albums[y].Year + return a.artistInfo.Albums[x].YearOrZero() < a.artistInfo.Albums[y].YearOrZero() } switch a.cfg.DiscographySort { case discographySorts[1]: /*year descending*/ sortFunc = func(x, y int) bool { - return a.artistInfo.Albums[x].Year > a.artistInfo.Albums[y].Year + return a.artistInfo.Albums[x].YearOrZero() > a.artistInfo.Albums[y].YearOrZero() } case discographySorts[2]: /*name*/ sortFunc = func(x, y int) bool { @@ -222,7 +222,7 @@ func (a *ArtistPage) getGridViewAlbumsModel() []widgets.GridViewItemModel { Name: al.Name, ID: al.ID, CoverArtID: al.CoverArtID, - Secondary: []string{strconv.Itoa(al.Year)}, + Secondary: []string{strconv.Itoa(al.YearOrZero())}, } }) } diff --git a/ui/util/util.go b/ui/util/util.go index 8b2c964b..8bf0ad2c 100644 --- a/ui/util/util.go +++ b/ui/util/util.go @@ -25,6 +25,75 @@ import ( "golang.org/x/net/html" ) +type DateFormat int + +const ( + DateFormatDMY DateFormat = iota + DateFormatMDY + DateFormatYMD +) + +func dateFormatForLocale(locale string) DateFormat { + var region string + if i := strings.Index(locale, "-"); i > 0 { + region = locale[i+1:] + } + switch strings.ToUpper(region) { + case "US": + return DateFormatMDY + case "CN", "JP", "KR", "HU", "MN", "LT": + return DateFormatYMD + default: + return DateFormatDMY + } +} + +func shortMonthName(month int) string { + var months = [12]string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"} + if month >= 1 && month <= 12 { + return lang.L(months[month-1]) + } + return "" +} + +func FormatItemDate(date mediaprovider.ItemDate) string { + var sb strings.Builder + df := dateFormatForLocale(fyne.CurrentDevice().Locale().String()) + switch df { + case DateFormatDMY: + if d := date.Day; d != nil { + sb.WriteString(fmt.Sprintf("%d ", *d)) + } + if m := date.Month; m != nil { + sb.WriteString(shortMonthName(*m) + " ") + } + if y := date.Year; y != nil { + sb.WriteString(fmt.Sprintf("%d", *y)) + } + case DateFormatMDY: + if m := date.Month; m != nil { + sb.WriteString(shortMonthName(*m) + " ") + } + if d := date.Day; d != nil { + sb.WriteString(fmt.Sprintf("%d, ", *d)) + } + if y := date.Year; y != nil { + sb.WriteString(fmt.Sprintf("%d", *y)) + } + case DateFormatYMD: + if y := date.Year; y != nil { + sb.WriteString(fmt.Sprintf("%d ", *y)) + } + if m := date.Month; m != nil { + sb.WriteString(shortMonthName(*m) + " ") + } + if d := date.Day; d != nil { + sb.WriteString(fmt.Sprintf("%d", *d)) + } + } + return sb.String() +} + var BoldRichTextStyle = widget.RichTextStyle{TextStyle: fyne.TextStyle{Bold: true}, Inline: true} func MakeOpaque(c color.Color) color.Color { diff --git a/ui/widgets/gridview.go b/ui/widgets/gridview.go index f81a10da..a438ee60 100644 --- a/ui/widgets/gridview.go +++ b/ui/widgets/gridview.go @@ -61,8 +61,8 @@ func (g gridViewAlbumIterator) NextN(n int) []GridViewItemModel { Secondary: al.ArtistNames, SecondaryIDs: al.ArtistIDs, } - if al.Year > 0 { - model.Suffix = strconv.Itoa(al.Year) + if y := al.Date.Year; y != nil { + model.Suffix = strconv.Itoa(*al.Date.Year) } return model })