diff --git a/conf/configuration.go b/conf/configuration.go index 1d51f8f4..a1f9afe1 100644 --- a/conf/configuration.go +++ b/conf/configuration.go @@ -31,17 +31,18 @@ type configOptions struct { ImageCacheSize string AutoImportPlaylists bool - SearchFullString bool - IgnoredArticles string - IndexGroups string - ProbeCommand string - CoverArtPriority string - CoverJpegQuality int - UIWelcomeMessage string - EnableGravatar bool - GATrackingID string - AuthRequestLimit int - AuthWindowLength time.Duration + SearchFullString bool + RecentlyAddedByModTime bool + IgnoredArticles string + IndexGroups string + ProbeCommand string + CoverArtPriority string + CoverJpegQuality int + UIWelcomeMessage string + EnableGravatar bool + GATrackingID string + AuthRequestLimit int + AuthWindowLength time.Duration Scanner scannerOptions @@ -134,6 +135,7 @@ func init() { // Config options only valid for file/env configuration viper.SetDefault("searchfullstring", false) + viper.SetDefault("recentlyaddedbymodtime", false) viper.SetDefault("ignoredarticles", "The El La Los Las Le Les Os As O A") viper.SetDefault("indexgroups", "A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) [Unknown]([)") viper.SetDefault("probecommand", "ffmpeg %s -f ffmetadata") diff --git a/model/mediafile.go b/model/mediafile.go index f54a778e..859fe226 100644 --- a/model/mediafile.go +++ b/model/mediafile.go @@ -46,8 +46,8 @@ type MediaFile struct { MbzAlbumArtistID string `json:"mbzAlbumArtistId" orm:"column(mbz_album_artist_id)"` MbzAlbumType string `json:"mbzAlbumType"` MbzAlbumComment string `json:"mbzAlbumComment"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + CreatedAt time.Time `json:"createdAt"` // Time this entry was created in the DB + UpdatedAt time.Time `json:"updatedAt"` // Time of file last update (mtime) } func (mf *MediaFile) ContentType() string { diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 66ec4b67..edca7780 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -31,10 +31,11 @@ func NewAlbumRepository(ctx context.Context, o orm.Ormer) model.AlbumRepository r.ormer = o r.tableName = "album" r.sortMappings = map[string]string{ - "name": "order_album_name asc, order_album_artist_name asc", - "artist": "compilation asc, order_album_artist_name asc, order_album_name asc", - "random": "RANDOM()", - "max_year": "max_year asc, name, order_album_name asc", + "name": "order_album_name asc, order_album_artist_name asc", + "artist": "compilation asc, order_album_artist_name asc, order_album_name asc", + "random": "RANDOM()", + "max_year": "max_year asc, name, order_album_name asc", + "recently_added": recentlyAddedSort(), } r.filterMappings = map[string]filterFunc{ "name": fullTextFilter, @@ -48,6 +49,13 @@ func NewAlbumRepository(ctx context.Context, o orm.Ormer) model.AlbumRepository return r } +func recentlyAddedSort() string { + if conf.Server.RecentlyAddedByModTime { + return "updated_at" + } + return "created_at" +} + func recentlyPlayedFilter(field string, value interface{}) Sqlizer { return Gt{"play_count": 0} } @@ -153,20 +161,27 @@ func (r *albumRepository) refresh(ids ...string) error { DiscSubtitles string Comments string Path string + MaxUpdatedAt string + MaxCreatedAt string } var albums []refreshAlbum const zwsp = string('\u200b') sel := Select(`f.album_id as id, f.album as name, f.artist, f.album_artist, f.artist_id, f.album_artist_id, - f.sort_album_name, f.sort_artist_name, f.sort_album_artist_name, - f.order_album_name, f.order_album_artist_name, f.path, group_concat(f.comment, "` + zwsp + `") as comments, - group_concat(f.mbz_album_id, ' ') as mbz_album_id, f.mbz_album_artist_id, f.mbz_album_type, f.mbz_album_comment, - f.catalog_num, f.compilation, f.genre, max(f.year) as max_year, sum(f.duration) as duration, - count(f.id) as song_count, a.id as current_id, + f.sort_album_name, f.sort_artist_name, f.sort_album_artist_name, f.order_album_name, f.order_album_artist_name, + f.path, f.mbz_album_artist_id, f.mbz_album_type, f.mbz_album_comment, f.catalog_num, f.compilation, f.genre, + count(f.id) as song_count, + sum(f.duration) as duration, + sum(f.size) as size, + max(f.year) as max_year, + max(f.updated_at) as max_updated_at, + max(f.created_at) as max_created_at, + a.id as current_id, + group_concat(f.comment, "` + zwsp + `") as comments, + group_concat(f.mbz_album_id, ' ') as mbz_album_id, group_concat(f.disc_subtitle, ' ') as disc_subtitles, group_concat(f.artist, ' ') as song_artists, group_concat(f.artist_id, ' ') as song_artist_ids, - group_concat(f.year, ' ') as years, - sum(f.size) as size`). + group_concat(f.year, ' ') as years`). From("media_file f"). LeftJoin("album a on f.album_id = a.id"). Where(Eq{"f.album_id": ids}).GroupBy("f.album_id") @@ -202,6 +217,14 @@ func (r *albumRepository) refresh(ids ...string) error { log.Trace(r.ctx, "Could not find album art", "id", al.ID, "name", al.Name) } + // Somehow, beego cannot parse the datetimes for the query above + if al.UpdatedAt, err = time.Parse(time.RFC3339Nano, al.MaxUpdatedAt); err != nil { + al.UpdatedAt = time.Now() + } + if al.CreatedAt, err = time.Parse(time.RFC3339Nano, al.MaxCreatedAt); err != nil { + al.CreatedAt = al.UpdatedAt + } + if al.Compilation { al.AlbumArtist = consts.VariousArtists al.AlbumArtistID = consts.VariousArtistsID @@ -213,12 +236,10 @@ func (r *albumRepository) refresh(ids ...string) error { al.MinYear = getMinYear(al.Years) al.MbzAlbumID = getMbzId(r.ctx, al.MbzAlbumID, r.tableName, al.Name) al.Comment = getComment(al.Comments, zwsp) - al.UpdatedAt = time.Now() if al.CurrentId != "" { toUpdate++ } else { toInsert++ - al.CreatedAt = time.Now() } al.AllArtistIDs = utils.SanitizeStrings(al.SongArtistIds, al.AlbumArtistID, al.ArtistID) al.FullText = getFullText(al.Name, al.Artist, al.AlbumArtist, al.SongArtists, diff --git a/scanner/mapping.go b/scanner/mapping.go index 2963f1ea..6ee2bf23 100644 --- a/scanner/mapping.go +++ b/scanner/mapping.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/kennygrant/sanitize" "github.com/microcosm-cc/bluemonday" @@ -64,8 +65,7 @@ func (s *mediaFileMapper) toMediaFile(md metadata.Metadata) model.MediaFile { mf.Comment = s.policy.Sanitize(md.Comment()) mf.Lyrics = s.policy.Sanitize(md.Lyrics()) - // TODO Get Creation time. https://github.com/djherbis/times ? - mf.CreatedAt = md.ModificationTime() + mf.CreatedAt = time.Now() mf.UpdatedAt = md.ModificationTime() return *mf diff --git a/server/subsonic/filter/filters.go b/server/subsonic/filter/filters.go index c5d3387d..2be2c6f7 100644 --- a/server/subsonic/filter/filters.go +++ b/server/subsonic/filter/filters.go @@ -10,7 +10,7 @@ import ( type Options model.QueryOptions func AlbumsByNewest() Options { - return Options{Sort: "createdAt", Order: "desc"} + return Options{Sort: "recently_added", Order: "desc"} } func AlbumsByRecent() Options { diff --git a/ui/src/album/albumLists.js b/ui/src/album/albumLists.js index e83700bc..f348844a 100644 --- a/ui/src/album/albumLists.js +++ b/ui/src/album/albumLists.js @@ -17,7 +17,7 @@ export default { }, recentlyAdded: { icon: LibraryAddIcon, - params: 'sort=created_at&order=DESC', + params: 'sort=recently_added&order=DESC', }, recentlyPlayed: { icon: VideoLibraryIcon,