feat(insights): add file suffix counting
This commit is contained in:
@@ -265,6 +265,10 @@ func (c *insightsCollector) collect(ctx context.Context) []byte {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Trace(ctx, "Error reading active users count", err)
|
log.Trace(ctx, "Error reading active users count", err)
|
||||||
}
|
}
|
||||||
|
data.Library.FileSuffixes, err = c.ds.MediaFile(ctx).CountBySuffix()
|
||||||
|
if err != nil {
|
||||||
|
log.Trace(ctx, "Error reading file suffixes count", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Check for smart playlists
|
// Check for smart playlists
|
||||||
data.Config.HasSmartPlaylists, err = c.hasSmartPlaylists(ctx)
|
data.Config.HasSmartPlaylists, err = c.hasSmartPlaylists(ctx)
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ type Data struct {
|
|||||||
Libraries int64 `json:"libraries"`
|
Libraries int64 `json:"libraries"`
|
||||||
ActiveUsers int64 `json:"activeUsers"`
|
ActiveUsers int64 `json:"activeUsers"`
|
||||||
ActivePlayers map[string]int64 `json:"activePlayers,omitempty"`
|
ActivePlayers map[string]int64 `json:"activePlayers,omitempty"`
|
||||||
|
FileSuffixes map[string]int64 `json:"fileSuffixes,omitempty"`
|
||||||
} `json:"library"`
|
} `json:"library"`
|
||||||
Config struct {
|
Config struct {
|
||||||
LogLevel string `json:"logLevel,omitempty"`
|
LogLevel string `json:"logLevel,omitempty"`
|
||||||
|
|||||||
@@ -353,6 +353,7 @@ type MediaFileCursor iter.Seq2[MediaFile, error]
|
|||||||
|
|
||||||
type MediaFileRepository interface {
|
type MediaFileRepository interface {
|
||||||
CountAll(options ...QueryOptions) (int64, error)
|
CountAll(options ...QueryOptions) (int64, error)
|
||||||
|
CountBySuffix(options ...QueryOptions) (map[string]int64, error)
|
||||||
Exists(id string) (bool, error)
|
Exists(id string) (bool, error)
|
||||||
Put(m *MediaFile) error
|
Put(m *MediaFile) error
|
||||||
Get(id string) (*MediaFile, error)
|
Get(id string) (*MediaFile, error)
|
||||||
|
|||||||
@@ -124,6 +124,25 @@ func (r *mediaFileRepository) CountAll(options ...model.QueryOptions) (int64, er
|
|||||||
return r.count(query, options...)
|
return r.count(query, options...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mediaFileRepository) CountBySuffix(options ...model.QueryOptions) (map[string]int64, error) {
|
||||||
|
sel := r.newSelect(options...).
|
||||||
|
Columns("lower(suffix) as suffix", "count(*) as count").
|
||||||
|
GroupBy("lower(suffix)")
|
||||||
|
var res []struct {
|
||||||
|
Suffix string
|
||||||
|
Count int64
|
||||||
|
}
|
||||||
|
err := r.queryAll(sel, &res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
counts := make(map[string]int64, len(res))
|
||||||
|
for _, c := range res {
|
||||||
|
counts[c.Suffix] = c.Count
|
||||||
|
}
|
||||||
|
return counts, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *mediaFileRepository) Exists(id string) (bool, error) {
|
func (r *mediaFileRepository) Exists(id string) (bool, error) {
|
||||||
return r.exists(Eq{"media_file.id": id})
|
return r.exists(Eq{"media_file.id": id})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,44 @@ var _ = Describe("MediaRepository", func() {
|
|||||||
Expect(mr.CountAll()).To(Equal(int64(10)))
|
Expect(mr.CountAll()).To(Equal(int64(10)))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Describe("CountBySuffix", func() {
|
||||||
|
var mp3File, flacFile1, flacFile2, flacUpperFile model.MediaFile
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
mp3File = model.MediaFile{ID: "suffix-mp3", LibraryID: 1, Suffix: "mp3", Path: "/test/file.mp3"}
|
||||||
|
flacFile1 = model.MediaFile{ID: "suffix-flac1", LibraryID: 1, Suffix: "flac", Path: "/test/file1.flac"}
|
||||||
|
flacFile2 = model.MediaFile{ID: "suffix-flac2", LibraryID: 1, Suffix: "flac", Path: "/test/file2.flac"}
|
||||||
|
flacUpperFile = model.MediaFile{ID: "suffix-FLAC", LibraryID: 1, Suffix: "FLAC", Path: "/test/file.FLAC"}
|
||||||
|
|
||||||
|
Expect(mr.Put(&mp3File)).To(Succeed())
|
||||||
|
Expect(mr.Put(&flacFile1)).To(Succeed())
|
||||||
|
Expect(mr.Put(&flacFile2)).To(Succeed())
|
||||||
|
Expect(mr.Put(&flacUpperFile)).To(Succeed())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
_ = mr.Delete(mp3File.ID)
|
||||||
|
_ = mr.Delete(flacFile1.ID)
|
||||||
|
_ = mr.Delete(flacFile2.ID)
|
||||||
|
_ = mr.Delete(flacUpperFile.ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("counts media files grouped by suffix with lowercase normalization", func() {
|
||||||
|
counts, err := mr.CountBySuffix()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// Should have lowercase keys only
|
||||||
|
Expect(counts).To(HaveKey("mp3"))
|
||||||
|
Expect(counts).To(HaveKey("flac"))
|
||||||
|
Expect(counts).ToNot(HaveKey("FLAC"))
|
||||||
|
|
||||||
|
// mp3: 1 file
|
||||||
|
Expect(counts["mp3"]).To(Equal(int64(1)))
|
||||||
|
// flac: 3 files (2 lowercase + 1 uppercase normalized)
|
||||||
|
Expect(counts["flac"]).To(Equal(int64(3)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
It("returns songs ordered by lyrics with a specific title/artist", func() {
|
It("returns songs ordered by lyrics with a specific title/artist", func() {
|
||||||
// attempt to mimic filters.SongsByArtistTitleWithLyricsFirst, except we want all items
|
// attempt to mimic filters.SongsByArtistTitleWithLyricsFirst, except we want all items
|
||||||
results, err := mr.GetAll(model.QueryOptions{
|
results, err := mr.GetAll(model.QueryOptions{
|
||||||
|
|||||||
Reference in New Issue
Block a user