[WIP] music platform user data scraper
teal-fm atproto
31
fork

Configure Feed

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

Merge pull request #60 from finfet-sh/bug/sp-fix-local-files-track-url

Spotify: Fix local files track URL

authored by matt.evil.gay and committed by

GitHub fb21b683 6ac5d464

+76
+13
service/spotify/spotify.go
··· 1 1 package spotify 2 2 3 3 import ( 4 + "crypto/sha256" 4 5 "encoding/base64" 5 6 "encoding/json" 6 7 "errors" ··· 433 434 } 434 435 } 435 436 437 + func generateLocalHash(track *models.Track) string { 438 + input := track.Name + track.Album + getFirstArtist(track) 439 + hash := sha256.Sum256([]byte(input)) 440 + return fmt.Sprintf("sp_local_%x", hash) 441 + } 442 + 436 443 func (s *Service) FetchCurrentTrack(userID int64) (*SpotifyTrackResponse, error) { 437 444 s.mu.RLock() 438 445 token, exists := s.userTokens[userID] ··· 567 574 ISRC: response.Item.ExternalIDs.ISRC, 568 575 HasStamped: false, 569 576 Timestamp: time.Now().UTC(), 577 + } 578 + 579 + // Local files have no URL. We hash the song name, album name, and 580 + // artist name to form a consistent URL. 581 + if track.URL == "" { 582 + track.URL = generateLocalHash(track) 570 583 } 571 584 572 585 return &SpotifyTrackResponse{Track: track, IsPlaying: response.IsPlaying}, nil
+63
service/spotify/spotify_test.go
··· 7 7 "log" 8 8 "net/http" 9 9 "net/http/httptest" 10 + "strings" 10 11 "testing" 11 12 "time" 12 13 ··· 1350 1351 } 1351 1352 }) 1352 1353 } 1354 + 1355 + // ===== generateLocalHash Tests ===== 1356 + 1357 + func TestGenerateLocalHash(t *testing.T) { 1358 + t.Run("deterministic output", func(t *testing.T) { 1359 + track := createTestTrack("My Song", "My Artist", "", 240000, 0) 1360 + hash1 := generateLocalHash(track) 1361 + hash2 := generateLocalHash(track) 1362 + if hash1 != hash2 { 1363 + t.Errorf("Expected deterministic output, got %s and %s", hash1, hash2) 1364 + } 1365 + }) 1366 + 1367 + t.Run("has correct prefix", func(t *testing.T) { 1368 + track := createTestTrack("My Song", "My Artist", "", 240000, 0) 1369 + hash := generateLocalHash(track) 1370 + if !strings.HasPrefix(hash, "sp_local_") { 1371 + t.Errorf("Expected hash to start with 'sp_local_', got '%s'", hash) 1372 + } 1373 + }) 1374 + 1375 + t.Run("different tracks produce different hashes", func(t *testing.T) { 1376 + trackA := createTestTrack("Song A", "Artist A", "", 240000, 0) 1377 + trackB := createTestTrack("Song B", "Artist B", "", 240000, 0) 1378 + hashA := generateLocalHash(trackA) 1379 + hashB := generateLocalHash(trackB) 1380 + if hashA == hashB { 1381 + t.Errorf("Expected different hashes for different tracks, both got %s", hashA) 1382 + } 1383 + }) 1384 + 1385 + t.Run("uses Unknown Artist for empty artist list", func(t *testing.T) { 1386 + trackWithArtist := &models.Track{ 1387 + Name: "Local File", 1388 + Album: "My Album", 1389 + // Hardcoding the other song to Unknown Artist to show that they result in the same hash. 1390 + // This would (probably) never happen, but just for testing sake 1391 + Artist: []models.Artist{{Name: "Unknown Artist", ID: ""}}, 1392 + } 1393 + trackNoArtist := &models.Track{ 1394 + Name: "Local File", 1395 + Album: "My Album", 1396 + Artist: []models.Artist{}, 1397 + } 1398 + hashWith := generateLocalHash(trackWithArtist) 1399 + hashWithout := generateLocalHash(trackNoArtist) 1400 + if hashWith != hashWithout { 1401 + t.Errorf("Expected same hash when artist is 'Unknown Artist' vs empty list, got %s and %s", hashWith, hashWithout) 1402 + } 1403 + }) 1404 + 1405 + t.Run("album name affects hash", func(t *testing.T) { 1406 + trackA := createTestTrack("Same Song", "Same Artist", "", 240000, 0) 1407 + trackB := createTestTrack("Same Song", "Same Artist", "", 240000, 0) 1408 + trackB.Album = "Different Album" 1409 + hashA := generateLocalHash(trackA) 1410 + hashB := generateLocalHash(trackB) 1411 + if hashA == hashB { 1412 + t.Errorf("Expected different hashes for different albums, both got %s", hashA) 1413 + } 1414 + }) 1415 + }