A website inspired by Last.fm that will keep track of your listening statistics
lastfm music statistics
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Decouple image providing logic from the artist service and make it a seperate struct so it can be consumed by multiple services (like the user service).

oscar345 0f98580f cf67635e

+112 -65
+81
internal/providers/image.go
··· 1 + package providers 2 + 3 + import ( 4 + "context" 5 + "log" 6 + "path" 7 + "sync" 8 + 9 + "github.com/oscar345/keeptrack/internal/image" 10 + storagesvc "github.com/oscar345/keeptrack/pkg/storage" 11 + "golang.org/x/sync/errgroup" 12 + ) 13 + 14 + type MediaProvider struct { 15 + storage storagesvc.Storage 16 + artistImageFetcher image.ArtistImageFetcher 17 + } 18 + 19 + func NewMediaProvider(storage storagesvc.Storage, artistImageFetcher image.ArtistImageFetcher) *MediaProvider { 20 + return &MediaProvider{ 21 + storage: storage, 22 + artistImageFetcher: artistImageFetcher, 23 + } 24 + } 25 + 26 + func (mp *MediaProvider) GetArtistImage(ctx context.Context, mbid string) (string, error) { 27 + filename := createArtistImageFilename(mbid) 28 + 29 + if mp.storage.Exists(filename) { 30 + return mp.storage.GetURL(filename), nil 31 + } 32 + 33 + images, err := mp.artistImageFetcher.ListImages(ctx, mbid) 34 + if err != nil { 35 + return "", err 36 + } 37 + 38 + if len(images) == 0 { 39 + return "", nil 40 + } 41 + image := images[0] 42 + 43 + content, err := mp.artistImageFetcher.FetchImage(ctx, image) 44 + if err != nil { 45 + return "", err 46 + } 47 + 48 + if err := mp.storage.Save(content, filename); err != nil { 49 + return "", err 50 + } 51 + 52 + return mp.storage.GetURL(filename), nil 53 + } 54 + 55 + func (mp *MediaProvider) ListArtistsImages(ctx context.Context, mbids []string) (map[string]string, error) { 56 + g, ctx := errgroup.WithContext(ctx) 57 + 58 + var mu sync.Mutex 59 + result := make(map[string]string, len(mbids)) 60 + 61 + for _, mbid := range mbids { 62 + mbid := mbid 63 + g.Go(func() error { 64 + if url, err := mp.GetArtistImage(ctx, mbid); err == nil { 65 + mu.Lock() 66 + result[mbid] = url 67 + mu.Unlock() 68 + } else { 69 + log.Printf("failed to get artist image for %s: %v", mbid, err) 70 + } 71 + return nil 72 + }) 73 + } 74 + 75 + _ = g.Wait() 76 + return result, nil 77 + } 78 + 79 + func createArtistImageFilename(mbid string) string { 80 + return path.Join("images", "artists", mbid) 81 + }
+7 -1
internal/server/server.go
··· 9 9 _ "github.com/mattn/go-sqlite3" 10 10 "github.com/oscar345/keeptrack/internal/config" 11 11 "github.com/oscar345/keeptrack/internal/image" 12 + "github.com/oscar345/keeptrack/internal/providers" 12 13 "github.com/oscar345/keeptrack/internal/repo/db" 13 14 "github.com/oscar345/keeptrack/internal/services" 14 15 "github.com/oscar345/keeptrack/internal/web/router" ··· 45 46 artistRepo := db.NewArtistRepoDB(musicbrainzDB) 46 47 artistScrobbleRepo := db.NewArtistScrobbleRepoDB(statisticsDB) 47 48 artistImageFetcher := image.NewArtistImageFetcherFanArtTV(s.config.Services.FanartTV.APIKey) 49 + 48 50 storage := storagesvc.NewDiskStorage("/public", s.config.Storage.Disk.Path) 49 51 50 - artistService := services.NewArtistService(artistRepo, artistScrobbleRepo, artistImageFetcher, storage) 52 + mediaProvider := providers.NewMediaProvider(storage, artistImageFetcher) 53 + 54 + artistService := services.NewArtistService( 55 + artistRepo, artistScrobbleRepo, artistImageFetcher, mediaProvider, storage, 56 + ) 51 57 52 58 router := router. 53 59 New(artistService, s.config).
+9 -64
internal/services/artist.go
··· 2 2 3 3 import ( 4 4 "context" 5 - "log" 6 - "path" 7 - "sync" 8 5 9 6 "github.com/oscar345/keeptrack/internal/filters" 10 7 "github.com/oscar345/keeptrack/internal/image" 11 8 "github.com/oscar345/keeptrack/internal/models" 9 + "github.com/oscar345/keeptrack/internal/providers" 12 10 "github.com/oscar345/keeptrack/internal/repo" 13 11 "github.com/oscar345/keeptrack/pkg/enum" 14 12 "github.com/oscar345/keeptrack/pkg/pagination" 15 13 storagesvc "github.com/oscar345/keeptrack/pkg/storage" 16 - "golang.org/x/sync/errgroup" 17 14 ) 18 15 19 16 type ArtistService struct { 20 17 artistRepo repo.ArtistRepo 21 18 artistScrobbleRepo repo.ArtistScrobbleRepo 22 19 artistImageFetcher image.ArtistImageFetcher 20 + mediaProvider *providers.MediaProvider 23 21 storage storagesvc.Storage 24 22 } 25 23 ··· 27 25 artistRepo repo.ArtistRepo, 28 26 artistScrobbleRepo repo.ArtistScrobbleRepo, 29 27 artistImageFetcher image.ArtistImageFetcher, 28 + mediaProvider *providers.MediaProvider, 30 29 storage storagesvc.Storage, 31 30 ) ArtistService { 32 31 return ArtistService{ 33 32 artistRepo: artistRepo, 34 33 artistScrobbleRepo: artistScrobbleRepo, 35 34 artistImageFetcher: artistImageFetcher, 35 + mediaProvider: mediaProvider, 36 36 storage: storage, 37 37 } 38 38 } ··· 52 52 return nil, page, err 53 53 } 54 54 55 - images := as.listArtistImages(ctx, mbids) 55 + images, err := as.mediaProvider.ListArtistsImages(ctx, mbids) 56 + 57 + if err != nil { 58 + return nil, page, err 59 + } 56 60 57 61 items := enum.Map(counts, func(item models.CountMBID) models.Artist { 58 62 artist := artists[item.MBID] ··· 67 71 68 72 return items, page, nil 69 73 } 70 - 71 - func (as *ArtistService) listArtistImages(ctx context.Context, mbids []string) map[string]string { 72 - g, ctx := errgroup.WithContext(ctx) 73 - 74 - var mu sync.Mutex 75 - result := make(map[string]string, len(mbids)) 76 - 77 - for _, mbid := range mbids { 78 - mbid := mbid 79 - g.Go(func() error { 80 - if url, err := getArtistImage(ctx, as.artistImageFetcher, as.storage, mbid); err == nil { 81 - mu.Lock() 82 - result[mbid] = url 83 - mu.Unlock() 84 - } else { 85 - log.Printf("failed to get artist image for %s: %v", mbid, err) 86 - } 87 - return nil 88 - }) 89 - } 90 - 91 - _ = g.Wait() 92 - return result 93 - } 94 - 95 - func createArtistImageFilename(mbid string) string { 96 - return path.Join("images", "artists", mbid) 97 - } 98 - 99 - func getArtistImage( 100 - ctx context.Context, fetcher image.ArtistImageFetcher, storage storagesvc.Storage, mbid string, 101 - ) (string, error) { 102 - filename := createArtistImageFilename(mbid) 103 - 104 - if storage.Exists(filename) { 105 - return storage.GetURL(filename), nil 106 - } 107 - 108 - images, err := fetcher.ListImages(ctx, mbid) 109 - if err != nil { 110 - return "", err 111 - } 112 - 113 - if len(images) == 0 { 114 - return "", nil 115 - } 116 - image := images[0] 117 - 118 - content, err := fetcher.FetchImage(ctx, image) 119 - if err != nil { 120 - return "", err 121 - } 122 - 123 - if err := storage.Save(content, filename); err != nil { 124 - return "", err 125 - } 126 - 127 - return storage.GetURL(filename), nil 128 - }
+15
internal/services/recording.go
··· 1 + package services 2 + 3 + import "github.com/oscar345/keeptrack/internal/repo" 4 + 5 + type RecordingService struct { 6 + recordingRepo repo.RecordingRepo 7 + recordingLikeRepo repo.RecordingLikeRepo 8 + } 9 + 10 + func NewRecordingService(recordingRepo repo.RecordingRepo, recordingLikeRepo repo.RecordingLikeRepo) *RecordingService { 11 + return &RecordingService{ 12 + recordingRepo: recordingRepo, 13 + recordingLikeRepo: recordingLikeRepo, 14 + } 15 + }