[GH-ISSUE #472] Not able to get playlist, when reading token from a file #155

Closed
opened 2026-02-27 20:23:27 +03:00 by kerem · 1 comment
Owner

Originally created by @slyeet03 on GitHub (Apr 1, 2024).
Original GitHub issue: https://github.com/ramsayleung/rspotify/issues/472

Describe the bug
I stored the access token in a text file after the authorization process, and when i am trying to use that access token to get user's playlist then it is returning nothing.
When I run it the first time it works flawlessly.

To Reproduce
I have this code for authorisation:

const TOKEN_FILE: &str = "token.txt";

#[derive(Debug)]
pub struct SpotifyClient {
    pub spotify: AuthCodeSpotify,
    pub token: Option<Token>,
}

pub async fn get_spotify_client() -> Result<SpotifyClient, ClientError> {
    dotenv().ok();
    let client_id = env::var("CLIENT_ID").expect("You've not set the CLIENT_ID");
    let client_secret_id =
        env::var("CLIENT_SECRET_ID").expect("You've not set the CLIENT_SECRET_ID");

    // Using every possible scope
    let scopes = scopes!(
        "user-read-email",
        "user-read-private",
        "user-top-read",
        "user-read-recently-played",
        "user-follow-read",
        "user-library-read",
        "user-read-currently-playing",
        "user-read-playback-state",
        "user-read-playback-position",
        "playlist-read-collaborative",
        "playlist-read-private",
        "user-follow-modify",
        "user-library-modify",
        "user-modify-playback-state",
        "playlist-modify-public",
        "playlist-modify-private",
        "ugc-image-upload"
    );

    let mut oauth = OAuth::default();
    oauth.scopes = scopes;
    oauth.redirect_uri = "http://localhost:8888/callback".to_owned();

    let creds = Credentials::new(&client_id, &client_secret_id);
    let config = rspotify::Config::default();
    let spotify = AuthCodeSpotify::with_config(creds, oauth, config);

    let token = read_token_from_file().await;

    let mut spotify_client = SpotifyClient { spotify, token };

    if spotify_client.token.is_none() {
        let auth_url = spotify_client.spotify.get_authorize_url(true).unwrap();

        if webbrowser::open(&auth_url).is_err() {
            println!(
                "Failed to open the authorization URL. Please visit the URL manually: {}",
                auth_url
            );
        }

        println!("Enter redirected url:");
        let mut url_input = String::new();
        stdin().read_line(&mut url_input).unwrap();
        let url_string = &url_input.as_str();

        let url = Url::parse(url_string).expect("Failed to parse URL");
        let query_pairs = url.query_pairs();

        let mut code = String::new();
        let mut state = String::new();
        for (key, value) in query_pairs {
            if key == "code" {
                code = value.to_string();
            } else if key == "state" {
                state = value.to_string();
            }
        }

        spotify_client.spotify.request_token(&code.trim()).await?;
        spotify_client.token = spotify_client.spotify.token.lock().await.unwrap().clone();
        if let Some(t) = &spotify_client.token {
            write_token_to_file(t).await;
        }
    } else {
        let token = read_token_from_file().await;
        spotify_client.token = token;
    }

    Ok(spotify_client)
}

async fn read_token_from_file() -> Option<Token> {
    let path = PathBuf::from(TOKEN_FILE);
    if path.exists() {
        let mut file = File::open(path).expect("Failed to open token file");
        let mut contents = String::new();
        file.read_to_string(&mut contents)
            .expect("Failed to read token file");
        let token: Token = serde_json::from_str(&contents).unwrap();
        Some(token)
    } else {
        None
    }
}

async fn write_token_to_file(token: &Token) {
    let path = PathBuf::from(TOKEN_FILE);
    let mut file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(path)
        .expect("Failed to open token file");
    let json = serde_json::to_string(token).unwrap();
    file.write_all(json.as_bytes())
        .expect("Failed to write token to file");
}

and this for getting playlist:

async fn fetch_user_playlists() -> Result<(), ClientError> {
    let spotify_client = get_spotify_client().await?;
    println!("{:#?}", spotify_client);

    let mut playlists = Vec::new();
    let mut stream = spotify_client.spotify.current_user_playlists();

    while let Ok(Some(playlist)) = stream.try_next().await {
        println!("Playlist: {:#?}", playlist);
        playlists.push(playlist);
    }

    // Perform further processing on the `playlists` vector

    Ok(())
}

Expected behavior
To get a list of user's playlist.

Log/Output data
It returns nothing.

Additional context
I have checked the data stored, the token the client everything stores the correct value.

Originally created by @slyeet03 on GitHub (Apr 1, 2024). Original GitHub issue: https://github.com/ramsayleung/rspotify/issues/472 **Describe the bug** I stored the access token in a text file after the authorization process, and when i am trying to use that access token to get user's playlist then it is returning nothing. When I run it the first time it works flawlessly. **To Reproduce** I have this code for authorisation: ``` const TOKEN_FILE: &str = "token.txt"; #[derive(Debug)] pub struct SpotifyClient { pub spotify: AuthCodeSpotify, pub token: Option<Token>, } pub async fn get_spotify_client() -> Result<SpotifyClient, ClientError> { dotenv().ok(); let client_id = env::var("CLIENT_ID").expect("You've not set the CLIENT_ID"); let client_secret_id = env::var("CLIENT_SECRET_ID").expect("You've not set the CLIENT_SECRET_ID"); // Using every possible scope let scopes = scopes!( "user-read-email", "user-read-private", "user-top-read", "user-read-recently-played", "user-follow-read", "user-library-read", "user-read-currently-playing", "user-read-playback-state", "user-read-playback-position", "playlist-read-collaborative", "playlist-read-private", "user-follow-modify", "user-library-modify", "user-modify-playback-state", "playlist-modify-public", "playlist-modify-private", "ugc-image-upload" ); let mut oauth = OAuth::default(); oauth.scopes = scopes; oauth.redirect_uri = "http://localhost:8888/callback".to_owned(); let creds = Credentials::new(&client_id, &client_secret_id); let config = rspotify::Config::default(); let spotify = AuthCodeSpotify::with_config(creds, oauth, config); let token = read_token_from_file().await; let mut spotify_client = SpotifyClient { spotify, token }; if spotify_client.token.is_none() { let auth_url = spotify_client.spotify.get_authorize_url(true).unwrap(); if webbrowser::open(&auth_url).is_err() { println!( "Failed to open the authorization URL. Please visit the URL manually: {}", auth_url ); } println!("Enter redirected url:"); let mut url_input = String::new(); stdin().read_line(&mut url_input).unwrap(); let url_string = &url_input.as_str(); let url = Url::parse(url_string).expect("Failed to parse URL"); let query_pairs = url.query_pairs(); let mut code = String::new(); let mut state = String::new(); for (key, value) in query_pairs { if key == "code" { code = value.to_string(); } else if key == "state" { state = value.to_string(); } } spotify_client.spotify.request_token(&code.trim()).await?; spotify_client.token = spotify_client.spotify.token.lock().await.unwrap().clone(); if let Some(t) = &spotify_client.token { write_token_to_file(t).await; } } else { let token = read_token_from_file().await; spotify_client.token = token; } Ok(spotify_client) } async fn read_token_from_file() -> Option<Token> { let path = PathBuf::from(TOKEN_FILE); if path.exists() { let mut file = File::open(path).expect("Failed to open token file"); let mut contents = String::new(); file.read_to_string(&mut contents) .expect("Failed to read token file"); let token: Token = serde_json::from_str(&contents).unwrap(); Some(token) } else { None } } async fn write_token_to_file(token: &Token) { let path = PathBuf::from(TOKEN_FILE); let mut file = OpenOptions::new() .create(true) .write(true) .truncate(true) .open(path) .expect("Failed to open token file"); let json = serde_json::to_string(token).unwrap(); file.write_all(json.as_bytes()) .expect("Failed to write token to file"); } ``` and this for getting playlist: ``` async fn fetch_user_playlists() -> Result<(), ClientError> { let spotify_client = get_spotify_client().await?; println!("{:#?}", spotify_client); let mut playlists = Vec::new(); let mut stream = spotify_client.spotify.current_user_playlists(); while let Ok(Some(playlist)) = stream.try_next().await { println!("Playlist: {:#?}", playlist); playlists.push(playlist); } // Perform further processing on the `playlists` vector Ok(()) } ``` **Expected behavior** To get a list of user's playlist. **Log/Output data** It returns nothing. **Additional context** I have checked the data stored, the token the client everything stores the correct value.
kerem 2026-02-27 20:23:27 +03:00
Author
Owner

@slyeet03 commented on GitHub (Apr 6, 2024):

Found the solution, I just have to save the whole client itself instead of just the token.

<!-- gh-comment-id:2041036307 --> @slyeet03 commented on GitHub (Apr 6, 2024): Found the solution, I just have to save the whole client itself instead of just the token.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/rspotify#155
No description provided.