Skip to content

Commit

Permalink
Ramsay/update reqwest to 0.10 (#70)
Browse files Browse the repository at this point in the history
Ramsay/update reqwest to 0.10
  • Loading branch information
ramsayleung authored Jan 20, 2020
2 parents d3373ca + ab06041 commit d68ca7c
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 45 deletions.
3 changes: 3 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CLIENT_ID=e1dce60f1e274e20861ce5d96142a4d3
CLIENT_SECRET=23a3a18423b14bf383ce46c8ee271094
REDIRECT_URI=https://localhost:8888/callback
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
**/*.rs.bk
.idea/
*cache*
/.env
.tern-port
cmake-build-debug
*/.test_token
Expand Down
17 changes: 17 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,20 @@ rust:
matrix:
allow_failures:
- rust: nightly

script:
- cargo test
- cargo run --example artists_albums
- cargo run --example track
- cargo run --example artist_related_artists
- cargo run --example tracks
- cargo run --example artist_top_tracks
- cargo run --example user
- cargo run --example artists
- cargo run --example albums
- cargo run --example audios_features
- cargo run --example audio_analysis
- cargo run --example album_tracks
- cargo run --example audio_features
- cargo run --example artist
- cargo run --example album
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ log = "0.4"
percent-encoding = "1.0.1"
rand = "0.6.5"
random = "0.12.2"
reqwest = "=0.9.17"
reqwest ={ version = "0.10.1", features=["json","blocking"]}
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
Expand Down
47 changes: 26 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
[![Build Status](https://travis-ci.org/samrayleung/rspotify.svg?branch=master)](https://travis-ci.org/samrayleung/rspotify)
[![Crates.io](https://img.shields.io/crates/v/rspotify.svg)](https://crates.io/crates/rspotify)
[![Docs](https://docs.rs/rspotify/badge.svg)](https://docs.rs/crate/rspotify/)

# Rspotify - a Rust client for The Spotify Web API

## Disclaimer
This crate is heavily inspired by [spotipy](https://github.com/plamere/spotipy)-
A spotify api wrapper implemented in Python

This crate is heavily inspired by [spotipy](https://github.com/plamere/spotipy)- A spotify api wrapper implemented in Python

## Description

Rspotify is a lightweight wrapper for the [Spotify Web API](https://developer.spotify.com/web-api/) It includes helper functions for
**all Spotify's endpoints**, such as fetching metadata (search and look-up of
albums, artists, tracks, playlists, new releases) and user's information (follow
**all Spotify's endpoints**, such as fetching metadata (search and look-up of albums, artists, tracks, playlists, new releases) and user's information (follow
users, artists and playlists, and saved tracks management).

## Features
*rspotify* supports all of the features of the Spotify Web API including access
to all end points, and support for user authorization, notes that before
accessing to any end points, you need to be authorized. For details on the
capabilities you are encouraged to review the [Spotify Web Endpoint
Reference](https://developer.spotify.com/web-api/endpoint-reference/)
documentation

*rspotify* supports all of the features of the Spotify Web API including access to all end points, and support for user authorization, notes that before accessing to any end points, you need to be authorized. For details on the capabilities you are encouraged to review the [Spotify Web Endpoint Reference](https://developer.spotify.com/web-api/endpoint-reference/) documentation.

Nowaday, thanks to [`reqwest`](https://docs.rs/reqwest/0.10.1/reqwest/#proxies), `rspotify` now supports system proxy by default. `Reqwest` System proxies look in environment variables to set HTTP or HTTPS proxies. `HTTP_PROXY` or `http_proxy` provide http proxies for http connections while `HTTPS_PROXY` or `https_proxy` provide HTTPS proxies for HTTPS connections.(Notes that `reqwest` system proxy doesn't support socks proxy for now, check [this issue](https://github.com/seanmonstar/reqwest/issues/790) for more details)

## Installation

Expand All @@ -27,26 +29,24 @@ cargo install rspotify
Or you could get it from [github](https://github.com/samrayleung/rspotify)

## Getting Started

### Authorization
Since all methods require user authorization now, you will need to
generate an authorization token that indicates that the user has granted
permission for your application to perform the given task. You will need to
register your app to get the credentials necessary to make authorized calls.

Even if your script does not have an accessible URL you need to specify one when
registering your application where the spotify authentication API will redirect
to after successful login. The URL doesn't need to work or be accessible, you
can specify "http://localhost/", after successful login you just need to copy
the "http://localhost/?code=..." URL from your browser and paste it to the
console where your application is running. For example:

Since all methods require user authorization now, you will need to generate an authorization token that indicates that the user has granted permission for your application to perform the given task. You will need to register your app to get the credentials necessary to make authorized calls.

Even if your script does not have an accessible URL you need to specify one when registering your application where the spotify authentication API will redirect to after successful login. The URL doesn't need to work or be accessible, you can specify "http://localhost/", after successful login you just need to copy the "http://localhost/?code=..." URL from your browser and paste it to the console where your application is running. For example:
![](./doc/images/rspotify.gif)

In order to help other developers to get used to `rspotify`, I registerd a Spotify account with temporary email. Your guys could test `rspotify` with this account's `CLIENT_ID` and `CLIENT_SECRET`, check [.env file](./.env) for more details.

## Examples

If you have a use case you are interested in, you could check the
[examples](./examples), which has all kinds of detailed examples. For example,
If you want to get recently played history, you could check
[current_user_recently_played](./examples/current_user_recently_played.rs). This is
the example code:

``` rust
extern crate rspotify;

Expand Down Expand Up @@ -91,15 +91,20 @@ fn main() {
}

```

### API Documentation

For more API information, you could check [rspotify Api documentation](https://docs.rs/crate/rspotify)

### CHANGELOG

Please see the [CHANGELOG](./CHANGELOG.md) for a release history.

### Contribution

If you find any problem or have suggestions about this crate, please submit an
issue. Moreover, any pull request ,code review and feedback are welcome.

### License

[MIT](./LICENSE)
2 changes: 1 addition & 1 deletion examples/audio_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn main() {
let spotify = Spotify::default()
.client_credentials_manager(client_credential)
.build();
let track = "3JIxjvbbDrA9ztYlNcp3yL";
let track = "06AKEBrKUckW0KREUWRnvT";
let analysis = spotify.audio_analysis(track);
println!("{:?}", analysis);
}
4 changes: 2 additions & 2 deletions examples/current_user_saved_albums_contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ fn main() {
let mut album_ids = vec![];
let album_id1 = String::from("0pJJgBzj26qnE1nSQUxaB0");
let album_id2 = String::from("5ZAKzV4ZIa5Gt7z29OYHv0");
albums_ids.push(track_id2);
albums_ids.push(track_id1);
album_ids.push(album_id2);
album_ids.push(album_id1);
let result = spotify.current_user_saved_albums_contains(&album_ids);
println!("result:{:?}", result);
}
Expand Down
2 changes: 1 addition & 1 deletion examples/start_playback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() {
// this is the example device_id from spotify website,
// so it will raise a 403 error, just change this device_id to yours
let device_id = String::from("74ASZWbe4lXaubB36ztrGX");
let mut uris = vec!["spotify:track:4iV5W9uYEdYUVa79Axb7Rh".to_owned()];
let uris = vec!["spotify:track:4iV5W9uYEdYUVa79Axb7Rh".to_owned()];
match spotify.start_playback(Some(device_id), None, Some(uris), for_position(0), None) {
Ok(_) => println!("start playback successful"),
Err(_) => eprintln!("start playback failed"),
Expand Down
4 changes: 2 additions & 2 deletions examples/user_artist_check_follow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ fn main() {
let mut artist_ids = vec![];
let artist_id1 = String::from("74ASZWbe4lXaubB36ztrGX");
let artist_id2 = String::from("08td7MxkoHQkXnWAYD8d6Q");
artist_ids.push(artist_id1)
artist_ids.push(artist_id2)
artist_ids.push(artist_id1);
artist_ids.push(artist_id2);
let result = spotify.user_artist_check_follow(&artist_ids);
println!("result:{:?}", result);
}
Expand Down
2 changes: 1 addition & 1 deletion examples/user_playlist_change_detail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() {
// user_id and playlist_id to yours, or you will get a 403 forbidden error
let user_id = "2257tjys2e2u2ygfke42niy2q";
let playlist_id = "5jAOgWXCBKuinsGiZxjDQ5";
let mut playlist_name = "A New Playlist-update";
let playlist_name = "A New Playlist-update";
match spotify.user_playlist_change_detail(user_id,
playlist_id,
Some(playlist_name),
Expand Down
6 changes: 3 additions & 3 deletions src/spotify/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde_json;
use serde_json::Value;
use serde_json::map::Map;
use serde::de::Deserialize;
use reqwest::Client;
use reqwest::blocking::Client;
use reqwest::Method;
use reqwest::header::{AUTHORIZATION, CONTENT_TYPE, HeaderMap};
use reqwest::StatusCode;
Expand Down Expand Up @@ -62,8 +62,8 @@ impl fmt::Display for ApiError {
}
}
}
impl From<&reqwest::Response> for ApiError {
fn from(response: &reqwest::Response) -> Self {
impl From<&reqwest::blocking::Response> for ApiError {
fn from(response: &reqwest::blocking::Response) -> Self {
match response.status() {
StatusCode::UNAUTHORIZED => ApiError::Unauthorized,
StatusCode::TOO_MANY_REQUESTS => {
Expand Down
17 changes: 8 additions & 9 deletions src/spotify/oauth2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
// use 3rd party library
use chrono::prelude::*;
use serde_json;
use reqwest::Client;
use reqwest::blocking::Client;
use dotenv::dotenv;
use percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET};

// use built-in library
use std::env;
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use std::error::Error;
use std::fs::File;
use std::iter::FromIterator;
use std::io::prelude::*;
Expand Down Expand Up @@ -271,14 +270,14 @@ impl SpotifyOAuth {
let mut file = match File::open(&self.cache_path) {
Ok(file) => file,
Err(why) => {
error!("couldn't open {}: {:?}", display, why.description());
error!("couldn't open {}: {:?}", display, why.to_string());
return None;
}
};
let mut token_info_string = String::new();
match file.read_to_string(&mut token_info_string) {
Err(why) => {
error!("couldn't read {}: {}", display, why.description());
error!("couldn't read {}: {}", display, why.to_string());
None
}
Ok(_) => {
Expand Down Expand Up @@ -321,7 +320,7 @@ impl SpotifyOAuth {
}
Err(why) => {
panic!("couldn't convert token_info to string: {} ",
why.description());
why.to_string());
}
}
} else {
Expand Down Expand Up @@ -385,7 +384,7 @@ impl SpotifyOAuth {
}
Err(why) => {
panic!("couldn't convert token_info to string: {} ",
why.description());
why.to_string());
}
}
} else {
Expand Down Expand Up @@ -504,20 +503,20 @@ mod tests {
spotify_oauth.save_token_info(&token_info_string);
let display = spotify_oauth.cache_path.display();
let mut file = match File::open(&spotify_oauth.cache_path) {
Err(why) => panic!("couldn't open {}: {}", display, why.description()),
Err(why) => panic!("couldn't open {}: {}", display, why.to_string()),
Ok(file) => file,
};
let mut token_info_string_from_file = String::new();
match file.read_to_string(&mut token_info_string_from_file) {
Err(why) => panic!("couldn't read {}: {}", display, why.description()),
Err(why) => panic!("couldn't read {}: {}", display, why.to_string()),
Ok(_) => {
assert_eq!(token_info_string, token_info_string_from_file);
}
}
}
Err(why) => {
panic!("couldn't convert token_info to string: {} ",
why.description())
why.to_string())
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/test_with_credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ fn test_audio_analysis() {
let spotify = Spotify::default()
.client_credentials_manager(CLIENT_CREDENTIAL.lock().unwrap().clone())
.build();
let track = "3JIxjvbbDrA9ztYlNcp3yL";
let track = "06AKEBrKUckW0KREUWRnvT";
let analysis = spotify.audio_analysis(track);
assert!(analysis.is_ok());
}
Expand Down
8 changes: 6 additions & 2 deletions tests/test_with_oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use rspotify::spotify::senum::{Country, TimeRange, RepeatState};
use rspotify::spotify::util::get_token;
use rspotify::spotify::model::offset::for_position;

// Because of all these tests need to poll up the browser, it is impossible to
// run in a CI envirnment like travis, so I just ignore them all. You could
// delete the #[ignore] tag, and run it on your local machine.

#[test]#[ignore]
fn test_categories() {
let mut oauth = SpotifyOAuth::default().scope("user-follow-read").build();
Expand Down Expand Up @@ -658,7 +662,7 @@ fn test_start_playback() {
.client_credentials_manager(client_credential)
.build();
let device_id = String::from("74ASZWbe4lXaubB36ztrGX");
let mut uris = vec!["spotify:track:4iV5W9uYEdYUVa79Axb7Rh".to_owned()];
let uris = vec!["spotify:track:4iV5W9uYEdYUVa79Axb7Rh".to_owned()];
let result = spotify.start_playback(Some(device_id), None, Some(uris), for_position(0), None);
assert!(result.is_ok());
}
Expand Down Expand Up @@ -821,7 +825,7 @@ fn test_user_playlist_change_detail() {
.build();
let user_id = "2257tjys2e2u2ygfke42niy2q";
let playlist_id = "5jAOgWXCBKuinsGiZxjDQ5";
let mut playlist_name = "A New Playlist-update";
let playlist_name = "A New Playlist-update";
let result = spotify.user_playlist_change_detail(user_id,
playlist_id,
Some(playlist_name),
Expand Down

0 comments on commit d68ca7c

Please sign in to comment.