Last active
October 27, 2023 08:03
-
-
Save bethropolis/ce5c20b8b3a753625b1ac1fa0562d199 to your computer and use it in GitHub Desktop.
a program for getting artist and songs from spotify playlist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"encoding/json" | |
"fmt" | |
"net/http" | |
"os" | |
"strings" | |
) | |
type Track struct { | |
No int `json:"no"` | |
Song string `json:"song"` | |
Artist string `json:"artist"` | |
Cover string `json:"album_cover"` | |
} | |
func main() { | |
reader := bufio.NewReader(os.Stdin) | |
for { | |
authToken := GetAccessToken() // Use the function from spotify_auth.go to get the Spotify access token | |
fmt.Print("\nEnter the Spotify playlist ID: ") | |
playlistID, _ := reader.ReadString('\n') | |
playlistID = strings.TrimSpace(playlistID) | |
// Define the base URL for the Spotify API | |
baseURL := "https://api.spotify.com/v1/playlists/" + playlistID + "/tracks?offset=%d&limit=100" | |
// Create a slice to store the tracks | |
var trackData []Track | |
// Offset and limit for pagination | |
offset := 0 | |
limit := 100 | |
fmt.Println("\nFetching data...") | |
for { | |
// Make a GET request to the Spotify API | |
reqURL := fmt.Sprintf(baseURL, offset) | |
req, err := http.NewRequest("GET", reqURL, nil) | |
if err != nil { | |
fmt.Println("Error creating request:", err) | |
return | |
} | |
req.Header.Add("Authorization", "Bearer "+authToken) // Use the obtained access token | |
client := &http.Client{} | |
resp, err := client.Do(req) | |
if err != nil { | |
fmt.Println("Error making request:", err) | |
return | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode != http.StatusOK { | |
fmt.Println("Error: API request returned status", resp.Status) | |
return | |
} | |
// Parse the response and extract track data | |
var tracksResponse struct { | |
Items []struct { | |
AddedAt string `json:"added_at"` | |
AddedBy struct { | |
ID string `json:"id"` | |
} `json:"added_by"` | |
Track struct { | |
Name string `json:"name"` | |
Artists []struct { | |
Name string `json:"name"` | |
} `json:"artists"` | |
Album struct { | |
Images []struct { | |
URL string `json:"url"` | |
} `json:"images"` | |
} `json:"album"` | |
} `json:"track"` | |
} `json:"items"` | |
} | |
err = json.NewDecoder(resp.Body).Decode(&tracksResponse) | |
if err != nil { | |
fmt.Println("Error decoding response:", err) | |
return | |
} | |
// Extract and structure track data | |
for index, item := range tracksResponse.Items { | |
track := Track{ | |
No: offset + index + 1, | |
Song: item.Track.Name, | |
Artist: item.Track.Artists[0].Name, | |
} | |
if len(item.Track.Album.Images) > 0 { | |
track.Cover = item.Track.Album.Images[0].URL | |
} | |
trackData = append(trackData, track) | |
} | |
// Check if there are more tracks to fetch | |
if len(tracksResponse.Items) < limit { | |
fmt.Printf("Fetched %d tracks. Done.\n", offset+len(tracksResponse.Items)) | |
break | |
} | |
// Increment the offset for the next request | |
offset += limit | |
} | |
// Marshal the track data to JSON | |
jsonTrackData, err := json.MarshalIndent(trackData, "", " ") | |
if err != nil { | |
fmt.Println("Error marshalling track data:", err) | |
return | |
} | |
// Generate the JSON file name with the playlist ID | |
filename := "track_data_" + playlistID + ".json" | |
// Save the JSON data to a file | |
err = os.WriteFile(filename, jsonTrackData, 0644) // Use os.WriteFile instead of ioutil.WriteFile | |
if err != nil { | |
fmt.Println("Error saving track data to file:", err) | |
return | |
} | |
fmt.Printf("Track data saved to %s\n", filename) | |
// Ask the user if they want to fetch another playlist | |
fmt.Printf("\nDo you want to fetch another playlist? (yes/no): ") | |
answer, _ := reader.ReadString('\n') | |
answer = strings.TrimSpace(answer) | |
if answer != "yes" { | |
break | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/base64" | |
"encoding/json" | |
"fmt" | |
"net/http" | |
"net/url" | |
"strings" | |
"sync" | |
"time" | |
) | |
var ( | |
clientID = "SPOTIFY_CLIENT_TOKEN" | |
clientSecret = "SPOTIFY_CLIENT_SECRET" | |
authURL = "https://accounts.spotify.com/api/token" | |
authHeader string | |
token string | |
expiration time.Time | |
fetchMutex sync.Mutex | |
fetchOnce sync.Once | |
) | |
type SpotifyAuthResponse struct { | |
AccessToken string `json:"access_token"` | |
TokenType string `json:"token_type"` | |
ExpiresIn int `json:"expires_in"` | |
} | |
func init() { | |
authHeader = base64.StdEncoding.EncodeToString([]byte(clientID + ":" + clientSecret)) | |
} | |
func fetchAccessToken() error { | |
data := url.Values{} | |
data.Set("grant_type", "client_credentials") | |
body := strings.NewReader(data.Encode()) | |
client := &http.Client{} | |
req, err := http.NewRequest("POST", authURL, body) | |
if err != nil { | |
return err | |
} | |
req.Header.Set("Authorization", "Basic "+authHeader) | |
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | |
resp, err := client.Do(req) | |
if err != nil { | |
return err | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode != http.StatusOK { | |
return fmt.Errorf("Failed to obtain Spotify access token. Status code: %d", resp.StatusCode) | |
} | |
var authResponse SpotifyAuthResponse | |
err = json.NewDecoder(resp.Body).Decode(&authResponse) | |
if err != nil { | |
return err | |
} | |
token = authResponse.AccessToken | |
expiration = time.Now().Add(time.Second * time.Duration(authResponse.ExpiresIn)) | |
return nil | |
} | |
func GetAccessToken() string { | |
fetchOnce.Do(func() { | |
fmt.Println("Fetching new access token...") | |
err := fetchAccessToken() | |
if err != nil { | |
fmt.Println("Error fetching access token:", err) | |
} | |
}) | |
fetchMutex.Lock() | |
defer fetchMutex.Unlock() | |
if time.Now().After(expiration) { | |
err := fetchAccessToken() | |
if err != nil { | |
fmt.Println("Error fetching access token:", err) | |
} | |
} | |
fmt.Printf("Obtained access token :) \n") | |
return token | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
file structure
in the above
spotify_auth.go
replace the values for the variables below with your own
you can get your client token and client secret from developer.spotify.com
READ MORE HERE: https://developer.spotify.com/documentation/web-api/tutorials/code-flow
run the following in your folders directory:
initialize package:
run the program:
go run .
compile/build executable program: