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

clean up docs/comments

Changed files
+27 -14
oauth
service
spotify
+19 -3
.env.template
··· 1 - CLIENT_ID= 2 - CLIENT_SECRET= 3 - REDIRECT_URL= 1 + # Server configuration 2 + SERVER_PORT=8080 3 + SERVER_HOST=localhost 4 + 5 + # Spotify OAuth configuration 6 + SPOTIFY_CLIENT_ID= 7 + SPOTIFY_CLIENT_SECRET= 8 + SPOTIFY_AUTH_URL=https://accounts.spotify.com/authorize 9 + SPOTIFY_TOKEN_URL=https://accounts.spotify.com/api/token 10 + SPOTIFY_SCOPES=user-read-currently-playing user-read-email 11 + 12 + # Callback URLs 13 + CALLBACK_SPOTIFY=http://localhost:8080/callback/spotify 14 + 15 + # Tracker settings 16 + TRACKER_INTERVAL=30 17 + 18 + # Database settings 19 + DB_PATH=./piper.db
+6
README.md
··· 23 23 ``` 24 24 air 25 25 ``` 26 + 27 + air should automatically build and run piper, and watch for changes on relevant files. 28 + 29 + #### docker 30 + 31 + TODO
+1 -4
oauth/oauth2.go
··· 13 13 "golang.org/x/oauth2/spotify" 14 14 ) 15 15 16 - // OAuth2Service represents an OAuth2 service with PKCE support 17 16 type OAuth2Service struct { 18 17 config oauth2.Config 19 18 state string ··· 21 20 codeChallenge string 22 21 } 23 22 24 - // generateRandomState creates a random state string for CSRF protection 25 23 func generateRandomState() string { 26 24 b := make([]byte, 16) 27 25 rand.Read(b) ··· 32 30 func NewOAuth2Service(clientID, clientSecret, redirectURI string, scopes []string, provider string) *OAuth2Service { 33 31 var endpoint oauth2.Endpoint 34 32 35 - // Select the appropriate provider endpoint 36 33 switch strings.ToLower(provider) { 37 34 case "spotify": 38 35 endpoint = spotify.Endpoint 39 36 default: 40 - // Use custom endpoints if not a predefined provider 37 + // TODO: support custom endpoints plus lastfm 41 38 endpoint = oauth2.Endpoint{ 42 39 AuthURL: "https://example.com/auth", 43 40 TokenURL: "https://example.com/token",
+1 -6
oauth/oauth_manager.go
··· 14 14 SetAccessToken(token string) int64 15 15 } 16 16 17 - // OAuthServiceManager manages multiple OAuth services 17 + // manages multiple oauth2 client services 18 18 type OAuthServiceManager struct { 19 19 oauth2Services map[string]*OAuth2Service 20 20 sessionManager *session.SessionManager 21 21 mu sync.RWMutex 22 22 } 23 23 24 - // NewOAuthServiceManager creates a new OAuthServiceManager 25 24 func NewOAuthServiceManager() *OAuthServiceManager { 26 25 return &OAuthServiceManager{ 27 26 oauth2Services: make(map[string]*OAuth2Service), ··· 29 28 } 30 29 } 31 30 32 - // RegisterOAuth2Service adds a new OAuth2 service with PKCE to the manager 33 31 func (m *OAuthServiceManager) RegisterOAuth2Service(name string, service *OAuth2Service) { 34 32 m.mu.Lock() 35 33 defer m.mu.Unlock() 36 34 m.oauth2Services[name] = service 37 35 } 38 36 39 - // GetOAuth2Service retrieves an OAuth2 service by name 40 37 func (m *OAuthServiceManager) GetOAuth2Service(name string) (*OAuth2Service, bool) { 41 38 m.mu.RLock() 42 39 defer m.mu.RUnlock() ··· 44 41 return service, exists 45 42 } 46 43 47 - // HandleLogin creates a handler for the login endpoint for a specific service 48 44 func (m *OAuthServiceManager) HandleLogin(serviceName string) http.HandlerFunc { 49 45 return func(w http.ResponseWriter, r *http.Request) { 50 46 m.mu.RLock() ··· 60 56 } 61 57 } 62 58 63 - // HandleCallback creates a handler for the callback endpoint for a specific service 64 59 func (m *OAuthServiceManager) HandleCallback(serviceName string, tokenReceiver TokenReceiver) http.HandlerFunc { 65 60 return func(w http.ResponseWriter, r *http.Request) { 66 61 m.mu.RLock()
-1
service/spotify/playlists.go
··· 23 23 } 24 24 25 25 func (s *SpotifyService) getUserPlaylists(userID int64) (*PlaylistResponse, error) { 26 - 27 26 s.mu.RLock() 28 27 token, exists := s.userTokens[userID] 29 28 s.mu.RUnlock()