···1515 services map[string]AuthService
1616 sessionManager *session.SessionManager
1717 mu sync.RWMutex
1818+ logger *log.Logger
1819}
19202021func NewOAuthServiceManager(sessionManager *session.SessionManager) *OAuthServiceManager {
2122 return &OAuthServiceManager{
2223 services: make(map[string]AuthService),
2324 sessionManager: sessionManager,
2525+ logger: log.New(log.Writer(), "oauth: ", log.LstdFlags|log.Lmsgprefix),
2426 }
2527}
2628···2931 m.mu.Lock()
3032 defer m.mu.Unlock()
3133 m.services[name] = service
3232- log.Printf("Registered auth service: %s", name)
3434+ m.logger.Printf("Registered auth service: %s", name)
3335}
34363537// get an AuthService by registered name
···5153 return
5254 }
53555454- log.Printf("Auth service '%s' not found for login request", serviceName)
5656+ m.logger.Printf("Auth service '%s' not found for login request", serviceName)
5557 http.Error(w, fmt.Sprintf("Auth service '%s' not found", serviceName), http.StatusNotFound)
5658 }
5759}
···6264 service, exists := m.services[serviceName]
6365 m.mu.RUnlock()
64666565- log.Printf("Logging in with service %s", serviceName)
6767+ m.logger.Printf("Logging in with service %s", serviceName)
66686769 if !exists {
6868- log.Printf("Auth service '%s' not found for callback request", serviceName)
7070+ m.logger.Printf("Auth service '%s' not found for callback request", serviceName)
6971 http.Error(w, fmt.Sprintf("OAuth service '%s' not found", serviceName), http.StatusNotFound)
7072 return
7173 }
···7375 userID, err := service.HandleCallback(w, r)
74767577 if err != nil {
7676- log.Printf("Error handling callback for service '%s': %v", serviceName, err)
7878+ m.logger.Printf("Error handling callback for service '%s': %v", serviceName, err)
7779 http.Error(w, fmt.Sprintf("Error handling callback for service '%s'", serviceName), http.StatusInternalServerError)
7880 return
7981 }
···83858486 m.sessionManager.SetSessionCookie(w, session)
85878686- log.Printf("Created session for user %d via service %s", userID, serviceName)
8888+ m.logger.Printf("Created session for user %d via service %s", userID, serviceName)
87898890 http.Redirect(w, r, "/", http.StatusSeeOther)
8991 } else {
9090- log.Printf("Callback for service '%s' did not result in a valid user ID.", serviceName)
9292+ m.logger.Printf("Callback for service '%s' did not result in a valid user ID.", serviceName)
9193 // todo: redirect to an error page
9294 // right now this just redirects home but we don't want this behaviour ideally
9395 http.Redirect(w, r, "/", http.StatusSeeOther)
+45-40
service/lastfm/lastfm.go
···99 "log"
1010 "net/http"
1111 "net/url"
1212+ "os"
1213 "strconv"
1314 "sync"
1415 "time"
···4041 atprotoService *atprotoauth.ATprotoAuthService
4142 lastSeenNowPlaying map[string]Track
4243 mu sync.Mutex
4444+ logger *log.Logger
4345}
44464547func NewLastFMService(db *db.DB, apiKey string, musicBrainzService *musicbrainz.MusicBrainzService, atprotoService *atprotoauth.ATprotoAuthService) *LastFMService {
4848+ logger := log.New(os.Stdout, "lastfm: ", log.LstdFlags|log.Lmsgprefix)
4949+4650 return &LastFMService{
4751 db: db,
4852 httpClient: &http.Client{
···5660 musicBrainzService: musicBrainzService,
5761 lastSeenNowPlaying: make(map[string]Track),
5862 mu: sync.Mutex{},
6363+ logger: logger,
5964 }
6065}
61666267func (l *LastFMService) loadUsernames() error {
6368 u, err := l.db.GetAllUsersWithLastFM()
6469 if err != nil {
6565- log.Printf("Error loading users with Last.fm from DB: %v", err)
7070+ l.logger.Printf("Error loading users with Last.fm from DB: %v", err)
6671 return fmt.Errorf("failed to load users from database: %w", err)
6772 }
6873 usernames := make([]string, len(u))
···7176 if user.LastFMUsername != nil { // Check if the username is set
7277 usernames[i] = *user.LastFMUsername
7378 } else {
7474- log.Printf("User ID %d has Last.fm enabled but no username set", user.ID)
7979+ l.logger.Printf("User ID %d has Last.fm enabled but no username set", user.ID)
7580 }
7681 }
7782···8489 }
85908691 l.Usernames = filteredUsernames
8787- log.Printf("Loaded %d Last.fm usernames", len(l.Usernames))
9292+ l.logger.Printf("Loaded %d Last.fm usernames", len(l.Usernames))
88938994 return nil
9095}
···113118 return nil, fmt.Errorf("failed to create request for %s: %w", username, err)
114119 }
115120116116- log.Printf("Fetching recent tracks for user: %s", username)
121121+ l.logger.Printf("Fetching recent tracks for user: %s", username)
117122 resp, err := l.httpClient.Do(req)
118123 if err != nil {
119124 return nil, fmt.Errorf("failed to fetch recent tracks for %s: %w", username, err)
···134139 }
135140 if err := json.Unmarshal(bodyBytes, &recentTracksResp); err != nil {
136141 // Log the body content that failed to decode
137137- log.Printf("Failed to decode response body for %s: %s", username, string(bodyBytes))
142142+ l.logger.Printf("Failed to decode response body for %s: %s", username, string(bodyBytes))
138143 return nil, fmt.Errorf("failed to decode response for %s: %w", username, err)
139144 }
140145141146 if len(recentTracksResp.RecentTracks.Tracks) > 0 {
142142- log.Printf("Fetched %d tracks for %s. Most recent: %s - %s",
147147+ l.logger.Printf("Fetched %d tracks for %s. Most recent: %s - %s",
143148 len(recentTracksResp.RecentTracks.Tracks),
144149 username,
145150 recentTracksResp.RecentTracks.Tracks[0].Artist.Text,
146151 recentTracksResp.RecentTracks.Tracks[0].Name)
147152 } else {
148148- log.Printf("No recent tracks found for %s", username)
153153+ l.logger.Printf("No recent tracks found for %s", username)
149154 }
150155151156 return &recentTracksResp, nil
···153158154159func (l *LastFMService) StartListeningTracker(interval time.Duration) {
155160 if err := l.loadUsernames(); err != nil {
156156- log.Printf("Failed to perform initial username load: %v", err)
161161+ l.logger.Printf("Failed to perform initial username load: %v", err)
157162 // Decide if we should proceed without initial load or return error
158163 }
159164160165 if len(l.Usernames) == 0 {
161161- log.Println("No Last.fm users configured. Tracker will run but fetch cycles will be skipped until users are added.")
166166+ l.logger.Println("No Last.fm users configured. Tracker will run but fetch cycles will be skipped until users are added.")
162167 } else {
163163- log.Printf("Found %d Last.fm users.", len(l.Usernames))
168168+ l.logger.Printf("Found %d Last.fm users.", len(l.Usernames))
164169 }
165170166171 ticker := time.NewTicker(interval)
···169174 if len(l.Usernames) > 0 {
170175 l.fetchAllUserTracks(context.Background())
171176 } else {
172172- log.Println("Skipping initial fetch cycle as no users are configured.")
177177+ l.logger.Println("Skipping initial fetch cycle as no users are configured.")
173178 }
174179175180 for {
···177182 case <-ticker.C:
178183 // refresh usernames periodically from db
179184 if err := l.loadUsernames(); err != nil {
180180- log.Printf("Error reloading usernames in ticker: %v", err)
185185+ l.logger.Printf("Error reloading usernames in ticker: %v", err)
181186 // Continue ticker loop even if reload fails? Or log and potentially stop?
182187 continue // Continue for now
183188 }
184189 if len(l.Usernames) > 0 {
185190 l.fetchAllUserTracks(context.Background())
186191 } else {
187187- log.Println("No Last.fm users configured. Skipping fetch cycle.")
192192+ l.logger.Println("No Last.fm users configured. Skipping fetch cycle.")
188193 }
189194 // TODO: Implement graceful shutdown using context cancellation
190195 // case <-ctx.Done():
191191- // log.Println("Stopping Last.fm listening tracker.")
196196+ // l.logger.Println("Stopping Last.fm listening tracker.")
192197 // ticker.Stop()
193198 // return
194199 }
195200 }
196201 }()
197202198198- log.Printf("Last.fm Listening Tracker started with interval %v", interval)
203203+ l.logger.Printf("Last.fm Listening Tracker started with interval %v", interval)
199204}
200205201206// fetchAllUserTracks iterates through users and fetches their tracks.
202207func (l *LastFMService) fetchAllUserTracks(ctx context.Context) {
203203- log.Printf("Starting fetch cycle for %d users...", len(l.Usernames))
208208+ l.logger.Printf("Starting fetch cycle for %d users...", len(l.Usernames))
204209 var wg sync.WaitGroup // Use WaitGroup to fetch concurrently (optional)
205210 fetchErrors := make(chan error, len(l.Usernames)) // Channel for errors
206211207212 for _, username := range l.Usernames {
208213 if ctx.Err() != nil {
209209- log.Printf("Context cancelled before starting fetch for user %s.", username)
214214+ l.logger.Printf("Context cancelled before starting fetch for user %s.", username)
210215 break // Exit loop if context is cancelled
211216 }
212217···214219 go func(uname string) { // Launch fetch and process in a goroutine per user
215220 defer wg.Done()
216221 if ctx.Err() != nil {
217217- log.Printf("Context cancelled during fetch cycle for user %s.", uname)
222222+ l.logger.Printf("Context cancelled during fetch cycle for user %s.", uname)
218223 return // Exit goroutine if context is cancelled
219224 }
220225···223228 const fetchLimit = 5
224229 recentTracks, err := l.getRecentTracks(ctx, uname, fetchLimit)
225230 if err != nil {
226226- log.Printf("Error fetching tracks for %s: %v", uname, err)
231231+ l.logger.Printf("Error fetching tracks for %s: %v", uname, err)
227232 fetchErrors <- fmt.Errorf("fetch failed for %s: %w", uname, err) // Report error
228233 return
229234 }
230235231236 if recentTracks == nil || len(recentTracks.RecentTracks.Tracks) == 0 {
232232- log.Printf("No tracks returned for user %s", uname)
237237+ l.logger.Printf("No tracks returned for user %s", uname)
233238 return
234239 }
235240236241 // Process the fetched tracks
237242 if err := l.processTracks(ctx, uname, recentTracks.RecentTracks.Tracks); err != nil {
238238- log.Printf("Error processing tracks for %s: %v", uname, err)
243243+ l.logger.Printf("Error processing tracks for %s: %v", uname, err)
239244 fetchErrors <- fmt.Errorf("process failed for %s: %w", uname, err) // Report error
240245 }
241246 }(username)
···247252 // Log any errors that occurred during the fetch cycle
248253 errorCount := 0
249254 for err := range fetchErrors {
250250- log.Printf("Fetch cycle error: %v", err)
255255+ l.logger.Printf("Fetch cycle error: %v", err)
251256 errorCount++
252257 }
253258254259 if errorCount > 0 {
255255- log.Printf("Finished fetch cycle with %d errors.", errorCount)
260260+ l.logger.Printf("Finished fetch cycle with %d errors.", errorCount)
256261 } else {
257257- log.Println("Finished fetch cycle successfully.")
262262+ l.logger.Println("Finished fetch cycle successfully.")
258263 }
259264}
260265···274279 }
275280276281 if lastKnownTimestamp == nil {
277277- log.Printf("no previous scrobble timestamp found for user %s. processing latest track.", username)
282282+ l.logger.Printf("no previous scrobble timestamp found for user %s. processing latest track.", username)
278283 } else {
279279- log.Printf("last known scrobble for %s was at %s", username, lastKnownTimestamp.Format(time.RFC3339))
284284+ l.logger.Printf("last known scrobble for %s was at %s", username, lastKnownTimestamp.Format(time.RFC3339))
280285 }
281286282287 var (
···287292 // handle now playing track separately
288293 if len(tracks) > 0 && tracks[0].Attr != nil && tracks[0].Attr.NowPlaying == "true" {
289294 nowPlayingTrack := tracks[0]
290290- log.Printf("now playing track for %s: %s - %s", username, nowPlayingTrack.Artist.Text, nowPlayingTrack.Name)
295295+ l.logger.Printf("now playing track for %s: %s - %s", username, nowPlayingTrack.Artist.Text, nowPlayingTrack.Name)
291296 l.mu.Lock()
292297 lastSeen, existed := l.lastSeenNowPlaying[username]
293298 // if our current track matches with last seen
294299 // just compare artist/album/name for now
295300 if existed && lastSeen.Album == nowPlayingTrack.Album && lastSeen.Name == nowPlayingTrack.Name && lastSeen.Artist == nowPlayingTrack.Artist {
296296- log.Printf("current track matches last seen track for %s", username)
301301+ l.logger.Printf("current track matches last seen track for %s", username)
297302 } else {
298298- log.Printf("current track does not match last seen track for %s", username)
303303+ l.logger.Printf("current track does not match last seen track for %s", username)
299304 // aha! we record this!
300305 l.lastSeenNowPlaying[username] = nowPlayingTrack
301306 }
···312317 }
313318314319 if lastNonNowPlaying == nil {
315315- log.Printf("no non-now-playing tracks found for user %s.", username)
320320+ l.logger.Printf("no non-now-playing tracks found for user %s.", username)
316321 return nil
317322 }
318323319324 latestTrackTime := lastNonNowPlaying.Date
320325321326 // print both
322322- fmt.Printf("latestTrackTime: %s\n", latestTrackTime)
323323- fmt.Printf("lastKnownTimestamp: %s\n", lastKnownTimestamp)
327327+ l.logger.Printf("latestTrackTime: %s\n", latestTrackTime)
328328+ l.logger.Printf("lastKnownTimestamp: %s\n", lastKnownTimestamp)
324329325330 if lastKnownTimestamp != nil && lastKnownTimestamp.Equal(latestTrackTime.Time) {
326326- log.Printf("no new tracks to process for user %s.", username)
331331+ l.logger.Printf("no new tracks to process for user %s.", username)
327332 return nil
328333 }
329334330335 for _, track := range tracks {
331336 if track.Date == nil {
332332- log.Printf("skipping track without timestamp for %s: %s - %s", username, track.Artist.Text, track.Name)
337337+ l.logger.Printf("skipping track without timestamp for %s: %s - %s", username, track.Artist.Text, track.Name)
333338 continue
334339 }
335340···337342 // before or at last known
338343 if lastKnownTimestamp != nil && (trackTime.Before(*lastKnownTimestamp) || trackTime.Equal(*lastKnownTimestamp)) {
339344 if processedCount == 0 {
340340- log.Printf("reached already known scrobbles for user %s (track time: %s, last known: %s).",
345345+ l.logger.Printf("reached already known scrobbles for user %s (track time: %s, last known: %s).",
341346 username, trackTime.Format(time.RFC3339), lastKnownTimestamp.Format(time.RFC3339))
342347 }
343348 break
···360365361366 hydratedTrack, err := musicbrainz.HydrateTrack(l.musicBrainzService, baseTrack)
362367 if err != nil {
363363- log.Printf("error hydrating track for user %s: %s - %s: %v", username, track.Artist.Text, track.Name, err)
368368+ l.logger.Printf("error hydrating track for user %s: %s - %s: %v", username, track.Artist.Text, track.Name, err)
364369 // we can use the track without MBIDs, it's still valid
365370 hydratedTrack = &baseTrack
366371 }
367372 l.db.SaveTrack(user.ID, hydratedTrack)
368368- log.Printf("Submitting track")
373373+ l.logger.Printf("Submitting track")
369374 err = l.SubmitTrackToPDS(*user.ATProtoDID, hydratedTrack, ctx)
370375 if err != nil {
371371- log.Printf("error submitting track for user %s: %s - %s: %v", username, track.Artist.Text, track.Name, err)
376376+ l.logger.Printf("error submitting track for user %s: %s - %s: %v", username, track.Artist.Text, track.Name, err)
372377 }
373378 processedCount++
374379···382387 }
383388384389 if processedCount > 0 {
385385- log.Printf("processed %d new track(s) for user %s. latest timestamp: %s",
390390+ l.logger.Printf("processed %d new track(s) for user %s. latest timestamp: %s",
386391 processedCount, username, latestProcessedTime.Format(time.RFC3339))
387392 }
388393···407412 }
408413409414 // printout the session details
410410- fmt.Printf("Submitting track for the did: %+v\n", sess.DID)
415415+ l.logger.Printf("Submitting track for the did: %+v\n", sess.DID)
411416412417 artists := make([]*teal.AlphaFeedDefs_Artist, 0, len(track.Artist))
413418 for _, a := range track.Artist {
+11-8
service/musicbrainz/musicbrainz.go
···88 "log"
99 "net/http"
1010 "net/url"
1111+ "os"
1112 "sort"
1213 "strings"
1314 "sync" // Added for mutex
···7576 cacheMutex sync.RWMutex // Mutex to protect the cache
7677 cacheTTL time.Duration // Time-to-live for cache entries
7778 cleaner MetadataCleaner // Cleaner for cleaning up expired cache entries
7979+ logger *log.Logger // Logger for logging
7880}
79818082// NewMusicBrainzService creates a new service instance with rate limiting and caching.
···8385 limiter := rate.NewLimiter(rate.Every(time.Second), 1)
8486 // Set a default cache TTL (e.g., 1 hour)
8587 defaultCacheTTL := 1 * time.Hour
8686-8888+ logger := log.New(os.Stdout, "musicbrainz: ", log.LstdFlags|log.Lmsgprefix)
8789 return &MusicBrainzService{
8890 db: db,
8991 httpClient: &http.Client{
···9496 cacheTTL: defaultCacheTTL, // Set the cache TTL
9597 cleaner: *NewMetadataCleaner("Latin"), // Initialize the cleaner
9698 // cacheMutex is zero-value ready
9999+ logger: logger,
97100 }
98101}
99102···127130 s.cacheMutex.RUnlock()
128131129132 if found && now.Before(entry.expiresAt) {
130130- log.Printf("Cache hit for MusicBrainz search: key=%s", cacheKey)
133133+ s.logger.Printf("Cache hit for MusicBrainz search: key=%s", cacheKey)
131134 // Return the cached data directly. Consider if a deep copy is needed if callers modify results.
132135 return entry.recordings, nil
133136 }
134137 // --- Cache Miss or Expired ---
135138 if found {
136136- log.Printf("Cache expired for MusicBrainz search: key=%s", cacheKey)
139139+ s.logger.Printf("Cache expired for MusicBrainz search: key=%s", cacheKey)
137140 } else {
138138- log.Printf("Cache miss for MusicBrainz search: key=%s", cacheKey)
141141+ s.logger.Printf("Cache miss for MusicBrainz search: key=%s", cacheKey)
139142 }
140143141144 // --- Proceed with API call ---
···191194 expiresAt: time.Now().UTC().Add(s.cacheTTL),
192195 }
193196 s.cacheMutex.Unlock()
194194- log.Printf("Cached MusicBrainz search result for key=%s, TTL=%s", cacheKey, s.cacheTTL)
197197+ s.logger.Printf("Cached MusicBrainz search result for key=%s, TTL=%s", cacheKey, s.cacheTTL)
195198196199 // Return the newly fetched results
197200 return result.Recordings, nil
198201}
199202200203// GetBestRelease selects the 'best' release from a list based on specific criteria.
201201-func GetBestRelease(releases []MusicBrainzRelease, trackTitle string) *MusicBrainzRelease {
204204+func (s *MusicBrainzService) GetBestRelease(releases []MusicBrainzRelease, trackTitle string) *MusicBrainzRelease {
202205 if len(releases) == 0 {
203206 return nil
204207 }
···251254 }
252255253256 // 3. If none found, return the oldest release overall (which is the first one after sorting)
254254- log.Printf("Could not find a suitable release for '%s', picking oldest: '%s' (%s)", trackTitle, releases[0].Title, releases[0].ID)
257257+ s.logger.Printf("Could not find a suitable release for '%s', picking oldest: '%s' (%s)", trackTitle, releases[0].Title, releases[0].ID)
255258 r := releases[0]
256259 return &r
257260}
···279282 }
280283281284 firstResult := res[0]
282282- firstResultAlbum := GetBestRelease(firstResult.Releases, firstResult.Title)
285285+ firstResultAlbum := mb.GetBestRelease(firstResult.Releases, firstResult.Title)
283286284287 // woof. we Might not have any ISRCs!
285288 var bestISRC string
+47-42
service/spotify/spotify.go
···99 "log"
1010 "net/http"
1111 "net/url"
1212+ "os"
1213 "strings"
1314 "sync"
1415 "time"
···3435 userTracks map[int64]*models.Track
3536 userTokens map[int64]string
3637 mu sync.RWMutex
3838+ logger *log.Logger
3739}
38403941func NewSpotifyService(database *db.DB, atprotoService *atprotoauth.ATprotoAuthService, musicBrainzService *musicbrainz.MusicBrainzService) *SpotifyService {
4242+ logger := log.New(os.Stdout, "spotify: ", log.LstdFlags|log.Lmsgprefix)
4343+4044 return &SpotifyService{
4145 DB: database,
4246 atprotoService: atprotoService,
4347 mb: musicBrainzService,
4448 userTracks: make(map[int64]*models.Track),
4549 userTokens: make(map[int64]string),
5050+ logger: logger,
4651 }
4752}
48534954func (s *SpotifyService) SubmitTrackToPDS(did string, track *models.Track, ctx context.Context) error {
5055 client, err := s.atprotoService.GetATProtoClient()
5156 if err != nil || client == nil {
5252- log.Printf("Error getting ATProto client: %v", err)
5757+ s.logger.Printf("Error getting ATProto client: %v", err)
5358 return fmt.Errorf("failed to get ATProto client: %w", err)
5459 }
5560···110115111116 var out atproto.RepoCreateRecord_Output
112117 if err := xrpcClient.Do(ctx, authArgs, xrpc.Procedure, "application/json", "com.atproto.repo.createRecord", nil, input, &out); err != nil {
113113- log.Printf("Error creating record for DID %s: %v. Input: %+v", did, err, input)
118118+ s.logger.Printf("Error creating record for DID %s: %v. Input: %+v", did, err, input)
114119 return fmt.Errorf("failed to create record on PDS for DID %s: %w", did, err)
115120 }
116121117117- log.Printf("Successfully submitted track '%s' to PDS for DID %s. Record URI: %s", track.Name, did, out.Uri)
122122+ s.logger.Printf("Successfully submitted track '%s' to PDS for DID %s. Record URI: %s", track.Name, did, out.Uri)
118123 return nil
119124}
120125121126func (s *SpotifyService) SetAccessToken(token string, refreshToken string, userId int64, hasSession bool) (int64, error) {
122127 userID, err := s.identifyAndStoreUser(token, refreshToken, userId, hasSession)
123128 if err != nil {
124124- log.Printf("Error identifying and storing user: %v", err)
129129+ s.logger.Printf("Error identifying and storing user: %v", err)
125130 return 0, err
126131 }
127132 return userID, nil
···130135func (s *SpotifyService) identifyAndStoreUser(token string, refreshToken string, userId int64, hasSession bool) (int64, error) {
131136 userProfile, err := s.fetchSpotifyProfile(token)
132137 if err != nil {
133133- log.Printf("Error fetching Spotify profile: %v", err)
138138+ s.logger.Printf("Error fetching Spotify profile: %v", err)
134139 return 0, err
135140 }
136141137137- fmt.Printf("uid: %d hasSession: %t", userId, hasSession)
142142+ s.logger.Printf("uid: %d hasSession: %t", userId, hasSession)
138143139144 user, err := s.DB.GetUserBySpotifyID(userProfile.ID)
140145 if err != nil {
141146 // This error might mean DB connection issue, not just user not found.
142142- log.Printf("Error checking for user by Spotify ID %s: %v", userProfile.ID, err)
147147+ s.logger.Printf("Error checking for user by Spotify ID %s: %v", userProfile.ID, err)
143148 return 0, err
144149 }
145150···148153 // We don't intend users to log in via spotify!
149154 if user == nil {
150155 if !hasSession {
151151- log.Printf("User does not seem to exist")
156156+ s.logger.Printf("User does not seem to exist")
152157 return 0, fmt.Errorf("user does not seem to exist")
153158 } else {
154159 // overwrite prev user
155160 user, err = s.DB.AddSpotifySession(userId, userProfile.DisplayName, userProfile.Email, userProfile.ID, token, refreshToken, tokenExpiryTime)
156161 if err != nil {
157157- log.Printf("Error adding Spotify session for user ID %d: %v", userId, err)
162162+ s.logger.Printf("Error adding Spotify session for user ID %d: %v", userId, err)
158163 return 0, err
159164 }
160165 }
···162167 err = s.DB.UpdateUserToken(user.ID, token, refreshToken, tokenExpiryTime)
163168 if err != nil {
164169 // for now log and continue
165165- log.Printf("Error updating user token for user ID %d: %v", user.ID, err)
170170+ s.logger.Printf("Error updating user token for user ID %d: %v", user.ID, err)
166171 } else {
167167- log.Printf("Updated token for existing user: %s (ID: %d)", *user.Username, user.ID)
172172+ s.logger.Printf("Updated token for existing user: %s (ID: %d)", *user.Username, user.ID)
168173 }
169174 }
170175 user.AccessToken = &token
···174179 s.userTokens[user.ID] = token
175180 s.mu.Unlock()
176181177177- log.Printf("User authenticated via Spotify: %s (ID: %d)", *user.Username, user.ID)
182182+ s.logger.Printf("User authenticated via Spotify: %s (ID: %d)", *user.Username, user.ID)
178183 return user.ID, nil
179184}
180185···203208 token, err := s.refreshTokenInner(user.ID)
204209 if err != nil {
205210 //Probably should remove the access token and refresh in long run?
206206- log.Printf("Error refreshing token for user %d: %v", user.ID, err)
211211+ s.logger.Printf("Error refreshing token for user %d: %v", user.ID, err)
207212 continue
208213 }
209214 s.userTokens[user.ID] = token
210215 }
211216 }
212217213213- log.Printf("Loaded %d active users with valid tokens", count)
218218+ s.logger.Printf("Loaded %d active users with valid tokens", count)
214219 return nil
215220}
216221···280285 // Also clear the bad refresh token from the DB
281286 updateErr := s.DB.UpdateUserToken(userID, "", "", time.Now().UTC()) // Clear tokens
282287 if updateErr != nil {
283283- log.Printf("Failed to clear bad refresh token for user %d: %v", userID, updateErr)
288288+ s.logger.Printf("Failed to clear bad refresh token for user %d: %v", userID, updateErr)
284289 }
285290 return "", fmt.Errorf("spotify token refresh failed (%d): %s", resp.StatusCode, string(body))
286291 }
···306311 // Update DB
307312 if err := s.DB.UpdateUserToken(userID, tokenResponse.AccessToken, newRefreshToken, newExpiry); err != nil {
308313 // Log error but continue, as we have the token in memory
309309- log.Printf("Error updating user token in DB for user %d after refresh: %v", userID, err)
314314+ s.logger.Printf("Error updating user token in DB for user %d after refresh: %v", userID, err)
310315 }
311316312317 // Update in-memory cache
···314319 s.userTokens[userID] = tokenResponse.AccessToken
315320 s.mu.Unlock()
316321317317- log.Printf("Successfully refreshed token for user %d", userID)
322322+ s.logger.Printf("Successfully refreshed token for user %d", userID)
318323 return tokenResponse.AccessToken, nil
319324}
320325···329334func (s *SpotifyService) RefreshExpiredTokens() {
330335 users, err := s.DB.GetUsersWithExpiredTokens()
331336 if err != nil {
332332- log.Printf("Error fetching users with expired tokens: %v", err)
337337+ s.logger.Printf("Error fetching users with expired tokens: %v", err)
333338 return
334339 }
335340···344349345350 if err != nil {
346351 // just print out errors here for now
347347- log.Printf("Error from service/spotify/spotify.go when refreshing tokens: %s", err.Error())
352352+ s.logger.Printf("Error from service/spotify/spotify.go when refreshing tokens: %s", err.Error())
348353 }
349354350355 refreshed++
351356 }
352357353358 if refreshed > 0 {
354354- log.Printf("Refreshed tokens for %d users", refreshed)
359359+ s.logger.Printf("Refreshed tokens for %d users", refreshed)
355360 }
356361}
357362···412417 tracks, err := s.DB.GetRecentTracks(userID, 20)
413418 if err != nil {
414419 http.Error(w, "Error retrieving track history", http.StatusInternalServerError)
415415- log.Printf("Error retrieving track history: %v", err)
420420+ s.logger.Printf("Error retrieving track history: %v", err)
416421 return
417422 }
418423···454459455460 // oops, token expired or other client error
456461 if resp.StatusCode == 401 && attempt == 0 { // Only refresh on 401 on the first attempt
457457- log.Printf("Spotify token potentially expired for user %d, attempting refresh...", userID)
462462+ s.logger.Printf("Spotify token potentially expired for user %d, attempting refresh...", userID)
458463 newAccessToken, refreshErr := s.refreshTokenInner(userID)
459464 if refreshErr != nil {
460460- log.Printf("Token refresh failed for user %d: %v", userID, refreshErr)
465465+ s.logger.Printf("Token refresh failed for user %d: %v", userID, refreshErr)
461466 // No point retrying if refresh failed
462467 return nil, fmt.Errorf("spotify token expired or invalid for user %d and refresh failed: %w", userID, refreshErr)
463468 }
464464- log.Printf("Token refreshed for user %d, retrying request...", userID)
469469+ s.logger.Printf("Token refreshed for user %d, retrying request...", userID)
465470 token = newAccessToken // Update token for the next attempt
466471 req.Header.Set("Authorization", "Bearer "+token) // Update header for retry
467472 continue // Go to next attempt in the loop
···555560 for range ticker.C {
556561 err := s.LoadAllUsers()
557562 if err != nil {
558558- log.Printf("Error loading spotify users: %v", err)
563563+ s.logger.Printf("Error loading spotify users: %v", err)
559564 continue
560565 }
561566 // copy userIDs to avoid holding the lock too long
···569574 for _, userID := range userIDs {
570575 track, err := s.FetchCurrentTrack(userID)
571576 if err != nil {
572572- log.Printf("Error fetching track for user %d: %v", userID, err)
577577+ s.logger.Printf("Error fetching track for user %d: %v", userID, err)
573578 continue
574579 }
575580···603608604609 // just log when we stamp tracks
605610 if isNewTrack && isLastTrackStamped && !currentTrack.HasStamped {
606606- log.Printf("User %d stamped (previous) track: %s by %s", userID, currentTrack.Name, currentTrack.Artist)
611611+ s.logger.Printf("User %d stamped (previous) track: %s by %s", userID, currentTrack.Name, currentTrack.Artist)
607612 currentTrack.HasStamped = true
608613 if currentTrack.PlayID != 0 {
609614 s.DB.UpdateTrack(currentTrack.PlayID, currentTrack)
610615611611- log.Printf("Updated!")
616616+ s.logger.Printf("Updated!")
612617 }
613618 }
614619615620 if isStamped && !currentTrack.HasStamped {
616616- log.Printf("User %d stamped track: %s by %s", userID, track.Name, track.Artist)
621621+ s.logger.Printf("User %d stamped track: %s by %s", userID, track.Name, track.Artist)
617622 track.HasStamped = true
618623 // if currenttrack has a playid and the last track is the same as the current track
619624 if !isNewTrack && currentTrack.PlayID != 0 {
···624629 s.userTracks[userID] = track
625630 s.mu.Unlock()
626631627627- log.Printf("Updated!")
632632+ s.logger.Printf("Updated!")
628633 }
629634 }
630635631636 if isNewTrack {
632637 id, err := s.DB.SaveTrack(userID, track)
633638 if err != nil {
634634- log.Printf("Error saving track for user %d: %v", userID, err)
639639+ s.logger.Printf("Error saving track for user %d: %v", userID, err)
635640 continue
636641 }
637642···645650 // The 'track' variable is *models.Track and has been saved to DB, PlayID is populated.
646651 dbUser, errUser := s.DB.GetUserByID(userID) // Fetch user by their internal ID
647652 if errUser != nil {
648648- log.Printf("User %d: Error fetching user details for PDS submission: %v", userID, errUser)
653653+ s.logger.Printf("User %d: Error fetching user details for PDS submission: %v", userID, errUser)
649654 } else if dbUser == nil {
650650- log.Printf("User %d: User not found in DB. Skipping PDS submission.", userID)
655655+ s.logger.Printf("User %d: User not found in DB. Skipping PDS submission.", userID)
651656 } else if dbUser.ATProtoDID == nil || *dbUser.ATProtoDID == "" {
652652- log.Printf("User %d (%d): ATProto DID not set. Skipping PDS submission for track '%s'.", userID, dbUser.ATProtoDID, track.Name)
657657+ s.logger.Printf("User %d (%d): ATProto DID not set. Skipping PDS submission for track '%s'.", userID, dbUser.ATProtoDID, track.Name)
653658 } else {
654659 // User has a DID, proceed with hydration and submission
655660 var trackToSubmitToPDS *models.Track = track // Default to the original track (already *models.Track)
···658663 // and it returns *models.Track
659664 hydratedTrack, errHydrate := musicbrainz.HydrateTrack(s.mb, *track)
660665 if errHydrate != nil {
661661- log.Printf("User %d (%d): Error hydrating track '%s' with MusicBrainz: %v. Proceeding with original track data for PDS.", userID, dbUser.ATProtoDID, track.Name, errHydrate)
666666+ s.logger.Printf("User %d (%d): Error hydrating track '%s' with MusicBrainz: %v. Proceeding with original track data for PDS.", userID, dbUser.ATProtoDID, track.Name, errHydrate)
662667 } else {
663663- log.Printf("User %d (%d): Successfully hydrated track '%s' with MusicBrainz.", userID, dbUser.ATProtoDID, track.Name)
668668+ s.logger.Printf("User %d (%d): Successfully hydrated track '%s' with MusicBrainz.", userID, dbUser.ATProtoDID, track.Name)
664669 trackToSubmitToPDS = hydratedTrack // hydratedTrack is *models.Track
665670 }
666671 } else {
667667- log.Printf("User %d (%d): MusicBrainz service not configured. Proceeding with original track data for PDS.", userID, dbUser.ATProtoDID)
672672+ s.logger.Printf("User %d (%d): MusicBrainz service not configured. Proceeding with original track data for PDS.", userID, dbUser.ATProtoDID)
668673 }
669674670675 artistName := "Unknown Artist"
···672677 artistName = trackToSubmitToPDS.Artist[0].Name
673678 }
674679675675- log.Printf("User %d (%d): Attempting to submit track '%s' by %s to PDS (DID: %s)", userID, dbUser.ATProtoDID, trackToSubmitToPDS.Name, artistName, *dbUser.ATProtoDID)
680680+ s.logger.Printf("User %d (%d): Attempting to submit track '%s' by %s to PDS (DID: %s)", userID, dbUser.ATProtoDID, trackToSubmitToPDS.Name, artistName, *dbUser.ATProtoDID)
676681 // Use context.Background() for now, or pass down a context if available
677682 if errPDS := s.SubmitTrackToPDS(*dbUser.ATProtoDID, trackToSubmitToPDS, context.Background()); errPDS != nil {
678678- log.Printf("User %d (%d): Error submitting track '%s' to PDS: %v", userID, dbUser.ATProtoDID, trackToSubmitToPDS.Name, errPDS)
683683+ s.logger.Printf("User %d (%d): Error submitting track '%s' to PDS: %v", userID, dbUser.ATProtoDID, trackToSubmitToPDS.Name, errPDS)
679684 } else {
680680- log.Printf("User %d (%d): Successfully submitted track '%s' to PDS.", userID, dbUser.ATProtoDID, trackToSubmitToPDS.Name)
685685+ s.logger.Printf("User %d (%d): Successfully submitted track '%s' to PDS.", userID, dbUser.ATProtoDID, trackToSubmitToPDS.Name)
681686 }
682687 }
683688 // End of PDS submission block
684689685685- log.Printf("User %d is listening to: %s by %s", userID, track.Name, track.Artist)
690690+ s.logger.Printf("User %d is listening to: %s by %s", userID, track.Name, track.Artist)
686691 }
687692 }
688693689694 //unloading users to save memory and make sure we get new signups
690695 err = s.LoadAllUsers()
691696 if err != nil {
692692- log.Printf("Error loading spotify users: %v", err)
697697+ s.logger.Printf("Error loading spotify users: %v", err)
693698 }
694699 }
695700}