From e715956392ce94f19e7b57134851fbfa0399270f Mon Sep 17 00:00:00 2001 From: Nick Lehmann Date: Thu, 17 Feb 2022 10:51:21 +0100 Subject: [PATCH] First draft for write pagination --- src/clients/oauth.rs | 43 +++++- src/clients/pagination/mod.rs | 2 +- src/clients/pagination/stream.rs | 23 +++- tests/test_with_oauth.rs | 217 ++++++++++++++++++++++++++++++- 4 files changed, 272 insertions(+), 13 deletions(-) diff --git a/src/clients/oauth.rs b/src/clients/oauth.rs index 0c1a6511..fa6dac8f 100644 --- a/src/clients/oauth.rs +++ b/src/clients/oauth.rs @@ -18,6 +18,8 @@ use rspotify_model::idtypes::PlayContextId; use serde_json::{json, Map}; use url::Url; +use super::pagination::write_paginate; + /// This trait implements the methods available strictly to clients with user /// authorization, including some parts of the authentication flow that are /// shared, and the endpoints. @@ -300,14 +302,25 @@ pub trait OAuthClient: BaseClient { position: Option, ) -> ClientResult { let uris = items.into_iter().map(|id| id.uri()).collect::>(); - let params = build_json! { - "uris": uris, - optional "position": position, - }; let url = format!("playlists/{}/tracks", playlist_id.id()); - let result = self.endpoint_post(&url, ¶ms).await?; - convert_result(&result) + let chunk_size = 100; + + let last_response = write_paginate( + |chunk, position| { + let params = build_json! { + "uris": chunk, + optional "position": Some(position), + }; + + self.endpoint_post(&url, ¶ms) + }, + uris, + chunk_size, + ) + .await; + + convert_result(&last_response) } /// Replace all items in a playlist @@ -318,6 +331,7 @@ pub trait OAuthClient: BaseClient { /// - tracks - the list of track ids to add to the playlist /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/reorder-or-replace-playlists-tracks) + // TODO: Add write pagination async fn playlist_replace_items<'a>( &self, playlist_id: &PlaylistId, @@ -346,6 +360,7 @@ pub trait OAuthClient: BaseClient { /// - snapshot_id - optional playlist's snapshot ID /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/reorder-or-replace-playlists-tracks) + // TODO: Add write-pagination async fn playlist_reorder_items( &self, playlist_id: &PlaylistId, @@ -374,6 +389,7 @@ pub trait OAuthClient: BaseClient { /// - snapshot_id - optional id of the playlist snapshot /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-tracks-playlist) + // TODO: Add write-pagination async fn playlist_remove_all_occurrences_of_items<'a>( &self, playlist_id: &PlaylistId, @@ -428,6 +444,7 @@ pub trait OAuthClient: BaseClient { /// - snapshot_id: optional id of the playlist snapshot /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-tracks-playlist) + // TODO: Add write-pagination async fn playlist_remove_specific_occurrences_of_items<'a>( &self, playlist_id: &PlaylistId, @@ -622,6 +639,7 @@ pub trait OAuthClient: BaseClient { /// - track_ids - a list of track URIs, URLs or IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-tracks-user) + // TODO: Add write-pagination async fn current_user_saved_tracks_delete<'a>( &self, track_ids: impl IntoIterator + Send + 'a, @@ -639,6 +657,7 @@ pub trait OAuthClient: BaseClient { /// - track_ids - a list of track URIs, URLs or IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-tracks) + // TODO: Add write-pagination async fn current_user_saved_tracks_contains<'a>( &self, track_ids: impl IntoIterator + Send + 'a, @@ -654,6 +673,7 @@ pub trait OAuthClient: BaseClient { /// - track_ids - a list of track URIs, URLs or IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/save-tracks-user) + // TODO: Add write-pagination async fn current_user_saved_tracks_add<'a>( &self, track_ids: impl IntoIterator + Send + 'a, @@ -787,6 +807,7 @@ pub trait OAuthClient: BaseClient { /// - album_ids - a list of album URIs, URLs or IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/save-albums-user) + // TODO: Add write-pagination async fn current_user_saved_albums_add<'a>( &self, album_ids: impl IntoIterator + Send + 'a, @@ -803,6 +824,7 @@ pub trait OAuthClient: BaseClient { /// - album_ids - a list of album URIs, URLs or IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-albums-user) + // TODO: Add write-pagination async fn current_user_saved_albums_delete<'a>( &self, album_ids: impl IntoIterator + Send + 'a, @@ -820,6 +842,7 @@ pub trait OAuthClient: BaseClient { /// - album_ids - a list of album URIs, URLs or IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-albums) + // TODO: Add write-pagination async fn current_user_saved_albums_contains<'a>( &self, album_ids: impl IntoIterator + Send + 'a, @@ -835,6 +858,7 @@ pub trait OAuthClient: BaseClient { /// - artist_ids - a list of artist IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/follow-artists-users) + // TODO: Add write-pagination async fn user_follow_artists<'a>( &self, artist_ids: impl IntoIterator + Send + 'a, @@ -851,6 +875,7 @@ pub trait OAuthClient: BaseClient { /// - artist_ids - a list of artist IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/unfollow-artists-users) + // TODO: Add write-pagination async fn user_unfollow_artists<'a>( &self, artist_ids: impl IntoIterator + Send + 'a, @@ -868,6 +893,7 @@ pub trait OAuthClient: BaseClient { /// - artist_ids - the ids of the users that you want to /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/check-current-user-follows) + // TODO: Add write-pagination async fn user_artist_check_follow<'a>( &self, artist_ids: impl IntoIterator + Send + 'a, @@ -886,6 +912,7 @@ pub trait OAuthClient: BaseClient { /// - user_ids - a list of artist IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/follow-artists-users) + // TODO: Add write-pagination async fn user_follow_users<'a>( &self, user_ids: impl IntoIterator + Send + 'a, @@ -902,6 +929,7 @@ pub trait OAuthClient: BaseClient { /// - user_ids - a list of artist IDs /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/unfollow-artists-users) + // TODO: Add write-pagination async fn user_unfollow_users<'a>( &self, user_ids: impl IntoIterator + Send + 'a, @@ -1236,6 +1264,7 @@ pub trait OAuthClient: BaseClient { /// be added to the user’s library. /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/save-shows-user) + // TODO: Add write-pagination async fn save_shows<'a>( &self, show_ids: impl IntoIterator + Send + 'a, @@ -1289,6 +1318,7 @@ pub trait OAuthClient: BaseClient { /// - ids: Required. A comma-separated list of the Spotify IDs for the shows. Maximum: 50 IDs. /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/check-users-saved-shows) + // TODO: Add write-pagination async fn check_users_saved_shows<'a>( &self, ids: impl IntoIterator + Send + 'a, @@ -1309,6 +1339,7 @@ pub trait OAuthClient: BaseClient { /// - market: Optional. An ISO 3166-1 alpha-2 country code or the string from_token. /// /// [Reference](https://developer.spotify.com/documentation/web-api/reference/#/operations/remove-shows-user) + // TODO: Add write-pagination async fn remove_users_saved_shows<'a>( &self, show_ids: impl IntoIterator + Send + 'a, diff --git a/src/clients/pagination/mod.rs b/src/clients/pagination/mod.rs index 363b5cd4..b174de04 100644 --- a/src/clients/pagination/mod.rs +++ b/src/clients/pagination/mod.rs @@ -27,4 +27,4 @@ mod stream; #[cfg(feature = "__sync")] pub use iter::{paginate, Paginator}; #[cfg(feature = "__async")] -pub use stream::{paginate, Paginator}; +pub use stream::{paginate, write_paginate, Paginator}; diff --git a/src/clients/pagination/stream.rs b/src/clients/pagination/stream.rs index 8c383019..2b863e29 100644 --- a/src/clients/pagination/stream.rs +++ b/src/clients/pagination/stream.rs @@ -1,8 +1,8 @@ //! Asynchronous implementation of automatic pagination requests. -use crate::{model::Page, ClientResult}; +use crate::{model::Page, ClientError, ClientResult}; -use std::pin::Pin; +use std::{fmt::Debug, fmt::Display, pin::Pin}; use futures::{future::Future, stream::Stream}; @@ -34,3 +34,22 @@ where } }) } + +pub async fn write_paginate<'a, Item, Writer: 'a>( + writer: Writer, + items: Vec, + chunk_size: u32, +) -> String +where + Writer: Fn( + &[Item], + u32, + ) -> Pin> + Send>>, + Item: Display + Debug, +{ + let mut last_page = String::new(); + for chunk in items.chunks(chunk_size as usize) { + last_page = writer(chunk, chunk_size).await.unwrap(); + } + last_page +} diff --git a/tests/test_with_oauth.rs b/tests/test_with_oauth.rs index 0ac43585..695db6a5 100644 --- a/tests/test_with_oauth.rs +++ b/tests/test_with_oauth.rs @@ -639,8 +639,217 @@ async fn check_num_tracks(client: &AuthCodeSpotify, playlist_id: &PlaylistId, nu #[maybe_async] async fn check_playlist_tracks(client: &AuthCodeSpotify, playlist: &FullPlaylist) { + let many_track_ids = [ + "spotify:track:5F5LlqM7TC4On8aSTNQ708", + "spotify:track:6p6uByaFRKLblH2deQQN1R", + "spotify:track:460AIngb50zaaAwx88i5tU", + "spotify:track:0FuyNZ6v3M6fQC6Vn6uRmx", + "spotify:track:3PLwHMVcnwOpB3wlIyhz1w", + "spotify:track:0PI8YPuWLuBB0zlfPRsb0f", + "spotify:track:6ZlmOahw11fPit1cfZp3Sz", + "spotify:track:0xoIRdIMQmmgC7Jsklz7SW", + "spotify:track:0EH6RZdJ4gnh1rsnHjakrI", + "spotify:track:62PNy4tLDEwZZCFR0sm60B", + "spotify:track:5wvZuPV09LmPQxivk0np4T", + "spotify:track:0oIsNC7YcF48ozlsBacKRY", + "spotify:track:4VC17AsjxU6sMmN15bYB1B", + "spotify:track:6OBxDWinlB7U69GJaU4Vl7", + "spotify:track:5V4kzJFdwb3go8Khdg8iup", + "spotify:track:292TrokiRkPzSrZ59BPvYm", + "spotify:track:26vNIXrv6BI6l0gHHk81Hg", + "spotify:track:7cWBQY8BF6neLZNqsNzAp1", + "spotify:track:6iYeSyDFfP4Mg5laSXxpeG", + "spotify:track:1XY65rHJS742fF7hDBskDr", + "spotify:track:70tGEIwJB5woeqIlnYHH5D", + "spotify:track:2AGvQwCaZwTO2Jmd9ATgHP", + "spotify:track:6wIKwsRC9DEmfAllgBIGI0", + "spotify:track:0xd8BPE9x80Eaf8CWGusRA", + "spotify:track:3mcMFQcn0RhjuAcCyTITR3", + "spotify:track:6V92c2sNQz5zRtky1MkPv7", + "spotify:track:130MSkElbCeCKHZLs2xB71", + "spotify:track:4WZwDceyzLf3TBCdVWVZfF", + "spotify:track:2mZps6eeN4oYVrzNJRfEQl", + "spotify:track:1z79pqZqUoBzPwkvulT7zX", + "spotify:track:3fzyPZrU8wpJR67eJ0BpLa", + "spotify:track:2WAjGVNwKFZAxeKovo7OHR", + "spotify:track:3fd3ceryGrscyHzjBrqbhj", + "spotify:track:2L0WyaIQSU9WVwPMLpnLJi", + "spotify:track:2tENFE3ujnaLOP5UM9fIpP", + "spotify:track:0hOMvjHWYHaLXTTLMkjMNn", + "spotify:track:21MW2uNHXoMnd67KcQnOUQ", + "spotify:track:438sTebGykD66NV578Co40", + "spotify:track:3j3t2KzhUx5PDPqzvGONyy", + "spotify:track:1UWCMN9hGMcD8lm2dlaqsM", + "spotify:track:6NV4MvIuQHjnl0fE9km1Y6", + "spotify:track:09X7TIIgN3RS8nLHzrDBDN", + "spotify:track:3S8pudUsTC4oNeXJxAZQyu", + "spotify:track:2ynEUxUfifmNVcS7roMR9m", + "spotify:track:1eSdKaEBqHARKUD1HTxWlU", + "spotify:track:6hbM2VUWfHtbxnp6a35k9P", + "spotify:track:4U3SGkIeLdOI0e5nJ8xqfz", + "spotify:track:5AhEuMxTCTihSherpyXwA8", + "spotify:track:5p36wI3HIbtxGJqgW9IfWV", + "spotify:track:2imUtxBhnnecR5Bed3sTg9", + "spotify:track:22v5K7N5uZoCbFJGVemJvA", + "spotify:track:1uLezU4Q25S9XfJoMcLOkc", + "spotify:track:3qCach4fkarjb4nHoSZBAT", + "spotify:track:5dXiqfx1SBBIXLmoo7EGFY", + "spotify:track:2kC5QE8R6M2x0jp5m3vVq2", + "spotify:track:5UQQPiO4o7uBruwANgNMzT", + "spotify:track:3gCvOeBnNrIN6jGPazydD4", + "spotify:track:3Z1pGqeKSz2hTBlHpPophv", + "spotify:track:322xMrek7Oye4t7s23u7cM", + "spotify:track:1l6Smf5KiQAljgggvHwvOm", + "spotify:track:1h8RChLQSntaQrwW8uNT85", + "spotify:track:0MwTwnIxzBDvqi9unDzULA", + "spotify:track:3MP5IoFCUGJFLDTH5H9hK0", + "spotify:track:1203nRC7IhzdpJMe06tfos", + "spotify:track:3b90xbd4Hmk2TUQkRTw1MH", + "spotify:track:0qzdtjtQGxBwusN0Romg3l", + "spotify:track:40g48eSbs8g3EN1LLpd6mm", + "spotify:track:55mdqimXLmIBR5ZNF5YtOr", + "spotify:track:1usHkrG8vZ9ZxIpsp6v94E", + "spotify:track:4cEsN4TO0fSySeAzxNNQzj", + "spotify:track:02CPZ6zrZETvdbnJs5z7xB", + "spotify:track:0eoY80QymwM6nQ61mmfqmU", + "spotify:track:2YCfjYSMpEiHh22qoVnR57", + "spotify:track:76P5doQZFQQUZjYgeyzo8v", + "spotify:track:35bQ4rel7GNSjY8bTSioXQ", + "spotify:track:1OoUh2tv0oNHcbvXn7hx8B", + "spotify:track:5z9HMBVT4lvmhIU51GbiDI", + "spotify:track:1NA0DUu1I0pcPRcpg3aO87", + "spotify:track:7dOo4iQERaNrwgGS8Zgeub", + "spotify:track:3nwnKXCnznll8MhCI5pkDb", + "spotify:track:1BBacoPQkJTyD9udpbIgAa", + "spotify:track:66aVNocFLApjTfudNYVEiF", + "spotify:track:68RA8ykuWDwTgAn7ojJ5Kc", + "spotify:track:2BrYwGeLTN2MBxDU1ZaHnS", + "spotify:track:2dQxDxpUmXQwkdyorjrD8x", + "spotify:track:5YMLp3LDDY0T5nRaLbLzOH", + "spotify:track:41dRP2ShBhLcqfXZR79q7u", + "spotify:track:44iLbJnC8K5pZK56sjSjrn", + "spotify:track:2WrH04r76ta9WZXhSdidI8", + "spotify:track:0pPIIewNGzWHaxQ9h0sHLi", + "spotify:track:0dAbnZaG3iH64VD3CY0Ghn", + "spotify:track:3uyR6xvl4wgTmWIAx2J0nu", + "spotify:track:2K3qgAktdl7qYf767Zqsa0", + "spotify:track:1BalrpO4Jm1U9OEYjfRHS3", + "spotify:track:6kOSnyXVOLI8pApZLfQKvG", + "spotify:track:7DB3z4Xo8ix6vVaccEyv9h", + "spotify:track:6saT45aGfPjGvcZAEDwHuV", + "spotify:track:1zhD9NcPGOABy2fqUl2781", + "spotify:track:6f7FvVoOD9uKlofm4jLXn6", + "spotify:track:3c3WtmLV34X9XQkT1n8jn5", + "spotify:track:2gybgezceHzfhyiYCrOeEW", + "spotify:track:4RxMGnlScLGqIcwkjZKsEV", + "spotify:track:13Q866vT8Ses7iEtolBRrZ", + "spotify:track:4Z5s1LESqgQsOPl36VewAh", + "spotify:track:0OXPlvymmkGdhZ8i3AU4mu", + "spotify:track:0BI3nY3K6ip7sRzB4oWGzt", + "spotify:track:2gNEhoP1WmyZOz4xfWkiwX", + "spotify:track:1WVE6fsHpmoM6i2jw1FjYH", + "spotify:track:7w9pj2cU3Ukq4Ia8Pq8J9K", + "spotify:track:27M5yORKNX6iyF98xFpuEh", + "spotify:track:719MjPs3Y3fNymStOD8aMy", + "spotify:track:6AhINsGEM5M2GtnQ2Zxzeq", + "spotify:track:4UMj6HAftBnEs6mm1sSIWG", + "spotify:track:6XIlWm6lvkBbeoTakCkzoJ", + "spotify:track:4uiG8a0H9CYHRGI5EbeLj0", + "spotify:track:1RPCxEvotPwTW8xJhocOmV", + "spotify:track:3wdTUSziTXa4sTaTMURsQP", + "spotify:track:243I2WdcGsG3d6ydsNcaam", + "spotify:track:1KPqe4yuggQoMzlHt4JLmj", + "spotify:track:55TVHFjh5ZaAt8dOZaecZo", + "spotify:track:0cHBeAXAtnQ37lv8X8mbxv", + "spotify:track:2Adw90S7yANAgtMhiDXFE1", + "spotify:track:5oKjKxXLzNfqiPelCb2mz7", + "spotify:track:3s6jJkYwFwEWuRa4JwvJ7n", + "spotify:track:3oask4B0HkR3blqgwglM4r", + "spotify:track:0vDLTM0N18UugNYgt8STIw", + "spotify:track:2VPc5B4x6FMaOxGHeTPit4", + "spotify:track:6bM1z5bhEEsxttO5QbrZtC", + "spotify:track:2MhSc9MBA9Mfk7bARgtwWn", + "spotify:track:1AVCY0tHengz0OAoLIj36C", + "spotify:track:2LcRmvHA1lwHwaFtzbm0d2", + "spotify:track:6eQzqPniS4bBZfG5ej2TUL", + "spotify:track:1poyDHeaV8WAf29cR1Zk3L", + "spotify:track:0Cq6dYbYdUYXEtxVfhSZ52", + "spotify:track:5ekgk9E5jCzxqSUJxcEAVk", + "spotify:track:7qYZIYFVEk2lQGIg3ZB0fA", + "spotify:track:7aI6uXhu9Nl1oXGLIcu5Y8", + "spotify:track:1Jz5mZyOMeSogVpdvFKhKB", + "spotify:track:2BhOueZk9NQ269XuD2tnMg", + "spotify:track:19WGviHv5DKhvoqqJmrKRO", + "spotify:track:3Zdt2zbenPVsGDQfOGnbgP", + "spotify:track:4YS7cziBoUrO0Dqtczy8ls", + "spotify:track:5nVkaIXaqQtoMX4V1jncdO", + "spotify:track:6kZmXmoKAqzh7Dd3ttqkvi", + "spotify:track:3VqhFQevhOb4xDaLFeyEX0", + "spotify:track:0XDJ0moke0YRNG7sOup0MB", + "spotify:track:2H4lvngSfVLM2DxUqLZg5d", + "spotify:track:3pDDWhOWCYPPCjp7GIzGzJ", + "spotify:track:3plBrR6SS2rsJVRQDUuMJZ", + "spotify:track:5YB5OP1DF5LeLPP4kvY1r2", + "spotify:track:19yWSIWamGXck8GqPlwnbI", + "spotify:track:1SNpVIHlYIwmkOG7o7dAGl", + "spotify:track:3QtJFO9oOxF39ba6UuqUQG", + "spotify:track:20qaixxAwIDtdraAd9Wbtq", + "spotify:track:76Q0uXQEAJ79nU58HgySa8", + "spotify:track:6Ad4PTD20fKOvRJt5GN2Gi", + "spotify:track:5TDny4zqmIUHbPqOU2piRP", + "spotify:track:1EGeBH0HH2tQSm3COh89wI", + "spotify:track:1eb1pBq8imZoE9m7I2JTaM", + "spotify:track:5urFDgiRTQmE2rL5b5GvY9", + "spotify:track:54QxrEFZESIfuW7Ex7YwSd", + "spotify:track:3rrubeU6np8Yeya9mwtedg", + "spotify:track:0MOOHqSaflxhjMuw3XhhgU", + "spotify:track:4tDzwyAQAbKX6Kxlzuyve5", + "spotify:track:7eTsm0Msg9ddxgK65ZUs4K", + "spotify:track:5UeLuozsBQbBj1MmB6joHz", + "spotify:track:3Ov5GS35RJi2Sa5j2S7ai5", + "spotify:track:4O0hFdFxhsX7bjc13zunsb", + "spotify:track:3vTJP27ZGQMhrBqmXICfGB", + "spotify:track:7zUUo57PVdasUxG4Lrt37K", + "spotify:track:1KibqiW18YSYSCnhorGAh2", + "spotify:track:4wMMiSEzBgqpkTX4XyTNOU", + "spotify:track:7iFsFe1dvApvOmqqbPyW9t", + "spotify:track:2KzOl8UDgssvilD8c0cD1j", + "spotify:track:6C4Wugot6Cfw3H8VkiwIjD", + "spotify:track:3fdtNgNiwcwzluIQHU0l0N", + "spotify:track:7oLfES7gAl8sWILYrIfqSd", + "spotify:track:51CeWFqX7G69e98uHWH7qo", + "spotify:track:6NK1H3w4eY3JpjhysYBlmf", + "spotify:track:73YXGkN7g9oljiJKRNtgYs", + "spotify:track:2uquC1imZKe4GkfP7CuKNa", + "spotify:track:7oIie45AkGl7IA4yBu898V", + "spotify:track:0Lg4Vv8yT2kIu13MiCFFRH", + "spotify:track:05OUzuprHAYW7qx6WMPyAb", + "spotify:track:5be5sXDDKPAHIVz2S59v0P", + "spotify:track:2UfwzZdmafOdb03D5qhc2w", + "spotify:track:2leY1jnZ1B9OUjvjMB4MJX", + "spotify:track:26I6M5K8pGqYo72huex9XH", + "spotify:track:5S7vkxR89rq8kxx3BQnU3R", + "spotify:track:428BWdDsS3N5GlphJGPgZL", + "spotify:track:1E50pMxLo0YL4MGefwrN2O", + "spotify:track:0OJ3iSa0gHbmar91N80vVa", + "spotify:track:4jseVFPy24FCzXPGzIZyWY", + "spotify:track:1ncOLMcTu9rxE18fmcGwnd", + "spotify:track:7okXi589OVY6VFszHe6JO5", + "spotify:track:1dLz1RKcIqw5bms62CY8dQ", + "spotify:track:7KzXghoY2PTH7iqexeKHmM", + "spotify:track:5jjDPdHqxeHZMvIbSqCrX8", + ]; + + let track_ids: Vec = many_track_ids + .iter() + .map(|uri| TrackId::from_uri(uri).unwrap()) + .collect(); + + let playable_ids: Vec<&dyn PlayableId> = + track_ids.iter().map(|id| id as &dyn PlayableId).collect(); + // The tracks in the playlist, some of them repeated - let tracks: [&dyn PlayableId; 4] = [ + let _tracks: [&dyn PlayableId; 4] = [ &TrackId::from_uri("spotify:track:5iKndSu1XI74U2OZePzP8L").unwrap(), &TrackId::from_uri("spotify:track:5iKndSu1XI74U2OZePzP8L").unwrap(), &EpisodeId::from_uri("spotify/episode/381XrGKkcdNkLwfsQ4Mh5y").unwrap(), @@ -649,10 +858,10 @@ async fn check_playlist_tracks(client: &AuthCodeSpotify, playlist: &FullPlaylist // Firstly adding some tracks client - .playlist_add_items(&playlist.id, tracks, None) + .playlist_add_items(&playlist.id, playable_ids.into_iter(), None) .await .unwrap(); - check_num_tracks(client, &playlist.id, tracks.len() as i32).await; + check_num_tracks(client, &playlist.id, track_ids.len() as i32).await; // Reordering some tracks client @@ -660,7 +869,7 @@ async fn check_playlist_tracks(client: &AuthCodeSpotify, playlist: &FullPlaylist .await .unwrap(); // Making sure the number of tracks is the same - check_num_tracks(client, &playlist.id, tracks.len() as i32).await; + check_num_tracks(client, &playlist.id, track_ids.len() as i32).await; // Replacing the tracks let replaced_tracks: [&dyn PlayableId; 7] = [