#![allow(deprecated)]
mod util;
use rspotify::{
clients::pagination::Paginator,
model::{
AlbumId, ArtistId, Country, CurrentPlaybackContext, Device, EpisodeId, FullPlaylist,
ItemPositions, Market, Offset, PlaylistId, RecommendationsAttribute, RepeatState,
SearchType, TimeLimits, TimeRange, TrackId, UserId,
},
prelude::*,
scopes, AuthCodeSpotify, ClientResult, OAuth, Token,
};
use chrono::{prelude::*, Duration};
use maybe_async::maybe_async;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;
#[cfg(not(target_arch = "wasm32"))]
fn get_access_tokens() -> (Option<String>, Option<String>) {
use std::env;
(
env::var("RSPOTIFY_ACCESS_TOKEN").ok(),
env::var("RSPOTIFY_REFRESH_TOKEN").ok(),
)
}
#[cfg(target_arch = "wasm32")]
fn get_access_tokens() -> (Option<String>, Option<String>) {
let access_token = option_env!("RSPOTIFY_ACCESS_TOKEN").map(|s| s.to_string());
let refresh_token = option_env!("RSPOTIFY_REFRESH_TOKEN").map(|s| s.to_string());
(access_token, refresh_token)
}
#[maybe_async]
pub async fn oauth_client() -> AuthCodeSpotify {
let _ = env_logger::builder().is_test(true).try_init();
let (access_token, refresh_token) = get_access_tokens();
if let Some(access_token) = access_token {
let tok = Token {
access_token,
..Default::default()
};
AuthCodeSpotify::from_token(tok)
} else if let Some(refresh_token) = refresh_token {
let creds = util::get_credentials();
let scopes = scopes!(
"playlist-modify-private",
"playlist-modify-public",
"playlist-read-collaborative",
"playlist-read-private",
"ugc-image-upload",
"user-follow-modify",
"user-follow-read",
"user-library-modify",
"user-library-read",
"user-modify-playback-state",
"user-read-currently-playing",
"user-read-email",
"user-read-playback-position",
"user-read-playback-state",
"user-read-private",
"user-read-recently-played",
"user-top-read",
"user-library-modify",
"user-follow-modify",
"playlist-modify-public"
);
let oauth = OAuth::from_env(scopes).unwrap();
let token = Token {
refresh_token: Some(refresh_token),
..Default::default()
};
let spotify = AuthCodeSpotify::new(creds, oauth);
*spotify.token.lock().await.unwrap() = Some(token);
spotify.refresh_token().await.unwrap();
spotify
} else {
panic!(
"No access tokens configured. Please set `RSPOTIFY_ACCESS_TOKEN` \
or `RSPOTIFY_REFRESH_TOKEN`, which can be obtained with the \
`oauth_tokens` example: \
cargo run --example oauth_tokens --features env-file,cli,client-reqwest,reqwest-rustls-tls --no-default-features
"
)
}
}
#[maybe_async]
async fn fetch_all<T>(paginator: Paginator<'_, ClientResult<T>>) -> Vec<T> {
#[cfg(feature = "__async")]
{
use futures::stream::TryStreamExt;
paginator.try_collect::<Vec<_>>().await.unwrap()
}
#[cfg(feature = "__sync")]
{
paginator.filter_map(|a| a.ok()).collect::<Vec<_>>()
}
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_category_playlists() {
oauth_client()
.await
.category_playlists_manual(
"pop",
Some(Market::Country(Country::UnitedStates)),
Some(10),
None,
)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_playback() {
oauth_client()
.await
.current_playback(None, None::<&[_]>)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_playing() {
oauth_client()
.await
.current_playing(None, None::<&[_]>)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_user_followed_artists() {
oauth_client()
.await
.current_user_followed_artists(None, Some(10))
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_user_playing_track() {
oauth_client()
.await
.current_user_playing_item()
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_user_recently_played() {
let limit = TimeLimits::After(Utc::now() - Duration::try_days(2).unwrap());
oauth_client()
.await
.current_user_recently_played(Some(10), Some(limit))
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_user_saved_albums() {
let album_ids = [
AlbumId::from_id("6akEvsycLGftJxYudPjmqK").unwrap(),
AlbumId::from_id("628oezqK2qfmCjC6eXNors").unwrap(),
];
let client = oauth_client().await;
client
.current_user_saved_albums_add(album_ids.iter().map(AlbumId::as_ref))
.await
.unwrap();
let all_albums = fetch_all(client.current_user_saved_albums(None)).await;
let _albums_from_token =
fetch_all(client.current_user_saved_albums(Some(Market::FromToken))).await;
let all_uris = all_albums
.into_iter()
.map(|a| a.album.id)
.collect::<Vec<_>>();
assert!(
album_ids.iter().all(|item| all_uris.contains(item)),
"couldn't find the new saved albums"
);
client
.current_user_saved_albums_delete(album_ids)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_user_saved_tracks_add() {
let client = oauth_client().await;
let tracks_ids = [
TrackId::from_uri("spotify:track:4iV5W9uYEdYUVa79Axb7Rh").unwrap(),
TrackId::from_uri("spotify:track:1301WleyT98MSxVHPZCA6M").unwrap(),
];
client
.current_user_saved_tracks_add(tracks_ids.iter().map(TrackId::as_ref))
.await
.unwrap();
let contains = client
.current_user_saved_tracks_contains(tracks_ids.iter().map(TrackId::as_ref))
.await
.unwrap();
assert!(contains.into_iter().all(|x| x));
let all = fetch_all(client.current_user_saved_tracks(None)).await;
let all = all
.into_iter()
.filter_map(|saved| saved.track.id)
.collect::<Vec<_>>();
assert!(tracks_ids.iter().all(|track| all.contains(track)));
client
.current_user_saved_tracks_delete(tracks_ids)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_user_top_artists() {
oauth_client()
.await
.current_user_top_artists_manual(Some(TimeRange::ShortTerm), Some(10), Some(0))
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_current_user_top_tracks() {
oauth_client()
.await
.current_user_top_tracks_manual(Some(TimeRange::ShortTerm), Some(10), Some(0))
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_featured_playlists() {
let now: DateTime<Utc> = Utc::now();
oauth_client()
.await
.featured_playlists(None, None, Some(now), Some(10), Some(0))
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_me() {
oauth_client().await.me().await.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_playback() {
let client = oauth_client().await;
let uris = [
PlayableId::Track(TrackId::from_uri("spotify:track:4iV5W9uYEdYUVa79Axb7Rh").unwrap()),
PlayableId::Track(TrackId::from_uri("spotify:track:2DzSjFQKetFhkFCuDWhioi").unwrap()),
PlayableId::Episode(EpisodeId::from_id("0lbiy3LKzIY2fnyjioC11p").unwrap()),
];
let devices = client.device().await.unwrap();
let backup = client.current_playback(None, None::<&[_]>).await.unwrap();
for (i, device) in devices.iter().enumerate() {
let device_id = device.id.as_ref().unwrap();
let next_device_id = devices
.get(i + 1)
.unwrap_or(&devices[0])
.id
.as_ref()
.unwrap();
client
.start_uris_playback(
uris.iter().map(PlayableId::as_ref),
Some(device_id),
Some(Offset::Position(chrono::Duration::zero())),
None,
)
.await
.unwrap();
for i in 0..uris.len() - 1 {
client.next_track(Some(device_id)).await.unwrap();
if i != 0 {
client.previous_track(Some(device_id)).await.unwrap();
client.next_track(Some(device_id)).await.unwrap();
}
let playback = client.current_playback(None, None::<&[_]>).await.unwrap();
if let Some(playback) = playback {
if playback.is_playing {
client.pause_playback(Some(device_id)).await.unwrap();
client.resume_playback(None, None).await.unwrap();
} else {
client.resume_playback(None, None).await.unwrap();
client.pause_playback(Some(device_id)).await.unwrap();
}
}
}
client
.transfer_playback(next_device_id, Some(true))
.await
.unwrap();
}
if let Some(backup) = &backup {
let uri = backup.item.as_ref().map(|item| item.id());
if let Some(uri) = uri {
let offset = None;
let device = backup.device.id.as_deref();
let position = backup.progress;
client
.start_uris_playback(uri, device, offset, position)
.await
.unwrap();
}
}
if !backup.map(|b| b.is_playing).unwrap_or(false) {
client.pause_playback(None).await.unwrap();
}
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_recommendations() {
let seed_artists = [ArtistId::from_id("4NHQUGzhtTLFvgF5SZesLK").unwrap()];
let seed_tracks = [TrackId::from_id("0c6xIDDpzE81m2q797ordA").unwrap()];
let attributes = [
RecommendationsAttribute::MinEnergy(0.4),
RecommendationsAttribute::MinPopularity(50),
];
oauth_client()
.await
.recommendations(
attributes,
Some(seed_artists),
None::<Vec<&str>>,
Some(seed_tracks),
Some(Market::Country(Country::UnitedStates)),
Some(10),
)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_repeat() {
let client = oauth_client().await;
let backup = client.current_playback(None, None::<&[_]>).await.unwrap();
client.repeat(RepeatState::Off, None).await.unwrap();
if let Some(backup) = backup {
client.repeat(backup.repeat_state, None).await.unwrap()
}
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_search_album() {
let query = "album:arrival artist:abba";
oauth_client()
.await
.search(query, SearchType::Album, None, None, Some(10), Some(0))
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_search_artist() {
let query = "tania bowra";
oauth_client()
.await
.search(
query,
SearchType::Artist,
Some(Market::Country(Country::UnitedStates)),
None,
Some(10),
Some(0),
)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_search_playlist() {
let query = "\"doom metal\"";
oauth_client()
.await
.search(
query,
SearchType::Playlist,
Some(Market::Country(Country::UnitedStates)),
None,
Some(10),
Some(0),
)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_search_track() {
let query = "abba";
oauth_client()
.await
.search(
query,
SearchType::Track,
Some(Market::Country(Country::UnitedStates)),
None,
Some(10),
Some(0),
)
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_search_show() {
let query = "99% invisible";
oauth_client()
.await
.search(query, SearchType::Show, None, None, None, Some(0))
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_seek_track() {
let client = oauth_client().await;
let backup = client.current_playback(None, None::<&[_]>).await.unwrap();
client
.seek_track(chrono::Duration::try_seconds(25).unwrap(), None)
.await
.unwrap();
if let Some(CurrentPlaybackContext {
progress: Some(progress),
..
}) = backup
{
client.seek_track(progress, None).await.unwrap();
}
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_shuffle() {
let client = oauth_client().await;
let backup = client.current_playback(None, None::<&[_]>).await.unwrap();
client.shuffle(true, None).await.unwrap();
if let Some(backup) = backup {
client.shuffle(backup.shuffle_state, None).await.unwrap();
}
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_user_follow_artist() {
let client = oauth_client().await;
let artists = [
ArtistId::from_id("74ASZWbe4lXaubB36ztrGX").unwrap(),
ArtistId::from_id("08td7MxkoHQkXnWAYD8d6Q").unwrap(),
];
client
.user_follow_artists(artists.iter().map(ArtistId::as_ref))
.await
.unwrap();
client.user_unfollow_artists(artists).await.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_user_follow_users() {
let client = oauth_client().await;
let users = [
UserId::from_id("exampleuser01").unwrap(),
UserId::from_id("john").unwrap(),
];
client
.user_follow_users(users.iter().map(UserId::as_ref))
.await
.unwrap();
client.user_unfollow_users(users).await.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_user_follow_playlist() {
let client = oauth_client().await;
let playlist_id = PlaylistId::from_id("2v3iNvBX8Ay1Gt2uXtUKUT").unwrap();
client
.playlist_follow(playlist_id.as_ref(), Some(true))
.await
.unwrap();
client.playlist_unfollow(playlist_id).await.unwrap();
}
#[maybe_async]
async fn check_playlist_create(client: &AuthCodeSpotify) -> FullPlaylist {
let user = client.me().await.unwrap();
let name = "A New Playlist";
let playlist = client
.user_playlist_create(user.id.as_ref(), name, Some(false), None, None)
.await
.unwrap();
let fetched_playlist = client
.user_playlist(user.id.as_ref(), Some(playlist.id.as_ref()), None)
.await
.unwrap();
assert_eq!(playlist.id, fetched_playlist.id);
let _current_user_playlists = fetch_all(client.current_user_playlists()).await;
let name = "A New Playlist-update";
let description = "A random description";
client
.playlist_change_detail(
playlist.id.as_ref(),
Some(name),
Some(true),
Some(description),
Some(false),
)
.await
.unwrap();
playlist
}
#[maybe_async]
async fn check_num_tracks(client: &AuthCodeSpotify, playlist_id: PlaylistId<'_>, num: i32) {
let fetched_tracks = fetch_all(client.playlist_items(playlist_id, None, None)).await;
assert_eq!(fetched_tracks.len() as i32, num);
}
#[maybe_async]
async fn check_playlist_tracks(client: &AuthCodeSpotify, playlist: &FullPlaylist) {
let tracks = [
PlayableId::Track(TrackId::from_uri("spotify:track:5iKndSu1XI74U2OZePzP8L").unwrap()),
PlayableId::Track(TrackId::from_uri("spotify:track:5iKndSu1XI74U2OZePzP8L").unwrap()),
PlayableId::Episode(EpisodeId::from_uri("spotify/episode/381XrGKkcdNkLwfsQ4Mh5y").unwrap()),
PlayableId::Episode(EpisodeId::from_uri("spotify/episode/6O63eWrfWPvN41CsSyDXve").unwrap()),
];
client
.playlist_add_items(
playlist.id.as_ref(),
tracks.iter().map(PlayableId::as_ref),
None,
)
.await
.unwrap();
check_num_tracks(client, playlist.id.as_ref(), tracks.len() as i32).await;
client
.playlist_reorder_items(playlist.id.as_ref(), Some(0), Some(3), Some(2), None)
.await
.unwrap();
check_num_tracks(client, playlist.id.as_ref(), tracks.len() as i32).await;
let replaced_tracks = [
PlayableId::Track(TrackId::from_uri("spotify:track:4iV5W9uYEdYUVa79Axb7Rh").unwrap()),
PlayableId::Track(TrackId::from_uri("spotify:track:4iV5W9uYEdYUVa79Axb7Rh").unwrap()),
PlayableId::Track(TrackId::from_uri("spotify:track:1301WleyT98MSxVHPZCA6M").unwrap()),
PlayableId::Episode(EpisodeId::from_id("0lbiy3LKzIY2fnyjioC11p").unwrap()),
PlayableId::Track(TrackId::from_uri("spotify:track:5m2en2ndANCPembKOYr1xL").unwrap()),
PlayableId::Episode(EpisodeId::from_id("4zugY5eJisugQj9rj8TYuh").unwrap()),
PlayableId::Track(TrackId::from_uri("spotify:track:5m2en2ndANCPembKOYr1xL").unwrap()),
];
client
.playlist_replace_items(
playlist.id.as_ref(),
replaced_tracks.iter().map(|t| t.as_ref()),
)
.await
.unwrap();
check_num_tracks(client, playlist.id.as_ref(), replaced_tracks.len() as i32).await;
let tracks = [
ItemPositions {
id: PlayableId::Track(
TrackId::from_uri("spotify:track:4iV5W9uYEdYUVa79Axb7Rh").unwrap(),
),
positions: &[0],
},
ItemPositions {
id: PlayableId::Track(
TrackId::from_uri("spotify:track:5m2en2ndANCPembKOYr1xL").unwrap(),
),
positions: &[4, 6],
},
];
client
.playlist_remove_specific_occurrences_of_items(playlist.id.as_ref(), tracks, None)
.await
.unwrap();
check_num_tracks(
client,
playlist.id.as_ref(),
replaced_tracks.len() as i32 - 3,
)
.await;
let to_remove = vec![
PlayableId::Track(TrackId::from_uri("spotify:track:4iV5W9uYEdYUVa79Axb7Rh").unwrap()),
PlayableId::Episode(EpisodeId::from_id("0lbiy3LKzIY2fnyjioC11p").unwrap()),
];
client
.playlist_remove_all_occurrences_of_items(playlist.id.as_ref(), to_remove, None)
.await
.unwrap();
check_num_tracks(
client,
playlist.id.as_ref(),
replaced_tracks.len() as i32 - 5,
)
.await;
}
#[maybe_async]
async fn check_playlist_follow(client: &AuthCodeSpotify, playlist: &FullPlaylist) {
let user_ids = [
UserId::from_id("possan").unwrap(),
UserId::from_id("elogain").unwrap(),
];
let following = client
.playlist_check_follow(playlist.id.as_ref(), &user_ids)
.await
.unwrap();
assert_eq!(following, vec![false, false]);
client
.playlist_unfollow(playlist.id.as_ref())
.await
.unwrap();
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_playlist() {
let client = oauth_client().await;
let playlist = check_playlist_create(&client).await;
check_playlist_tracks(&client, &playlist).await;
check_playlist_follow(&client, &playlist).await;
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_volume() {
let client = oauth_client().await;
let backup = client.current_playback(None, None::<&[_]>).await.unwrap();
client.volume(78, None).await.unwrap();
if let Some(CurrentPlaybackContext {
device: Device {
volume_percent: Some(volume),
..
},
..
}) = backup
{
client.volume(volume as u8, None).await.unwrap();
}
}
#[maybe_async::test(
feature = "__sync",
async(all(feature = "__async", not(target_arch = "wasm32")), tokio::test),
async(all(feature = "__async", target_arch = "wasm32"), wasm_bindgen_test)
)]
#[ignore]
async fn test_add_queue() {
let birdy_uri =
PlayableId::Track(TrackId::from_uri("spotify:track:6rqhFgbbKwnb9MLmUQDhG6").unwrap());
oauth_client()
.await
.add_item_to_queue(birdy_uri, None)
.await
.unwrap();
}