Skip to content

Commit

Permalink
Merge pull request #110 from ramsayleung/reduce-core-dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
ramsayleung authored Aug 28, 2020
2 parents 9fd5173 + 170c279 commit 0112977
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 88 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --features env-file

lints:
name: Lints
Expand Down
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
## 0.11 (unreleased)

- Rewritten documentation in hopes that it's easier to get started with Rspotify.
- Reduced the number of examples. Instead of having an example for each endpoint, which is repetitive and unhelpful for newcomers, some real-life examples are now included. If you'd like to add your own example, please do!
- Add `add_item_to_queue` endpoint.
- Fix typo in `transfer_playback`: `device_id` to `device_ids`.
- Fix race condition when using a single client from multiple threads (see [#114](https://github.com/ramsayleung/rspotify/pull/114) for more information).
- Rspotify should now be considerably lighter and less bloated:
+ Remove unused dependencies: `base64`, `env_logger`, `derive_builder`, `random`, `url`. <!-- NOTE: derive_builder might not be removed after all -->
+ Remove `itertools` dependency by using the standard library.
+ Remove `rand` in place of `getrandom` to [reduce total dependencies and compile times](https://github.com/ramsayleung/rspotify/issues/108#issuecomment-673587185).
+ `webbrowser` and access to functions that use it (`util::get_token`, `util::get_token_without_cache` and `util::request_token`) can be disabled for the non-CLI applications with the `browser` feature. It's still enabled by default due to [its frequent usage](https://github.com/ramsayleung/rspotify/pull/110#issuecomment-674410604).
+ Reduced repetitive code and boilerplate internally in several places.
- Updated dependencies to the latest versions, integrated Dependabot to keep track of them.

**Breaking changes:**
- `dotenv` support is now optional. You can enable it with the `env-file` feature to have the same behavior as before.
- Fix typo in `user_playlist_remove_specific_occurrenes_of_tracks`, now it's `user_playlist_remove_specific_occurrences_of_tracks`.

## 0.10 (2020/07/01)

- Add `get_access_token_without_cache` and `refresh_access_token_without_cache` to get and refresh access token without caching it.
Expand Down Expand Up @@ -39,7 +58,7 @@
- Code optimize, remove a unnecessary mut and add a missing reference
- Fix reqwest breaking change
- Add missing devices type
- Add `position_ms` to `start_playback
- Add `position_ms` to `start_playback`

## 0.6 (2019/07/22)

Expand Down
55 changes: 43 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,34 @@ name = "rspotify"
version = "0.10.0"
license = "MIT"
readme = "README.md"
description="Spotify API wrapper"
homepage="https://github.com/samrayleung/rspotify"
repository="https://github.com/samrayleung/rspotify"
keywords=["spotify","api"]
description = "Spotify API wrapper"
homepage = "https://github.com/ramsayleung/rspotify"
repository = "https://github.com/ramsayleung/rspotify"
keywords = ["spotify","api"]
edition = "2018"

[dependencies]
chrono = { version = "0.4.13", features = ["serde", "rustc-serialize"] }
dotenv = "0.15.0"
dotenv = { version = "0.15.0", optional = true }
failure = "0.1.8"
lazy_static = "1.4.0"
log = "0.4.11"
percent-encoding = "2.1.0"
rand = "0.7.3"
getrandom = "0.1.14"
reqwest = { version = "0.10.7", features = ["json", "socks"], default-features = false }
serde = { version = "1.0.115", features = ["derive"] }
serde_json = "1.0.57"
webbrowser = "0.5.5"
webbrowser = { version = "0.5.5", optional = true }

[dev-dependencies]
async_once = { version = "0.1.0", features = ["tokio"] }
tokio = { version = "0.2.22", features = ["full"] }
futures = "0.3.5"

[features]
default = ["reqwest/default-tls"]
default = ["reqwest/default-tls", "browser"]
env-file = ["dotenv"]
browser = ["webbrowser"]
blocking = ["reqwest/default-tls", "reqwest/blocking"]
# Passing the TLS features to reqwest.
native-tls = ["reqwest/native-tls"]
Expand All @@ -39,22 +41,51 @@ native-tls-vendored-blocking = ["reqwest/native-tls-vendored", "reqwest/blocking
rustls-tls = ["reqwest/rustls-tls"]
rustls-tls-blocking = ["reqwest/rustls-tls", "reqwest/blocking"]

[package.metadata.docs.rs]
# Also documenting the blocking module
features = ["blocking"]

[[example]]
name = "album"
required-features = ["env-file"]
path = "examples/album.rs"

[[example]]
name = "current_user_recently_played"
required-features = ["env-file"]
path = "examples/current_user_recently_played.rs"

[[example]]
name = "track"
required-features = ["env-file"]
path = "examples/track.rs"

[[example]]
name = "tracks"
required-features = ["env-file"]
path = "examples/tracks.rs"

[[example]]
name = "with_refresh_token"
required-features = ["env-file"]
path = "examples/with_refresh_token.rs"

[[example]]
name = "device"
required-features = ["blocking"]
required-features = ["env-file", "blocking"]
path = "examples/blocking/device.rs"

[[example]]
name = "me"
required-features = ["blocking"]
required-features = ["env-file", "blocking"]
path = "examples/blocking/me.rs"

[[example]]
name = "blocking_search"
required-features = ["blocking"]
required-features = ["env-file", "blocking"]
path = "examples/blocking/search.rs"

[[example]]
name = "seek_track"
required-features = ["blocking"]
required-features = ["env-file", "blocking"]
path = "examples/blocking/seek_track.rs"
6 changes: 2 additions & 4 deletions examples/webapp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ version = "0.1.0"
authors = ["Ramsay <ramsayleung@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rocket = "0.4.5"
rocket_contrib = {version = "0.4.5", features= ["tera_templates"]}
rspotify = {version = "0.10.0", features = ["blocking"]}
rocket_contrib = { version = "0.4.5", features = ["tera_templates"] }
rspotify = { path = "../..", features = ["blocking"] }
23 changes: 11 additions & 12 deletions examples/webapp/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
//! In this example, the token is saved into a cache file. If you are building a real-world web
//! app, it's easy to save token into database, by calling the function
//! `util::get_token_without_cache()`, instead of `util::get_token()`, which saves token by
//! default.
#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate rocket;

use rocket::http::Cookie;
use rocket::http::Cookies;
use rocket::http::{Cookie, Cookies};
use rocket::response::Redirect;
use rocket_contrib::json;
use rocket_contrib::json::JsonValue;
use rocket_contrib::templates::Template;
use rspotify::blocking::client::Spotify;
use std::fs;
use std::path::Path;
use std::path::PathBuf;

use rspotify::blocking::oauth2::SpotifyClientCredentials;
use rspotify::blocking::oauth2::SpotifyOAuth;
use rspotify::blocking::oauth2::{SpotifyClientCredentials, SpotifyOAuth};
use rspotify::blocking::util;
use std::env;

use std::env;
use std::collections::HashMap;
/// In this example, the token is saved into a cache file. If you are building a real-world web
/// app, it's easy to save token into database, by calling the function
/// `util::get_token_without_cache()`, instead of `util::get_token()`, which saves token by
/// default.
use std::fs;
use std::path::{Path, PathBuf};

#[derive(Debug, Responder)]
pub enum AppResponse {
Expand Down
3 changes: 0 additions & 3 deletions examples/with_refresh_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
//! tokens](https://github.com/felix-hilden/tekore/issues/86),
//! so in the case of Spotify it doesn't seem to revoke them at all.
use dotenv::dotenv;

use rspotify::client::Spotify;
use rspotify::oauth2::{SpotifyClientCredentials, SpotifyOAuth};
use rspotify::util::get_token_without_cache;
Expand Down Expand Up @@ -81,7 +79,6 @@ async fn do_things(spotify: Spotify) {
#[tokio::main]
async fn main() {
// The default credentials from the `.env` file will be used by default.
dotenv().ok();
let mut oauth = SpotifyOAuth::default()
.scope("user-follow-read user-follow-modify")
.build();
Expand Down
41 changes: 31 additions & 10 deletions src/blocking/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,16 +823,37 @@ impl Spotify {
self.convert_result::<CUDResult>(&result)
}

/// [remove tracks playlist](https://developer.spotify.com/web-api/remove-tracks-playlist/)
/// Removes all occurrences of the given tracks from the given playlist
/// Parameters:
/// - user_id - the id of the user
/// - playlist_id - the id of the playlist
/// - tracks - an array of map containing Spotify URIs of the tracks
/// to remove with their current positions in the playlist. For example:
/// { "tracks": [{ "uri": "spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "positions": [0,3] },{
/// "uri": "spotify:track:1301WleyT98MSxVHPZCA6M", "positions": [7] }] }
/// - snapshot_id - optional id of the playlist snapshot
/// [remove tracks playlist
/// ](https://developer.spotify.com/web-api/remove-tracks-playlist/).
///
/// Removes specfic occurrences of the given tracks from the given
/// playlist. Parameters:
///
/// - user_id: the id of the user
/// - playlist_id: the id of the playlist
/// - tracks: an array of map containing Spotify URIs of the tracks to remove
/// with their current positions in the playlist. For example:
///
/// ```json
/// {
/// "tracks":[
/// {
/// "uri":"spotify:track:4iV5W9uYEdYUVa79Axb7Rh",
/// "positions":[
/// 0,
/// 3
/// ]
/// },
/// {
/// "uri":"spotify:track:1301WleyT98MSxVHPZCA6M",
/// "positions":[
/// 7
/// ]
/// }
/// ]
/// }
/// ```
/// - snapshot_id: optional id of the playlist snapshot
pub fn user_playlist_remove_specific_occurrenes_of_tracks(
&self,
user_id: &str,
Expand Down
11 changes: 8 additions & 3 deletions src/blocking/oauth2.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! The module contains function about authorization and client-credential
// use 3rd party library
use chrono::prelude::*;
use dotenv::dotenv;
use log::{debug, error, trace};
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use reqwest::blocking::Client;
Expand Down Expand Up @@ -98,7 +97,10 @@ impl TokenInfo {
impl SpotifyClientCredentials {
/// Build default SpotifyClientCredentials
pub fn default() -> SpotifyClientCredentials {
dotenv().ok();
#[cfg(feature = "env-file")]
{
dotenv::dotenv().ok();
}
let client_id = env::var("CLIENT_ID").unwrap_or_default();
let client_secret = env::var("CLIENT_SECRET").unwrap_or_default();
trace!(
Expand Down Expand Up @@ -207,7 +209,10 @@ impl SpotifyOAuth {
// }

pub fn default() -> SpotifyOAuth {
dotenv().ok();
#[cfg(feature = "env-file")]
{
dotenv::dotenv().ok();
}
let client_id = env::var("CLIENT_ID").unwrap_or_default();
let client_secret = env::var("CLIENT_SECRET").unwrap_or_default();
let redirect_uri = env::var("REDIRECT_URI").unwrap_or_default();
Expand Down
21 changes: 14 additions & 7 deletions src/blocking/util.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
//! Utils function
use chrono::prelude::*;
use rand::distributions::Alphanumeric;
use rand::{self, Rng};
use webbrowser;
use getrandom::getrandom;

use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::io;
use std::string::ToString;

use super::oauth2::{SpotifyOAuth, TokenInfo};
Expand All @@ -19,9 +16,14 @@ pub fn datetime_to_timestamp(elapsed: u32) -> i64 {
}
/// Generate `length` random chars
pub fn generate_random_string(length: usize) -> String {
rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(length)
let alphanum: &[u8] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".as_bytes();
let mut buf = vec![0u8; length];
getrandom(&mut buf).unwrap();
let range = alphanum.len();

buf.iter()
.map(|byte| alphanum[*byte as usize % range] as char)
.collect()
}

Expand Down Expand Up @@ -71,6 +73,7 @@ pub fn convert_str_to_map(query_str: &mut str) -> HashMap<&str, &str> {
map
}

#[cfg(feature = "browser")]
pub fn request_token(spotify_oauth: &mut SpotifyOAuth) {
let state = generate_random_string(16);
let auth_url = spotify_oauth.get_authorize_url(Some(&state), None);
Expand Down Expand Up @@ -98,7 +101,9 @@ pub fn process_token_without_cache(
}

/// Get tokenInfo by Authorization
#[cfg(feature = "browser")]
pub fn get_token(spotify_oauth: &mut SpotifyOAuth) -> Option<TokenInfo> {
use std::io;
match spotify_oauth.get_cached_token() {
Some(token_info) => Some(token_info),
None => {
Expand All @@ -114,7 +119,9 @@ pub fn get_token(spotify_oauth: &mut SpotifyOAuth) -> Option<TokenInfo> {
}

/// Get tokenInfo by Authorization without cache.
#[cfg(feature = "browser")]
pub fn get_token_without_cache(spotify_oauth: &mut SpotifyOAuth) -> Option<TokenInfo> {
use std::io;
request_token(spotify_oauth);
println!("Enter the URL you were redirected to: ");
let mut input = String::new();
Expand Down
34 changes: 26 additions & 8 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,14 +808,32 @@ impl Spotify {
/// [remove tracks playlist](https://developer.spotify.com/web-api/remove-tracks-playlist/)
/// Removes specfic occurrences of the given tracks from the given playlist
/// Parameters:
/// - user_id - the id of the user
/// - playlist_id - the id of the playlist
/// - tracks - an array of map containing Spotify URIs of the tracks
/// to remove with their current positions in the playlist. For example:
/// { "tracks": [{ "uri": "spotify:track:4iV5W9uYEdYUVa79Axb7Rh", "positions": [0,3] },{
/// "uri": "spotify:track:1301WleyT98MSxVHPZCA6M", "positions": [7] }] }
/// - snapshot_id - optional id of the playlist snapshot
pub async fn user_playlist_remove_specific_occurrenes_of_tracks(
/// - user_id: the id of the user
/// - playlist_id: the id of the playlist
/// - tracks: an array of map containing Spotify URIs of the tracks to remove
/// with their current positions in the playlist. For example:
///
/// ```json
/// {
/// "tracks":[
/// {
/// "uri":"spotify:track:4iV5W9uYEdYUVa79Axb7Rh",
/// "positions":[
/// 0,
/// 3
/// ]
/// },
/// {
/// "uri":"spotify:track:1301WleyT98MSxVHPZCA6M",
/// "positions":[
/// 7
/// ]
/// }
/// ]
/// }
/// ```
/// - snapshot_id: optional id of the playlist snapshot
pub async fn user_playlist_remove_specific_occurrences_of_tracks(
&self,
user_id: &str,
playlist_id: &str,
Expand Down
Loading

0 comments on commit 0112977

Please sign in to comment.