From 7e95b9b2cbeb077a72625548e3034819d13062fe Mon Sep 17 00:00:00 2001 From: jo Date: Fri, 14 Apr 2023 12:00:16 +0100 Subject: [PATCH] create typescript sdk --- .env.template | 6 + .gitignore | 18 + CODEOWNERS.md | 9 + CODE_OF_CONDUCT.md | 69 + CONTRIBUTING.md | 155 + LICENSE | 13 + OWNERS.md | 15 + SECURITY.md | 16 + catalog-info.yaml | 7 + example/.env.template | 2 + example/env.d.ts | 8 + example/index.html | 26 + example/script.ts | 26 + example/style.css | 33 + package-lock.json | 3148 ++++++++ package.json | 46 + readme.md | 228 + src/SpotifyApi.test.ts | 83 + src/SpotifyApi.ts | 142 + src/auth/AccessTokenHelpers.ts | 58 + src/auth/AuthorizationCodeWithPKCEStrategy.ts | 118 + src/auth/ClientCredentialsStrategy.ts | 55 + src/auth/IAuthStrategy.ts | 4 + src/auth/ImplicitGrantStrategy.ts | 60 + src/caching/GenericCache.test.ts | 189 + src/caching/GenericCache.ts | 119 + src/caching/ICacheStore.ts | 5 + src/caching/InMemoryCachingStrategy.ts | 24 + src/caching/LocalStorageCachingStrategy.ts | 22 + src/endpoints/AlbumsEndpoints.test.ts | 40 + src/endpoints/AlbumsEndpoints.ts | 24 + src/endpoints/ArtistsEndpoint.test.ts | 57 + src/endpoints/ArtistsEndpoints.ts | 36 + src/endpoints/AudiobooksEndpoints.test.ts | 43 + src/endpoints/AudiobooksEndpoints.ts | 22 + src/endpoints/BrowseEndpoints.test.ts | 45 + src/endpoints/BrowseEndpoints.ts | 31 + src/endpoints/ChaptersEndpoints.test.ts | 31 + src/endpoints/ChaptersEndpoints.ts | 20 + src/endpoints/CurrentUserEndpoints.test.ts | 179 + src/endpoints/CurrentUserEndpoints.ts | 177 + src/endpoints/EndpointsBase.ts | 33 + src/endpoints/EpisodesEndpoints.test.ts | 31 + src/endpoints/EpisodesEndpoints.ts | 17 + src/endpoints/MarketsEndpoints.test.ts | 22 + src/endpoints/MarketsEndpoints.ts | 7 + src/endpoints/PlayerEndpoints.ts | 94 + src/endpoints/PlaylistsEndpoints.test.ts | 47 + src/endpoints/PlaylistsEndpoints.ts | 87 + .../RecommendationsEndpoints.test.ts | 26 + src/endpoints/RecommendationsEndpoints.ts | 12 + src/endpoints/SearchEndpoints.test.ts | 21 + src/endpoints/SearchEndpoints.ts | 12 + src/endpoints/ShowsEndpoints.test.ts | 39 + src/endpoints/ShowsEndpoints.ts | 23 + src/endpoints/TracksEndpoints.test.ts | 57 + src/endpoints/TracksEndpoints.ts | 34 + src/endpoints/UsersEndpoints.test.ts | 23 + src/endpoints/UsersEndpoints.ts | 8 + .../ConsoleLoggingErrorHandler.ts | 6 + src/errorhandling/NoOpErrorHandler.ts | 6 + src/index.ts | 1 + .../DocumentLocationRedirectionStrategy.ts | 8 + .../DefaultResponseValidator.ts | 20 + .../DefaultResponseDeserializer.ts | 12 + src/test/AuthAsRealUserForTests.ts | 68 + src/test/FakeAuthStrategy.ts | 32 + src/test/FetchApiMock.ts | 44 + src/test/FetchApiSpy.ts | 49 + src/test/SpotifyApiBuilder.ts | 94 + src/test/data/validAlbumResult.ts | 349 + src/test/data/validAlbumTracksResult.ts | 297 + src/test/data/validArtist.ts | 44 + src/test/data/validAudioBook.ts | 1238 +++ src/test/data/validAudiobookChapters.ts | 731 ++ src/test/data/validCategories.ts | 254 + src/test/data/validCategory.ts | 9 + src/test/data/validChapterApiResponse.ts | 109 + src/test/data/validEpisode.ts | 242 + src/test/data/validGenres.ts | 132 + src/test/data/validMarkets.ts | 190 + src/test/data/validPlaylist.ts | 6856 +++++++++++++++++ src/test/data/validShow.ts | 2224 ++++++ src/test/data/validTrack.ts | 68 + src/test/data/validUser.ts | 23 + src/types.d.ts | 609 ++ tsconfig.json | 22 + vite.config.ts | 15 + vitest.config.ts | 10 + 89 files changed, 19764 insertions(+) create mode 100644 .env.template create mode 100644 .gitignore create mode 100644 CODEOWNERS.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 OWNERS.md create mode 100644 SECURITY.md create mode 100644 catalog-info.yaml create mode 100644 example/.env.template create mode 100644 example/env.d.ts create mode 100644 example/index.html create mode 100644 example/script.ts create mode 100644 example/style.css create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 readme.md create mode 100644 src/SpotifyApi.test.ts create mode 100644 src/SpotifyApi.ts create mode 100644 src/auth/AccessTokenHelpers.ts create mode 100644 src/auth/AuthorizationCodeWithPKCEStrategy.ts create mode 100644 src/auth/ClientCredentialsStrategy.ts create mode 100644 src/auth/IAuthStrategy.ts create mode 100644 src/auth/ImplicitGrantStrategy.ts create mode 100644 src/caching/GenericCache.test.ts create mode 100644 src/caching/GenericCache.ts create mode 100644 src/caching/ICacheStore.ts create mode 100644 src/caching/InMemoryCachingStrategy.ts create mode 100644 src/caching/LocalStorageCachingStrategy.ts create mode 100644 src/endpoints/AlbumsEndpoints.test.ts create mode 100644 src/endpoints/AlbumsEndpoints.ts create mode 100644 src/endpoints/ArtistsEndpoint.test.ts create mode 100644 src/endpoints/ArtistsEndpoints.ts create mode 100644 src/endpoints/AudiobooksEndpoints.test.ts create mode 100644 src/endpoints/AudiobooksEndpoints.ts create mode 100644 src/endpoints/BrowseEndpoints.test.ts create mode 100644 src/endpoints/BrowseEndpoints.ts create mode 100644 src/endpoints/ChaptersEndpoints.test.ts create mode 100644 src/endpoints/ChaptersEndpoints.ts create mode 100644 src/endpoints/CurrentUserEndpoints.test.ts create mode 100644 src/endpoints/CurrentUserEndpoints.ts create mode 100644 src/endpoints/EndpointsBase.ts create mode 100644 src/endpoints/EpisodesEndpoints.test.ts create mode 100644 src/endpoints/EpisodesEndpoints.ts create mode 100644 src/endpoints/MarketsEndpoints.test.ts create mode 100644 src/endpoints/MarketsEndpoints.ts create mode 100644 src/endpoints/PlayerEndpoints.ts create mode 100644 src/endpoints/PlaylistsEndpoints.test.ts create mode 100644 src/endpoints/PlaylistsEndpoints.ts create mode 100644 src/endpoints/RecommendationsEndpoints.test.ts create mode 100644 src/endpoints/RecommendationsEndpoints.ts create mode 100644 src/endpoints/SearchEndpoints.test.ts create mode 100644 src/endpoints/SearchEndpoints.ts create mode 100644 src/endpoints/ShowsEndpoints.test.ts create mode 100644 src/endpoints/ShowsEndpoints.ts create mode 100644 src/endpoints/TracksEndpoints.test.ts create mode 100644 src/endpoints/TracksEndpoints.ts create mode 100644 src/endpoints/UsersEndpoints.test.ts create mode 100644 src/endpoints/UsersEndpoints.ts create mode 100644 src/errorhandling/ConsoleLoggingErrorHandler.ts create mode 100644 src/errorhandling/NoOpErrorHandler.ts create mode 100644 src/index.ts create mode 100644 src/redirection/DocumentLocationRedirectionStrategy.ts create mode 100644 src/responsevalidation/DefaultResponseValidator.ts create mode 100644 src/serialization/DefaultResponseDeserializer.ts create mode 100644 src/test/AuthAsRealUserForTests.ts create mode 100644 src/test/FakeAuthStrategy.ts create mode 100644 src/test/FetchApiMock.ts create mode 100644 src/test/FetchApiSpy.ts create mode 100644 src/test/SpotifyApiBuilder.ts create mode 100644 src/test/data/validAlbumResult.ts create mode 100644 src/test/data/validAlbumTracksResult.ts create mode 100644 src/test/data/validArtist.ts create mode 100644 src/test/data/validAudioBook.ts create mode 100644 src/test/data/validAudiobookChapters.ts create mode 100644 src/test/data/validCategories.ts create mode 100644 src/test/data/validCategory.ts create mode 100644 src/test/data/validChapterApiResponse.ts create mode 100644 src/test/data/validEpisode.ts create mode 100644 src/test/data/validGenres.ts create mode 100644 src/test/data/validMarkets.ts create mode 100644 src/test/data/validPlaylist.ts create mode 100644 src/test/data/validShow.ts create mode 100644 src/test/data/validTrack.ts create mode 100644 src/test/data/validUser.ts create mode 100644 src/types.d.ts create mode 100644 tsconfig.json create mode 100644 vite.config.ts create mode 100644 vitest.config.ts diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..a0e3ff5 --- /dev/null +++ b/.env.template @@ -0,0 +1,6 @@ +INTEGRATION_TESTS_SPOTIFY_CLIENT_ID=your_spotify_client_id_for_tests +INTEGRATION_TESTS_SPOTIFY_CLIENT_SECRET=your_spotify_client_secret_for_tests +INTEGRATION_TESTS_USER_EMAIL=some@validuser.co.uk +INTEGRATION_TESTS_USER_PASSWORD=some-valid-password +VITE_SPOTIFY_CLIENT_ID=your_spotify_client_id_for_tests +VITE_REDIRECT_TARGET=http://localhost:3000 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e580ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +!**/glob-import/dir/node_modules +.DS_Store +.idea +*.cpuprofile +*.local +*.log +/.vscode/ +/docs/.vitepress/cache +/packages/vite/LICENSE +dist +dist-ssr +explorations +node_modules +temp +TODOs.md +.eslintcache +/*.env +/example/.env diff --git a/CODEOWNERS.md b/CODEOWNERS.md new file mode 100644 index 0000000..5ed9399 --- /dev/null +++ b/CODEOWNERS.md @@ -0,0 +1,9 @@ +# This file registers ownership for certain parts of the repository. + +Review from a member of the corresponding code owner is required to merge pull requests. + +The last matching pattern takes precedence. +https://help.github.com/articles/about-codeowners/ + + +Owners: @spotify/dx diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..47ec1b9 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,69 @@ +# Code of Conduct + +This code of conduct outlines our expectations for participants within the **Spotify FOSS** community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community. + +Our open source community strives to: + +- **Be friendly and patient.** +- **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. +- **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. +- **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. +- **Be careful in the words that we choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. +- **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. + +## Definitions + +Harassment includes, but is not limited to: + +- Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, age, regional discrimination, political or religious affiliation +- Unwelcome comments regarding a person’s lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment +- Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a person's gender identity. You must address people by the name they give you when not addressing them by their username or handle +- Physical contact and simulated physical contact (eg, textual descriptions like “_hug_” or “_backrub_”) without consent or after a request to stop +- Threats of violence, both physical and psychological +- Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm +- Deliberate intimidation +- Stalking or following +- Harassing photography or recording, including logging online activity for harassment purposes +- Sustained disruption of discussion +- Unwelcome sexual attention, including gratuitous or off-topic sexual images or behaviour +- Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others +- Continued one-on-one communication after requests to cease +- Deliberate “outing” of any aspect of a person’s identity without their consent except as necessary to protect others from intentional abuse +- Publication of non-harassing private communication + +Our open source community prioritizes marginalized people’s safety over privileged people’s comfort. We will not act on complaints regarding: + +- ‘Reverse’ -isms, including ‘reverse racism,’ ‘reverse sexism,’ and ‘cisphobia’ +- Reasonable communication of boundaries, such as “leave me alone,” “go away,” or “I’m not discussing this with you” +- Refusal to explain or debate social justice concepts +- Communicating in a ‘tone’ you don’t find congenial +- Criticizing racist, sexist, cissexist, or otherwise oppressive behavior or assumptions + +### Diversity Statement + +We encourage everyone to participate and are committed to building a community for all. Although we will fail at times, we seek to treat everyone both as fairly and equally as possible. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong. + +Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected +characteristics above, including participants with disabilities. + +### Reporting Issues + +If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via **fossboard@spotify.com**. All reports will be handled with discretion. In your report please include: + +- Your contact information. +- Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please + include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link. +- Any additional information that may be helpful. + +After filing a report, a representative will contact you personally, review the incident, follow up with any additional questions, and make a decision as to how to respond. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. If the complaint originates from a member of the response team, it will be handled by a different member of the response team. We will respect confidentiality requests for the purpose of protecting victims of abuse. + +### Attribution & Acknowledgements + +We all stand on the shoulders of giants across many open source communities. We'd like to thank the communities and projects that established codes of conduct and diversity statements as our inspiration: + +- [Django](https://www.djangoproject.com/conduct/reporting/) +- [Python](https://www.python.org/community/diversity/) +- [Ubuntu](http://www.ubuntu.com/about/about-ubuntu/conduct) +- [Contributor Covenant](http://contributor-covenant.org/) +- [Geek Feminism](http://geekfeminism.org/about/code-of-conduct/) +- [Citizen Code of Conduct](http://citizencodeofconduct.org/) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0f543cc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,155 @@ +# How to Contribute + +We'd love to get patches from you! + +## Getting Started + +If you find a bug, please open an issue, create a PR or [chat to the team on our forum](https://community.spotify.com/t5/Spotify-for-Developers/bd-p/Spotify_Developer). + +## Building dependencies + +Because this SDK uses `fetch` both in Node and the Browser, and ESM, it requires the following: + +- Node 18.0.0 or higher +- A modern, version infinite, browser + +To install the project, cd into the project and run + +```bash +npm install +``` + +## Building the Project + +To run the project, cd into the project and run + +```bash +npm run start +``` + +## Tests + +To run the tests, you need to have a Spotify account. + +You will need to create a new app in the Spotify Developer portal, and add a redirect URI of `http://localhost:3000`. + +Add the following environment variables: + +- `INTEGRATION_TESTS_SPOTIFY_CLIENT_ID` +- `INTEGRATION_TESTS_SPOTIFY_CLIENT_SECRET` +- `INTEGRATION_TESTS_USER_EMAIL` +- `INTEGRATION_TESTS_USER_PASSWORD` + +The latter two credentials are used to run integration tests in the scope of a *real user account*. This is required to test endpoints that require a user's authorization, such as `followPlaylist`. You need to make sure that your user has access to whichever Spotify app your client credentials and secret are for. + +You can run the tests with `npm run test`, or using a plugin like [Wallaby](https://wallabyjs.com/). + +We support `dotenv`, so you can add these to a `.env` file in the root of the repository. + +To run the embedded example app, you will need to add the following environment variables: + +- `VITE_SPOTIFY_CLIENT_ID`=the same value as set in INTEGRATION_TESTS_SPOTIFY_CLIENT_ID +- `VITE_REDIRECT_TARGET`=http://localhost:3000 + +For the example app to work, this .env file needs to be in the ./example folder. + +## Workflow + +We follow the [GitHub Flow Workflow](https://guides.github.com/introduction/flow/) + +### TODO: Below is an Example + +1. Fork the project +2. Check out the `main` branch +3. Create a feature branch +4. Write code and tests for your change +5. From your branch, make a pull request +6. Work with repo maintainers to get your change reviewed +7. Wait for your change to be pulled +8. Delete your feature branch + +## Testing + +To run the tests, you need to have a Spotify account. + +You will need to create a new app in the Spotify Developer portal, and add a redirect URI of `http://localhost:3000`. + +You will need to add the following environment variables: + +- `INTEGRATION_TESTS_SPOTIFY_CLIENT_ID` +- `INTEGRATION_TESTS_SPOTIFY_CLIENT_SECRET` +- `INTEGRATION_TESTS_USER_EMAIL` +- `INTEGRATION_TESTS_USER_PASSWORD` + +The latter two credentials are used to run integration tests in the scope of a *real user account*. This is required to test endpoints that require a user's authorization, such as `followPlaylist`. You need to make sure that your user has access to whichever Spotify app your client credentials and secret are for. + +You can run the tests with `npm run test`, or using a plugin like [Wallaby](https://wallabyjs.com/). + +We support `dotenv`, so you can add these to a `.env` file in the root of the repository. + +To run the embedded example app, you will need to add the following environment variables: + +```bash +VITE_SPOTIFY_CLIENT_ID=the same value as set in INTEGRATION_TESTS_SPOTIFY_CLIENT_ID +VITE_REDIRECT_TARGET=http://localhost:3000 +``` + +For the example app to work, this .env file needs to be in the ./example folder. + +## Issues + +When creating an issue please try to adhere to the following format: + + module-name: One line summary of the issue (less than 72 characters) + + ### Expected behavior + + As concisely as possible, describe the expected behavior. + + ### Actual behavior + + As concisely as possible, describe the observed behavior. + + ### Steps to reproduce the behavior + + List all relevant steps to reproduce the observed behavior. + +## Pull Requests + +We adhere to a specific format for commit messages. Please write your commit +messages along these guidelines: + + module-name: One line description of your change (less than 72 characters) + + Problem + + Explain the context and why you're making that change. What is the problem + you're trying to solve? In some cases there is not a problem and this can be + thought of being the motivation for your change. + + Solution + + Describe the modifications you've done. + + Result + + What will change as a result of your pull request? Note that sometimes this + section is unnecessary because it is self-explanatory based on the solution. + +Some important notes regarding the summary line: + +- Describe what was done; not the result +- Use the active voice +- Use the present tense +- Capitalize properly +- Do not end in a period — this is a title/subject +- Prefix the subject with its scope + +# License + +By contributing your code, you agree to license your contribution under the +terms of the [LICENSE](LICENSE) + +# Code of Conduct + +Read our [Code of Conduct](CODE_OF_CONDUCT.md) for the project. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ed80bb5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2020 Spotify, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/OWNERS.md b/OWNERS.md new file mode 100644 index 0000000..3388d89 --- /dev/null +++ b/OWNERS.md @@ -0,0 +1,15 @@ +# Owners + +- See [CONTRIBUTING.md](CONTRIBUTING.md) for general contribution guidelines. + +## Core Developers + +- $FIRSTNAME $LASTNAME ($GHUSERNAME, Spotify) +- $FIRSTNAME $LASTNAME ($GHUSERNAME, Spotify) +- $FIRSTNAME $LASTNAME ($GHUSERNAME, Spotify) + +## Triagers + +- FIRSTNAME LASTNAME (@GHUSERNAME, $AFFILIATION) +- FIRSTNAME LASTNAME (@GHUSERNAME, $AFFILIATION) +- FIRSTNAME LASTNAME (@GHUSERNAME, $AFFILIATION) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..89155ad --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +We're big believers in protecting your privacy and security. As a company, we not only have a vested interest, but also a deep desire to see the Internet remain as safe as possible for us all. + +So, needless to say, we take security issues very seriously. + +In our opinion, the practice of 'responsible disclosure' is the best way to safeguard the Internet. It allows individuals to notify companies like Spotify of any security threats before going public with the information. This gives us a fighting chance to resolve the problem before the criminally-minded become aware of it. + +Responsible disclosure is the industry best practice, and we recommend it as a procedure to anyone researching security vulnerabilities. + +## Reporting a Vulnerability + +If you have discovered a vulnerability in this open source project or another serious security issue, +please submit it to the Spotify bounty program hosted by HackerOne. + +https://hackerone.com/spotify diff --git a/catalog-info.yaml b/catalog-info.yaml new file mode 100644 index 0000000..67516b0 --- /dev/null +++ b/catalog-info.yaml @@ -0,0 +1,7 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: Web-API-Typescript-SDK +spec: + type: library + owner: DX diff --git a/example/.env.template b/example/.env.template new file mode 100644 index 0000000..b364575 --- /dev/null +++ b/example/.env.template @@ -0,0 +1,2 @@ +VITE_SPOTIFY_CLIENT_ID=your_spotify_client_id_for_tests +VITE_REDIRECT_TARGET=http://localhost:3000 \ No newline at end of file diff --git a/example/env.d.ts b/example/env.d.ts new file mode 100644 index 0000000..acbaf3c --- /dev/null +++ b/example/env.d.ts @@ -0,0 +1,8 @@ +interface ImportMetaEnv { + readonly VITE_SPOTIFY_CLIENT_ID: string + readonly VITE_REDIRECT_TARGET: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/example/index.html b/example/index.html new file mode 100644 index 0000000..5406339 --- /dev/null +++ b/example/index.html @@ -0,0 +1,26 @@ + + + + + + Example + + + + + +

Display Spotify profile data

+ +
+

Logged in as

+ + +
+ + diff --git a/example/script.ts b/example/script.ts new file mode 100644 index 0000000..9dc4734 --- /dev/null +++ b/example/script.ts @@ -0,0 +1,26 @@ +import { SpotifyApi } from "../src/index"; +import AuthorizationCodeWithPKCEStrategy from "../src/auth/AuthorizationCodeWithPKCEStrategy"; + +const implicitGrantStrategy = new AuthorizationCodeWithPKCEStrategy( + import.meta.env.VITE_SPOTIFY_CLIENT_ID, + import.meta.env.VITE_REDIRECT_TARGET, + ['user-read-private', 'user-read-email', 'playlist-modify-public', 'playlist-modify-private, user-read-playback-state, user-modify-playback-state'] +); + +const spotify = new SpotifyApi(implicitGrantStrategy); +const profile = await spotify.currentUser.profile(); +console.log(profile); + +document.getElementById("displayName")!.innerText = profile.display_name; +if (profile.images[0]) { + const profileImage = new Image(200, 200); + profileImage.src = profile.images[0].url; + document.getElementById("avatar")!.appendChild(profileImage); +} +document.getElementById("id")!.innerText = profile.id; +document.getElementById("email")!.innerText = profile.email; +document.getElementById("uri")!.innerText = profile.uri; +document.getElementById("uri")!.setAttribute("href", profile.external_urls.spotify); +document.getElementById("url")!.innerText = profile.href; +document.getElementById("url")!.setAttribute("href", profile.href); +document.getElementById("imgUrl")!.innerText = profile.images[0]?.url ?? '(no profile image)'; diff --git a/example/style.css b/example/style.css new file mode 100644 index 0000000..f5dd46d --- /dev/null +++ b/example/style.css @@ -0,0 +1,33 @@ +html { + font-family: Arial, Helvetica, sans-serif; +} + +body { + margin: 0 auto; + max-width: 700px; +} + +section { + display: grid; + grid-template-columns: auto 1fr; +} + +h2 { + grid-column: span 2; +} + +ul { + max-width: 500px; + margin: 0; + list-style: none; + line-height: 1.5em; +} + +li { + font-weight: bold; +} + +li span { + font-weight: normal; + overflow-wrap: break-word; +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c8d86c2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3148 @@ +{ + "name": "spotifyjs", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "spotifyjs", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@peculiar/webcrypto": "^1.4.1", + "@types/node": "^18.15.1", + "@types/uuid": "^9.0.1", + "dotenv": "^16.0.3", + "jsdom": "^21.1.1", + "playwright": "^1.31.2", + "typescript": "^4.9.5", + "uuid": "^9.0.0", + "vite": "^4.1.4", + "vitest": "^0.29.2" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.6.tgz", + "integrity": "sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==", + "dev": true, + "dependencies": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@peculiar/webcrypto": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.1.tgz", + "integrity": "sha512-eK4C6WTNYxoI7JOabMoZICiyqRRtJB220bh0Mbj5RwRycleZf9BPyZoxsTvpP0FpmVS2aS13NKOuh5/tN3sIRw==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.3.0", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.1", + "webcrypto-core": "^1.7.4" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "node_modules/@types/chai-subset": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/node": { + "version": "18.15.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.1.tgz", + "integrity": "sha512-U2TWca8AeHSmbpi314QBESRk7oPjSZjDsR+c+H4ECC1l+kFgpZf8Ydhv3SJpPy51VyZHHqxlb6mTTqYNNRVAIw==", + "dev": true + }, + "node_modules/@types/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", + "dev": true + }, + "node_modules/@vitest/expect": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.29.2.tgz", + "integrity": "sha512-wjrdHB2ANTch3XKRhjWZN0UueFocH0cQbi2tR5Jtq60Nb3YOSmakjdAvUa2JFBu/o8Vjhj5cYbcMXkZxn1NzmA==", + "dev": true, + "dependencies": { + "@vitest/spy": "0.29.2", + "@vitest/utils": "0.29.2", + "chai": "^4.3.7" + } + }, + "node_modules/@vitest/runner": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.29.2.tgz", + "integrity": "sha512-A1P65f5+6ru36AyHWORhuQBJrOOcmDuhzl5RsaMNFe2jEkoj0faEszQS4CtPU/LxUYVIazlUtZTY0OEZmyZBnA==", + "dev": true, + "dependencies": { + "@vitest/utils": "0.29.2", + "p-limit": "^4.0.0", + "pathe": "^1.1.0" + } + }, + "node_modules/@vitest/spy": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.29.2.tgz", + "integrity": "sha512-Hc44ft5kaAytlGL2PyFwdAsufjbdOvHklwjNy/gy/saRbg9Kfkxfh+PklLm1H2Ib/p586RkQeNFKYuJInUssyw==", + "dev": true, + "dependencies": { + "tinyspy": "^1.0.2" + } + }, + "node_modules/@vitest/utils": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.29.2.tgz", + "integrity": "sha512-F14/Uc+vCdclStS2KEoXJlOLAEyqRhnw0gM27iXw9bMTcyKRPJrQ+rlC6XZ125GIPvvKYMPpVxNhiou6PsEeYQ==", + "dev": true, + "dependencies": { + "cli-truncate": "^3.1.0", + "diff": "^5.1.0", + "loupe": "^2.3.6", + "picocolors": "^1.0.0", + "pretty-format": "^27.5.1" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dev": true, + "dependencies": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/domexception": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" + } + }, + "node_modules/escodegen": { + "version": "2.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/form-data": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.1.tgz", + "integrity": "sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.2", + "acorn-globals": "^7.0.0", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/levn": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mlly": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.2.0.tgz", + "integrity": "sha512-+c7A3CV0KGdKcylsI6khWyts/CYrGTrRVo4R/I7u/cUsy0Conxa6LUhiEzVKIw14lc2L5aiO4+SeVe4TeGRKww==", + "dev": true, + "dependencies": { + "acorn": "^8.8.2", + "pathe": "^1.1.0", + "pkg-types": "^1.0.2", + "ufo": "^1.1.1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", + "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", + "dev": true + }, + "node_modules/optionator": { + "version": "0.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz", + "integrity": "sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/pkg-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.2.tgz", + "integrity": "sha512-hM58GKXOcj8WTqUXnsQyJYXdeAPbythQgEF3nTcEo+nkD49chjQ9IKm/QJy9xf6JakXptz86h7ecP2024rrLaQ==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.1.1", + "pathe": "^1.1.0" + } + }, + "node_modules/playwright": { + "version": "1.31.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.31.2.tgz", + "integrity": "sha512-jpC47n2PKQNtzB7clmBuWh6ftBRS/Bt5EGLigJ9k2QAKcNeYXZkEaDH5gmvb6+AbcE0DO6GnXdbl9ogG6Eh+og==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "playwright-core": "1.31.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/playwright-core": { + "version": "1.31.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.2.tgz", + "integrity": "sha512-a1dFgCNQw4vCsG7bnojZjDnPewZcw7tZUNFN0ZkcLYKj+mPmXvg4MpaaKZ5SgqPsOmqIf2YsVRkgqiRDxD+fDQ==", + "dev": true, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", + "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "dev": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve/node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.19.1.tgz", + "integrity": "sha512-lAbrdN7neYCg/8WaoWn/ckzCtz+jr70GFfYdlf50OF7387HTg+wiuiqJRFYawwSPpqfqDNYqK7smY/ks2iAudg==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.2.tgz", + "integrity": "sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==", + "dev": true + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-literal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz", + "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.8.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.4.0.tgz", + "integrity": "sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.1.tgz", + "integrity": "sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.1.1.tgz", + "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/tough-cookie/node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/tough-cookie/node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tough-cookie/node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ufo": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.1.1.tgz", + "integrity": "sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==", + "dev": true + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.4.tgz", + "integrity": "sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==", + "dev": true, + "dependencies": { + "esbuild": "^0.16.14", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.10.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.29.2.tgz", + "integrity": "sha512-5oe1z6wzI3gkvc4yOBbDBbgpiWiApvuN4P55E8OI131JGrSuo4X3SOZrNmZYo4R8Zkze/dhi572blX0zc+6SdA==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.1.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.16.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/vitest": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.29.2.tgz", + "integrity": "sha512-ydK9IGbAvoY8wkg29DQ4ivcVviCaUi3ivuPKfZEVddMTenFHUfB8EEDXQV8+RasEk1ACFLgMUqAaDuQ/Nk+mQA==", + "dev": true, + "dependencies": { + "@types/chai": "^4.3.4", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.29.2", + "@vitest/runner": "0.29.2", + "@vitest/spy": "0.29.2", + "@vitest/utils": "0.29.2", + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.7", + "debug": "^4.3.4", + "local-pkg": "^0.4.2", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "source-map": "^0.6.1", + "std-env": "^3.3.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.3.1", + "tinyspy": "^1.0.2", + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.29.2", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": ">=v14.16.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@vitest/browser": "*", + "@vitest/ui": "*", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/webcrypto-core": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.6.tgz", + "integrity": "sha512-TBPiewB4Buw+HI3EQW+Bexm19/W4cP/qZG/02QJCXN+iN+T5sl074vZ3rJcle/ZtDBQSgjkbsQO/1eFcxnSBUA==", + "dev": true, + "dependencies": { + "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "dev": true, + "optional": true + }, + "@peculiar/asn1-schema": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.6.tgz", + "integrity": "sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==", + "dev": true, + "requires": { + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "@peculiar/json-schema": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", + "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", + "dev": true, + "requires": { + "tslib": "^2.0.0" + } + }, + "@peculiar/webcrypto": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.1.tgz", + "integrity": "sha512-eK4C6WTNYxoI7JOabMoZICiyqRRtJB220bh0Mbj5RwRycleZf9BPyZoxsTvpP0FpmVS2aS13NKOuh5/tN3sIRw==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.3.0", + "@peculiar/json-schema": "^1.1.12", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.1", + "webcrypto-core": "^1.7.4" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "dev": true + }, + "@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "@types/chai-subset": { + "version": "1.3.3", + "dev": true, + "requires": { + "@types/chai": "*" + } + }, + "@types/node": { + "version": "18.15.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.1.tgz", + "integrity": "sha512-U2TWca8AeHSmbpi314QBESRk7oPjSZjDsR+c+H4ECC1l+kFgpZf8Ydhv3SJpPy51VyZHHqxlb6mTTqYNNRVAIw==", + "dev": true + }, + "@types/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", + "dev": true + }, + "@vitest/expect": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.29.2.tgz", + "integrity": "sha512-wjrdHB2ANTch3XKRhjWZN0UueFocH0cQbi2tR5Jtq60Nb3YOSmakjdAvUa2JFBu/o8Vjhj5cYbcMXkZxn1NzmA==", + "dev": true, + "requires": { + "@vitest/spy": "0.29.2", + "@vitest/utils": "0.29.2", + "chai": "^4.3.7" + } + }, + "@vitest/runner": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.29.2.tgz", + "integrity": "sha512-A1P65f5+6ru36AyHWORhuQBJrOOcmDuhzl5RsaMNFe2jEkoj0faEszQS4CtPU/LxUYVIazlUtZTY0OEZmyZBnA==", + "dev": true, + "requires": { + "@vitest/utils": "0.29.2", + "p-limit": "^4.0.0", + "pathe": "^1.1.0" + } + }, + "@vitest/spy": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.29.2.tgz", + "integrity": "sha512-Hc44ft5kaAytlGL2PyFwdAsufjbdOvHklwjNy/gy/saRbg9Kfkxfh+PklLm1H2Ib/p586RkQeNFKYuJInUssyw==", + "dev": true, + "requires": { + "tinyspy": "^1.0.2" + } + }, + "@vitest/utils": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.29.2.tgz", + "integrity": "sha512-F14/Uc+vCdclStS2KEoXJlOLAEyqRhnw0gM27iXw9bMTcyKRPJrQ+rlC6XZ125GIPvvKYMPpVxNhiou6PsEeYQ==", + "dev": true, + "requires": { + "cli-truncate": "^3.1.0", + "diff": "^5.1.0", + "loupe": "^2.3.6", + "picocolors": "^1.0.0", + "pretty-format": "^27.5.1" + } + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + }, + "acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "requires": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "acorn-walk": { + "version": "8.2.0", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "dev": true, + "requires": { + "debug": "4" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "asn1js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", + "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "dev": true, + "requires": { + "pvtsutils": "^1.3.2", + "pvutils": "^1.1.3", + "tslib": "^2.4.0" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "dev": true + }, + "cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + } + }, + "combined-stream": { + "version": "1.0.8", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "requires": { + "rrweb-cssom": "^0.6.0" + } + }, + "data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + } + }, + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.4", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "dev": true + }, + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true + }, + "domexception": { + "version": "4.0.0", + "dev": true, + "requires": { + "webidl-conversions": "^7.0.0" + } + }, + "dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" + } + }, + "escodegen": { + "version": "2.0.0", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "4.0.1", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "html-encoding-sniffer": { + "version": "3.0.0", + "dev": true, + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, + "http-proxy-agent": { + "version": "5.0.0", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.6.3", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "dev": true + }, + "jsdom": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-21.1.1.tgz", + "integrity": "sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "acorn": "^8.8.2", + "acorn-globals": "^7.0.0", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + } + }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "mime-db": { + "version": "1.52.0", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mlly": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.2.0.tgz", + "integrity": "sha512-+c7A3CV0KGdKcylsI6khWyts/CYrGTrRVo4R/I7u/cUsy0Conxa6LUhiEzVKIw14lc2L5aiO4+SeVe4TeGRKww==", + "dev": true, + "requires": { + "acorn": "^8.8.2", + "pathe": "^1.1.0", + "pkg-types": "^1.0.2", + "ufo": "^1.1.1" + } + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "nwsapi": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", + "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + }, + "dependencies": { + "entities": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "dev": true + } + } + }, + "path-parse": { + "version": "1.0.7", + "dev": true + }, + "pathe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.0.tgz", + "integrity": "sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "dev": true + }, + "pkg-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.2.tgz", + "integrity": "sha512-hM58GKXOcj8WTqUXnsQyJYXdeAPbythQgEF3nTcEo+nkD49chjQ9IKm/QJy9xf6JakXptz86h7ecP2024rrLaQ==", + "dev": true, + "requires": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.1.1", + "pathe": "^1.1.0" + } + }, + "playwright": { + "version": "1.31.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.31.2.tgz", + "integrity": "sha512-jpC47n2PKQNtzB7clmBuWh6ftBRS/Bt5EGLigJ9k2QAKcNeYXZkEaDH5gmvb6+AbcE0DO6GnXdbl9ogG6Eh+og==", + "dev": true, + "requires": { + "playwright-core": "1.31.2" + } + }, + "playwright-core": { + "version": "1.31.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.31.2.tgz", + "integrity": "sha512-a1dFgCNQw4vCsG7bnojZjDnPewZcw7tZUNFN0ZkcLYKj+mPmXvg4MpaaKZ5SgqPsOmqIf2YsVRkgqiRDxD+fDQ==", + "dev": true + }, + "postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "prelude-ls": { + "version": "1.1.2", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "pvtsutils": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", + "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "dev": true, + "requires": { + "tslib": "^2.4.0" + } + }, + "pvutils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", + "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "dev": true + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "dependencies": { + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + } + } + }, + "rollup": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.19.1.tgz", + "integrity": "sha512-lAbrdN7neYCg/8WaoWn/ckzCtz+jr70GFfYdlf50OF7387HTg+wiuiqJRFYawwSPpqfqDNYqK7smY/ks2iAudg==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "dev": true + }, + "saxes": { + "version": "6.0.0", + "dev": true, + "requires": { + "xmlchars": "^2.2.0" + } + }, + "siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + } + } + }, + "source-map": { + "version": "0.6.1", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "std-env": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.2.tgz", + "integrity": "sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + } + } + }, + "strip-literal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz", + "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", + "dev": true, + "requires": { + "acorn": "^8.8.2" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true + }, + "symbol-tree": { + "version": "3.2.4", + "dev": true + }, + "tinybench": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.4.0.tgz", + "integrity": "sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==", + "dev": true + }, + "tinypool": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.1.tgz", + "integrity": "sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==", + "dev": true + }, + "tinyspy": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.1.1.tgz", + "integrity": "sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==", + "dev": true + }, + "tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "dev": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + } + } + }, + "tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "requires": { + "punycode": "^2.3.0" + } + }, + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, + "ufo": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.1.1.tgz", + "integrity": "sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==", + "dev": true + }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true + }, + "vite": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.4.tgz", + "integrity": "sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==", + "dev": true, + "requires": { + "esbuild": "^0.16.14", + "fsevents": "~2.3.2", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.10.0" + } + }, + "vite-node": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.29.2.tgz", + "integrity": "sha512-5oe1z6wzI3gkvc4yOBbDBbgpiWiApvuN4P55E8OI131JGrSuo4X3SOZrNmZYo4R8Zkze/dhi572blX0zc+6SdA==", + "dev": true, + "requires": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.1.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0" + } + }, + "vitest": { + "version": "0.29.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.29.2.tgz", + "integrity": "sha512-ydK9IGbAvoY8wkg29DQ4ivcVviCaUi3ivuPKfZEVddMTenFHUfB8EEDXQV8+RasEk1ACFLgMUqAaDuQ/Nk+mQA==", + "dev": true, + "requires": { + "@types/chai": "^4.3.4", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.29.2", + "@vitest/runner": "0.29.2", + "@vitest/spy": "0.29.2", + "@vitest/utils": "0.29.2", + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.7", + "debug": "^4.3.4", + "local-pkg": "^0.4.2", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "source-map": "^0.6.1", + "std-env": "^3.3.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.3.1", + "tinyspy": "^1.0.2", + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.29.2", + "why-is-node-running": "^2.2.2" + }, + "dependencies": { + "local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true + } + } + }, + "w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "requires": { + "xml-name-validator": "^4.0.0" + } + }, + "webcrypto-core": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.6.tgz", + "integrity": "sha512-TBPiewB4Buw+HI3EQW+Bexm19/W4cP/qZG/02QJCXN+iN+T5sl074vZ3rJcle/ZtDBQSgjkbsQO/1eFcxnSBUA==", + "dev": true, + "requires": { + "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/json-schema": "^1.1.12", + "asn1js": "^3.0.1", + "pvtsutils": "^1.3.2", + "tslib": "^2.4.0" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "dev": true + }, + "whatwg-encoding": { + "version": "2.0.0", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + } + }, + "whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true + }, + "whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "requires": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + } + }, + "why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "requires": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + } + }, + "word-wrap": { + "version": "1.2.3", + "dev": true + }, + "ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "requires": {} + }, + "xml-name-validator": { + "version": "4.0.0", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "dev": true + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..daee313 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "spotify-web-api-ts-skd", + "version": "1.0.0", + "description": "A typescript SDK for the Spotify Web API", + "main": "index.js", + "scripts": { + "start": "npx vite serve", + "test": "vitest run", + "ci": "npm run test && npm run build", + "build": "tsc" + }, + "exports": { + "import": "./dist/index.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/spotify/spotify-web-api-ts-sdk" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@peculiar/webcrypto": "^1.4.1", + "@types/node": "^18.15.1", + "@types/uuid": "^9.0.1", + "dotenv": "^16.0.3", + "jsdom": "^21.1.1", + "playwright": "^1.31.2", + "typescript": "^4.9.5", + "uuid": "^9.0.0", + "vite": "^4.1.4", + "vitest": "^0.29.2" + }, + "publishConfig": { + "access": "public" + }, + "keywords": [ + "spotify", + "webapi" + ], + "wallaby": { + "autoDetect": [ + "vitest" + ], + "trace": true + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..17f9b98 --- /dev/null +++ b/readme.md @@ -0,0 +1,228 @@ +# Spotify Web API SDK - TypeScript + +This is a JavaScript/TypeScript SDK for the [Spotify Web API](https://developer.spotify.com/web-api/). + +## Requirements + +Because we use `fetch` both in Node and the Browser, and ESM, we require the following: + +- Node 18.0.0 or higher +- A modern, version infinite, browser + +## Running the example app + +First install the dependencies: + +```bash +npm install +``` + +Create a `.env` file in the example directory with your `client_id` and redirect url: + +```bash .env +VITE_SPOTIFY_CLIENT_ID=your_spotify_client_id_for_tests +VITE_REDIRECT_TARGET=http://localhost:3000 +``` + +To run the app: + +```bash +npm run start +``` + +### Creating a client instance + +Creating an instance of the SDK is easy, and can be done in a number of ways depending on which form of authentication you want to use. + +```js +import SpotifyWebApi from 'spotify-web-api-sdk'; + +// Choose one of the following: +const sdk = SpotifyApi.withUserAuthorization("client-id", "https://localhost:3000", ["scope1", "scope2"]); +const sdk = SpotifyApi.withClientCredentials("client-id", "secret", ["scope1", "scope2"]); +const sdk = SpotifyApi.withImplicitGrant("client-id", "secret", ["scope1", "scope2"]); +``` + +Each of these factory methods will return a `SpotifyApi` instance, which you can use to make requests to the Spotify Web API. + +### Authentication Methods + +- Authorization Code Flow with PKCE +- Client Credentials Flow +- Implicit Grant Flow + +We do auto-token refresh when expired and a refresh token is available. + +### Extensibility + +All of the constructors support a configuration object that lets you override the default behavior of the SDK. + +Our defaults look like this, and each of the properties is optional, and can be overridden. + +```ts +const defaultConfig: SdkConfiguration = { + fetch: (req: RequestInfo | URL, init: RequestInit | undefined) => fetch(req, init), + beforeRequest: (_: string, __: RequestInit) => { }, + afterRequest: (_: string, __: RequestInit, ___: Response) => { }, + deserializer: new DefaultResponseDeserializer(), + responseValidator: new DefaultResponseValidator(), + errorHandler: new NoOpErrorHandler(), + redirectionStrategy: new DocumentLocationRedirectionStrategy(), + cachingStrategy: new LocalStorageCachingStrategy() +}; +``` + +As a general rule, this options should be overridden when you create your instance of the client, and you probably won't have to change any of them unless you have some very specific requirements. + +You can provide the options like this, to any of the constructors or static initilisation methods: + +```js +const opts = { + fetch: (req, init) => { + console.log("Called via my custom fetch!"); + return fetch(req, init); + } +} + +const sdk = SpotifyApi.withUserAuthorization("client-id", "https://callback", ["scope1"], opts); +``` + +All the below examples are in TypeScript, but the same method signatures all apply to JavaScript - just without the Type information. + +### Extensibility - fetch + +You can override the default Fetch implementation by passing in a function that takes a `RequestInfo` and `RequestInit` and returns a `Promise`. By default, we use the browser and nodes built in `fetch` implementation. + +```js +const opts = { + fetch: (req, init) => { + // Do something with the request + return fetch(req, init); + } +} +``` + +### Extensibility - beforeRequest and afterRequest + +You can override the default `beforeRequest` and `afterRequest` callbacks by passing in functions that take a `RequestInfo` and `RequestInit` and return nothing. By default, we do nothing. + +You can use these functions to implement custom instrumentation, logging, or other functionality. + +```js +const opts = { + beforeRequest: (req, init) => { + console.log("Called before the request is made"); + }, + afterRequest: (req, init, res) => { + console.log("Called after the request is made"); + } +} +``` + +### Extensibility - deserializer + +You can override the default deserializer by passing in a class that implements the `IResponseDeserializer` interface. By default, we use the `DefaultResponseDeserializer` class. + +To implement your own, you need to provide an object with the following method signature: + +```ts +async deserialize(response: Response): Promise { + // Implement your custom deserialization logic here +} +``` + +You'll probably never need to do this unless you feel the need to add custom logging around deserialization behaviour or wish to customise the default objects returned during serialization failures. + +### Extensibility - responseValidator + +You can override the default response validator by passing in a class that implements the `IValidateResponses` interface. By default, we use the `DefaultResponseValidator` class. + +Our default impelementation validates the following: + +- The response status code is in the 200 range +- Errors are thrown for 400 and 500 range status codes +- Non-200 response codes throw errors with the API response body inside of them + +If you need to customise this behaviour, replace the implementation like this: + +```ts +export default class MyResponseValidator implements IValidateResponses { + public async validateResponse(response: Response): Promise { + // Something here + } +} +``` + +### Extensibility - errorHandler + +You can override the default error handler by passing in a class that implements the `IHandleErrors` interface. By default, we use the `NoOpErrorHandler` class which... does nothing! + +If you need to customise this behaviour, replace the implementation like this: + +```ts +export default class MyErrorHandler implements IHandleErrors { + public async handleErrors(error: any): Promise { + return false; + } +} +``` + +If you return `true` from your error handler, the SDK will not throw an error, and treat it as handleed, returning null from the request that triggered it. Returning false will re-throw the original error after your handler has run. + +### Extensibility - redirectionStrategy + +You can override the default redirection strategy by passing in a class that implements the `IRedirect` interface. By default, we use the `DocumentLocationRedirectionStrategy` class. + +```ts +export default class DocumentLocationRedirectionStrategy implements IRedirectionStrategy { + public async redirect(targetUrl: string | URL): Promise { + document.location = targetUrl.toString(); + } + + public async onReturnFromRedirect(): Promise { + } +} +``` + +You might want to override this behaviour if you use a client side framework like React or Vue and you need to record some state, or trigger some opration before the redirect for oAuth / token exchange happens. For example - you might want to add something to localStorage that you can read back when the user returns to the application. + +### Extensibility - cachingStrategy + +You can override the default caching strategy by passing in a class that implements the `ICache` interface. By default, we use the `LocalStorageCachingStrategy` class. + +```ts +interface ICachingStrategy { + getOrCreate(cacheKey: string, createFunction: () => Promise): Promise; + get(cacheKey: string): T & ICachable | null; + setCacheItem(cacheKey: string, item: T & ICachable): void; + remove(cacheKey: string): void; +} +``` + +We provide a default browser (localStorage) caching strategy and (TODO) a node in-memory caching strategy. + +## Running the tests + +To run the tests, you need to have a Spotify account. + +You will need to create a new app in the Spotify Developer portal, and add a redirect URI of `http://localhost:3000`. + +You will need to add the following environment variables: + +- `INTEGRATION_TESTS_SPOTIFY_CLIENT_ID` +- `INTEGRATION_TESTS_SPOTIFY_CLIENT_SECRET` +- `INTEGRATION_TESTS_USER_EMAIL` +- `INTEGRATION_TESTS_USER_PASSWORD` + +The latter two credentials are used to run integration tests in the scope of a *real user account*. This is required to test endpoints that require a user's authorization, such as `followPlaylist`. You need to make sure that your user has access to whichever Spotify app your client credentials and secret are for. + +You can run the tests with `npm run test`, or using a plugin like [Wallaby](https://wallabyjs.com/). + +We support `dotenv`, so you can add these to a `.env` file in the root of the repository. + +To run the embedded example app, you will need to add the following environment variables: + +- `VITE_SPOTIFY_CLIENT_ID`=the same value as set in INTEGRATION_TESTS_SPOTIFY_CLIENT_ID +- `VITE_REDIRECT_TARGET`=http://localhost:3000 + +For the example app to work, this .env file needs to be in the ./example folder. diff --git a/src/SpotifyApi.test.ts b/src/SpotifyApi.test.ts new file mode 100644 index 0000000..6cfafd4 --- /dev/null +++ b/src/SpotifyApi.test.ts @@ -0,0 +1,83 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { SpotifyApi } from "./SpotifyApi"; +import { buildUnitTestSdkInstance } from "./test/SpotifyApiBuilder"; +import { FakeAuthStrategy } from "./test/FakeAuthStrategy"; +import { FetchApiMock } from "./test/FetchApiMock"; +import { validAlbumResult } from "./test/data/validAlbumResult"; + +describe("SpotifyAPI Instance", () => { + let sut: SpotifyApi; + let fetchMock: FetchApiMock; + beforeEach(() => { + [sut, fetchMock] = buildUnitTestSdkInstance(); + }); + + describe("uses provided authenticate strategy", () => { + it("makes API requests with API token returned form auth strategy", async () => { + fetchMock.queueResponseBody(200, validAlbumResult()); + + await sut.albums.get("album-id-here"); + + const [headers, bodyString] = fetchMock.issuedRequestHeadersAndBody(0); + expect((headers as any).Authorization).toBe(`Bearer ${FakeAuthStrategy.FAKE_AUTH_TOKEN}`) + }); + }); + + describe("has default handling or error codes", () => { + it("401 errors throw bad or expired token Error", async () => { + fetchMock.queueResponseBody(401, {}); + + await expect(async () => { + await sut.albums.get("album-id-here"); + }).rejects.toThrowError("Bad or expired token"); + }); + + it("403 errors throw oAuth Error", async () => { + fetchMock.queueResponseBody(403, {}); + + await expect(async () => { + await sut.albums.get("album-id-here"); + }).rejects.toThrowError("Bad OAuth request"); + }); + + it("429 errors throw rate limit Error", async () => { + fetchMock.queueResponseBody(429, {}); + + await expect(async () => { + await sut.albums.get("album-id-here"); + }).rejects.toThrowError("The app has exceeded its rate limits."); + }); + + it("204 returns null for no-content responses", async () => { + fetchMock.queueResponseBody(204, null); + + const result = await sut.albums.get("album-id-here"); + + expect(result).toBeNull(); + }); + + it("other Non-200 other response codes throws unrecognised response code error", async () => { + fetchMock.queueResponseBody(123, null); + + await expect(async () => { + await sut.albums.get("album-id-here"); + }).rejects.toThrowError("Unrecognised response code: 123"); + }); + + it("can create an instance with the authorization code strategy configured", async () => { + const sut = SpotifyApi.withUserAuthorization("client-id", "https://localhost:3000", ["scope1", "scope2"]); + expect(sut["authenticationStrategy"].constructor.name).toBe("AuthorizationCodeWithPKCEStrategy"); + }); + + it("can create an instance with the client credentials strategy configured", async () => { + const sut = SpotifyApi.withClientCredentials("client-id", "secret", ["scope1", "scope2"]); + expect(sut["authenticationStrategy"].constructor.name).toBe("ClientCredentialsStrategy"); + }); + + it("can create an instance with the implicit grant strategy configured", async () => { + const sut = SpotifyApi.withImplicitGrant("client-id", "secret", ["scope1", "scope2"]); + expect(sut["authenticationStrategy"].constructor.name).toBe("ImplicitGrantStrategy"); + }); + + }); +}); diff --git a/src/SpotifyApi.ts b/src/SpotifyApi.ts new file mode 100644 index 0000000..8c613b2 --- /dev/null +++ b/src/SpotifyApi.ts @@ -0,0 +1,142 @@ +import AlbumsEndpoints from "./endpoints/AlbumsEndpoints"; +import ArtistsEndpoints from "./endpoints/ArtistsEndpoints"; +import AudiobooksEndpoints from "./endpoints/AudiobooksEndpoints"; +import BrowseEndpoints from "./endpoints/BrowseEndpoints"; +import ChaptersEndpoints from "./endpoints/ChaptersEndpoints"; +import EpisodesEndpoints from "./endpoints/EpisodesEndpoints"; +import RecommendationsEndpoints from "./endpoints/RecommendationsEndpoints"; +import MarketsEndpoints from "./endpoints/MarketsEndpoints"; +import PlayerEndpoints from "./endpoints/PlayerEndpoints"; +import PlaylistsEndpoints from "./endpoints/PlaylistsEndpoints"; +import SearchEndpoints, { SearchExecutionFunction } from "./endpoints/SearchEndpoints"; +import ShowsEndpoints from "./endpoints/ShowsEndpoints"; +import TracksEndpoints from "./endpoints/TracksEndpoints"; +import IAuthStrategy from "./auth/IAuthStrategy"; +import UsersEndpoints from "./endpoints/UsersEndpoints"; +import CurrentUserEndpoints from "./endpoints/CurrentUserEndpoints"; +import ClientCredentialsStrategy from "./auth/ClientCredentialsStrategy"; +import ImplicitGrantStrategy from "./auth/ImplicitGrantStrategy"; +import AuthorizationCodeWithPKCEStrategy from "./auth/AuthorizationCodeWithPKCEStrategy"; +import DefaultResponseDeserializer from "./serialization/DefaultResponseDeserializer"; +import DefaultResponseValidator from "./responsevalidation/DefaultResponseValidator"; +import NoOpErrorHandler from "./errorhandling/NoOpErrorHandler"; +import DocumentLocationRedirectionStrategy from "./redirection/DocumentLocationRedirectionStrategy"; +import LocalStorageCachingStrategy from "./caching/LocalStorageCachingStrategy"; + +export class SpotifyApi { + private sdkConfig: SdkConfiguration; + private static rootUrl: string = "https://api.spotify.com/v1/"; + + private authenticationStrategy: IAuthStrategy; + + public albums: AlbumsEndpoints; + public artists: ArtistsEndpoints; + public audiobooks: AudiobooksEndpoints; + public browse: BrowseEndpoints; + public chapters: ChaptersEndpoints; + public episodes: EpisodesEndpoints; + public recommendations: RecommendationsEndpoints; + public markets: MarketsEndpoints; + public player: PlayerEndpoints; + public playlists: PlaylistsEndpoints; + public shows: ShowsEndpoints; + public tracks: TracksEndpoints; + public users: UsersEndpoints; + public search: SearchExecutionFunction; + + public currentUser: CurrentUserEndpoints; + + public constructor(authentication: IAuthStrategy, config?: SdkOptions) { + this.sdkConfig = this.initilizeSdk(config); + + this.albums = new AlbumsEndpoints(this); + this.artists = new ArtistsEndpoints(this); + this.audiobooks = new AudiobooksEndpoints(this); + this.browse = new BrowseEndpoints(this); + this.chapters = new ChaptersEndpoints(this); + this.episodes = new EpisodesEndpoints(this); + this.recommendations = new RecommendationsEndpoints(this); + this.markets = new MarketsEndpoints(this); + this.player = new PlayerEndpoints(this); + this.playlists = new PlaylistsEndpoints(this); + this.shows = new ShowsEndpoints(this); + this.tracks = new TracksEndpoints(this); + this.users = new UsersEndpoints(this); + this.currentUser = new CurrentUserEndpoints(this); + + const search = new SearchEndpoints(this); + this.search = search.execute.bind(search); + + this.authenticationStrategy = authentication; + this.authenticationStrategy.setConfiguration(this.sdkConfig); + } + + public async makeRequest(method: "GET" | "POST" | "PUT" | "DELETE", url: string, body: any = undefined): Promise { + try { + const token = await this.authenticationStrategy.getAccessToken(); + + const fullUrl = SpotifyApi.rootUrl + url; + const opts: RequestInit = { + method: method, + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json" + }, + body: body ? JSON.stringify(body) : undefined + }; + + this.sdkConfig.beforeRequest(fullUrl, opts); + const result = await this.sdkConfig.fetch(fullUrl, opts); + this.sdkConfig.afterRequest(fullUrl, opts, result); + + if (result.status === 204) { + return null as TReturnType; + } + + await this.sdkConfig.responseValidator.validateResponse(result); + return this.sdkConfig.deserializer.deserialize(result); + } catch (error) { + const handled = await this.sdkConfig.errorHandler.handleErrors(error); + if (!handled) { + throw error; + } + return null as TReturnType; + } + } + + private initilizeSdk(config: SdkOptions | undefined): SdkConfiguration { + const defaultConfig: SdkConfiguration = { + fetch: (req: RequestInfo | URL, init: RequestInit | undefined) => fetch(req, init), + beforeRequest: (_: string, __: RequestInit) => { }, + afterRequest: (_: string, __: RequestInit, ___: Response) => { }, + deserializer: new DefaultResponseDeserializer(), + responseValidator: new DefaultResponseValidator(), + errorHandler: new NoOpErrorHandler(), + redirectionStrategy: new DocumentLocationRedirectionStrategy(), + cachingStrategy: new LocalStorageCachingStrategy() + }; + + return { ...defaultConfig, ...config }; + } + + public switchAuthenticationStrategy(authentication: IAuthStrategy) { + this.authenticationStrategy = authentication; + this.authenticationStrategy.setConfiguration(this.sdkConfig); + this.authenticationStrategy.getAccessToken(); // trigger any redirects + } + + public static withUserAuthorization(clientId: string, redirectUri: string, scopes: string[] = [], config?: SdkOptions): SpotifyApi { + const strategy = new AuthorizationCodeWithPKCEStrategy(clientId, redirectUri, scopes); + return new SpotifyApi(strategy, config); + } + + public static withClientCredentials(clientId: string, clientSecret: string, scopes: string[] = [], config?: SdkOptions): SpotifyApi { + const strategy = new ClientCredentialsStrategy(clientId, clientSecret, scopes); + return new SpotifyApi(strategy, config); + } + + public static withImplicitGrant(clientId: string, redirectUri: string, scopes: string[] = [], config?: SdkOptions): SpotifyApi { + const strategy = new ImplicitGrantStrategy(clientId, redirectUri, scopes); + return new SpotifyApi(strategy, config); + } +} diff --git a/src/auth/AccessTokenHelpers.ts b/src/auth/AccessTokenHelpers.ts new file mode 100644 index 0000000..4e7d004 --- /dev/null +++ b/src/auth/AccessTokenHelpers.ts @@ -0,0 +1,58 @@ +export default class AccessTokenHelpers { + public static async refreshCachedAccessToken(clientId: string, item: AccessToken) { + const updated = await AccessTokenHelpers.refreshToken(clientId, item.refresh_token); + return AccessTokenHelpers.toCachable(updated); + } + + public static toCachable(item: AccessToken): ICachable & AccessToken { + return { ...item, expires: Date.now() + (item.expires_in * 1000) }; + } + + private static async refreshToken(clientId: string, refreshToken: string): Promise { + const params = new URLSearchParams(); + params.append("client_id", clientId); + params.append("grant_type", "refresh_token"); + params.append("refresh_token", refreshToken); + + const result = await fetch("https://accounts.spotify.com/api/token", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: params + }); + + const text = await result.text(); + + if (!result.ok) { + throw new Error(`Failed to refresh token: ${result.statusText}, ${text}`); + } + + const json: AccessToken = JSON.parse(text); + return json; + } + + public static generateCodeVerifier(length: number) { + let text = ''; + let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + + for (let i = 0; i < length; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + } + + public static async generateCodeChallenge(codeVerifier: string) { + const data = new TextEncoder().encode(codeVerifier); + + if (!window.crypto || !window.crypto.subtle) { + const { Crypto } = require("@peculiar/webcrypto"); + const crypto = new Crypto(); + window.crypto = crypto; + } + + const digest = await window.crypto.subtle.digest('SHA-256', data); + return btoa(String.fromCharCode.apply(null, [...new Uint8Array(digest)])) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + } +} diff --git a/src/auth/AuthorizationCodeWithPKCEStrategy.ts b/src/auth/AuthorizationCodeWithPKCEStrategy.ts new file mode 100644 index 0000000..44ade63 --- /dev/null +++ b/src/auth/AuthorizationCodeWithPKCEStrategy.ts @@ -0,0 +1,118 @@ +import AccessTokenHelpers from "./AccessTokenHelpers"; +import IAuthStrategy from "./IAuthStrategy"; + +interface CachedVerifier extends ICachable { + verifier: string; + expiresOnAccess: boolean; +} + +export default class AuthorizationCodeWithPKCEStrategy implements IAuthStrategy { + + private configuration: SdkConfiguration | null = null; + private static emptyAccessToken: AccessToken = { access_token: "", token_type: "", expires_in: 0, refresh_token: "" }; + protected get cache(): ICachingStrategy { return this.configuration!.cachingStrategy; } + + constructor( + protected clientId: string, + protected redirectUri: string, + protected scopes: string[] + ) { + } + + public setConfiguration(configuration: SdkConfiguration): void { + this.configuration = configuration; + } + + public async getAccessToken(): Promise { + const cacheKey = "spotify-sdk:AuthorizationCodeWithPKCEStrategy:token"; + + const token = await this.cache.getOrCreate(cacheKey, async () => { + const token = await this.redirectOrVerifyToken(); + return AccessTokenHelpers.toCachable(token); + }, async (expiring) => { + return AccessTokenHelpers.refreshCachedAccessToken(this.clientId, expiring); + }); + + return token?.access_token; + } + + private async redirectOrVerifyToken(): Promise { + const hashParams = new URLSearchParams(window.location.search); + const code = hashParams.get("code"); + + if (!code) { + const verifier = AccessTokenHelpers.generateCodeVerifier(128); + const challenge = await AccessTokenHelpers.generateCodeChallenge(verifier); + + const singleUseVerifier: CachedVerifier = { verifier, expiresOnAccess: true }; + this.cache.setCacheItem("spotify-sdk:verifier", singleUseVerifier); + + const redirectTarget = await this.generateRedirectUrlForUser(this.scopes, challenge); + await this.configuration!.redirectionStrategy.redirect(redirectTarget); + + // Redirected away at this point, just make TypeScript happy :) + return AuthorizationCodeWithPKCEStrategy.emptyAccessToken; + } + + this.removeCodeFromUrl(); + + const cachedItem = await this.cache.get("spotify-sdk:verifier"); + const verifier = cachedItem?.verifier; + + if (!verifier) { + throw new Error("No verifier found in cache - can't validate query string callback parameters."); + } + + await this.configuration!.redirectionStrategy.onReturnFromRedirect(); + return await this.exchangeCodeForToken(code, verifier!); + } + + private removeCodeFromUrl() { + const url = new URL(window.location.href); + url.searchParams.delete("code"); + + const newUrl = url.search ? url.href : url.href.replace('?', ''); + window.history.replaceState({}, document.title, newUrl); + } + + protected async generateRedirectUrlForUser(scopes: string[], challenge: string) { + scopes = scopes ?? []; + const scope = scopes.join(' '); + + const params = new URLSearchParams(); + params.append("client_id", this.clientId); + params.append("response_type", "code"); + params.append("redirect_uri", this.redirectUri); + params.append("scope", scope); + params.append("code_challenge_method", "S256"); + params.append("code_challenge", challenge); + + return `https://accounts.spotify.com/authorize?${params.toString()}`; + } + + protected async exchangeCodeForToken(code: string, verifier: string): Promise { + const params = new URLSearchParams(); + params.append("client_id", this.clientId); + params.append("grant_type", "authorization_code"); + params.append("code", code); + params.append("redirect_uri", this.redirectUri); + params.append("code_verifier", verifier!); + + const result = await fetch("https://accounts.spotify.com/api/token", { + method: "POST", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: params + }); + + const text = await result.text(); + + if (!result.ok) { + throw new Error(`Failed to exchange code for token: ${result.statusText}, ${text}`); + } + + const json: AccessToken = JSON.parse(text); + return json; + } + +} + diff --git a/src/auth/ClientCredentialsStrategy.ts b/src/auth/ClientCredentialsStrategy.ts new file mode 100644 index 0000000..b0f0914 --- /dev/null +++ b/src/auth/ClientCredentialsStrategy.ts @@ -0,0 +1,55 @@ +import AccessTokenHelpers from "./AccessTokenHelpers"; +import IAuthStrategy from "./IAuthStrategy"; + +export default class ClientCredentialsStrategy implements IAuthStrategy { + + private configuration: SdkConfiguration | null = null; + private get cache(): ICachingStrategy { return this.configuration!.cachingStrategy; } + + constructor( + private clientId: string, + private clientSecret: string, + private scopes: string[] = [] + ) { + } + + public setConfiguration(configuration: SdkConfiguration): void { + this.configuration = configuration; + } + + public async getAccessToken(): Promise { + const cacheKey = "spotify-sdk:ClientCredentialsStrategy:token"; + + const token = await this.cache.getOrCreate(cacheKey, async () => { + const token = await this.getTokenFromApi(); + return AccessTokenHelpers.toCachable(token); + }); + + return token?.access_token; + } + + private async getTokenFromApi(): Promise { + const options = { + grant_type: 'client_credentials', + scope: this.scopes.join(' ') + } as any; + + const bodyAsString = Object.keys(options).map(key => key + '=' + options[key]).join('&'); + + const result = await fetch("https://accounts.spotify.com/api/token", { + method: 'POST', + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Authorization": 'Basic ' + (new Buffer(this.clientId + ':' + this.clientSecret).toString('base64')) + }, + body: bodyAsString + }); + + if (result.status !== 200) { + throw new Error("Failed to get access token."); + } + + const json = await result.json(); + return json; + } +} diff --git a/src/auth/IAuthStrategy.ts b/src/auth/IAuthStrategy.ts new file mode 100644 index 0000000..1849ae9 --- /dev/null +++ b/src/auth/IAuthStrategy.ts @@ -0,0 +1,4 @@ +export default interface IAuthStrategy { + setConfiguration(configuration: SdkConfiguration): void; + getAccessToken(): Promise; +} diff --git a/src/auth/ImplicitGrantStrategy.ts b/src/auth/ImplicitGrantStrategy.ts new file mode 100644 index 0000000..cd20dea --- /dev/null +++ b/src/auth/ImplicitGrantStrategy.ts @@ -0,0 +1,60 @@ +import AccessTokenHelpers from "./AccessTokenHelpers"; +import IAuthStrategy from "./IAuthStrategy"; + +export default class ImplicitGrantStrategy implements IAuthStrategy { + private configuration: SdkConfiguration | null = null; + private static emptyAccessToken: AccessToken = { access_token: "", token_type: "", expires_in: 0, refresh_token: "" }; + private get cache(): ICachingStrategy { return this.configuration!.cachingStrategy; } + + constructor( + private clientId: string, + private redirectUri: string, + private scopes: string[] + ) { + } + + public setConfiguration(configuration: SdkConfiguration): void { + this.configuration = configuration; + } + + public async getAccessToken(): Promise { + const cacheKey = "spotify-sdk:ImplicitGrantStrategy:token"; + + const token = await this.cache.getOrCreate(cacheKey, async () => { + const token = await this.redirectOrVerifyToken(); + return AccessTokenHelpers.toCachable(token); + }, async (expiring) => { + return AccessTokenHelpers.refreshCachedAccessToken(this.clientId, expiring); + }); + + return token?.access_token; + } + + private async redirectOrVerifyToken(): Promise { + const hashParams = new URLSearchParams(window.location.hash.substring(1)); + const accessToken = hashParams.get("access_token"); + + if (accessToken) { + return Promise.resolve({ + access_token: accessToken, + token_type: hashParams.get("token_type") ?? "", + expires_in: parseInt(hashParams.get("expires_in") ?? "0"), + refresh_token: hashParams.get("refresh_token") ?? "" + }); + } + + const scopes = this.scopes ?? []; + var scope = scopes.join(' '); + + const params = new URLSearchParams(); + params.append("client_id", this.clientId); + params.append("response_type", "token"); + params.append("redirect_uri", this.redirectUri); + params.append("scope", scope); + + const authUrl = 'https://accounts.spotify.com/authorize?' + params.toString(); + + this.configuration!.redirectionStrategy.redirect(authUrl); + return ImplicitGrantStrategy.emptyAccessToken; + } +} diff --git a/src/caching/GenericCache.test.ts b/src/caching/GenericCache.test.ts new file mode 100644 index 0000000..a679d40 --- /dev/null +++ b/src/caching/GenericCache.test.ts @@ -0,0 +1,189 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import GenericCache from "./GenericCache"; +import { ICacheStore } from "./ICacheStore"; + +describe('GenericCache', () => { + + let store: ICacheStore; + let sut: GenericCache; + beforeEach(() => { + store = new TestCacheStore(); + sut = new GenericCache(store); + }); + + it("get item that isn't in the cache, returns null", async () => { + const result = await sut.get<{ test: string }>('test'); + expect(result).toBeNull(); + }); + + it('should set and get a value', async () => { + sut.set('test', { test: "test" }, 1000); + const result = await sut.get<{ test: string }>('test'); + expect(result?.test).toBe('test'); + }); + + it('should remove a value', async () => { + sut.set('test', { test: "test" }, 1000); + sut.remove('test'); + const result = await sut.get<{ test: string }>('test'); + expect(result).toBeNull(); + }); + + it('should return null for expired value', async () => { + sut.set('test', { test: "test" }, 0); + const result = await sut.get<{ test: string }>('test'); + expect(result).toBeNull(); + }); + + it("should return and remove value if expiresOnAccess is true", async () => { + const value = { test: "test", expiresOnAccess: true }; + sut.setCacheItem('test', value); + + const result = await sut.get<{ test: string }>('test'); + expect(result).toEqual(value); + + const result2 = await sut.get<{ test: string }>('test'); + expect(result2).toBeNull(); + }); + + it("should throw an error if the factory func fails to create an object", async () => { + await expect(sut.getOrCreate('test', async () => { + return null as any; + })).rejects.toThrow("Could not create cache item"); + }); + + it("should return the created object if the factory func succeeds", async () => { + const result = await sut.getOrCreate('test', async () => { + return { test: "test" }; + }); + expect(result.test).toBe("test"); + }); + + it("should return existing item if it exists in the cache when getOrCreate is called", async () => { + sut.set('test', { test: "test" }, 1000); + + const result = await sut.getOrCreate('test', async () => { + return { test: "test2" }; + }); + + expect(result.test).toBe("test"); + }); + + it("can renew an item if an update function is provided and it's within two minutes of expiry", async () => { + sut = new GenericCache(store, new Map(), 100); // Auto-renew checks every 100ms + const expiry = Date.now() + (1 * (60 * 1000)); // One minute from now + + await sut.getOrCreate('test', async () => { + return { test: "test", expires: expiry, }; + }, async (item) => { + return { test: "test2", expires: Date.now() + 10 * (60 * 1000) }; + }); + + await wait(500); + + const result = await sut.get<{ test: string }>('test'); + + expect(result!.test).toBe("test2"); + }); + + it("does not renew an item if an update function is provided and it's not yet within two minutes of expiry", async () => { + sut = new GenericCache(store, new Map(), 100); // Auto-renew checks every 100ms + const expiry = Date.now() + (3 * (60 * 1000)); // Three minutes from now + + await sut.getOrCreate('test', async () => { + return { test: "test", expires: expiry, }; + }, async (item) => { + throw new Error("Should not be called"); + }); + + await wait(500); + + const result = await sut.get<{ test: string }>('test'); + + expect(result!.test).toBe("test"); + }); + + it("renewal triggered by get request when auto-renewal disabled and item within refresh window", async () => { + sut = new GenericCache(store, new Map(), -1); // Auto-renewal disabled + const expiry = Date.now() + (1 * (60 * 1000)); // One minute from now + + await sut.getOrCreate('test', async () => { + return { test: "test", expires: expiry, }; + }, async (item) => { + return { test: "test2", expires: Date.now() + 10 * (60 * 1000) }; + }); + + let result = await sut.get<{ test: string }>('test'); + + expect(result!.test).toBe("test2"); + }); + + it("renewal triggered by get request, which errors, when auto-renewal disabled, returns un-renewed item", async () => { + sut = new GenericCache(store, new Map(), -1); // Auto-renewal disabled + const expiry = Date.now() + (1 * (60 * 1000)); // One minute from now + + await sut.getOrCreate('test', async () => { + return { test: "test", expires: expiry, }; + }, async (item) => { + throw new Error("Test error"); + }); + + let result = await sut.get<{ test: string }>('test'); + + expect(result!.test).toBe("test"); + }); + + it("renewal triggered by autorenew, fails gracefully, returns un-renewed item", async () => { + sut = new GenericCache(store, new Map(), 100); // Auto-renew checks every 100ms + const expiry = Date.now() + (1 * (60 * 1000)); // One minute from now + + await sut.getOrCreate('test', async () => { + return { test: "test", expires: expiry, }; + }, async (item) => { + throw new Error("Test error"); + }); + + await wait(500); + + const result = await sut.get<{ test: string }>('test'); + + expect(result!.test).toBe("test"); + }); + + it("renewal triggered for item which has already been explicitly removed, skips renewal attempt", async () => { + sut = new GenericCache(store, new Map(), 10); // Auto-renew checks every 100ms + const expiry = Date.now() + (1 * (60 * 1000)); // One minute from now + + let renewCalled = false; + + await sut.getOrCreate('test', async () => { + return { test: "test", expires: expiry, }; + }, async (item) => { + renewCalled = true; + throw new Error("Should not be called"); + }); + + sut.remove('test'); + + await wait(50); + expect(renewCalled).toBe(false); + }); +}); + +const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +class TestCacheStore implements ICacheStore { + private cache = new Map(); + + public get(key: string): string | null { + return this.cache.get(key) ?? null; + } + + public set(key: string, value: string): void { + this.cache.set(key, value); + } + + public remove(key: string): void { + this.cache.delete(key); + } +} \ No newline at end of file diff --git a/src/caching/GenericCache.ts b/src/caching/GenericCache.ts new file mode 100644 index 0000000..c626eb8 --- /dev/null +++ b/src/caching/GenericCache.ts @@ -0,0 +1,119 @@ +import { ICacheStore } from "./ICacheStore"; + +export default class GenericCache implements ICachingStrategy { + constructor( + private storage: ICacheStore, + private updateFunctions: Map Promise> = new Map(), + private autoRenewInterval: number = 10000, + private autoRenewWindow: number = 2 * 60 * 1000 // Two minutes + ) { + if (this.autoRenewInterval > 0) { + setInterval(() => this.autoRenewRenewableItems(), this.autoRenewInterval); + } + } + + public async getOrCreate( + cacheKey: string, + createFunction: () => Promise, + updateFunction?: (item: T) => Promise + ): Promise { + const item = await this.get(cacheKey); + if (item) { + return item; + } + + const newCacheItem = await createFunction(); + if (!newCacheItem) { + throw new Error("Could not create cache item"); + } + + this.setCacheItem(cacheKey, newCacheItem); + if (updateFunction) { + this.updateFunctions.set(cacheKey, updateFunction); + } + + return newCacheItem; + } + + public async get(cacheKey: string): Promise { + let asString = this.storage.get(cacheKey); + let cachedItem: T & ICachable = asString ? JSON.parse(asString) : null; + + if (this.itemDueToExpire(cachedItem) && this.updateFunctions.has(cacheKey)) { + const updateFunction = this.updateFunctions.get(cacheKey); + await this.tryUpdateItem(cacheKey, cachedItem, updateFunction!); + + // Ensure updated item is returned + asString = this.storage.get(cacheKey); + cachedItem = asString ? JSON.parse(asString) : null; + } + + if (!cachedItem) { + return null; + } + + if (cachedItem.expires && (cachedItem.expires === -1 || cachedItem.expires <= Date.now())) { + this.remove(cacheKey); + return null; + } + + if (cachedItem.expiresOnAccess && cachedItem.expiresOnAccess === true) { + this.remove(cacheKey); + return cachedItem; + } + + return cachedItem; + } + + public set(cacheKey: string, value: object, expiresIn: number): void { + const expires = Date.now() + expiresIn; + const cacheItem: ICachable = { ...value, expires }; + this.setCacheItem(cacheKey, cacheItem); + } + + public setCacheItem(cacheKey: string, cacheItem: ICachable): void { + const asString = JSON.stringify(cacheItem); + this.storage.set(cacheKey, asString); + } + + public remove(cacheKey: string): void { + this.storage.remove(cacheKey); + } + + private itemDueToExpire(item: ICachable): boolean { + if (!item) { + return false; + } + + if (!item.expires) { + return false; + } + + return item.expires - Date.now() < (this.autoRenewWindow); + } + + private async autoRenewRenewableItems() { + this.updateFunctions.forEach(async (updateFunction, key) => { + const cachedItem = await this.get(key); + if (!cachedItem) { + return; + } + + if (updateFunction && this.itemDueToExpire(cachedItem)) { + await this.tryUpdateItem(key, cachedItem, updateFunction); + } + }); + } + + private async tryUpdateItem(key: string, cachedItem: ICachable, updateFunction: (item: ICachable) => Promise) { + try { + const updated = await updateFunction(cachedItem); + if (updated) { + this.setCacheItem(key, updated); + } + } catch (e) { + console.error(e); + } + } + +} diff --git a/src/caching/ICacheStore.ts b/src/caching/ICacheStore.ts new file mode 100644 index 0000000..198783e --- /dev/null +++ b/src/caching/ICacheStore.ts @@ -0,0 +1,5 @@ +export interface ICacheStore { + get(key: string): string | null; + set(key: string, value: string): void; + remove(key: string): void; +} diff --git a/src/caching/InMemoryCachingStrategy.ts b/src/caching/InMemoryCachingStrategy.ts new file mode 100644 index 0000000..748badf --- /dev/null +++ b/src/caching/InMemoryCachingStrategy.ts @@ -0,0 +1,24 @@ +import GenericCache from "./GenericCache"; +import { ICacheStore } from "./ICacheStore"; + +export default class InMemoryCachingStrategy extends GenericCache { + constructor() { + super(new DictionaryCacheStore()); + } +} + +class DictionaryCacheStore implements ICacheStore { + private cache = new Map(); + + public get(key: string): string | null { + return this.cache.get(key) ?? null; + } + + public set(key: string, value: string): void { + this.cache.set(key, value); + } + + public remove(key: string): void { + this.cache.delete(key); + } +} diff --git a/src/caching/LocalStorageCachingStrategy.ts b/src/caching/LocalStorageCachingStrategy.ts new file mode 100644 index 0000000..8a65b0a --- /dev/null +++ b/src/caching/LocalStorageCachingStrategy.ts @@ -0,0 +1,22 @@ +import GenericCache from "./GenericCache"; +import { ICacheStore } from "./ICacheStore"; + +export default class LocalStorageCachingStrategy extends GenericCache { + constructor() { + super(new LocalStorageCacheStore()); + } +} + +class LocalStorageCacheStore implements ICacheStore { + public get(key: string): string | null { + return localStorage.getItem(key); + } + + public set(key: string, value: string): void { + localStorage.setItem(key, value); + } + + public remove(key: string): void { + localStorage.removeItem(key); + } +} diff --git a/src/endpoints/AlbumsEndpoints.test.ts b/src/endpoints/AlbumsEndpoints.test.ts new file mode 100644 index 0000000..8850d72 --- /dev/null +++ b/src/endpoints/AlbumsEndpoints.test.ts @@ -0,0 +1,40 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { validAlbumTracksResult } from "../test/data/validAlbumTracksResult"; +import { validAlbumResult } from "../test/data/validAlbumResult"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; + +describe("Integration: Albums Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getAlbum can return information for valid album", async () => { + const item = validAlbumResult(); + const result = await sut.albums.get(item.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/albums/${item.id}`); + expect(result.name).toBe(item.name); + }); + + it("getAlbums can return multiple items at once", async () => { + const item = validAlbumResult(); + const result = await sut.albums.get([item.id, item.id]); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/albums?ids=${item.id}%2C${item.id}`); + expect(result.length).toBe(2); + expect(result[0].id).toBe(item.id); + expect(result[1].id).toBe(item.id); + }); + + it("getAlbumTracks returns correct tracks for valid album", async () => { + const item = validAlbumResult(); + const result = await sut.albums.tracks(item.id); + + expect(result.items.length).toBe(validAlbumTracksResult().items.length); + }); +}); diff --git a/src/endpoints/AlbumsEndpoints.ts b/src/endpoints/AlbumsEndpoints.ts new file mode 100644 index 0000000..52713c9 --- /dev/null +++ b/src/endpoints/AlbumsEndpoints.ts @@ -0,0 +1,24 @@ +import EndpointsBase from './EndpointsBase'; + +export default class AlbumsEndpoints extends EndpointsBase { + + public async get(id: string, market?: Market): Promise; + public async get(ids: string[], market?: Market): Promise; + public async get(idOrIds: string | string[], market?: Market) { + if (typeof idOrIds === 'string') { + const params = this.paramsFor({ market }); + const album = await this.getRequest(`albums/${idOrIds}${params}`); + return album; + } + + const params = this.paramsFor({ ids: idOrIds, market }); + // TODO: only returns top 20, validate here + const response = await this.getRequest(`albums${params}`); + return response.albums; + } + + public tracks(albumId: string, market?: Market, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ market, limit, offset }); + return this.getRequest>(`albums/${albumId}/tracks${params}`); + } +} diff --git a/src/endpoints/ArtistsEndpoint.test.ts b/src/endpoints/ArtistsEndpoint.test.ts new file mode 100644 index 0000000..4a6e3ee --- /dev/null +++ b/src/endpoints/ArtistsEndpoint.test.ts @@ -0,0 +1,57 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { validArtist } from "../test/data/validArtist"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; + +describe("Integration: Artists Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getArtist can return information", async () => { + const valid = validArtist(); + const result = await sut.artists.get(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/artists/${valid.id}`); + expect(result.name).toBe(valid.name); + }); + + it("getArtists can return multiple items", async () => { + const valid = validArtist(); + const result = await sut.artists.get([valid.id, valid.id]); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/artists?ids=${valid.id}%2C${valid.id}`); + expect(result.length).toBe(2); + expect(result[0].name).toBe(valid.name); + expect(result[1].name).toBe(valid.name); + }); + + it("getArtistAlbums can return information", async () => { + const valid = validArtist(); + const result = await sut.artists.albums(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/artists/${valid.id}/albums`); + expect(result.items.length).toBeGreaterThan(0); + }); + + it("getArtistTopTracks can return information", async () => { + const valid = validArtist(); + const result = await sut.artists.topTracks(valid.id, "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/artists/${valid.id}/top-tracks?market=GB`); + expect(result.tracks.length).toBeGreaterThan(0); + }); + + it("getArtistRelatedArtists can return information", async () => { + const valid = validArtist(); + const result = await sut.artists.relatedArtists(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/artists/${valid.id}/related-artists`); + expect(result.artists.length).toBeGreaterThan(0); + }); + +}); diff --git a/src/endpoints/ArtistsEndpoints.ts b/src/endpoints/ArtistsEndpoints.ts new file mode 100644 index 0000000..006b5cb --- /dev/null +++ b/src/endpoints/ArtistsEndpoints.ts @@ -0,0 +1,36 @@ +import EndpointsBase from './EndpointsBase'; + +export default class ArtistsEndpoints extends EndpointsBase { + + public async get(id: string): Promise; + public async get(ids: string[]): Promise; + public async get(idOrIds: string | string[]) { + if (typeof idOrIds === 'string') { + const artist = this.getRequest(`artists/${idOrIds}`); + return artist; + } + + const params = this.paramsFor({ ids:idOrIds }); + // TODO: only returns top 50, validate here + const response = await this.getRequest(`artists${params}`); + return response.artists; + } + + public albums(id: string, includeGroups?: string, market?: Market, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ "include_groups": includeGroups, market, limit, offset }); + return this.getRequest>(`artists/${id}/albums${params}`); + } + + public topTracks(id: string, market: Market) { + // BUG: market is flagged as optional in the docs, but it's actually required for this endpoint + // otherwise you get a 400 + + const params = this.paramsFor({ market }); + return this.getRequest(`artists/${id}/top-tracks${params}`); + } + + public relatedArtists(id: string) { + return this.getRequest(`artists/${id}/related-artists`); + } + +} diff --git a/src/endpoints/AudiobooksEndpoints.test.ts b/src/endpoints/AudiobooksEndpoints.test.ts new file mode 100644 index 0000000..4fe458a --- /dev/null +++ b/src/endpoints/AudiobooksEndpoints.test.ts @@ -0,0 +1,43 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { validAudioBook } from "../test/data/validAudioBook"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validAudiobookChapters } from "../test/data/validAudiobookChapters"; + +describe("Integration: Audiobooks Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getAudiobook can return information", async () => { + const item = validAudioBook(); + const result = await sut.audiobooks.get(item.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/audiobooks/${item.id}`); + expect(result.id).toBe(item.id); + }); + + it("getAudiobooks can return multiple items at once", async () => { + const item = validAudioBook(); + const result = await sut.audiobooks.get([item.id, item.id]); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/audiobooks?ids=${item.id}%2C${item.id}`); + expect(result.length).toBe(2); + expect(result[0].id).toBe(item.id); + expect(result[1].id).toBe(item.id); + }); + + it("getAudiobookChapters can return information", async () => { + const item = validAudioBook(); + const chapters = validAudiobookChapters(); + + const result = await sut.audiobooks.getAudiobookChapters(item.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/audiobooks/${item.id}/chapters`); + expect(result.items.length).toBeGreaterThan(0); + }); +}); diff --git a/src/endpoints/AudiobooksEndpoints.ts b/src/endpoints/AudiobooksEndpoints.ts new file mode 100644 index 0000000..4aab3de --- /dev/null +++ b/src/endpoints/AudiobooksEndpoints.ts @@ -0,0 +1,22 @@ +import EndpointsBase from './EndpointsBase'; + +export default class AudiobooksEndpoints extends EndpointsBase { + public async get(id: string, market?: Market): Promise; + public async get(ids: string[], market?: Market): Promise; + public async get(idOrIds: string | string[], market?: Market) { + if (typeof idOrIds === 'string') { + const params = this.paramsFor({ market }); + return this.getRequest(`audiobooks/${idOrIds}${params}`); + } + + const params = this.paramsFor({ ids: idOrIds, market }); + const response = await this.getRequest(`audiobooks${params}`); + return response.audiobooks; + } + + public getAudiobookChapters(id: string, market?: Market, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ market, limit, offset }); + return this.getRequest>(`audiobooks/${id}/chapters${params}`); + } + +} diff --git a/src/endpoints/BrowseEndpoints.test.ts b/src/endpoints/BrowseEndpoints.test.ts new file mode 100644 index 0000000..e1030b2 --- /dev/null +++ b/src/endpoints/BrowseEndpoints.test.ts @@ -0,0 +1,45 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validCategory } from "../test/data/validCategory"; + +describe("Integration: Browse Categories Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getCategories can return information", async () => { + const result = await sut.browse.getCategories();//? + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/browse/categories`); + expect(result.categories.items.length).toBeGreaterThan(0); + }); + + it("getCategory can return information", async () => { + const valid = validCategory(); + + const result = await sut.browse.getCategory(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/browse/categories/${valid.id}`); + expect(result).toStrictEqual(valid); + }); + + it("getCategorysPlaylists returns playlists", async () => { + // Seems broken? + + const valid = validCategory(); + const result = await sut.browse.getPlaylistsForCategory(valid.id); + + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/browse/categories/${valid.id}/playlists`); + expect(result.playlists.items.length).toBeGreaterThan(0); + }); + + it("getNewReleases returns some new releases", async () => { + const result = await sut.browse.getNewReleases(); + expect(result.albums.items.length).toBeGreaterThan(0); + }); +}); \ No newline at end of file diff --git a/src/endpoints/BrowseEndpoints.ts b/src/endpoints/BrowseEndpoints.ts new file mode 100644 index 0000000..6384424 --- /dev/null +++ b/src/endpoints/BrowseEndpoints.ts @@ -0,0 +1,31 @@ +import EndpointsBase from './EndpointsBase'; + +export default class BrowseEndpoints extends EndpointsBase { + + public getCategories(country?: CountryCodeA2, locale?: string, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ country, locale, limit, offset }); + + return this.getRequest(`browse/categories${params}`); + } + + public getCategory(categoryId: string, country?: CountryCodeA2, locale?: string) { + const params = this.paramsFor({ country, locale }); + + return this.getRequest(`browse/categories/${categoryId}${params}`); + } + + public getNewReleases(country?: string, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ country, limit, offset }); + return this.getRequest(`browse/new-releases${params}`); + } + + public getFeaturedPlaylists(country?: CountryCodeA2, locale?: string, timestamp?: string, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ country, locale, timestamp, limit, offset }); + return this.getRequest(`browse/featured-playlists${params}`); + } + + public getPlaylistsForCategory(category_id: string, country?: CountryCodeA2, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ country, limit, offset }); + return this.getRequest(`browse/categories/${category_id}/playlists${params}`); + } +} diff --git a/src/endpoints/ChaptersEndpoints.test.ts b/src/endpoints/ChaptersEndpoints.test.ts new file mode 100644 index 0000000..13f57d7 --- /dev/null +++ b/src/endpoints/ChaptersEndpoints.test.ts @@ -0,0 +1,31 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validAudiobookChapterResponse } from "../test/data/validChapterApiResponse"; + +describe("Integration: Chapters Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getChapter can return information", async () => { + const valid = validAudiobookChapterResponse(); + const result = await sut.chapters.get(valid.id, "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/chapters/${valid.id}?market=GB`); + expect(result.id).toBe(valid.id); + }); + + it("getChapters can return multiple items at once", async () => { + const valid = validAudiobookChapterResponse(); + const result = await sut.chapters.get([valid.id, valid.id], "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/chapters?ids=${valid.id}%2C${valid.id}&market=GB`); + expect(result[0].id).toBe(valid.id); + expect(result[1].id).toBe(valid.id); + }); +}); diff --git a/src/endpoints/ChaptersEndpoints.ts b/src/endpoints/ChaptersEndpoints.ts new file mode 100644 index 0000000..b249ada --- /dev/null +++ b/src/endpoints/ChaptersEndpoints.ts @@ -0,0 +1,20 @@ +import EndpointsBase from './EndpointsBase'; + +// These are mandatory, and the only supported market codes for the Chapters API +export type ChapterMarket = "GB" | "US" | "IE" | "NZ" | "AU"; + +export default class ChaptersEndpoints extends EndpointsBase { + public get(id: string, market: ChapterMarket): Promise; + public get(ids: string[], market: ChapterMarket): Promise; + public async get(idOrIds: string | string[], market: ChapterMarket) { + if (typeof idOrIds === 'string') { + const params = this.paramsFor({ market }); + return this.getRequest(`chapters/${idOrIds}${params}`); + } + + // TODO: Only returns top 50, validate / pre-check here + const params = this.paramsFor({ ids: idOrIds, market }); + const response = await this.getRequest(`chapters${params}`); + return response.chapters; + } +} diff --git a/src/endpoints/CurrentUserEndpoints.test.ts b/src/endpoints/CurrentUserEndpoints.test.ts new file mode 100644 index 0000000..36c7ad1 --- /dev/null +++ b/src/endpoints/CurrentUserEndpoints.test.ts @@ -0,0 +1,179 @@ +import { beforeAll, describe, expect, it } from "vitest"; +import { buildIntegrationTestUserSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validArtist } from "../test/data/validArtist"; +import { validAlbumResult } from "../test/data/validAlbumResult"; + +describe("Integration: Users Endpoints (logged in user)", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeAll(() => { + [sut, fetchSpy] = buildIntegrationTestUserSdkInstance(); + }); + + it("getCurrentUsersProfile returns a real user", async () => { + const result = await sut.currentUser.profile(); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me"); + expect(result.id.length).toBeGreaterThan(0); + }); + + it("getUsersTopItems returns items", async () => { + const result = await sut.currentUser.topItems("artists"); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/top/artists"); + expect(result.limit).toBeGreaterThan(0); + }); + + it("getFollowedArtists returns artists", async () => { + const result = await sut.currentUser.followedArtists(); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/following?type=artist"); + expect(result.artists.items.length).toBeGreaterThan(0); + }); + + it("un/followArtistsOrUsersforCurrentUser can add and remove follows for artists", async () => { + await sut.currentUser.followArtistsOrUsers(["0qJpY7K8p7g6sacvaGNt6i"], "artist"); + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/following?type=artist"); + + const result = await sut.currentUser.followedArtists(); + expect(result.artists.items.find((a) => a.id === '0qJpY7K8p7g6sacvaGNt6i')).toBeTruthy(); + + await sut.currentUser.unfollowArtistsOrUsers(["0qJpY7K8p7g6sacvaGNt6i"], "artist"); + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/following?type=artist"); + + const result2 = await sut.currentUser.followedArtists(); + expect(result2.artists.items.find((a) => a.id === '0qJpY7K8p7g6sacvaGNt6i')).toBeFalsy(); + }); + + it("checkUserFollowsArtistsOrUsers correctly identifies followed artist", async () => { + const valid = validArtist(); + const followed = await sut.currentUser.followedArtists(); + const knownFollowedArtist = followed.artists.items.find((a) => a.id === valid.id)!; + + const result = await sut.currentUser.followsArtistsOrUsers([knownFollowedArtist.id], "artist"); + + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/me/following/contains?ids=${valid.id}&type=artist`); + expect(result[0]).toBeTruthy(); + }); + + it("getUsersSavedAlbums returns items", async () => { + const result = await sut.currentUser.albums.savedAlbums(); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/albums"); + expect(result.items.length).toBeGreaterThan(0); + }); + + it("checkCurrentUsersSavedAlbums returns true for saved known album", async () => { + const valid = validAlbumResult(); + const result = await sut.currentUser.albums.hasSavedAlbums([valid.id]); + + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/me/albums/contains?ids=${valid.id}`); + expect(result[0]).toBe(true); + }); + + it("create and modify playlists for a user works", async () => { + const valid = validAlbumResult(); + const validTrack = valid.tracks.items[0]; + + const me = await sut.currentUser.profile(); + const result = await sut.playlists.createPlaylist(me.id, { + name: "test playlist name!", + description: "test playlist description!" + }); + + await sut.playlists.addItemsToPlaylist(result.id, [validTrack.uri, validTrack.uri, validTrack.uri, "spotify:track:0ZEigpVOtVunIcimL7dJuh"]); + + const snapshotUpdated = await sut.playlists.movePlaylistItems(result.id, 3, 1, 0); // Move last track to start + + let playlist = await sut.playlists.getPlaylist(result.id); + expect(playlist.tracks.items.length).toBe(4); + expect(playlist.tracks.items[1].track.id).toBe(validTrack.id); + + await sut.playlists.removeItemsFromPlaylist(result.id, { + snapshot_id: snapshotUpdated.snapshot_id, + tracks: [{ uri: validTrack.uri }] + }); + + const playlistWithoutTracks = await sut.playlists.getPlaylist(result.id); + expect(playlistWithoutTracks.tracks.items.length).toBe(1); + + await sut.playlists.changePlaylistDetails(result.id, { + name: "test playlist name 2", + description: "test playlist description 2" + }); + + const playlist2 = await sut.playlists.getPlaylist(result.id); + expect(playlist2.name).toBe("test playlist name 2"); + }); + + it("getCurrentUsersPlaylists returns playlists", async () => { + const result = await sut.currentUser.playlists.playlists(); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/playlists"); + expect(result.items.length).toBeGreaterThan(0); + }); + + it("can save and remove album for user", async () => { + const album = "6yWMN087PgSimbcVmHLEwG"; // Aenema by Tool + + await sut.currentUser.albums.saveAlbums([album]); + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/me/albums`); + + const result = await sut.currentUser.albums.savedAlbums(); + expect(result.items.find((a) => a.album.id === album)).toBeTruthy(); + + await sut.currentUser.albums.removeSavedAlbums([album]); + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/me/albums`); + + const result2 = await sut.currentUser.albums.savedAlbums(); + expect(result2.items.find((a) => a.album.id === album)).toBeFalsy(); + }); + + it("getFeaturedPlaylists returns playlists", async () => { + const result = await sut.browse.getFeaturedPlaylists(); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/browse/featured-playlists"); + expect(result.playlists.items.length).toBeGreaterThan(0); + }); + + it("getCategorysPlaylists returns playlists", async () => { + const category_id = "0JQ5DAqbMKFEC4WFtoNRpw"; + const result = await sut.browse.getPlaylistsForCategory(category_id); + + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/browse/categories/${category_id}/playlists`); + expect(result.playlists.items.length).toBeGreaterThan(0); + }); + + it("getCurrentUsersSavedAudiobooks returns playlists", async () => { + const result = await sut.currentUser.audiobooks.savedAudiobooks(); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/audiobooks"); + expect(result.items.length).toBeGreaterThan(0); + }); + + it("checkCurrentUsersSavedAudiobooks returns true for saved book", async () => { + const result = await sut.currentUser.audiobooks.hasSavedAudiobooks(["19Xw49IjNbOCCoebfy3qA9"]); + + expect(fetchSpy.lastRequest().input).toBe("https://api.spotify.com/v1/me/audiobooks/contains?ids=19Xw49IjNbOCCoebfy3qA9"); + expect(result[0]).toBeTruthy(); + }); + + it("can save and remove audiobook for user", async () => { + await sut.currentUser.audiobooks.saveAudiobooks(["2lwSCFrbU1Y7tH3BYS0aeM"]); + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/me/audiobooks`); + + const result2 = await sut.currentUser.audiobooks.savedAudiobooks(); + expect(result2.items.find((a) => a.id === "2lwSCFrbU1Y7tH3BYS0aeM")).toBeTruthy(); + + await sut.currentUser.audiobooks.removeSavedAudiobooks(["2lwSCFrbU1Y7tH3BYS0aeM"]); + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/me/audiobooks`); + + const result3 = await sut.currentUser.audiobooks.savedAudiobooks(); + expect(result3.items.find((a) => a.id === "2lwSCFrbU1Y7tH3BYS0aeM")).toBeFalsy(); + }); + + +}, { timeout: 20000 }); diff --git a/src/endpoints/CurrentUserEndpoints.ts b/src/endpoints/CurrentUserEndpoints.ts new file mode 100644 index 0000000..ec27eb9 --- /dev/null +++ b/src/endpoints/CurrentUserEndpoints.ts @@ -0,0 +1,177 @@ +import { SpotifyApi } from '../SpotifyApi'; +import EndpointsBase from './EndpointsBase'; + +export default class CurrentUserEndpoints extends EndpointsBase { + public albums: CurrentUserAlbumsEndpoints; + public audiobooks: CurrentUserAudiobooksEndpoints; + public episodes: CurrentUserEpisodesEndpoints; + public playlists: CurrentUserPlaylistsEndpoints; + public shows: CurrentUserShowsEndpoints; + public tracks: CurrentUserTracksEndpoints; + + constructor(api: SpotifyApi) { + super(api); + + this.albums = new CurrentUserAlbumsEndpoints(api); + this.audiobooks = new CurrentUserAudiobooksEndpoints(api); + this.episodes = new CurrentUserEpisodesEndpoints(api); + this.playlists = new CurrentUserPlaylistsEndpoints(api); + this.shows = new CurrentUserShowsEndpoints(api); + this.tracks = new CurrentUserTracksEndpoints(api); + } + + public profile() { + return this.getRequest('me'); + } + + public topItems(type: "artists" | "tracks") { + return this.getRequest>(`me/top/${type}`); + } + + public followedArtists(after?: string, limit?: MaxInt<50>) { + const params = this.paramsFor({ type: "artist", after, limit }); + return this.getRequest(`me/following${params}`); + } + + public async followArtistsOrUsers(ids: string[], type: 'artist' | 'user') { + const params = this.paramsFor({ type }); + await this.putRequest(`me/following${params}`, { ids }); + } + + public async unfollowArtistsOrUsers(ids: string[], type: 'artist' | 'user') { + const params = this.paramsFor({ type }); + await this.deleteRequest(`me/following${params}`, { ids }); + } + + public followsArtistsOrUsers(ids: string[], type: 'artist' | 'user') { + const params = this.paramsFor({ ids, type }); + return this.getRequest(`me/following/contains${params}`); + } +} + + +class CurrentUserAlbumsEndpoints extends EndpointsBase { + public savedAlbums(limit?: MaxInt<50>, offset?: number, market?: Market) { + const params = this.paramsFor({ limit, offset, market }); + return this.getRequest>(`me/albums${params}`); + } + + public async saveAlbums(ids: string[]) { + await this.putRequest('me/albums', ids); + } + + public async removeSavedAlbums(ids: string[]) { + await this.deleteRequest('me/albums', ids); + } + + public hasSavedAlbums(ids: string[]) { + const params = this.paramsFor({ ids }); + return this.getRequest(`me/albums/contains${params}`); + } +} + +class CurrentUserAudiobooksEndpoints extends EndpointsBase { + public savedAudiobooks(limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ limit, offset }); + return this.getRequest>(`me/audiobooks${params}`); + } + + public async saveAudiobooks(ids: string[]) { + await this.putRequest('me/audiobooks', ids); + } + + public async removeSavedAudiobooks(ids: string[]) { + await this.deleteRequest('me/audiobooks', ids); + } + + public hasSavedAudiobooks(ids: string[]) { + const params = this.paramsFor({ ids }); + return this.getRequest(`me/audiobooks/contains${params}`); + } +} + +class CurrentUserEpisodesEndpoints extends EndpointsBase { + public savedEpisodes(market?: Market, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ market, limit, offset }); + return this.getRequest(`me/episodes${params}`); + } + + public saveEpisodes(ids: string[]) { + return this.putRequest(`me/episodes`, ids) + } + + public removeSavedEpisodes(ids: string[]) { + return this.deleteRequest(`me/episodes`, ids) + } + + public hasSavedEpisodes(ids: string[]) { + const params = this.paramsFor({ ids }); + return this.getRequest(`me/episodes/contains${params}`); + } +} + +class CurrentUserPlaylistsEndpoints extends EndpointsBase { + public playlists(limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ limit, offset }); + return this.getRequest>(`me/playlists${params}`); + } + + public follow(playlist_id: string) { + return this.putRequest(`playlists/${playlist_id}/followers`); + } + + public unfollow(playlist_id: string) { + return this.deleteRequest(`playlists/${playlist_id}/followers`); + } + + public isFollowing(playlistId: string, ids: string[]) { + const params = this.paramsFor({ ids }); + return this.getRequest(`playlists/${playlistId}/followers/contains${params}`) + } +} + +class CurrentUserShowsEndpoints extends EndpointsBase { + + public savedShows(limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ limit, offset }) + return this.getRequest(`me/shows${params}`); + } + + public saveShows(ids: string[]) { + const idString = ids.join(','); + const params = this.paramsFor({ idString }); + return this.putRequest(`me/shows${params}`); + } + + public removeSavedShows(ids: string[], market?: Market) { + const idString = ids.join(','); + const params = this.paramsFor({ idString, market }); + return this.deleteRequest(`me/shows${params}`); + } + + public hasSavedShow(ids: string[]) { + const idString = ids.join(','); + const params = this.paramsFor({ idString }); + return this.getRequest(`me/shows/contains${params}`); + } +} + +class CurrentUserTracksEndpoints extends EndpointsBase { + public savedTracks(limit?: MaxInt<50>, offset?: number, market?: Market) { + const params = this.paramsFor({ limit, offset, market }); + return this.getRequest(`me/tracks${params}`); + } + public saveTracks(ids: string[]) { + return this.putRequest('me/tracks', ids); + } + + public removeSavedTracks(ids: string[]) { + return this.deleteRequest('me/tracks', ids); + } + + public hasSavedTracks(ids: string[]) { + const params = this.paramsFor({ ids }); + return this.getRequest(`me/tracks/contains${params}`); + } +} + diff --git a/src/endpoints/EndpointsBase.ts b/src/endpoints/EndpointsBase.ts new file mode 100644 index 0000000..d02d61f --- /dev/null +++ b/src/endpoints/EndpointsBase.ts @@ -0,0 +1,33 @@ +import { SpotifyApi } from "../SpotifyApi"; + +export default class EndpointsBase { + constructor(protected api: SpotifyApi) { + } + + protected async getRequest(url: string): Promise { + return await this.api.makeRequest("GET", url); + } + + protected async postRequest(url: string, body?: TBody): Promise { + return await this.api.makeRequest("POST", url, body); + } + + protected async putRequest(url: string, body?: TBody): Promise { + return await this.api.makeRequest("PUT", url, body); + } + + protected async deleteRequest(url: string, body?: TBody): Promise { + return await this.api.makeRequest("DELETE", url, body); + } + + protected paramsFor(args: any) { + const params = new URLSearchParams(); + for (let key of Object.getOwnPropertyNames(args)) { + if (args[key]) { + params.append(key, args[key].toString()); + } + } + return [...params].length > 0 ? `?${params.toString()}` : ""; + } +} + diff --git a/src/endpoints/EpisodesEndpoints.test.ts b/src/endpoints/EpisodesEndpoints.test.ts new file mode 100644 index 0000000..fb837fa --- /dev/null +++ b/src/endpoints/EpisodesEndpoints.test.ts @@ -0,0 +1,31 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validEpisode } from "../test/data/validEpisode"; + +describe("Integration: Episodes Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getEpisode can return information", async () => { + const valid = validEpisode(); + const result = await sut.episodes.get(valid.id, "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/episodes/${valid.id}?market=GB`); + expect(result).toStrictEqual(valid); + }); + + it("getEpisodes can return multiple items at once", async () => { + const valid = validEpisode(); + const result = await sut.episodes.get([valid.id, valid.id], "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/episodes?ids=${valid.id}%2C${valid.id}&market=GB`); + expect(result[0].id).toBe(valid.id); + expect(result[1].id).toBe(valid.id); + }); +}); diff --git a/src/endpoints/EpisodesEndpoints.ts b/src/endpoints/EpisodesEndpoints.ts new file mode 100644 index 0000000..da82287 --- /dev/null +++ b/src/endpoints/EpisodesEndpoints.ts @@ -0,0 +1,17 @@ +import EndpointsBase from './EndpointsBase'; + +export default class EpisodesEndpoints extends EndpointsBase { + + public get(id: string, market: Market): Promise + public get(ids: string[], market: Market): Promise + public async get(idOrIds: string | string[], market: Market) { + if (typeof idOrIds === 'string') { + const params = this.paramsFor({ market }); + return this.getRequest(`episodes/${idOrIds}${params}`); + } + + const params = this.paramsFor({ ids: idOrIds, market }); + const response = await this.getRequest(`episodes${params}`); + return response.episodes; + } +} diff --git a/src/endpoints/MarketsEndpoints.test.ts b/src/endpoints/MarketsEndpoints.test.ts new file mode 100644 index 0000000..1137913 --- /dev/null +++ b/src/endpoints/MarketsEndpoints.test.ts @@ -0,0 +1,22 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validMarkets } from "../test/data/validMarkets"; + +describe("Integration: Episodes Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getAvailableMarkets can return information", async () => { + const valid = validMarkets(); + const result = await sut.markets.getAvailableMarkets(); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/markets`); + expect(result).toStrictEqual(valid); + }); +}); \ No newline at end of file diff --git a/src/endpoints/MarketsEndpoints.ts b/src/endpoints/MarketsEndpoints.ts new file mode 100644 index 0000000..283d4e9 --- /dev/null +++ b/src/endpoints/MarketsEndpoints.ts @@ -0,0 +1,7 @@ +import EndpointsBase from './EndpointsBase'; + +export default class MarketsEndpoints extends EndpointsBase { + public getAvailableMarkets() { + return this.getRequest('markets'); + } +} diff --git a/src/endpoints/PlayerEndpoints.ts b/src/endpoints/PlayerEndpoints.ts new file mode 100644 index 0000000..fff374f --- /dev/null +++ b/src/endpoints/PlayerEndpoints.ts @@ -0,0 +1,94 @@ +import EndpointsBase from './EndpointsBase'; + +interface QueryRange { + timestamp: number; + type: "before" | "after" +} + +export default class PlayerEndpoints extends EndpointsBase { + public getPlaybackState(market?: Market, additionalTypes?: string) { + const params = this.paramsFor({ market, additionalTypes }); + return this.getRequest(`me/player${params}`); + } + + public getAvailableDevices() { + return this.getRequest('me/player/devices'); + } + + public getCurrentlyPlayingTrack(market?: Market, additionalTypes?: string) { + const params = this.paramsFor({ market, additionalTypes }); + return this.getRequest(`me/player/currently-playing${params}`); + } + + public getRecentlyPlayedTracks(limit?: MaxInt<50>, queryRange?: QueryRange) { + const paramObj: any = { limit }; + + if (queryRange) { + if (queryRange.type === "before") { + paramObj.before = queryRange.timestamp + } else if (queryRange.type === "after") { + paramObj.after = queryRange.timestamp + } + } + + const params = this.paramsFor(paramObj); + return this.getRequest(`me/player/recently-played${params}`); + } + + public getUsersQueue() { + return this.getRequest('me/player/queue'); + } + + public transferPlayback(device_ids: string[], play?: boolean) { + if (device_ids.length > 1) { + throw new Error("Although an array is accepted, only a single device_id is currently supported. Supplying more than one will return 400 Bad Request"); + } + return this.putRequest('me/player', { device_ids, play }); + } + + public startResumePlayback(device_id: string, context_uri?: string, uris?: string[], offset?: object, positionMs?: number) { + const params = this.paramsFor({ device_id }); + + return this.putRequest(`me/player/play${params}`, {context_uri, uris, offset, positionMs}); + } + + public pausePlayback(device_id: string) { + const params = this.paramsFor({ device_id }); + return this.putRequest(`me/player/pause${params}`); + } + + public skipToNext(device_id: string) { + const params = this.paramsFor({ device_id }); + return this.postRequest(`me/player/next${params}`); + } + + public skipToPrevious(device_id: string) { + const params = this.paramsFor({ device_id }); + return this.postRequest(`me/player/previous${params}`); + } + + public seekToPosition(position_ms: number, device_id?: string) { + const params = this.paramsFor({ position_ms, device_id }); + return this.putRequest(`me/player/seek${params}`); + } + + public setRepeatMode(state: 'track' | 'context' | 'off', device_id?: string) { + const params = this.paramsFor({ state, device_id }); + this.putRequest(`me/player/repeat${params}`); + } + + public setPlaybackVolume(volume_percent: number, device_id?: string) { + const params = this.paramsFor({ volume_percent, device_id }); + this.putRequest(`me/player/volume${params}`); + } + + public togglePlaybackShuffle(state: boolean, device_id?: string) { + const params = this.paramsFor({ state, device_id }); + this.putRequest(`me/player/shuffle${params}`); + } + + public addItemToPlaybackQueue(uri: string, device_id?: string) { + const params = this.paramsFor({ uri, device_id }); + this.putRequest(`me/player/queue${params}`); + } +} diff --git a/src/endpoints/PlaylistsEndpoints.test.ts b/src/endpoints/PlaylistsEndpoints.test.ts new file mode 100644 index 0000000..f98197a --- /dev/null +++ b/src/endpoints/PlaylistsEndpoints.test.ts @@ -0,0 +1,47 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validPlaylist } from "../test/data/validPlaylist"; +import { validUser } from "../test/data/validUser"; + +describe("Integration: Playlists Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getPlaylist can return information", async () => { + const valid = validPlaylist(); + const result = await sut.playlists.getPlaylist(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/playlists/${valid.id}`); + expect(result.tracks.items.length).toBeGreaterThan(0); + }); + + it("getPlaylist can return information", async () => { + const valid = validPlaylist(); + const result = await sut.playlists.getPlaylistItems(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/playlists/${valid.id}/tracks`); + expect(result.items.length).toBeGreaterThan(0); + }); + + it("getUsersPlaylists can return information", async () => { + const valid = validUser(); + const result = await sut.playlists.getUsersPlaylists(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/users/${valid.id}/playlists`); + expect(result.items.length).toBeGreaterThan(0); + }); + + it("getPlaylistCoverImage returns image info", async () => { + const playlistId = "37i9dQZF1DWXIcbzpLauPS"; + const result = await sut.playlists.getPlaylistCoverImage(playlistId); + + expect(fetchSpy.lastRequest().input).toBe(`https://api.spotify.com/v1/playlists/${playlistId}/images`); + expect(result[0].url.length).toBeGreaterThan(0); + }); +}); \ No newline at end of file diff --git a/src/endpoints/PlaylistsEndpoints.ts b/src/endpoints/PlaylistsEndpoints.ts new file mode 100644 index 0000000..7bf6fc6 --- /dev/null +++ b/src/endpoints/PlaylistsEndpoints.ts @@ -0,0 +1,87 @@ +import EndpointsBase from './EndpointsBase'; + +export default class PlaylistsEndpoints extends EndpointsBase { + + public getPlaylist(playlist_id: string, market?: Market, fields?: string, additional_types?: string) { + // TODO: better support for fields + const params = this.paramsFor({ market, fields, additional_types }); + return this.getRequest(`playlists/${playlist_id}${params}`); + } + + public getPlaylistItems(playlist_id: string, market?: Market, fields?: string, limit?: MaxInt<50>, offset?: number, additional_types?: string) { + // TODO: better support for fields + const params = this.paramsFor({ market, fields, limit, offset, additional_types }); + return this.getRequest>(`playlists/${playlist_id}/tracks${params}`); + } + + public async changePlaylistDetails(playlist_id: string, request: ChangePlaylistDetailsRequest) { + await this.putRequest(`playlists/${playlist_id}`, request); + } + + public movePlaylistItems(playlist_id: string, range_start: number, range_length: number, moveToPosition: number) { + return this.updatePlaylistItems(playlist_id, { + range_start, + range_length, + insert_before: moveToPosition + }); + } + + public updatePlaylistItems(playlist_id: string, request: UpdatePlaylistItemsRequest) { + return this.putRequest(`playlists/${playlist_id}/tracks`, request); + } + + public async addItemsToPlaylist(playlist_id: string, uris?: string[], position?: number) { + await this.postRequest(`playlists/${playlist_id}/tracks`, { position, uris: uris }); + } + + public async removeItemsFromPlaylist(playlist_id: string, request: RemovePlaylistItemsRequest) { + await this.deleteRequest(`playlists/${playlist_id}/tracks`, request); + } + + public getUsersPlaylists(user_id: string, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ limit, offset }); + return this.getRequest>(`users/${user_id}/playlists${params}`); + } + + public createPlaylist(user_id: string, request: CreatePlaylistRequest) { + return this.postRequest(`users/${user_id}/playlists`, request); + } + + public getPlaylistCoverImage(playlist_id: string) { + return this.getRequest(`playlists/${playlist_id}/images`); + } + + public async addCustomPlaylistCoverImage(playlist_id: string) { + // There are no docs for this, seems broken. + await this.putRequest(`playlists/${playlist_id}/images`); + } + +} + +interface RemovePlaylistItemsRequest { + tracks: Array<{ uri: string }>; + snapshot_id?: string; +} + +interface UpdatePlaylistItemsRequest { + uris?: string[]; + range_start?: number; + insert_before?: number; + range_length?: number; + snapshot_id?: string; +} + +interface ChangePlaylistDetailsRequest { + name?: string; + public?: boolean; + collaborative?: boolean; + description?: string; +} + +// TODO: deduplicate this from above +interface CreatePlaylistRequest { + name: string; + public?: boolean; + collaborative?: boolean; + description?: string; +} diff --git a/src/endpoints/RecommendationsEndpoints.test.ts b/src/endpoints/RecommendationsEndpoints.test.ts new file mode 100644 index 0000000..17effd8 --- /dev/null +++ b/src/endpoints/RecommendationsEndpoints.test.ts @@ -0,0 +1,26 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validGenres } from "../test/data/validGenres"; + +describe("Integration: Episodes Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getGenres can return information", async () => { + const valid = validGenres(); + const result = await sut.recommendations.genreSeeds(); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/recommendations/available-genre-seeds`); + expect(result).toStrictEqual(valid); + }); + + it("get can return recommendations", async () => { + const result = await sut.recommendations.get(); + }) +}); diff --git a/src/endpoints/RecommendationsEndpoints.ts b/src/endpoints/RecommendationsEndpoints.ts new file mode 100644 index 0000000..028daaa --- /dev/null +++ b/src/endpoints/RecommendationsEndpoints.ts @@ -0,0 +1,12 @@ +import EndpointsBase from './EndpointsBase'; + +export default class RecommendationsEndpoints extends EndpointsBase { + public get() { + throw new Error("not implemented, too many params :O") + return this.getRequest('recommendations'); + } + + public genreSeeds() { + return this.getRequest('recommendations/available-genre-seeds'); + } +} diff --git a/src/endpoints/SearchEndpoints.test.ts b/src/endpoints/SearchEndpoints.test.ts new file mode 100644 index 0000000..5335477 --- /dev/null +++ b/src/endpoints/SearchEndpoints.test.ts @@ -0,0 +1,21 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; + +describe("Integration: Search Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getTrack can return information", async () => { + const q = "Katatonia" + const result = await sut.search(q, ["artist"]); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/search?q=${q}&type=artist`); + expect(result.artists.items[0].name).toBe("Katatonia"); + }); +}); \ No newline at end of file diff --git a/src/endpoints/SearchEndpoints.ts b/src/endpoints/SearchEndpoints.ts new file mode 100644 index 0000000..a8bb005 --- /dev/null +++ b/src/endpoints/SearchEndpoints.ts @@ -0,0 +1,12 @@ +import EndpointsBase from './EndpointsBase'; + +export interface SearchExecutionFunction { + (q: string, type: ItemTypes[], market?: Market, limit?: MaxInt<50>, offset?: number, include_external?: string): Promise; +} + +export default class SearchEndpoints extends EndpointsBase { + public async execute(q: string, type: ItemTypes[], market?: Market, limit?: MaxInt<50>, offset?: number, include_external?: string) { + const params = this.paramsFor({ q, type, market, limit, offset, include_external }); + return await this.getRequest(`search${params}`); + } +} diff --git a/src/endpoints/ShowsEndpoints.test.ts b/src/endpoints/ShowsEndpoints.test.ts new file mode 100644 index 0000000..d28bede --- /dev/null +++ b/src/endpoints/ShowsEndpoints.test.ts @@ -0,0 +1,39 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validShow } from "../test/data/validShow"; + +describe("Integration: Shows Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getShow can return information", async () => { + const valid = validShow(); + const result = await sut.shows.get(valid.id, "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/shows/${valid.id}?market=GB`); + expect(result.id).toBe(valid.id); + }); + + it("getShows can return information", async () => { + const valid = validShow(); + const result = await sut.shows.get([valid.id, valid.id], "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/shows?ids=${valid.id}%2C${valid.id}&market=GB`); + expect(result[0].id).toBe(valid.id); + expect(result[1].id).toBe(valid.id); + }); + + it("getShowEpisodes can return information", async () => { + const valid = validShow(); + const result = await sut.shows.episodes(valid.id, "GB"); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/shows/${valid.id}/episodes?market=GB`); + expect(result.items.length).toBeGreaterThan(0); + }); +}); diff --git a/src/endpoints/ShowsEndpoints.ts b/src/endpoints/ShowsEndpoints.ts new file mode 100644 index 0000000..8b42569 --- /dev/null +++ b/src/endpoints/ShowsEndpoints.ts @@ -0,0 +1,23 @@ +import EndpointsBase from './EndpointsBase'; + +export default class ShowsEndpoints extends EndpointsBase { + + public get(id: string, market: Market): Promise; + public get(ids: string[], market: Market): Promise + public async get(idOrIds: string | string[], market: Market) { + if(typeof idOrIds === 'string') { + const params = this.paramsFor({ market }) + return this.getRequest(`shows/${idOrIds}${params}`); + } + + // TODO: only returns 50, validate here + const params = this.paramsFor({ ids: idOrIds, market }); + const response = await this.getRequest(`shows${params}`); + return response.shows; + } + + public episodes(id: string, market?: Market, limit?: MaxInt<50>, offset?: number) { + const params = this.paramsFor({ market, limit, offset }) + return this.getRequest>(`shows/${id}/episodes${params}`); + } +} diff --git a/src/endpoints/TracksEndpoints.test.ts b/src/endpoints/TracksEndpoints.test.ts new file mode 100644 index 0000000..06f3d4c --- /dev/null +++ b/src/endpoints/TracksEndpoints.test.ts @@ -0,0 +1,57 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validTrack } from "../test/data/validTrack"; + +describe("Integration: Tracks Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getTrack can return information", async () => { + const valid = validTrack(); + const result = await sut.tracks.get(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/tracks/${valid.id}`); + expect(result.id).toBe(valid.id); + }); + + it("getTracks can return multiple items", async () => { + const valid = validTrack(); + const result = await sut.tracks.get([valid.id, valid.id]); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/tracks?ids=${valid.id}%2C${valid.id}`); + expect(result[0].id).toBe(valid.id); + expect(result[1].id).toBe(valid.id); + }); + + it("audioFeatures can return information", async () => { + const valid = validTrack(); + const result = await sut.tracks.audioFeatures(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/audio-features/${valid.id}`); + expect(result.id).toBe(valid.id); + }); + + it("audioFeatures can return multiple items", async () => { + const valid = validTrack(); + const result = await sut.tracks.audioFeatures([valid.id, valid.id]); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/audio-features?ids=${valid.id}%2C${valid.id}`); + expect(result[0].id).toBe(valid.id); + expect(result[1].id).toBe(valid.id); + }); + + it("audioAnalysis can return information", async () => { + const valid = validTrack(); + const result = await sut.tracks.audioAnalysis(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/audio-analysis/${valid.id}`); + expect(result.track.tempo).toBeGreaterThan(0); + }); + +}); diff --git a/src/endpoints/TracksEndpoints.ts b/src/endpoints/TracksEndpoints.ts new file mode 100644 index 0000000..d2227cc --- /dev/null +++ b/src/endpoints/TracksEndpoints.ts @@ -0,0 +1,34 @@ +import EndpointsBase from './EndpointsBase'; + +export default class TracksEndpoints extends EndpointsBase { + + public get(id: string, market?: Market): Promise + public get(ids: string[], market?: Market): Promise + public async get(idOrIds: string | string[], market?: Market) { + if(typeof idOrIds === 'string') { + const params = this.paramsFor({ market }); + return this.getRequest(`tracks/${idOrIds}${params}`); + } + + const params = this.paramsFor({ ids: idOrIds, market }); + // TODO: only returns top 20, validate here + const response = await this.getRequest(`tracks${params}`); + return response.tracks; + } + + public audioFeatures(id: string): Promise + public audioFeatures(ids: string[]): Promise + public async audioFeatures(idOrIds: string | string[]) { + if (typeof idOrIds === 'string') { + return this.getRequest(`audio-features/${idOrIds}`); + } + const params = this.paramsFor({ ids: idOrIds }); + const response = await this.getRequest(`audio-features${params}`); + return response.audio_features; + } + + public audioAnalysis(id: string) { + return this.getRequest(`audio-analysis/${id}`); + } + +} diff --git a/src/endpoints/UsersEndpoints.test.ts b/src/endpoints/UsersEndpoints.test.ts new file mode 100644 index 0000000..eb2bf75 --- /dev/null +++ b/src/endpoints/UsersEndpoints.test.ts @@ -0,0 +1,23 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { buildIntegrationTestSdkInstance } from "../test/SpotifyApiBuilder"; +import { SpotifyApi } from "../SpotifyApi"; +import { FetchApiSpy } from "../test/FetchApiSpy"; +import { validUser } from "../test/data/validUser"; + +describe("Integration: Users Endpoints", () => { + let sut: SpotifyApi; + let fetchSpy: FetchApiSpy; + + beforeEach(() => { + [sut, fetchSpy] = buildIntegrationTestSdkInstance(); + }); + + it("getUserProfile can return information", async () => { + const valid = validUser(); + const result = await sut.users.profile(valid.id); + + expect(fetchSpy.request(0).input).toBe(`https://api.spotify.com/v1/users/${valid.id}`); + expect(result.id).toBe(valid.id); + expect(result.display_name).toBe(valid.display_name); + }); +}); diff --git a/src/endpoints/UsersEndpoints.ts b/src/endpoints/UsersEndpoints.ts new file mode 100644 index 0000000..1b04362 --- /dev/null +++ b/src/endpoints/UsersEndpoints.ts @@ -0,0 +1,8 @@ +import EndpointsBase from './EndpointsBase'; + +export default class UsersEndpoints extends EndpointsBase { + + public profile(userId: string) { + return this.getRequest(`users/${userId}`); + } +} diff --git a/src/errorhandling/ConsoleLoggingErrorHandler.ts b/src/errorhandling/ConsoleLoggingErrorHandler.ts new file mode 100644 index 0000000..eedf708 --- /dev/null +++ b/src/errorhandling/ConsoleLoggingErrorHandler.ts @@ -0,0 +1,6 @@ +export default class ConsoleLoggingErrorHandler implements IHandleErrors { + public async handleErrors(error: any): Promise { + console.log(error); + return false; + } +} diff --git a/src/errorhandling/NoOpErrorHandler.ts b/src/errorhandling/NoOpErrorHandler.ts new file mode 100644 index 0000000..958009d --- /dev/null +++ b/src/errorhandling/NoOpErrorHandler.ts @@ -0,0 +1,6 @@ +export default class NoOpErrorHandler implements IHandleErrors { + public async handleErrors(error: any): Promise { + return false; + } +} + diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..ffd0a49 --- /dev/null +++ b/src/index.ts @@ -0,0 +1 @@ +export * from "./SpotifyApi"; diff --git a/src/redirection/DocumentLocationRedirectionStrategy.ts b/src/redirection/DocumentLocationRedirectionStrategy.ts new file mode 100644 index 0000000..60503aa --- /dev/null +++ b/src/redirection/DocumentLocationRedirectionStrategy.ts @@ -0,0 +1,8 @@ +export default class DocumentLocationRedirectionStrategy implements IRedirectionStrategy { + public async redirect(targetUrl: string | URL): Promise { + document.location = targetUrl.toString(); + } + + public async onReturnFromRedirect(): Promise { + } +} diff --git a/src/responsevalidation/DefaultResponseValidator.ts b/src/responsevalidation/DefaultResponseValidator.ts new file mode 100644 index 0000000..fe9079a --- /dev/null +++ b/src/responsevalidation/DefaultResponseValidator.ts @@ -0,0 +1,20 @@ +export default class DefaultResponseValidator implements IValidateResponses { + public async validateResponse(response: Response): Promise { + + switch (response.status) { + case 401: + throw new Error("Bad or expired token. This can happen if the user revoked a token or the access token has expired. You should re-authenticate the user."); + case 403: + const body = await response.text(); + throw new Error(`Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately, re-authenticating the user won't help here. Body: ${body}`); + case 429: + throw new Error("The app has exceeded its rate limits."); + default: + if (!response.status.toString().startsWith('20')) { + const body = await response.text(); + throw new Error(`Unrecognised response code: ${response.status} - ${response.statusText}. Body: ${body}`); + } + } + + } +} diff --git a/src/serialization/DefaultResponseDeserializer.ts b/src/serialization/DefaultResponseDeserializer.ts new file mode 100644 index 0000000..a7aaebd --- /dev/null +++ b/src/serialization/DefaultResponseDeserializer.ts @@ -0,0 +1,12 @@ +export default class DefaultResponseDeserializer implements IResponseDeserializer { + public async deserialize(response: Response): Promise { + const text = await response.text(); + + if (text.length > 0) { + const json = JSON.parse(text); + return json as TReturnType; + } + + return null as TReturnType; + } +} diff --git a/src/test/AuthAsRealUserForTests.ts b/src/test/AuthAsRealUserForTests.ts new file mode 100644 index 0000000..ea73de9 --- /dev/null +++ b/src/test/AuthAsRealUserForTests.ts @@ -0,0 +1,68 @@ +import playwright from "playwright"; +import AuthorizationCodeWithPKCEStrategy from "../auth/AuthorizationCodeWithPKCEStrategy"; +import AccessTokenHelpers from "../auth/AccessTokenHelpers"; + +export default class AuthAsSpecifcUserForTests extends AuthorizationCodeWithPKCEStrategy { + constructor( + protected clientId: string, + protected scopes: string[], + private email: string, + private password: string + ) { + super(clientId, "http://localhost:3000", scopes); + } + + public async getAccessToken(): Promise { + const token = await this.cache.getOrCreate("spotify-sdk:token", async () => { + const token = await this.useBrowserAutomationToGetToken(); + const expires = Date.now() + (token.expires_in * 1000); + return { ...token, expires }; + }); + + return token?.access_token; + } + + private async useBrowserAutomationToGetToken(): Promise { + const verifier = AccessTokenHelpers.generateCodeVerifier(128); + const challenge = await AccessTokenHelpers.generateCodeChallenge(verifier); + + const location = await super.generateRedirectUrlForUser(this.scopes, challenge); + + // Redirect to Spotify auth page using playwright + const browser = await playwright.chromium.launch({ headless: true }); + const context = await browser.newContext(); + const page = await context.newPage(); + await page.goto(location); + await page.waitForSelector('input[id="login-username"]'); + + // Fill in the email and password + await page.fill('input[id="login-username"]', this.email); + await page.fill('input[id="login-password"]', this.password); + await page.click('button[id="login-button"]'); + + await page.waitForSelector('button[data-testid="auth-accept"]'); + + let capturedUrl = ""; + try { + await page.click('button[data-testid="auth-accept"]'); + await page.waitForRequest(r => { + const url = r.url(); + capturedUrl = url; + return url.includes("http://localhost:3000"); + }); + } catch (e) { + console.log(capturedUrl, e); + } + + const url = new URL(capturedUrl); + const hashParams = new URLSearchParams(url.searchParams); + const code = hashParams.get("code"); + + // Close the browser + await browser.close(); + + // Exchange the code for a token + const token = await this.exchangeCodeForToken(code!, verifier); + return token; + } +} \ No newline at end of file diff --git a/src/test/FakeAuthStrategy.ts b/src/test/FakeAuthStrategy.ts new file mode 100644 index 0000000..13d8d6c --- /dev/null +++ b/src/test/FakeAuthStrategy.ts @@ -0,0 +1,32 @@ +import IAuthStrategy from "../auth/IAuthStrategy"; + +export class FakeAuthStrategy implements IAuthStrategy { + public static FAKE_AUTH_TOKEN = "fake-auth-token"; + private promiseToResolve: Promise; + private res: any; + + private returnedToken; + + constructor(autoResolve: boolean = true, returnedToken: string = FakeAuthStrategy.FAKE_AUTH_TOKEN) { + + this.returnedToken = returnedToken; + + this.promiseToResolve = new Promise((res, rej) => { + this.res = res; + if (autoResolve) { + res(this.returnedToken); + } + }); + } + + public setConfiguration(configuration: SdkConfiguration): void { + } + + public getAccessToken(): Promise { + return this.promiseToResolve; + } + + public fakeAuthed() { + this.res(this.returnedToken); + } +} diff --git a/src/test/FetchApiMock.ts b/src/test/FetchApiMock.ts new file mode 100644 index 0000000..d1354e4 --- /dev/null +++ b/src/test/FetchApiMock.ts @@ -0,0 +1,44 @@ +export type FetchParams = { input: RequestInfo | URL; init?: RequestInit; }; + +export class FetchApiMock { + public issuedRequests: Array = []; + private responseQueue: Array = []; + + public fetch(input: RequestInfo | URL, init?: RequestInit | undefined): Promise { + this.issuedRequests.push({ input, init }); + return Promise.resolve(this.responseQueue.pop()!); + } + + public queueResponse(response: Response) { + this.responseQueue.push(response); + } + + public queueResponseBody(status: number, body: any) { + this.queueRawResponseBody(status, JSON.stringify(body)); + } + + public queueRawResponseBody(status: number, body: string) { + const fakeResponse = { + status: status, + text: () => { + return JSON.stringify(body); + } + } as any; + + this.queueResponse(fakeResponse); + } + + public isssuedRequest(offset: number) { + return this.issuedRequests[offset]; + } + + public issuedRequestHeadersAndBody(offset: number): [HeadersInit, string] { + const request = this.isssuedRequest(offset); + const { init } = request; + const headers = init?.headers as any; + const body = init?.body as string; + return [headers, body]; + } +} + + diff --git a/src/test/FetchApiSpy.ts b/src/test/FetchApiSpy.ts new file mode 100644 index 0000000..831b768 --- /dev/null +++ b/src/test/FetchApiSpy.ts @@ -0,0 +1,49 @@ +import fs from 'fs'; +import { v4 as uuidv4 } from "uuid"; + +export class FetchApiSpy { + private issuedRequests: Array<{ input: RequestInfo | URL; init?: RequestInit; }> = []; + private logResults: boolean; + + constructor(logResults: boolean = false) { + this.logResults = logResults; + } + + public async fetch(input: RequestInfo | URL, init?: RequestInit | undefined): Promise { + this.issuedRequests.push({ input, init }); + const result = fetch(input, init); + + if (this.logResults) { + const awaited = await result; + const clone = awaited.clone(); + + if (!fs.existsSync("temp")) { + fs.mkdirSync("temp"); + } + + const uniqueId = uuidv4(); + const bodyText = await clone.text(); + + const fileContents = ` +// URL: ${awaited.url} +// Status: ${awaited.status} +// Status Text: ${awaited.statusText} + +${bodyText}`.trim(); + + fs.writeFileSync(`temp/${uniqueId}.json`, fileContents); + + return awaited; + } + + return result; + } + + public request(offset: number) { + return this.issuedRequests[0]; + } + + public lastRequest() { + return this.issuedRequests[this.issuedRequests.length - 1]; + } +} diff --git a/src/test/SpotifyApiBuilder.ts b/src/test/SpotifyApiBuilder.ts new file mode 100644 index 0000000..bb29016 --- /dev/null +++ b/src/test/SpotifyApiBuilder.ts @@ -0,0 +1,94 @@ +import { SpotifyApi } from "../SpotifyApi"; +import ClientCredentialsStrategy from "../auth/ClientCredentialsStrategy"; +import { FakeAuthStrategy } from "./FakeAuthStrategy"; +import { FetchApiMock } from "./FetchApiMock"; +import { FetchApiSpy } from "./FetchApiSpy"; +import AuthAsSpecifcUserForTests from "./AuthAsRealUserForTests"; + +import dotenv from "dotenv"; +dotenv.config(); + +export function buildIntegrationTestSdkInstance(logResults: boolean = false): [SpotifyApi, FetchApiSpy] { + // This should be replaced with a representative server-side auth flow + // that returns a valid access token. + + // We'll load access keys from the .env file, so if it's not provided + // all the integration tests will deliberately fail and not hit + // the Spotify API + + const clientId = process.env.INTEGRATION_TESTS_SPOTIFY_CLIENT_ID; + const clientSecret = process.env.INTEGRATION_TESTS_SPOTIFY_CLIENT_SECRET; + + if (!clientId || !clientSecret) { + throw new Error("No client ID or secret provided. Please provide a valid Spotify client ID and secret in the /.env file as: INTEGRATION_TESTS_SPOTIFY_CLIENT_ID and INTEGRATION_TESTS_SPOTIFY_CLIENT_SECRET"); + } + + const authStrat = new ClientCredentialsStrategy(clientId, clientSecret); + + const fetchSpy = new FetchApiSpy(logResults); + const sdkConfig = { + fetch: (input: RequestInfo | URL, init?: RequestInit | undefined) => { + return fetchSpy.fetch(input, init); + } + } + + const sdkInstance = new SpotifyApi(authStrat, sdkConfig); + + return [sdkInstance, fetchSpy]; +} + +export function buildIntegrationTestUserSdkInstance(logResults: boolean = false): [SpotifyApi, FetchApiSpy] { + const clientId = process.env.INTEGRATION_TESTS_SPOTIFY_CLIENT_ID; + const email = process.env.INTEGRATION_TESTS_USER_EMAIL; + const password = process.env.INTEGRATION_TESTS_USER_PASSWORD; + + if (!clientId || !email || !password) { + throw new Error("No client ID, or secret, or email, or password provided. Please provide a valid Spotify client ID and secret in the /.env file."); + } + + const authStrat = new AuthAsSpecifcUserForTests(clientId, [ + "user-read-private", + "user-read-email", + "playlist-modify-public", + "playlist-modify-private", + "playlist-read-private", + "playlist-read-collaborative", + "user-library-modify", + "user-library-read", + "user-top-read", + "user-read-recently-played", + "user-follow-read", + "user-follow-modify", + "user-read-playback-position", + "user-read-playback-state", + "user-modify-playback-state", + "user-read-currently-playing", + "app-remote-control", + "streaming" + ], email, password); + + const fetchSpy = new FetchApiSpy(logResults); + const sdkConfig = { + fetch: (input: RequestInfo | URL, init?: RequestInit | undefined) => { + return fetchSpy.fetch(input, init); + } + } + + const sdkInstance = new SpotifyApi(authStrat, sdkConfig); + + return [sdkInstance, fetchSpy]; +} + +export function buildUnitTestSdkInstance(): [SpotifyApi, FetchApiMock] { + const authStrat = new FakeAuthStrategy(); + const fetchMock = new FetchApiMock(); + const sdkConfig = { + fetch: (input: RequestInfo | URL, init?: RequestInit | undefined) => { + return fetchMock.fetch(input, init); + } + } + + const sdkInstance = new SpotifyApi(authStrat, sdkConfig); + + return [sdkInstance, fetchMock]; +} diff --git a/src/test/data/validAlbumResult.ts b/src/test/data/validAlbumResult.ts new file mode 100644 index 0000000..3f417bf --- /dev/null +++ b/src/test/data/validAlbumResult.ts @@ -0,0 +1,349 @@ +export function validAlbumResult() { + return { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AU", "AZ", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "MH", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RW", "SA", "SB", "SC", "SE", "SG", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "ZA", "ZM", "ZW"], + "copyrights": [{ + "text": "(C) 2022 Napalm Records Handels GmbH", + "type": "C" + }, { + "text": "(P) 2022 Napalm Records Handels Gmbh", + "type": "P" + }], + "external_ids": { + "upc": "840588171736" + }, + "external_urls": { + "spotify": "https://open.spotify.com/album/4EcfbzCtbJDk2wMwhT4D1h" + }, + "genres": [], + "href": "https://api.spotify.com/v1/albums/4EcfbzCtbJDk2wMwhT4D1h", + "id": "4EcfbzCtbJDk2wMwhT4D1h", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2731465df104ab9c7772fe0da9b", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e021465df104ab9c7772fe0da9b", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048511465df104ab9c7772fe0da9b", + "width": 64 + }], + "label": "Napalm Records Handels GmbH", + "name": "Sky Void of Stars", + "popularity": 57, + "release_date": "2023-01-20", + "release_date_precision": "day", + "total_tracks": 11, + "tracks": { + "href": "https://api.spotify.com/v1/albums/4EcfbzCtbJDk2wMwhT4D1h/tracks?offset=0&limit=50&locale=*", + "items": [{ + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 221200, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/2RM5Lx7VIp6GrLRsg2yXwW" + }, + "href": "https://api.spotify.com/v1/tracks/2RM5Lx7VIp6GrLRsg2yXwW", + "id": "2RM5Lx7VIp6GrLRsg2yXwW", + "is_local": false, + "name": "Austerity", + "preview_url": "https://p.scdn.co/mp3-preview/92060dafd9885ae188be4b7bb3640ad41bf221b3?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 1, + "type": "track", + "uri": "spotify:track:2RM5Lx7VIp6GrLRsg2yXwW" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 269106, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/64izlxZoHpcP1BSMLOFVld" + }, + "href": "https://api.spotify.com/v1/tracks/64izlxZoHpcP1BSMLOFVld", + "id": "64izlxZoHpcP1BSMLOFVld", + "is_local": false, + "name": "Colossal Shade", + "preview_url": "https://p.scdn.co/mp3-preview/1bb8e2f22742f172fda20afb8f5b74b9ab3423df?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 2, + "type": "track", + "uri": "spotify:track:64izlxZoHpcP1BSMLOFVld" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 300560, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/3wFpyxWBsobjg8jOTgcdCM" + }, + "href": "https://api.spotify.com/v1/tracks/3wFpyxWBsobjg8jOTgcdCM", + "id": "3wFpyxWBsobjg8jOTgcdCM", + "is_local": false, + "name": "Opaline", + "preview_url": "https://p.scdn.co/mp3-preview/6656b1ba8062c76b3d10daed8e49b82adbda7485?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 3, + "type": "track", + "uri": "spotify:track:3wFpyxWBsobjg8jOTgcdCM" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 248533, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/1ARmblMbvIf4hD5IVhwCkB" + }, + "href": "https://api.spotify.com/v1/tracks/1ARmblMbvIf4hD5IVhwCkB", + "id": "1ARmblMbvIf4hD5IVhwCkB", + "is_local": false, + "name": "Birds", + "preview_url": "https://p.scdn.co/mp3-preview/a63b5da204ce6c24c2f119ddb439d98eabd7c9fb?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 4, + "type": "track", + "uri": "spotify:track:1ARmblMbvIf4hD5IVhwCkB" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 239613, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/57oPzGWcjklkbwX1Zxu3aI" + }, + "href": "https://api.spotify.com/v1/tracks/57oPzGWcjklkbwX1Zxu3aI", + "id": "57oPzGWcjklkbwX1Zxu3aI", + "is_local": false, + "name": "Drab Moon", + "preview_url": "https://p.scdn.co/mp3-preview/7319eb4d38de1036062499ec20757b9daff60439?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 5, + "type": "track", + "uri": "spotify:track:57oPzGWcjklkbwX1Zxu3aI" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 257426, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/7aAkwLYl0dguLeCzzHXap7" + }, + "href": "https://api.spotify.com/v1/tracks/7aAkwLYl0dguLeCzzHXap7", + "id": "7aAkwLYl0dguLeCzzHXap7", + "is_local": false, + "name": "Author", + "preview_url": "https://p.scdn.co/mp3-preview/95ab24e1a3922735ceb64d57bb00bfc6d2e10a26?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 6, + "type": "track", + "uri": "spotify:track:7aAkwLYl0dguLeCzzHXap7" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 312373, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/2JurXfd61zNHSRj7d5Pb6O" + }, + "href": "https://api.spotify.com/v1/tracks/2JurXfd61zNHSRj7d5Pb6O", + "id": "2JurXfd61zNHSRj7d5Pb6O", + "is_local": false, + "name": "Impermanence", + "preview_url": "https://p.scdn.co/mp3-preview/67db9ed10548d6627fa863927476563f24f57431?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 7, + "type": "track", + "uri": "spotify:track:2JurXfd61zNHSRj7d5Pb6O" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 285080, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/5FVFwjpC20OGjApOhPacVi" + }, + "href": "https://api.spotify.com/v1/tracks/5FVFwjpC20OGjApOhPacVi", + "id": "5FVFwjpC20OGjApOhPacVi", + "is_local": false, + "name": "Sclera", + "preview_url": "https://p.scdn.co/mp3-preview/fc1af73a9b197ce646b9867c301e6b86681dfc18?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 8, + "type": "track", + "uri": "spotify:track:5FVFwjpC20OGjApOhPacVi" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 248760, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/6miZE4vSkmreF5eZUX1l0I" + }, + "href": "https://api.spotify.com/v1/tracks/6miZE4vSkmreF5eZUX1l0I", + "id": "6miZE4vSkmreF5eZUX1l0I", + "is_local": false, + "name": "Atrium", + "preview_url": "https://p.scdn.co/mp3-preview/f0db211f6c1d67206a76dc954a58bf09c279483f?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 9, + "type": "track", + "uri": "spotify:track:6miZE4vSkmreF5eZUX1l0I" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 368213, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/2wmyK7qt2IwSLl34OFk432" + }, + "href": "https://api.spotify.com/v1/tracks/2wmyK7qt2IwSLl34OFk432", + "id": "2wmyK7qt2IwSLl34OFk432", + "is_local": false, + "name": "No Beacon to Illuminate Our Fall", + "preview_url": "https://p.scdn.co/mp3-preview/9852171c62fdb2630768467d840c10550458c826?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 10, + "type": "track", + "uri": "spotify:track:2wmyK7qt2IwSLl34OFk432" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 287840, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/4FbvnEoKHsPlwwBzCc7S4S" + }, + "href": "https://api.spotify.com/v1/tracks/4FbvnEoKHsPlwwBzCc7S4S", + "id": "4FbvnEoKHsPlwwBzCc7S4S", + "is_local": false, + "name": "Absconder (Bonus Track)", + "preview_url": "https://p.scdn.co/mp3-preview/a31db9a76acbc061ad5a5613bfebfcda71d771f2?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 11, + "type": "track", + "uri": "spotify:track:4FbvnEoKHsPlwwBzCc7S4S" + }], + "limit": 50, + "next": null, + "offset": 0, + "previous": null, + "total": 11 + }, + "type": "album", + "uri": "spotify:album:4EcfbzCtbJDk2wMwhT4D1h" + }; +} diff --git a/src/test/data/validAlbumTracksResult.ts b/src/test/data/validAlbumTracksResult.ts new file mode 100644 index 0000000..cc53212 --- /dev/null +++ b/src/test/data/validAlbumTracksResult.ts @@ -0,0 +1,297 @@ +export function validAlbumTracksResult() { + return { + "href": "https://api.spotify.com/v1/albums/4EcfbzCtbJDk2wMwhT4D1h/tracks?offset=0&limit=20&locale=*", + "items": [{ + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 221200, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/2RM5Lx7VIp6GrLRsg2yXwW" + }, + "href": "https://api.spotify.com/v1/tracks/2RM5Lx7VIp6GrLRsg2yXwW", + "id": "2RM5Lx7VIp6GrLRsg2yXwW", + "is_local": false, + "name": "Austerity", + "preview_url": "https://p.scdn.co/mp3-preview/92060dafd9885ae188be4b7bb3640ad41bf221b3?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 1, + "type": "track", + "uri": "spotify:track:2RM5Lx7VIp6GrLRsg2yXwW" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 269106, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/64izlxZoHpcP1BSMLOFVld" + }, + "href": "https://api.spotify.com/v1/tracks/64izlxZoHpcP1BSMLOFVld", + "id": "64izlxZoHpcP1BSMLOFVld", + "is_local": false, + "name": "Colossal Shade", + "preview_url": "https://p.scdn.co/mp3-preview/1bb8e2f22742f172fda20afb8f5b74b9ab3423df?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 2, + "type": "track", + "uri": "spotify:track:64izlxZoHpcP1BSMLOFVld" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 300560, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/3wFpyxWBsobjg8jOTgcdCM" + }, + "href": "https://api.spotify.com/v1/tracks/3wFpyxWBsobjg8jOTgcdCM", + "id": "3wFpyxWBsobjg8jOTgcdCM", + "is_local": false, + "name": "Opaline", + "preview_url": "https://p.scdn.co/mp3-preview/6656b1ba8062c76b3d10daed8e49b82adbda7485?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 3, + "type": "track", + "uri": "spotify:track:3wFpyxWBsobjg8jOTgcdCM" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 248533, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/1ARmblMbvIf4hD5IVhwCkB" + }, + "href": "https://api.spotify.com/v1/tracks/1ARmblMbvIf4hD5IVhwCkB", + "id": "1ARmblMbvIf4hD5IVhwCkB", + "is_local": false, + "name": "Birds", + "preview_url": "https://p.scdn.co/mp3-preview/a63b5da204ce6c24c2f119ddb439d98eabd7c9fb?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 4, + "type": "track", + "uri": "spotify:track:1ARmblMbvIf4hD5IVhwCkB" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 239613, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/57oPzGWcjklkbwX1Zxu3aI" + }, + "href": "https://api.spotify.com/v1/tracks/57oPzGWcjklkbwX1Zxu3aI", + "id": "57oPzGWcjklkbwX1Zxu3aI", + "is_local": false, + "name": "Drab Moon", + "preview_url": "https://p.scdn.co/mp3-preview/7319eb4d38de1036062499ec20757b9daff60439?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 5, + "type": "track", + "uri": "spotify:track:57oPzGWcjklkbwX1Zxu3aI" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 257426, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/7aAkwLYl0dguLeCzzHXap7" + }, + "href": "https://api.spotify.com/v1/tracks/7aAkwLYl0dguLeCzzHXap7", + "id": "7aAkwLYl0dguLeCzzHXap7", + "is_local": false, + "name": "Author", + "preview_url": "https://p.scdn.co/mp3-preview/95ab24e1a3922735ceb64d57bb00bfc6d2e10a26?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 6, + "type": "track", + "uri": "spotify:track:7aAkwLYl0dguLeCzzHXap7" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 312373, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/2JurXfd61zNHSRj7d5Pb6O" + }, + "href": "https://api.spotify.com/v1/tracks/2JurXfd61zNHSRj7d5Pb6O", + "id": "2JurXfd61zNHSRj7d5Pb6O", + "is_local": false, + "name": "Impermanence", + "preview_url": "https://p.scdn.co/mp3-preview/67db9ed10548d6627fa863927476563f24f57431?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 7, + "type": "track", + "uri": "spotify:track:2JurXfd61zNHSRj7d5Pb6O" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 285080, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/5FVFwjpC20OGjApOhPacVi" + }, + "href": "https://api.spotify.com/v1/tracks/5FVFwjpC20OGjApOhPacVi", + "id": "5FVFwjpC20OGjApOhPacVi", + "is_local": false, + "name": "Sclera", + "preview_url": "https://p.scdn.co/mp3-preview/fc1af73a9b197ce646b9867c301e6b86681dfc18?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 8, + "type": "track", + "uri": "spotify:track:5FVFwjpC20OGjApOhPacVi" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 248760, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/6miZE4vSkmreF5eZUX1l0I" + }, + "href": "https://api.spotify.com/v1/tracks/6miZE4vSkmreF5eZUX1l0I", + "id": "6miZE4vSkmreF5eZUX1l0I", + "is_local": false, + "name": "Atrium", + "preview_url": "https://p.scdn.co/mp3-preview/f0db211f6c1d67206a76dc954a58bf09c279483f?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 9, + "type": "track", + "uri": "spotify:track:6miZE4vSkmreF5eZUX1l0I" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 368213, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/2wmyK7qt2IwSLl34OFk432" + }, + "href": "https://api.spotify.com/v1/tracks/2wmyK7qt2IwSLl34OFk432", + "id": "2wmyK7qt2IwSLl34OFk432", + "is_local": false, + "name": "No Beacon to Illuminate Our Fall", + "preview_url": "https://p.scdn.co/mp3-preview/9852171c62fdb2630768467d840c10550458c826?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 10, + "type": "track", + "uri": "spotify:track:2wmyK7qt2IwSLl34OFk432" + }, { + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "href": "https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id": "2CWWgbxApjbyByxBBCvGTm", + "name": "Katatonia", + "type": "artist", + "uri": "spotify:artist:2CWWgbxApjbyByxBBCvGTm" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + "disc_number": 1, + "duration_ms": 287840, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/track/4FbvnEoKHsPlwwBzCc7S4S" + }, + "href": "https://api.spotify.com/v1/tracks/4FbvnEoKHsPlwwBzCc7S4S", + "id": "4FbvnEoKHsPlwwBzCc7S4S", + "is_local": false, + "name": "Absconder (Bonus Track)", + "preview_url": "https://p.scdn.co/mp3-preview/a31db9a76acbc061ad5a5613bfebfcda71d771f2?cid=3c5328c75f1f44c086b25e73608c453b", + "track_number": 11, + "type": "track", + "uri": "spotify:track:4FbvnEoKHsPlwwBzCc7S4S" + }], + "limit": 20, + "next": null, + "offset": 0, + "previous": null, + "total": 11 + }; +} diff --git a/src/test/data/validArtist.ts b/src/test/data/validArtist.ts new file mode 100644 index 0000000..f69bad0 --- /dev/null +++ b/src/test/data/validArtist.ts @@ -0,0 +1,44 @@ +export function validArtist() { + return { + "external_urls":{ + "spotify":"https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm" + }, + "followers":{ + "href":null, + "total":327891 + }, + "genres":[ + "doom metal", + "finnish metal", + "gothic metal", + "metal", + "progressive metal", + "swedish doom metal", + "swedish metal", + "swedish progressive metal" + ], + "href":"https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm", + "id":"2CWWgbxApjbyByxBBCvGTm", + "images":[ + { + "height":640, + "url":"https://i.scdn.co/image/ab6761610000e5eba65f5211ef06d534018b7a11", + "width":640 + }, + { + "height":320, + "url":"https://i.scdn.co/image/ab67616100005174a65f5211ef06d534018b7a11", + "width":320 + }, + { + "height":160, + "url":"https://i.scdn.co/image/ab6761610000f178a65f5211ef06d534018b7a11", + "width":160 + } + ], + "name":"Katatonia", + "popularity":57, + "type":"artist", + "uri":"spotify:artist:2CWWgbxApjbyByxBBCvGTm" + } +} \ No newline at end of file diff --git a/src/test/data/validAudioBook.ts b/src/test/data/validAudioBook.ts new file mode 100644 index 0000000..8b612a3 --- /dev/null +++ b/src/test/data/validAudioBook.ts @@ -0,0 +1,1238 @@ +export function validAudioBook() { + return { + "authors": [{ + "name": "Blake Pierce" + }], + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "chapters": { + "href": "https://api.spotify.com/v1/audiobooks/19Xw49IjNbOCCoebfy3qA9/chapters", + "items": [{ + "id": "1T07H2V5GwrpPNAH6032ES", + "description": "", + "chapter_number": 0, + "duration_ms": 13000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Opening Credits", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1T07H2V5GwrpPNAH6032ES", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1T07H2V5GwrpPNAH6032ES" + }, + "href": "https://api.spotify.com/v1/chapters/1T07H2V5GwrpPNAH6032ES" + }, { + "id": "0rbIxlxueTO1Wg5mGCT77s", + "description": "", + "chapter_number": 1, + "duration_ms": 696000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Prologue", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:0rbIxlxueTO1Wg5mGCT77s", + "external_urls": { + "spotify": "https://open.spotify.com/episode/0rbIxlxueTO1Wg5mGCT77s" + }, + "href": "https://api.spotify.com/v1/chapters/0rbIxlxueTO1Wg5mGCT77s" + }, { + "id": "5TuUcQWzecVJhKgLMZotv7", + "description": "", + "chapter_number": 2, + "duration_ms": 966000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 1", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:5TuUcQWzecVJhKgLMZotv7", + "external_urls": { + "spotify": "https://open.spotify.com/episode/5TuUcQWzecVJhKgLMZotv7" + }, + "href": "https://api.spotify.com/v1/chapters/5TuUcQWzecVJhKgLMZotv7" + }, { + "id": "3bPxArIDWFcncv1aR4JAPp", + "description": "", + "chapter_number": 3, + "duration_ms": 811000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 2", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3bPxArIDWFcncv1aR4JAPp", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3bPxArIDWFcncv1aR4JAPp" + }, + "href": "https://api.spotify.com/v1/chapters/3bPxArIDWFcncv1aR4JAPp" + }, { + "id": "6qADFIBqbuM6aJ1YgtLLZm", + "description": "", + "chapter_number": 4, + "duration_ms": 951000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 3", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6qADFIBqbuM6aJ1YgtLLZm", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6qADFIBqbuM6aJ1YgtLLZm" + }, + "href": "https://api.spotify.com/v1/chapters/6qADFIBqbuM6aJ1YgtLLZm" + }, { + "id": "1Jo0neduDYe1Ya9ql97g4a", + "description": "", + "chapter_number": 5, + "duration_ms": 1540000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 4", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1Jo0neduDYe1Ya9ql97g4a", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1Jo0neduDYe1Ya9ql97g4a" + }, + "href": "https://api.spotify.com/v1/chapters/1Jo0neduDYe1Ya9ql97g4a" + }, { + "id": "3ecwzcJTImiGyGhzmSumI7", + "description": "", + "chapter_number": 6, + "duration_ms": 699000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 5", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3ecwzcJTImiGyGhzmSumI7", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3ecwzcJTImiGyGhzmSumI7" + }, + "href": "https://api.spotify.com/v1/chapters/3ecwzcJTImiGyGhzmSumI7" + }, { + "id": "4HsRzyXsJVoBUvR4Xt82oX", + "description": "", + "chapter_number": 7, + "duration_ms": 1172000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 6", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4HsRzyXsJVoBUvR4Xt82oX", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4HsRzyXsJVoBUvR4Xt82oX" + }, + "href": "https://api.spotify.com/v1/chapters/4HsRzyXsJVoBUvR4Xt82oX" + }, { + "id": "4pVdMPSp3T7JIipZZPWiPX", + "description": "", + "chapter_number": 8, + "duration_ms": 1213000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 7", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4pVdMPSp3T7JIipZZPWiPX", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4pVdMPSp3T7JIipZZPWiPX" + }, + "href": "https://api.spotify.com/v1/chapters/4pVdMPSp3T7JIipZZPWiPX" + }, { + "id": "4BpnfoAKO1wODOcvpuhCLW", + "description": "", + "chapter_number": 9, + "duration_ms": 583433, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 8", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4BpnfoAKO1wODOcvpuhCLW", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4BpnfoAKO1wODOcvpuhCLW" + }, + "href": "https://api.spotify.com/v1/chapters/4BpnfoAKO1wODOcvpuhCLW" + }, { + "id": "0SbolrnxD934rE47mijXdM", + "description": "", + "chapter_number": 10, + "duration_ms": 1279000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 9", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:0SbolrnxD934rE47mijXdM", + "external_urls": { + "spotify": "https://open.spotify.com/episode/0SbolrnxD934rE47mijXdM" + }, + "href": "https://api.spotify.com/v1/chapters/0SbolrnxD934rE47mijXdM" + }, { + "id": "650UdN6gdWlGxaAWHIdu5l", + "description": "", + "chapter_number": 11, + "duration_ms": 834155, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 10", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:650UdN6gdWlGxaAWHIdu5l", + "external_urls": { + "spotify": "https://open.spotify.com/episode/650UdN6gdWlGxaAWHIdu5l" + }, + "href": "https://api.spotify.com/v1/chapters/650UdN6gdWlGxaAWHIdu5l" + }, { + "id": "6HoTgp3boToVtepTPBi65O", + "description": "", + "chapter_number": 12, + "duration_ms": 1196191, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 11", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6HoTgp3boToVtepTPBi65O", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6HoTgp3boToVtepTPBi65O" + }, + "href": "https://api.spotify.com/v1/chapters/6HoTgp3boToVtepTPBi65O" + }, { + "id": "2kIY4BbG6Maihn3RHaxZFv", + "description": "", + "chapter_number": 13, + "duration_ms": 1745000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 12", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:2kIY4BbG6Maihn3RHaxZFv", + "external_urls": { + "spotify": "https://open.spotify.com/episode/2kIY4BbG6Maihn3RHaxZFv" + }, + "href": "https://api.spotify.com/v1/chapters/2kIY4BbG6Maihn3RHaxZFv" + }, { + "id": "3FGE2fCCy1k1GraIZYwzAO", + "description": "", + "chapter_number": 14, + "duration_ms": 988170, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 13", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3FGE2fCCy1k1GraIZYwzAO", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3FGE2fCCy1k1GraIZYwzAO" + }, + "href": "https://api.spotify.com/v1/chapters/3FGE2fCCy1k1GraIZYwzAO" + }, { + "id": "3RHUQSE95qnc90dNYsqkeV", + "description": "", + "chapter_number": 15, + "duration_ms": 711708, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 14", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3RHUQSE95qnc90dNYsqkeV", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3RHUQSE95qnc90dNYsqkeV" + }, + "href": "https://api.spotify.com/v1/chapters/3RHUQSE95qnc90dNYsqkeV" + }, { + "id": "6rxsGtyNPxfuQ7PhGsSMsd", + "description": "", + "chapter_number": 16, + "duration_ms": 1990560, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 15", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6rxsGtyNPxfuQ7PhGsSMsd", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6rxsGtyNPxfuQ7PhGsSMsd" + }, + "href": "https://api.spotify.com/v1/chapters/6rxsGtyNPxfuQ7PhGsSMsd" + }, { + "id": "4VQ8xRmrw4tMDZT2UeHTAg", + "description": "", + "chapter_number": 17, + "duration_ms": 1146505, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 16", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4VQ8xRmrw4tMDZT2UeHTAg", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4VQ8xRmrw4tMDZT2UeHTAg" + }, + "href": "https://api.spotify.com/v1/chapters/4VQ8xRmrw4tMDZT2UeHTAg" + }, { + "id": "1NIeTrmcAl4sycqmBJ2FdV", + "description": "", + "chapter_number": 18, + "duration_ms": 1230000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 17", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1NIeTrmcAl4sycqmBJ2FdV", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1NIeTrmcAl4sycqmBJ2FdV" + }, + "href": "https://api.spotify.com/v1/chapters/1NIeTrmcAl4sycqmBJ2FdV" + }, { + "id": "6uToEJSGlinLBXoTKUT5ZY", + "description": "", + "chapter_number": 19, + "duration_ms": 939956, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 18", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6uToEJSGlinLBXoTKUT5ZY", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6uToEJSGlinLBXoTKUT5ZY" + }, + "href": "https://api.spotify.com/v1/chapters/6uToEJSGlinLBXoTKUT5ZY" + }, { + "id": "2X32afoB5BwLHj2TBYboun", + "description": "", + "chapter_number": 20, + "duration_ms": 915065, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 19", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:2X32afoB5BwLHj2TBYboun", + "external_urls": { + "spotify": "https://open.spotify.com/episode/2X32afoB5BwLHj2TBYboun" + }, + "href": "https://api.spotify.com/v1/chapters/2X32afoB5BwLHj2TBYboun" + }, { + "id": "1yB00XrfOws0t3NdYnnjC8", + "description": "", + "chapter_number": 21, + "duration_ms": 887000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 20", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1yB00XrfOws0t3NdYnnjC8", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1yB00XrfOws0t3NdYnnjC8" + }, + "href": "https://api.spotify.com/v1/chapters/1yB00XrfOws0t3NdYnnjC8" + }, { + "id": "3tYVVB5HjDLB9IKqqOeW9K", + "description": "", + "chapter_number": 22, + "duration_ms": 805000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 21", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3tYVVB5HjDLB9IKqqOeW9K", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3tYVVB5HjDLB9IKqqOeW9K" + }, + "href": "https://api.spotify.com/v1/chapters/3tYVVB5HjDLB9IKqqOeW9K" + }, { + "id": "7AU20h79rESepo0P5emlDg", + "description": "", + "chapter_number": 23, + "duration_ms": 1158000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 22", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:7AU20h79rESepo0P5emlDg", + "external_urls": { + "spotify": "https://open.spotify.com/episode/7AU20h79rESepo0P5emlDg" + }, + "href": "https://api.spotify.com/v1/chapters/7AU20h79rESepo0P5emlDg" + }, { + "id": "6CaLMS5NDRBv92mXlyLXN5", + "description": "", + "chapter_number": 24, + "duration_ms": 718000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 23", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6CaLMS5NDRBv92mXlyLXN5", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6CaLMS5NDRBv92mXlyLXN5" + }, + "href": "https://api.spotify.com/v1/chapters/6CaLMS5NDRBv92mXlyLXN5" + }, { + "id": "20DOsaj422Tz8NCmfe20Cc", + "description": "", + "chapter_number": 25, + "duration_ms": 929553, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 24", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:20DOsaj422Tz8NCmfe20Cc", + "external_urls": { + "spotify": "https://open.spotify.com/episode/20DOsaj422Tz8NCmfe20Cc" + }, + "href": "https://api.spotify.com/v1/chapters/20DOsaj422Tz8NCmfe20Cc" + }, { + "id": "2ydIFXmydqzPFBfhFulbhH", + "description": "", + "chapter_number": 26, + "duration_ms": 999000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 25", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:2ydIFXmydqzPFBfhFulbhH", + "external_urls": { + "spotify": "https://open.spotify.com/episode/2ydIFXmydqzPFBfhFulbhH" + }, + "href": "https://api.spotify.com/v1/chapters/2ydIFXmydqzPFBfhFulbhH" + }, { + "id": "6tv4qyAojYpAU6by995r26", + "description": "", + "chapter_number": 27, + "duration_ms": 861000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 26", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6tv4qyAojYpAU6by995r26", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6tv4qyAojYpAU6by995r26" + }, + "href": "https://api.spotify.com/v1/chapters/6tv4qyAojYpAU6by995r26" + }, { + "id": "6r4i5fnGgRKefCW79XH9aK", + "description": "", + "chapter_number": 28, + "duration_ms": 853000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 27", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6r4i5fnGgRKefCW79XH9aK", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6r4i5fnGgRKefCW79XH9aK" + }, + "href": "https://api.spotify.com/v1/chapters/6r4i5fnGgRKefCW79XH9aK" + }, { + "id": "1k9JjtyYYT8rpp6hgNerh7", + "description": "", + "chapter_number": 29, + "duration_ms": 1065822, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 28", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1k9JjtyYYT8rpp6hgNerh7", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1k9JjtyYYT8rpp6hgNerh7" + }, + "href": "https://api.spotify.com/v1/chapters/1k9JjtyYYT8rpp6hgNerh7" + }, { + "id": "5daI7NwSNpFdvsm3jyJHdP", + "description": "", + "chapter_number": 30, + "duration_ms": 741663, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Epilogue", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:5daI7NwSNpFdvsm3jyJHdP", + "external_urls": { + "spotify": "https://open.spotify.com/episode/5daI7NwSNpFdvsm3jyJHdP" + }, + "href": "https://api.spotify.com/v1/chapters/5daI7NwSNpFdvsm3jyJHdP" + }, { + "id": "1MRNNvF9YBoRkb6T5HkQ9w", + "description": "", + "chapter_number": 31, + "duration_ms": 17000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Ending Credits", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1MRNNvF9YBoRkb6T5HkQ9w", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1MRNNvF9YBoRkb6T5HkQ9w" + }, + "href": "https://api.spotify.com/v1/chapters/1MRNNvF9YBoRkb6T5HkQ9w" + }, { + "id": "1OMottuenpheykC1dMgjxN", + "description": "", + "chapter_number": 32, + "duration_ms": 300000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Girl, Alone (An Ella Dark FBI Suspense Thriller—Book 1)", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1OMottuenpheykC1dMgjxN", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1OMottuenpheykC1dMgjxN" + }, + "href": "https://api.spotify.com/v1/chapters/1OMottuenpheykC1dMgjxN" + }], + "limit": 50, + "next": null, + "offset": 0, + "previous": null, + "total": 33 + }, + "copyrights": [], + "description": "Author(s): Blake Pierce\nNarrator(s): Abigail Reno\n\n

“A MASTERPIECE OF THRILLER AND MYSTERY. Blake Pierce did a magnificent job developing characters with a psychological side so well described that we feel inside their minds, follow their fears and cheer for their success. Full of twists, this book will keep you awake until the turn of the last page.”

--Books and Movie Reviews, Roberto Mattos (re Once Gone)


GIRL, ALONE (An Ella Dark FBI Suspense Thriller—Book 1) is the debut novel in a long-anticipated new series by #1 bestseller and USA Today bestselling author Blake Pierce, whose bestseller Once Gone (a free download) has received over 1,000 five star reviews.


FBI Agent Ella Dark, 29, is given her big chance to achieve her life’s dream: to join the Behavorial Crimes Unit. Ella has a hidden obsession: she has studied serial killers from the time she could read, devastated by the murder of her own sister. With her photographic memory, she has obtained an encyclopedic knowledge of every serial killer, every victim and every case. Singled out for her brilliant mind, Ella is invited to join the big leagues.


But when a killer strikes in the swamps of Louisiana, Ella soon comes to learn that the real thing is nothing she could expect. Face to face with a real murder, a real killer, and a real ticking clock, Ella realizes she can’t rely on her knowledge. She must learn to trust her instinct, and allow herself to enter the dark canals of a real killer’s mind. If she gets it wrong, her career is at stake.


And so is the next victim’s life.


Will Ella’s talent be an asset? Or the source of her downfall?


A page-turning and harrowing crime thriller featuring a brilliant and tortured FBI agent, the ELLA DARK series is a riveting mystery, packed with suspense, twists and turns, revelations, and driven by a breakneck pace that will keep you flipping pages late into the night.

", + "edition": "Unabridged", + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/show/19Xw49IjNbOCCoebfy3qA9" + }, + "href": "https://api.spotify.com/v1/audiobooks/19Xw49IjNbOCCoebfy3qA9", + "html_description": "Author(s): Blake Pierce
Narrator(s): Abigail Reno
<p>“A MASTERPIECE OF THRILLER AND MYSTERY. Blake Pierce did a magnificent job developing characters with a psychological side so well described that we feel inside their minds, follow their fears and cheer for their success. Full of twists, this book will keep you awake until the turn of the last page.”</p><p>--Books and Movie Reviews, Roberto Mattos (re Once Gone)</p><p><br></p><p>GIRL, ALONE (An Ella Dark FBI Suspense Thriller—Book 1) is the debut novel in a long-anticipated new series by #1 bestseller and USA Today bestselling author Blake Pierce, whose bestseller Once Gone (a free download) has received over 1,000 five star reviews.</p><p><br></p><p>FBI Agent Ella Dark, 29, is given her big chance to achieve her life’s dream: to join the Behavorial Crimes Unit. Ella has a hidden obsession: she has studied serial killers from the time she could read, devastated by the murder of her own sister. With her photographic memory, she has obtained an encyclopedic knowledge of every serial killer, every victim and every case. Singled out for her brilliant mind, Ella is invited to join the big leagues.</p><p><br></p><p>But when a killer strikes in the swamps of Louisiana, Ella soon comes to learn that the real thing is nothing she could expect. Face to face with a real murder, a real killer, and a real ticking clock, Ella realizes she can’t rely on her knowledge. She must learn to trust her instinct, and allow herself to enter the dark canals of a real killer’s mind. If she gets it wrong, her career is at stake.</p><p><br></p><p>And so is the next victim’s life.</p><p><br></p><p>Will Ella’s talent be an asset? Or the source of her downfall?</p><p><br></p><p>A page-turning and harrowing crime thriller featuring a brilliant and tortured FBI agent, the ELLA DARK series is a riveting mystery, packed with suspense, twists and turns, revelations, and driven by a breakneck pace that will keep you flipping pages late into the night.</p>", + "id": "19Xw49IjNbOCCoebfy3qA9", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": ["English"], + "media_type": "audio", + "name": "Girl, Alone (An Ella Dark FBI Suspense Thriller—Book 1): 01", + "narrators": [{ + "name": "Abigail Reno" + }], + "publisher": "Lukeman Literary Management", + "total_chapters": 33, + "type": "audiobook", + "uri": "spotify:show:19Xw49IjNbOCCoebfy3qA9" + }; +} diff --git a/src/test/data/validAudiobookChapters.ts b/src/test/data/validAudiobookChapters.ts new file mode 100644 index 0000000..c8a5c01 --- /dev/null +++ b/src/test/data/validAudiobookChapters.ts @@ -0,0 +1,731 @@ +export function validAudiobookChapters() { + return { + "href": "https://api.spotify.com/v1/audiobooks/19Xw49IjNbOCCoebfy3qA9/chapters", + "items": [{ + "id": "1T07H2V5GwrpPNAH6032ES", + "description": "", + "chapter_number": 0, + "duration_ms": 13000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Opening Credits", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1T07H2V5GwrpPNAH6032ES", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1T07H2V5GwrpPNAH6032ES" + }, + "href": "https://api.spotify.com/v1/chapters/1T07H2V5GwrpPNAH6032ES" + }, { + "id": "0rbIxlxueTO1Wg5mGCT77s", + "description": "", + "chapter_number": 1, + "duration_ms": 696000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Prologue", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:0rbIxlxueTO1Wg5mGCT77s", + "external_urls": { + "spotify": "https://open.spotify.com/episode/0rbIxlxueTO1Wg5mGCT77s" + }, + "href": "https://api.spotify.com/v1/chapters/0rbIxlxueTO1Wg5mGCT77s" + }, { + "id": "5TuUcQWzecVJhKgLMZotv7", + "description": "", + "chapter_number": 2, + "duration_ms": 966000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 1", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:5TuUcQWzecVJhKgLMZotv7", + "external_urls": { + "spotify": "https://open.spotify.com/episode/5TuUcQWzecVJhKgLMZotv7" + }, + "href": "https://api.spotify.com/v1/chapters/5TuUcQWzecVJhKgLMZotv7" + }, { + "id": "3bPxArIDWFcncv1aR4JAPp", + "description": "", + "chapter_number": 3, + "duration_ms": 811000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 2", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3bPxArIDWFcncv1aR4JAPp", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3bPxArIDWFcncv1aR4JAPp" + }, + "href": "https://api.spotify.com/v1/chapters/3bPxArIDWFcncv1aR4JAPp" + }, { + "id": "6qADFIBqbuM6aJ1YgtLLZm", + "description": "", + "chapter_number": 4, + "duration_ms": 951000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 3", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6qADFIBqbuM6aJ1YgtLLZm", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6qADFIBqbuM6aJ1YgtLLZm" + }, + "href": "https://api.spotify.com/v1/chapters/6qADFIBqbuM6aJ1YgtLLZm" + }, { + "id": "1Jo0neduDYe1Ya9ql97g4a", + "description": "", + "chapter_number": 5, + "duration_ms": 1540000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 4", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1Jo0neduDYe1Ya9ql97g4a", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1Jo0neduDYe1Ya9ql97g4a" + }, + "href": "https://api.spotify.com/v1/chapters/1Jo0neduDYe1Ya9ql97g4a" + }, { + "id": "3ecwzcJTImiGyGhzmSumI7", + "description": "", + "chapter_number": 6, + "duration_ms": 699000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 5", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3ecwzcJTImiGyGhzmSumI7", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3ecwzcJTImiGyGhzmSumI7" + }, + "href": "https://api.spotify.com/v1/chapters/3ecwzcJTImiGyGhzmSumI7" + }, { + "id": "4HsRzyXsJVoBUvR4Xt82oX", + "description": "", + "chapter_number": 7, + "duration_ms": 1172000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 6", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4HsRzyXsJVoBUvR4Xt82oX", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4HsRzyXsJVoBUvR4Xt82oX" + }, + "href": "https://api.spotify.com/v1/chapters/4HsRzyXsJVoBUvR4Xt82oX" + }, { + "id": "4pVdMPSp3T7JIipZZPWiPX", + "description": "", + "chapter_number": 8, + "duration_ms": 1213000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 7", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4pVdMPSp3T7JIipZZPWiPX", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4pVdMPSp3T7JIipZZPWiPX" + }, + "href": "https://api.spotify.com/v1/chapters/4pVdMPSp3T7JIipZZPWiPX" + }, { + "id": "4BpnfoAKO1wODOcvpuhCLW", + "description": "", + "chapter_number": 9, + "duration_ms": 583433, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 8", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4BpnfoAKO1wODOcvpuhCLW", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4BpnfoAKO1wODOcvpuhCLW" + }, + "href": "https://api.spotify.com/v1/chapters/4BpnfoAKO1wODOcvpuhCLW" + }, { + "id": "0SbolrnxD934rE47mijXdM", + "description": "", + "chapter_number": 10, + "duration_ms": 1279000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 9", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:0SbolrnxD934rE47mijXdM", + "external_urls": { + "spotify": "https://open.spotify.com/episode/0SbolrnxD934rE47mijXdM" + }, + "href": "https://api.spotify.com/v1/chapters/0SbolrnxD934rE47mijXdM" + }, { + "id": "650UdN6gdWlGxaAWHIdu5l", + "description": "", + "chapter_number": 11, + "duration_ms": 834155, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 10", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:650UdN6gdWlGxaAWHIdu5l", + "external_urls": { + "spotify": "https://open.spotify.com/episode/650UdN6gdWlGxaAWHIdu5l" + }, + "href": "https://api.spotify.com/v1/chapters/650UdN6gdWlGxaAWHIdu5l" + }, { + "id": "6HoTgp3boToVtepTPBi65O", + "description": "", + "chapter_number": 12, + "duration_ms": 1196191, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 11", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6HoTgp3boToVtepTPBi65O", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6HoTgp3boToVtepTPBi65O" + }, + "href": "https://api.spotify.com/v1/chapters/6HoTgp3boToVtepTPBi65O" + }, { + "id": "2kIY4BbG6Maihn3RHaxZFv", + "description": "", + "chapter_number": 13, + "duration_ms": 1745000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 12", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:2kIY4BbG6Maihn3RHaxZFv", + "external_urls": { + "spotify": "https://open.spotify.com/episode/2kIY4BbG6Maihn3RHaxZFv" + }, + "href": "https://api.spotify.com/v1/chapters/2kIY4BbG6Maihn3RHaxZFv" + }, { + "id": "3FGE2fCCy1k1GraIZYwzAO", + "description": "", + "chapter_number": 14, + "duration_ms": 988170, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 13", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3FGE2fCCy1k1GraIZYwzAO", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3FGE2fCCy1k1GraIZYwzAO" + }, + "href": "https://api.spotify.com/v1/chapters/3FGE2fCCy1k1GraIZYwzAO" + }, { + "id": "3RHUQSE95qnc90dNYsqkeV", + "description": "", + "chapter_number": 15, + "duration_ms": 711708, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 14", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:3RHUQSE95qnc90dNYsqkeV", + "external_urls": { + "spotify": "https://open.spotify.com/episode/3RHUQSE95qnc90dNYsqkeV" + }, + "href": "https://api.spotify.com/v1/chapters/3RHUQSE95qnc90dNYsqkeV" + }, { + "id": "6rxsGtyNPxfuQ7PhGsSMsd", + "description": "", + "chapter_number": 16, + "duration_ms": 1990560, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 15", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6rxsGtyNPxfuQ7PhGsSMsd", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6rxsGtyNPxfuQ7PhGsSMsd" + }, + "href": "https://api.spotify.com/v1/chapters/6rxsGtyNPxfuQ7PhGsSMsd" + }, { + "id": "4VQ8xRmrw4tMDZT2UeHTAg", + "description": "", + "chapter_number": 17, + "duration_ms": 1146505, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 16", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:4VQ8xRmrw4tMDZT2UeHTAg", + "external_urls": { + "spotify": "https://open.spotify.com/episode/4VQ8xRmrw4tMDZT2UeHTAg" + }, + "href": "https://api.spotify.com/v1/chapters/4VQ8xRmrw4tMDZT2UeHTAg" + }, { + "id": "1NIeTrmcAl4sycqmBJ2FdV", + "description": "", + "chapter_number": 18, + "duration_ms": 1230000, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 17", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:1NIeTrmcAl4sycqmBJ2FdV", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1NIeTrmcAl4sycqmBJ2FdV" + }, + "href": "https://api.spotify.com/v1/chapters/1NIeTrmcAl4sycqmBJ2FdV" + }, { + "id": "6uToEJSGlinLBXoTKUT5ZY", + "description": "", + "chapter_number": 19, + "duration_ms": 939956, + "explicit": false, + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + }], + "languages": [""], + "name": "Chapter 18", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "html_description": "", + "available_markets": ["AU", "ET", "GB", "IE", "NZ", "US"], + "type": "chapter", + "uri": "spotify:episode:6uToEJSGlinLBXoTKUT5ZY", + "external_urls": { + "spotify": "https://open.spotify.com/episode/6uToEJSGlinLBXoTKUT5ZY" + }, + "href": "https://api.spotify.com/v1/chapters/6uToEJSGlinLBXoTKUT5ZY" + }], + "limit": 20, + "next": null, + "offset": 0, + "previous": null, + "total": 33 + } +} \ No newline at end of file diff --git a/src/test/data/validCategories.ts b/src/test/data/validCategories.ts new file mode 100644 index 0000000..027d855 --- /dev/null +++ b/src/test/data/validCategories.ts @@ -0,0 +1,254 @@ +export function validCategories() { + return { + "categories":{ + "href":"https://api.spotify.com/v1/browse/categories?country=GB&offset=0&limit=20", + "items":[ + { + "href":"https://api.spotify.com/v1/browse/categories/toplists", + "icons":[ + { + "height":275, + "url":"https://t.scdn.co/media/derived/toplists_11160599e6a04ac5d6f2757f5511778f_0_0_275_275.jpg", + "width":275 + } + ], + "id":"toplists", + "name":"Top Lists" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFLVaM30PMBm4", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/8e508d7eb5b843a89c368c9507ecc429.jpeg", + "width":null + } + ], + "id":"0JQ5DAqbMKFLVaM30PMBm4", + "name":"Summer" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFEC4WFtoNRpw", + "icons":[ + { + "height":274, + "url":"https://t.scdn.co/media/derived/pop-274x274_447148649685019f5e2a03a39e78ba52_0_0_274_274.jpg", + "width":274 + } + ], + "id":"0JQ5DAqbMKFEC4WFtoNRpw", + "name":"Pop" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFAXlCG6QvYQ4", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/media/links/workout-274x274.jpg", + "width":null + } + ], + "id":"0JQ5DAqbMKFAXlCG6QvYQ4", + "name":"Workout" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFQ00XGBls6ym", + "icons":[ + { + "height":274, + "url":"https://t.scdn.co/media/original/hip-274_0a661854d61e29eace5fe63f73495e68_274x274.jpg", + "width":274 + } + ], + "id":"0JQ5DAqbMKFQ00XGBls6ym", + "name":"Hip-Hop" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFzHmL4tf05da", + "icons":[ + { + "height":274, + "url":"https://t.scdn.co/media/original/mood-274x274_976986a31ac8c49794cbdc7246fd5ad7_274x274.jpg", + "width":274 + } + ], + "id":"0JQ5DAqbMKFzHmL4tf05da", + "name":"Mood" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFA6SOHvT3gck", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/fada056dcfd54cd28faf80d62b7059c6.jpeg", + "width":null + } + ], + "id":"0JQ5DAqbMKFA6SOHvT3gck", + "name":"Party" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFF1br7dZcRtK", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/c5495b9f0f694ffcb39c9217d4ed4375", + "width":null + } + ], + "id":"0JQ5DAqbMKFF1br7dZcRtK", + "name":"Pride" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFHOzuVTgTizF", + "icons":[ + { + "height":274, + "url":"https://t.scdn.co/media/derived/edm-274x274_0ef612604200a9c14995432994455a6d_0_0_274_274.jpg", + "width":274 + } + ], + "id":"0JQ5DAqbMKFHOzuVTgTizF", + "name":"Dance/Electronic" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFFtlLYUHv8bT", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/ee9451b3ed474c82b1da8f9b5eafc88f.jpeg", + "width":null + } + ], + "id":"0JQ5DAqbMKFFtlLYUHv8bT", + "name":"Alternative" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFCWjUTdzaG0e", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/fe06caf056474bc58862591cd60b57fc.jpeg", + "width":null + } + ], + "id":"0JQ5DAqbMKFCWjUTdzaG0e", + "name":"Indie" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFPw634sFwguI", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/084155aeaa724ea1bd393a017d67b709", + "width":null + } + ], + "id":"0JQ5DAqbMKFPw634sFwguI", + "name":"EQUAL" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFLb2EqgLtpjC", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/3710b68657574bc79df14bd74629e5ac", + "width":null + } + ], + "id":"0JQ5DAqbMKFLb2EqgLtpjC", + "name":"Wellness" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFDXXwE9BDJAr", + "icons":[ + { + "height":274, + "url":"https://t.scdn.co/media/derived/rock_9ce79e0a4ef901bbd10494f5b855d3cc_0_0_274_274.jpg", + "width":274 + } + ], + "id":"0JQ5DAqbMKFDXXwE9BDJAr", + "name":"Rock" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFF9bY76LXmfI", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/cad629fb65a14de4beddb38510e27cb1", + "width":null + } + ], + "id":"0JQ5DAqbMKFF9bY76LXmfI", + "name":"Frequency" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFEZPnFQSFB1T", + "icons":[ + { + "height":274, + "url":"https://t.scdn.co/media/derived/r-b-274x274_fd56efa72f4f63764b011b68121581d8_0_0_274_274.jpg", + "width":274 + } + ], + "id":"0JQ5DAqbMKFEZPnFQSFB1T", + "name":"R&B" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFN2GMExExvrS", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/448949e524284cea9aedbf32aa69d90f.jpeg", + "width":null + } + ], + "id":"0JQ5DAqbMKFN2GMExExvrS", + "name":"Throwback" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFx0uLQR2okcc", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/04da469dd7be4dab96659aa1fa9f0ac9.jpeg", + "width":null + } + ], + "id":"0JQ5DAqbMKFx0uLQR2okcc", + "name":"At Home" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFCfObibaOZbv", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/0d39395309ba47838ef12ce987f19d16.jpeg", + "width":null + } + ], + "id":"0JQ5DAqbMKFCfObibaOZbv", + "name":"Gaming" + }, + { + "href":"https://api.spotify.com/v1/browse/categories/0JQ5DAqbMKFOOxftoKZxod", + "icons":[ + { + "height":null, + "url":"https://t.scdn.co/images/c6677aa51acf4121b66b9d1f231bd427.png", + "width":null + } + ], + "id":"0JQ5DAqbMKFOOxftoKZxod", + "name":"RADAR" + } + ], + "limit":20, + "next":"https://api.spotify.com/v1/browse/categories?country=GB&offset=20&limit=20", + "offset":0, + "previous":null, + "total":54 + } + } +} \ No newline at end of file diff --git a/src/test/data/validCategory.ts b/src/test/data/validCategory.ts new file mode 100644 index 0000000..b3a710a --- /dev/null +++ b/src/test/data/validCategory.ts @@ -0,0 +1,9 @@ +export function validCategory() { + return { href: 'https://api.spotify.com/v1/browse/categories/toplists', + icons: + [ { height: 275, + url: 'https://t.scdn.co/media/derived/toplists_11160599e6a04ac5d6f2757f5511778f_0_0_275_275.jpg', + width: 275 } ], + id: 'toplists', + name: 'Top Lists' } +} \ No newline at end of file diff --git a/src/test/data/validChapterApiResponse.ts b/src/test/data/validChapterApiResponse.ts new file mode 100644 index 0000000..09fa4a6 --- /dev/null +++ b/src/test/data/validChapterApiResponse.ts @@ -0,0 +1,109 @@ +export function validAudiobookChapterResponse() { + return { + "restrictions": { + "reason": "payment_required" + }, + "id": "1T07H2V5GwrpPNAH6032ES", + "description": "", + "chapter_number": 0, + "duration_ms": 13000, + "explicit": false, + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + } + ], + "languages": [ + "" + ], + "name": "Opening Credits", + "audio_preview_url": null, + "release_date": "0000-01-01", + "release_date_precision": "day", + "resume_point": { + "fully_played": false, + "resume_position_ms": 0 + }, + "is_playable": false, + "html_description": "", + "audiobook": { + "authors": [ + { + "name": "Blake Pierce" + } + ], + "chapters": { + "href": null, + "items": [ + + ], + "limit": 0, + "next": null, + "offset": 0, + "previous": null, + "total": null + }, + "copyrights": [ + + ], + "description": "Author(s): Blake Pierce\nNarrator(s): Abigail Reno\n\n

“A MASTERPIECE OF THRILLER AND MYSTERY. Blake Pierce did a magnificent job developing characters with a psychological side so well described that we feel inside their minds, follow their fears and cheer for their success. Full of twists, this book will keep you awake until the turn of the last page.”

--Books and Movie Reviews, Roberto Mattos (re Once Gone)


GIRL, ALONE (An Ella Dark FBI Suspense Thriller—Book 1) is the debut novel in a long-anticipated new series by #1 bestseller and USA Today bestselling author Blake Pierce, whose bestseller Once Gone (a free download) has received over 1,000 five star reviews.


FBI Agent Ella Dark, 29, is given her big chance to achieve her life’s dream: to join the Behavorial Crimes Unit. Ella has a hidden obsession: she has studied serial killers from the time she could read, devastated by the murder of her own sister. With her photographic memory, she has obtained an encyclopedic knowledge of every serial killer, every victim and every case. Singled out for her brilliant mind, Ella is invited to join the big leagues.


But when a killer strikes in the swamps of Louisiana, Ella soon comes to learn that the real thing is nothing she could expect. Face to face with a real murder, a real killer, and a real ticking clock, Ella realizes she can’t rely on her knowledge. She must learn to trust her instinct, and allow herself to enter the dark canals of a real killer’s mind. If she gets it wrong, her career is at stake.


And so is the next victim’s life.


Will Ella’s talent be an asset? Or the source of her downfall?


A page-turning and harrowing crime thriller featuring a brilliant and tortured FBI agent, the ELLA DARK series is a riveting mystery, packed with suspense, twists and turns, revelations, and driven by a breakneck pace that will keep you flipping pages late into the night.

", + "edition": null, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/show/19Xw49IjNbOCCoebfy3qA9" + }, + "href": "https://api.spotify.com/v1/audiobooks/19Xw49IjNbOCCoebfy3qA9", + "html_description": "Author(s): Blake Pierce
Narrator(s): Abigail Reno
<p>“A MASTERPIECE OF THRILLER AND MYSTERY. Blake Pierce did a magnificent job developing characters with a psychological side so well described that we feel inside their minds, follow their fears and cheer for their success. Full of twists, this book will keep you awake until the turn of the last page.”</p><p>--Books and Movie Reviews, Roberto Mattos (re Once Gone)</p><p><br></p><p>GIRL, ALONE (An Ella Dark FBI Suspense Thriller—Book 1) is the debut novel in a long-anticipated new series by #1 bestseller and USA Today bestselling author Blake Pierce, whose bestseller Once Gone (a free download) has received over 1,000 five star reviews.</p><p><br></p><p>FBI Agent Ella Dark, 29, is given her big chance to achieve her life’s dream: to join the Behavorial Crimes Unit. Ella has a hidden obsession: she has studied serial killers from the time she could read, devastated by the murder of her own sister. With her photographic memory, she has obtained an encyclopedic knowledge of every serial killer, every victim and every case. Singled out for her brilliant mind, Ella is invited to join the big leagues.</p><p><br></p><p>But when a killer strikes in the swamps of Louisiana, Ella soon comes to learn that the real thing is nothing she could expect. Face to face with a real murder, a real killer, and a real ticking clock, Ella realizes she can’t rely on her knowledge. She must learn to trust her instinct, and allow herself to enter the dark canals of a real killer’s mind. If she gets it wrong, her career is at stake.</p><p><br></p><p>And so is the next victim’s life.</p><p><br></p><p>Will Ella’s talent be an asset? Or the source of her downfall?</p><p><br></p><p>A page-turning and harrowing crime thriller featuring a brilliant and tortured FBI agent, the ELLA DARK series is a riveting mystery, packed with suspense, twists and turns, revelations, and driven by a breakneck pace that will keep you flipping pages late into the night.</p>", + "id": "19Xw49IjNbOCCoebfy3qA9", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/ab676663000022a8f0722f9b6390ed3420e6f0a0", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/ab6766630000db5bf0722f9b6390ed3420e6f0a0", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/ab6766630000703bf0722f9b6390ed3420e6f0a0", + "width": 64 + } + ], + "languages": [ + "English" + ], + "media_type": "audio", + "name": "Girl, Alone (An Ella Dark FBI Suspense Thriller—Book 1): 01", + "narrators": [ + { + "name": "Abigail Reno" + } + ], + "publisher": "Lukeman Literary Management", + "total_chapters": null, + "type": "audiobook", + "uri": "spotify:show:19Xw49IjNbOCCoebfy3qA9" + }, + "type": "chapter", + "uri": "spotify:episode:1T07H2V5GwrpPNAH6032ES", + "external_urls": { + "spotify": "https://open.spotify.com/episode/1T07H2V5GwrpPNAH6032ES" + }, + "href": "https://api.spotify.com/v1/chapters/1T07H2V5GwrpPNAH6032ES" + } +} \ No newline at end of file diff --git a/src/test/data/validEpisode.ts b/src/test/data/validEpisode.ts new file mode 100644 index 0000000..7ae668e --- /dev/null +++ b/src/test/data/validEpisode.ts @@ -0,0 +1,242 @@ +export function validEpisode() { + return { + audio_preview_url: null, + description: 'Covid-19 hasn’t gone away and, due to travel restrictions, neither has Louis Theroux. In the second outing of his podcast series, he tracks down more high-profile guests he’s been longing to talk to - a fascinating mix of the celebrated, the controversial and the mysterious. In the last episode of the series, Louis catches up with actor, writer and director Justin Theroux - who also happens to be Louis\'s cousin. With Justin in Mexico and Louis in Texas, they discuss family holidays in Cape Cod, ADHD and the perils of fighting with rocks. . Producer: Sara Jane Hall Assistant Producer: Molly Schneider A Mindhouse production for BBC Radio 4', + duration_ms: 4259474, + explicit: true, + external_urls: { spotify: 'https://open.spotify.com/episode/0I8z8uyoJ03X6SiLDo0h96' }, + href: 'https://api.spotify.com/v1/episodes/0I8z8uyoJ03X6SiLDo0h96', + html_description: 'Covid-19 hasn’t gone away and, due to travel restrictions, neither has Louis Theroux. In the second outing of his podcast series, he tracks down more high-profile guests he’s been longing to talk to - a fascinating mix of the celebrated, the controversial and the mysterious.

In the last episode of the series, Louis catches up with actor, writer and director Justin Theroux - who also happens to be Louis's cousin. With Justin in Mexico and Louis in Texas, they discuss family holidays in Cape Cod, ADHD and the perils of fighting with rocks. .
Producer: Sara Jane Hall
Assistant Producer: Molly Schneider
A Mindhouse production for BBC Radio 4', + id: '0I8z8uyoJ03X6SiLDo0h96', + images: + [{ + height: 640, + url: 'https://i.scdn.co/image/ab6765630000ba8adeffb326939c9ca192a0f289', + width: 640 + }, + { + height: 300, + url: 'https://i.scdn.co/image/ab67656300005f1fdeffb326939c9ca192a0f289', + width: 300 + }, + { + height: 64, + url: 'https://i.scdn.co/image/ab6765630000f68ddeffb326939c9ca192a0f289', + width: 64 + }], + is_externally_hosted: true, + is_playable: true, + language: 'en', + languages: ['en'], + name: '20. Justin Theroux', + release_date: '2021-02-01', + release_date_precision: 'day', + show: + { + available_markets: + ["AD", + "AE", + "AG", + "AL", + "AM", + "AO", + "AR", + "AT", + "AU", + "AZ", + "BA", + "BB", + "BE", + "BF", + "BG", + "BH", + "BI", + "BJ", + "BN", + "BO", + "BR", + "BS", + "BT", + "BW", + "BZ", + "CA", + "CH", + "CI", + "CL", + "CM", + "CO", + "CR", + "CV", + "CW", + "CY", + "CZ", + "DE", + "DJ", + "DK", + "DM", + "DO", + "DZ", + "EC", + "EE", + "EG", + "ES", + "FI", + "FJ", + "FM", + "FR", + "GA", + "GB", + "GD", + "GE", + "GH", + "GM", + "GN", + "GQ", + "GR", + "GT", + "GW", + "GY", + "HK", + "HN", + "HR", + "HT", + "HU", + "ID", + "IE", + "IL", + "IN", + "IS", + "IT", + "JM", + "JO", + "JP", + "KE", + "KH", + "KI", + "KM", + "KN", + "KR", + "KW", + "LA", + "LB", + "LC", + "LI", + "LR", + "LS", + "LT", + "LU", + "LV", + "MA", + "MC", + "ME", + "MG", + "MH", + "MK", + "ML", + "MN", + "MO", + "MR", + "MT", + "MU", + "MV", + "MW", + "MX", + "MY", + "MZ", + "NA", + "NE", + "NG", + "NI", + "NL", + "NO", + "NP", + "NR", + "NZ", + "OM", + "PA", + "PE", + "PG", + "PH", + "PL", + "PS", + "PT", + "PW", + "PY", + "QA", + "RO", + "RS", + "RW", + "SA", + "SB", + "SC", + "SE", + "SG", + "SI", + "SK", + "SL", + "SM", + "SN", + "SR", + "ST", + "SV", + "SZ", + "TD", + "TG", + "TH", + "TL", + "TN", + "TO", + "TR", + "TT", + "TV", + "TW", + "TZ", + "UA", + "US", + "UY", + "UZ", + "VC", + "VN", + "VU", + "WS", + "XK", + "ZA", + "ZM", + "ZW", + ], + copyrights: [], + description: 'Stuck at home, Louis is using the lockdown to track down some high-profile people he\'s been longing to talk to - from all walks of life and on both sides of the Atlantic.', + explicit: false, + external_urls: { spotify: 'https://open.spotify.com/show/4mCovOfuUDnEju95HXGD8o' }, + href: 'https://api.spotify.com/v1/shows/4mCovOfuUDnEju95HXGD8o', + html_description: 'Stuck at home, Louis is using the lockdown to track down some high-profile people he's been longing to talk to - from all walks of life and on both sides of the Atlantic.', + id: '4mCovOfuUDnEju95HXGD8o', + images: + [{ + height: 640, + url: 'https://i.scdn.co/image/ab6765630000ba8adeffb326939c9ca192a0f289', + width: 640 + }, + { + height: 300, + url: 'https://i.scdn.co/image/ab67656300005f1fdeffb326939c9ca192a0f289', + width: 300 + }, + { + height: 64, + url: 'https://i.scdn.co/image/ab6765630000f68ddeffb326939c9ca192a0f289', + width: 64 + }], + is_externally_hosted: true, + languages: ['en'], + media_type: 'audio', + name: 'Grounded with Louis Theroux', + publisher: 'BBC Radio 4', + total_episodes: 22, + type: 'show', + uri: 'spotify:show:4mCovOfuUDnEju95HXGD8o' + }, + type: 'episode', + uri: 'spotify:episode:0I8z8uyoJ03X6SiLDo0h96' + } +} \ No newline at end of file diff --git a/src/test/data/validGenres.ts b/src/test/data/validGenres.ts new file mode 100644 index 0000000..556d3d3 --- /dev/null +++ b/src/test/data/validGenres.ts @@ -0,0 +1,132 @@ +export function validGenres() { + return { + "genres": [ + "acoustic", + "afrobeat", + "alt-rock", + "alternative", + "ambient", + "anime", + "black-metal", + "bluegrass", + "blues", + "bossanova", + "brazil", + "breakbeat", + "british", + "cantopop", + "chicago-house", + "children", + "chill", + "classical", + "club", + "comedy", + "country", + "dance", + "dancehall", + "death-metal", + "deep-house", + "detroit-techno", + "disco", + "disney", + "drum-and-bass", + "dub", + "dubstep", + "edm", + "electro", + "electronic", + "emo", + "folk", + "forro", + "french", + "funk", + "garage", + "german", + "gospel", + "goth", + "grindcore", + "groove", + "grunge", + "guitar", + "happy", + "hard-rock", + "hardcore", + "hardstyle", + "heavy-metal", + "hip-hop", + "holidays", + "honky-tonk", + "house", + "idm", + "indian", + "indie", + "indie-pop", + "industrial", + "iranian", + "j-dance", + "j-idol", + "j-pop", + "j-rock", + "jazz", + "k-pop", + "kids", + "latin", + "latino", + "malay", + "mandopop", + "metal", + "metal-misc", + "metalcore", + "minimal-techno", + "movies", + "mpb", + "new-age", + "new-release", + "opera", + "pagode", + "party", + "philippines-opm", + "piano", + "pop", + "pop-film", + "post-dubstep", + "power-pop", + "progressive-house", + "psych-rock", + "punk", + "punk-rock", + "r-n-b", + "rainy-day", + "reggae", + "reggaeton", + "road-trip", + "rock", + "rock-n-roll", + "rockabilly", + "romance", + "sad", + "salsa", + "samba", + "sertanejo", + "show-tunes", + "singer-songwriter", + "ska", + "sleep", + "songwriter", + "soul", + "soundtracks", + "spanish", + "study", + "summer", + "swedish", + "synth-pop", + "tango", + "techno", + "trance", + "trip-hop", + "turkish", + "work-out", + "world-music", + ] + } +} \ No newline at end of file diff --git a/src/test/data/validMarkets.ts b/src/test/data/validMarkets.ts new file mode 100644 index 0000000..ddad94a --- /dev/null +++ b/src/test/data/validMarkets.ts @@ -0,0 +1,190 @@ +export function validMarkets() { + return { + "markets": [ + "AD", + "AE", + "AG", + "AL", + "AM", + "AO", + "AR", + "AT", + "AU", + "AZ", + "BA", + "BB", + "BD", + "BE", + "BF", + "BG", + "BH", + "BI", + "BJ", + "BN", + "BO", + "BR", + "BS", + "BT", + "BW", + "BY", + "BZ", + "CA", + "CD", + "CG", + "CH", + "CI", + "CL", + "CM", + "CO", + "CR", + "CV", + "CW", + "CY", + "CZ", + "DE", + "DJ", + "DK", + "DM", + "DO", + "DZ", + "EC", + "EE", + "EG", + "ES", + "ET", + "FI", + "FJ", + "FM", + "FR", + "GA", + "GB", + "GD", + "GE", + "GH", + "GM", + "GN", + "GQ", + "GR", + "GT", + "GW", + "GY", + "HK", + "HN", + "HR", + "HT", + "HU", + "ID", + "IE", + "IL", + "IN", + "IQ", + "IS", + "IT", + "JM", + "JO", + "JP", + "KE", + "KG", + "KH", + "KI", + "KM", + "KN", + "KR", + "KW", + "KZ", + "LA", + "LB", + "LC", + "LI", + "LK", + "LR", + "LS", + "LT", + "LU", + "LV", + "LY", + "MA", + "MC", + "MD", + "ME", + "MG", + "MH", + "MK", + "ML", + "MN", + "MO", + "MR", + "MT", + "MU", + "MV", + "MW", + "MX", + "MY", + "MZ", + "NA", + "NE", + "NG", + "NI", + "NL", + "NO", + "NP", + "NR", + "NZ", + "OM", + "PA", + "PE", + "PG", + "PH", + "PK", + "PL", + "PS", + "PT", + "PW", + "PY", + "QA", + "RO", + "RS", + "RW", + "SA", + "SB", + "SC", + "SE", + "SG", + "SI", + "SK", + "SL", + "SM", + "SN", + "SR", + "ST", + "SV", + "SZ", + "TD", + "TG", + "TH", + "TJ", + "TL", + "TN", + "TO", + "TR", + "TT", + "TV", + "TW", + "TZ", + "UA", + "UG", + "US", + "UY", + "UZ", + "VC", + "VE", + "VN", + "VU", + "WS", + "XK", + "ZA", + "ZM", + "ZW" + ] + } +} \ No newline at end of file diff --git a/src/test/data/validPlaylist.ts b/src/test/data/validPlaylist.ts new file mode 100644 index 0000000..1295b62 --- /dev/null +++ b/src/test/data/validPlaylist.ts @@ -0,0 +1,6856 @@ +export function validPlaylist() { + return { + "collaborative": false, + "description": "Metalcore at its finest. Cover: The Plot In You", + "external_urls": { + "spotify": "https://open.spotify.com/playlist/37i9dQZF1DWXIcbzpLauPS" + }, + "followers": { + "href": null, + "total": 874446 + }, + "href": "https://api.spotify.com/v1/playlists/37i9dQZF1DWXIcbzpLauPS", + "id": "37i9dQZF1DWXIcbzpLauPS", + "images": [{ + "height": null, + "url": "https://i.scdn.co/image/ab67706f0000000314cb3a01a01600d41c954b24", + "width": null + }], + "name": "The Core", + "owner": { + "display_name": "Spotify", + "external_urls": { + "spotify": "https://open.spotify.com/user/spotify" + }, + "href": "https://api.spotify.com/v1/users/spotify", + "id": "spotify", + "type": "user", + "uri": "spotify:user:spotify" + }, + "primary_color": "#FFFFFF", + "public": true, + "snapshot_id": "MTY3ODQyNjc1MSwwMDAwMDAwMDY1M2Y3ZjZhYTQyNjE5NmYzZWEwMGI2YTI4NmUwZGY2", + "tracks": { + "href": "https://api.spotify.com/v1/playlists/37i9dQZF1DWXIcbzpLauPS/tracks?offset=0&limit=100&locale=*", + "items": [{ + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1cJ5tVoeAEFcZBAwSZ0CtF" + }, + "href": "https://api.spotify.com/v1/artists/1cJ5tVoeAEFcZBAwSZ0CtF", + "id": "1cJ5tVoeAEFcZBAwSZ0CtF", + "name": "The Plot In You", + "type": "artist", + "uri": "spotify:artist:1cJ5tVoeAEFcZBAwSZ0CtF" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/2efABZ7jsJTkRkZALraqEM" + }, + "href": "https://api.spotify.com/v1/albums/2efABZ7jsJTkRkZALraqEM", + "id": "2efABZ7jsJTkRkZALraqEM", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273d5ed54d7e37d4dd456ec28f1", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02d5ed54d7e37d4dd456ec28f1", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851d5ed54d7e37d4dd456ec28f1", + "width": 64 + }], + "is_playable": true, + "name": "Left Behind", + "release_date": "2023-02-08", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:2efABZ7jsJTkRkZALraqEM" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1cJ5tVoeAEFcZBAwSZ0CtF" + }, + "href": "https://api.spotify.com/v1/artists/1cJ5tVoeAEFcZBAwSZ0CtF", + "id": "1cJ5tVoeAEFcZBAwSZ0CtF", + "name": "The Plot In You", + "type": "artist", + "uri": "spotify:artist:1cJ5tVoeAEFcZBAwSZ0CtF" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 206924, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "US5262325259" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5G6jZFDAFlpAA9v5LTV4NI" + }, + "href": "https://api.spotify.com/v1/tracks/5G6jZFDAFlpAA9v5LTV4NI", + "id": "5G6jZFDAFlpAA9v5LTV4NI", + "is_local": false, + "name": "Left Behind", + "popularity": 63, + "preview_url": null, + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:5G6jZFDAFlpAA9v5LTV4NI" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3Uobr6LgQpBbk6k4QGAb3V" + }, + "href": "https://api.spotify.com/v1/artists/3Uobr6LgQpBbk6k4QGAb3V", + "id": "3Uobr6LgQpBbk6k4QGAb3V", + "name": "I Prevail", + "type": "artist", + "uri": "spotify:artist:3Uobr6LgQpBbk6k4QGAb3V" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6SjY4WK6VMFYEINGVOHzGa" + }, + "href": "https://api.spotify.com/v1/albums/6SjY4WK6VMFYEINGVOHzGa", + "id": "6SjY4WK6VMFYEINGVOHzGa", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273fdf16e6dc8b69f3e7c2b258b", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02fdf16e6dc8b69f3e7c2b258b", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851fdf16e6dc8b69f3e7c2b258b", + "width": 64 + }], + "is_playable": true, + "name": "TRUE POWER", + "release_date": "2022-08-19", + "release_date_precision": "day", + "total_tracks": 15, + "type": "album", + "uri": "spotify:album:6SjY4WK6VMFYEINGVOHzGa" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3Uobr6LgQpBbk6k4QGAb3V" + }, + "href": "https://api.spotify.com/v1/artists/3Uobr6LgQpBbk6k4QGAb3V", + "id": "3Uobr6LgQpBbk6k4QGAb3V", + "name": "I Prevail", + "type": "artist", + "uri": "spotify:artist:3Uobr6LgQpBbk6k4QGAb3V" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 234945, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "US5262224771" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2OYtcqflvzQwh3cMPmTHs4" + }, + "href": "https://api.spotify.com/v1/tracks/2OYtcqflvzQwh3cMPmTHs4", + "id": "2OYtcqflvzQwh3cMPmTHs4", + "is_local": false, + "name": "There’s Fear In Letting Go", + "popularity": 65, + "preview_url": null, + "track": true, + "track_number": 2, + "type": "track", + "uri": "spotify:track:2OYtcqflvzQwh3cMPmTHs4" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/5pqvAI85RMxL9K0xHvSwGu" + }, + "href": "https://api.spotify.com/v1/artists/5pqvAI85RMxL9K0xHvSwGu", + "id": "5pqvAI85RMxL9K0xHvSwGu", + "name": "Currents", + "type": "artist", + "uri": "spotify:artist:5pqvAI85RMxL9K0xHvSwGu" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/7daOpSeAgyfQMEd3YbIGPZ" + }, + "href": "https://api.spotify.com/v1/albums/7daOpSeAgyfQMEd3YbIGPZ", + "id": "7daOpSeAgyfQMEd3YbIGPZ", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273f0e5b42bf1beaf304000025e", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02f0e5b42bf1beaf304000025e", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851f0e5b42bf1beaf304000025e", + "width": 64 + }], + "is_playable": true, + "name": "Remember Me", + "release_date": "2023-02-01", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:7daOpSeAgyfQMEd3YbIGPZ" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/5pqvAI85RMxL9K0xHvSwGu" + }, + "href": "https://api.spotify.com/v1/artists/5pqvAI85RMxL9K0xHvSwGu", + "id": "5pqvAI85RMxL9K0xHvSwGu", + "name": "Currents", + "type": "artist", + "uri": "spotify:artist:5pqvAI85RMxL9K0xHvSwGu" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 244254, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DED832200494" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1xqt7wT0YY9YpP9jrTuVgG" + }, + "href": "https://api.spotify.com/v1/tracks/1xqt7wT0YY9YpP9jrTuVgG", + "id": "1xqt7wT0YY9YpP9jrTuVgG", + "is_local": false, + "name": "Remember Me", + "popularity": 61, + "preview_url": "https://p.scdn.co/mp3-preview/a7d1c1a50c2eeda31ced2bc42fcb05da82080d6b?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:1xqt7wT0YY9YpP9jrTuVgG" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2n2RSaZqBuUUukhbLlpnE6" + }, + "href": "https://api.spotify.com/v1/artists/2n2RSaZqBuUUukhbLlpnE6", + "id": "2n2RSaZqBuUUukhbLlpnE6", + "name": "Sleep Token", + "type": "artist", + "uri": "spotify:artist:2n2RSaZqBuUUukhbLlpnE6" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/42fcciBOkkvnEu8dN7mByX" + }, + "href": "https://api.spotify.com/v1/albums/42fcciBOkkvnEu8dN7mByX", + "id": "42fcciBOkkvnEu8dN7mByX", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273eb7a831300d4835a4c16f8c1", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02eb7a831300d4835a4c16f8c1", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851eb7a831300d4835a4c16f8c1", + "width": 64 + }], + "is_playable": true, + "name": "The Summoning", + "release_date": "2023-01-06", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:42fcciBOkkvnEu8dN7mByX" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2n2RSaZqBuUUukhbLlpnE6" + }, + "href": "https://api.spotify.com/v1/artists/2n2RSaZqBuUUukhbLlpnE6", + "id": "2n2RSaZqBuUUukhbLlpnE6", + "name": "Sleep Token", + "type": "artist", + "uri": "spotify:artist:2n2RSaZqBuUUukhbLlpnE6" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 395716, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "GBUM72200352" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1yCE0X5qLWOrLkR8NC0ZUJ" + }, + "href": "https://api.spotify.com/v1/tracks/1yCE0X5qLWOrLkR8NC0ZUJ", + "id": "1yCE0X5qLWOrLkR8NC0ZUJ", + "is_local": false, + "name": "The Summoning", + "popularity": 72, + "preview_url": "https://p.scdn.co/mp3-preview/37dae98703ecc268384d30ed33045254aa4198c9?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:1yCE0X5qLWOrLkR8NC0ZUJ" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3GzWhE2xadJiW8MqRKIVSK" + }, + "href": "https://api.spotify.com/v1/artists/3GzWhE2xadJiW8MqRKIVSK", + "id": "3GzWhE2xadJiW8MqRKIVSK", + "name": "Underoath", + "type": "artist", + "uri": "spotify:artist:3GzWhE2xadJiW8MqRKIVSK" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/0rEiAGXHPJUbsNsKP9TfkH" + }, + "href": "https://api.spotify.com/v1/albums/0rEiAGXHPJUbsNsKP9TfkH", + "id": "0rEiAGXHPJUbsNsKP9TfkH", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27328a6fa27549a55d58ec64108", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0228a6fa27549a55d58ec64108", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485128a6fa27549a55d58ec64108", + "width": 64 + }], + "is_playable": true, + "name": "Let Go", + "release_date": "2023-03-03", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:0rEiAGXHPJUbsNsKP9TfkH" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3GzWhE2xadJiW8MqRKIVSK" + }, + "href": "https://api.spotify.com/v1/artists/3GzWhE2xadJiW8MqRKIVSK", + "id": "3GzWhE2xadJiW8MqRKIVSK", + "name": "Underoath", + "type": "artist", + "uri": "spotify:artist:3GzWhE2xadJiW8MqRKIVSK" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 230002, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "US5ED2302825" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2iHdiDAIYBPOqnNxVrNBYO" + }, + "href": "https://api.spotify.com/v1/tracks/2iHdiDAIYBPOqnNxVrNBYO", + "id": "2iHdiDAIYBPOqnNxVrNBYO", + "is_local": false, + "name": "Let Go", + "popularity": 53, + "preview_url": "https://p.scdn.co/mp3-preview/2110d3608273235aa40f9cdb1f7442ae7abdadb2?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2iHdiDAIYBPOqnNxVrNBYO" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6kNKUYGn6VNGsRoXmyoDPK" + }, + "href": "https://api.spotify.com/v1/artists/6kNKUYGn6VNGsRoXmyoDPK", + "id": "6kNKUYGn6VNGsRoXmyoDPK", + "name": "The Amity Affliction", + "type": "artist", + "uri": "spotify:artist:6kNKUYGn6VNGsRoXmyoDPK" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3R8VofbgLwq9q48eueOCqC" + }, + "href": "https://api.spotify.com/v1/albums/3R8VofbgLwq9q48eueOCqC", + "id": "3R8VofbgLwq9q48eueOCqC", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273bd698fde531754890e1fbfd8", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02bd698fde531754890e1fbfd8", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851bd698fde531754890e1fbfd8", + "width": 64 + }], + "is_playable": true, + "name": "I See Dead People", + "release_date": "2023-02-13", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:3R8VofbgLwq9q48eueOCqC" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6kNKUYGn6VNGsRoXmyoDPK" + }, + "href": "https://api.spotify.com/v1/artists/6kNKUYGn6VNGsRoXmyoDPK", + "id": "6kNKUYGn6VNGsRoXmyoDPK", + "name": "The Amity Affliction", + "type": "artist", + "uri": "spotify:artist:6kNKUYGn6VNGsRoXmyoDPK" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/2SQXiX0AGHf3Aw43or85KX" + }, + "href": "https://api.spotify.com/v1/artists/2SQXiX0AGHf3Aw43or85KX", + "id": "2SQXiX0AGHf3Aw43or85KX", + "name": "Louie Knuxx", + "type": "artist", + "uri": "spotify:artist:2SQXiX0AGHf3Aw43or85KX" + }], + "available_markets": ["AR", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 216579, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "USSTT2300027" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/3UgZA53hNSPbwtNJ7x8Bd9" + }, + "href": "https://api.spotify.com/v1/tracks/3UgZA53hNSPbwtNJ7x8Bd9", + "id": "3UgZA53hNSPbwtNJ7x8Bd9", + "is_local": false, + "name": "I See Dead People", + "popularity": 57, + "preview_url": "https://p.scdn.co/mp3-preview/1dac2fe174ea815e3b061532eb529a63d2688ab2?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:3UgZA53hNSPbwtNJ7x8Bd9" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2fqPOGxG12nEERj8YG7p22" + }, + "href": "https://api.spotify.com/v1/artists/2fqPOGxG12nEERj8YG7p22", + "id": "2fqPOGxG12nEERj8YG7p22", + "name": "Catch Your Breath", + "type": "artist", + "uri": "spotify:artist:2fqPOGxG12nEERj8YG7p22" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3TshwnXhNfppmFUrlP4BZV" + }, + "href": "https://api.spotify.com/v1/albums/3TshwnXhNfppmFUrlP4BZV", + "id": "3TshwnXhNfppmFUrlP4BZV", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273f6b1995099ca3a4a38493ca6", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02f6b1995099ca3a4a38493ca6", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851f6b1995099ca3a4a38493ca6", + "width": 64 + }], + "is_playable": true, + "name": "Dial Tone", + "release_date": "2022-05-20", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:3TshwnXhNfppmFUrlP4BZV" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2fqPOGxG12nEERj8YG7p22" + }, + "href": "https://api.spotify.com/v1/artists/2fqPOGxG12nEERj8YG7p22", + "id": "2fqPOGxG12nEERj8YG7p22", + "name": "Catch Your Breath", + "type": "artist", + "uri": "spotify:artist:2fqPOGxG12nEERj8YG7p22" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 200495, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZES82294531" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5tX5qGeEImk2CZYyGHrq9I" + }, + "href": "https://api.spotify.com/v1/tracks/5tX5qGeEImk2CZYyGHrq9I", + "id": "5tX5qGeEImk2CZYyGHrq9I", + "is_local": false, + "name": "Dial Tone", + "popularity": 70, + "preview_url": "https://p.scdn.co/mp3-preview/25b7d6d8861b4d5fd49c59c9a4329429d8cf3d32?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:5tX5qGeEImk2CZYyGHrq9I" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6OLm78czd7Y80yrzwAb7FK" + }, + "href": "https://api.spotify.com/v1/artists/6OLm78czd7Y80yrzwAb7FK", + "id": "6OLm78czd7Y80yrzwAb7FK", + "name": "Arrival Of Autumn", + "type": "artist", + "uri": "spotify:artist:6OLm78czd7Y80yrzwAb7FK" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4JpyEPmtqUY38STlkVZrFM" + }, + "href": "https://api.spotify.com/v1/albums/4JpyEPmtqUY38STlkVZrFM", + "id": "4JpyEPmtqUY38STlkVZrFM", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273d8f54d079f6bddbdd2b231d1", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02d8f54d079f6bddbdd2b231d1", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851d8f54d079f6bddbdd2b231d1", + "width": 64 + }], + "is_playable": true, + "name": "Scars", + "release_date": "2023-02-24", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:4JpyEPmtqUY38STlkVZrFM" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6OLm78czd7Y80yrzwAb7FK" + }, + "href": "https://api.spotify.com/v1/artists/6OLm78czd7Y80yrzwAb7FK", + "id": "6OLm78czd7Y80yrzwAb7FK", + "name": "Arrival Of Autumn", + "type": "artist", + "uri": "spotify:artist:6OLm78czd7Y80yrzwAb7FK" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 211440, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DED832200632" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2vBwejT7xi8pDeGYxmY8vi" + }, + "href": "https://api.spotify.com/v1/tracks/2vBwejT7xi8pDeGYxmY8vi", + "id": "2vBwejT7xi8pDeGYxmY8vi", + "is_local": false, + "name": "Scars", + "popularity": 36, + "preview_url": "https://p.scdn.co/mp3-preview/5828e2c2b317e0603b07fb2f78edff263aa7f000?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2vBwejT7xi8pDeGYxmY8vi" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3LkSiHbjqOHCKCqBfEZOTv" + }, + "href": "https://api.spotify.com/v1/artists/3LkSiHbjqOHCKCqBfEZOTv", + "id": "3LkSiHbjqOHCKCqBfEZOTv", + "name": "Atreyu", + "type": "artist", + "uri": "spotify:artist:3LkSiHbjqOHCKCqBfEZOTv" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6d5waVDcEQEcM6BKbkBiNx" + }, + "href": "https://api.spotify.com/v1/albums/6d5waVDcEQEcM6BKbkBiNx", + "id": "6d5waVDcEQEcM6BKbkBiNx", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27373eec5685d9d61b0f330ba22", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0273eec5685d9d61b0f330ba22", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485173eec5685d9d61b0f330ba22", + "width": 64 + }], + "is_playable": true, + "name": "Drowning", + "release_date": "2023-01-27", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:6d5waVDcEQEcM6BKbkBiNx" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3LkSiHbjqOHCKCqBfEZOTv" + }, + "href": "https://api.spotify.com/v1/artists/3LkSiHbjqOHCKCqBfEZOTv", + "id": "3LkSiHbjqOHCKCqBfEZOTv", + "name": "Atreyu", + "type": "artist", + "uri": "spotify:artist:3LkSiHbjqOHCKCqBfEZOTv" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 165557, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "GBPVV2204851" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4l0UQ0zDIPYaaa5FF2Kvwt" + }, + "href": "https://api.spotify.com/v1/tracks/4l0UQ0zDIPYaaa5FF2Kvwt", + "id": "4l0UQ0zDIPYaaa5FF2Kvwt", + "is_local": false, + "name": "Drowning", + "popularity": 62, + "preview_url": "https://p.scdn.co/mp3-preview/b51c14eb81b306cf406e1c70e2e6e4701fad8123?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:4l0UQ0zDIPYaaa5FF2Kvwt" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6MwPCCR936cYfM1dLsGVnl" + }, + "href": "https://api.spotify.com/v1/artists/6MwPCCR936cYfM1dLsGVnl", + "id": "6MwPCCR936cYfM1dLsGVnl", + "name": "Motionless In White", + "type": "artist", + "uri": "spotify:artist:6MwPCCR936cYfM1dLsGVnl" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/0DoVnWjNFYoUfq7qe36jxh" + }, + "href": "https://api.spotify.com/v1/albums/0DoVnWjNFYoUfq7qe36jxh", + "id": "0DoVnWjNFYoUfq7qe36jxh", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2733528a891d36d16d760cda271", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e023528a891d36d16d760cda271", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048513528a891d36d16d760cda271", + "width": 64 + }], + "is_playable": true, + "name": "Scoring The End Of The World", + "release_date": "2022-06-10", + "release_date_precision": "day", + "total_tracks": 13, + "type": "album", + "uri": "spotify:album:0DoVnWjNFYoUfq7qe36jxh" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6MwPCCR936cYfM1dLsGVnl" + }, + "href": "https://api.spotify.com/v1/artists/6MwPCCR936cYfM1dLsGVnl", + "id": "6MwPCCR936cYfM1dLsGVnl", + "name": "Motionless In White", + "type": "artist", + "uri": "spotify:artist:6MwPCCR936cYfM1dLsGVnl" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 212082, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "NLA322200044" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1e1rQNYCZToyBDDka1Io34" + }, + "href": "https://api.spotify.com/v1/tracks/1e1rQNYCZToyBDDka1Io34", + "id": "1e1rQNYCZToyBDDka1Io34", + "is_local": false, + "name": "Werewolf", + "popularity": 63, + "preview_url": "https://p.scdn.co/mp3-preview/e52846517ba5e4ff77e3af12fc1ec68881922671?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 3, + "type": "track", + "uri": "spotify:track:1e1rQNYCZToyBDDka1Io34" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4HrkLxQHZ5mgCtIVpiH5QX" + }, + "href": "https://api.spotify.com/v1/artists/4HrkLxQHZ5mgCtIVpiH5QX", + "id": "4HrkLxQHZ5mgCtIVpiH5QX", + "name": "From Ashes to New", + "type": "artist", + "uri": "spotify:artist:4HrkLxQHZ5mgCtIVpiH5QX" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3QIB6uRdIiuTKHBzYY5GCc" + }, + "href": "https://api.spotify.com/v1/albums/3QIB6uRdIiuTKHBzYY5GCc", + "id": "3QIB6uRdIiuTKHBzYY5GCc", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273c17731bea256938e8de1f15f", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02c17731bea256938e8de1f15f", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851c17731bea256938e8de1f15f", + "width": 64 + }], + "is_playable": true, + "name": "Nightmare", + "release_date": "2023-02-03", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:3QIB6uRdIiuTKHBzYY5GCc" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4HrkLxQHZ5mgCtIVpiH5QX" + }, + "href": "https://api.spotify.com/v1/artists/4HrkLxQHZ5mgCtIVpiH5QX", + "id": "4HrkLxQHZ5mgCtIVpiH5QX", + "name": "From Ashes to New", + "type": "artist", + "uri": "spotify:artist:4HrkLxQHZ5mgCtIVpiH5QX" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 187835, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "USDPK2300001" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0u9PGHiydskvvPmyPVvm73" + }, + "href": "https://api.spotify.com/v1/tracks/0u9PGHiydskvvPmyPVvm73", + "id": "0u9PGHiydskvvPmyPVvm73", + "is_local": false, + "name": "Nightmare", + "popularity": 62, + "preview_url": "https://p.scdn.co/mp3-preview/a6334ecd136f840ae911e8294580891496d0da71?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:0u9PGHiydskvvPmyPVvm73" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/77rcxvpDqP78d90dL3DNNe" + }, + "href": "https://api.spotify.com/v1/artists/77rcxvpDqP78d90dL3DNNe", + "id": "77rcxvpDqP78d90dL3DNNe", + "name": "Kingdom Of Giants", + "type": "artist", + "uri": "spotify:artist:77rcxvpDqP78d90dL3DNNe" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6kldsD8IODEdYNlNAXPCed" + }, + "href": "https://api.spotify.com/v1/albums/6kldsD8IODEdYNlNAXPCed", + "id": "6kldsD8IODEdYNlNAXPCed", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2739e44ab4aecacd0060e1adcef", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e029e44ab4aecacd0060e1adcef", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048519e44ab4aecacd0060e1adcef", + "width": 64 + }], + "is_playable": true, + "name": "Wasted Space", + "release_date": "2023-03-03", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:6kldsD8IODEdYNlNAXPCed" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/77rcxvpDqP78d90dL3DNNe" + }, + "href": "https://api.spotify.com/v1/artists/77rcxvpDqP78d90dL3DNNe", + "id": "77rcxvpDqP78d90dL3DNNe", + "name": "Kingdom Of Giants", + "type": "artist", + "uri": "spotify:artist:77rcxvpDqP78d90dL3DNNe" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 206850, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DED832300079" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2swqb0ij8Xpksi4A7tqE6i" + }, + "href": "https://api.spotify.com/v1/tracks/2swqb0ij8Xpksi4A7tqE6i", + "id": "2swqb0ij8Xpksi4A7tqE6i", + "is_local": false, + "name": "Wasted Space", + "popularity": 48, + "preview_url": "https://p.scdn.co/mp3-preview/8e092b34292c9e65ebb185de3e118d15bfd39093?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2swqb0ij8Xpksi4A7tqE6i" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/159qqlGwzE04xyqpfAwRLo" + }, + "href": "https://api.spotify.com/v1/artists/159qqlGwzE04xyqpfAwRLo", + "id": "159qqlGwzE04xyqpfAwRLo", + "name": "Parkway Drive", + "type": "artist", + "uri": "spotify:artist:159qqlGwzE04xyqpfAwRLo" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/36McCMdCRYn5j6iSMiqdG4" + }, + "href": "https://api.spotify.com/v1/albums/36McCMdCRYn5j6iSMiqdG4", + "id": "36McCMdCRYn5j6iSMiqdG4", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273e4551f6b8bdde8aaeaed85cd", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02e4551f6b8bdde8aaeaed85cd", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851e4551f6b8bdde8aaeaed85cd", + "width": 64 + }], + "is_playable": true, + "name": "Darker Still", + "release_date": "2022-09-09", + "release_date_precision": "day", + "total_tracks": 11, + "type": "album", + "uri": "spotify:album:36McCMdCRYn5j6iSMiqdG4" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/159qqlGwzE04xyqpfAwRLo" + }, + "href": "https://api.spotify.com/v1/artists/159qqlGwzE04xyqpfAwRLo", + "id": "159qqlGwzE04xyqpfAwRLo", + "name": "Parkway Drive", + "type": "artist", + "uri": "spotify:artist:159qqlGwzE04xyqpfAwRLo" + }], + "available_markets": ["AR", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 261811, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "USEP42215003" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1jKH10ufuA4EzUCdobVxu0" + }, + "href": "https://api.spotify.com/v1/tracks/1jKH10ufuA4EzUCdobVxu0", + "id": "1jKH10ufuA4EzUCdobVxu0", + "is_local": false, + "name": "Glitch", + "popularity": 58, + "preview_url": "https://p.scdn.co/mp3-preview/4359caacc095c600327b42aecf3adbe72bbe7a3f?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 3, + "type": "track", + "uri": "spotify:track:1jKH10ufuA4EzUCdobVxu0" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/5p9CTsn5ueGU4oScNX1axu" + }, + "href": "https://api.spotify.com/v1/artists/5p9CTsn5ueGU4oScNX1axu", + "id": "5p9CTsn5ueGU4oScNX1axu", + "name": "August Burns Red", + "type": "artist", + "uri": "spotify:artist:5p9CTsn5ueGU4oScNX1axu" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4DBR3CJvtw972fOYg93ndQ" + }, + "href": "https://api.spotify.com/v1/albums/4DBR3CJvtw972fOYg93ndQ", + "id": "4DBR3CJvtw972fOYg93ndQ", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2736772c4a06609357dcee846de", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e026772c4a06609357dcee846de", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048516772c4a06609357dcee846de", + "width": 64 + }], + "is_playable": true, + "name": "Backfire", + "release_date": "2023-01-25", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:4DBR3CJvtw972fOYg93ndQ" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/5p9CTsn5ueGU4oScNX1axu" + }, + "href": "https://api.spotify.com/v1/artists/5p9CTsn5ueGU4oScNX1axu", + "id": "5p9CTsn5ueGU4oScNX1axu", + "name": "August Burns Red", + "type": "artist", + "uri": "spotify:artist:5p9CTsn5ueGU4oScNX1axu" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 262925, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DED832200434" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/6qA3JeQaSLng3XmIFr7IC0" + }, + "href": "https://api.spotify.com/v1/tracks/6qA3JeQaSLng3XmIFr7IC0", + "id": "6qA3JeQaSLng3XmIFr7IC0", + "is_local": false, + "name": "Backfire", + "popularity": 53, + "preview_url": "https://p.scdn.co/mp3-preview/8204b3f54a2b2dfe5c9e3ea1150ffbd778b4bdee?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:6qA3JeQaSLng3XmIFr7IC0" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0FZcPgWI3BsFQl4rOAGSHT" + }, + "href": "https://api.spotify.com/v1/artists/0FZcPgWI3BsFQl4rOAGSHT", + "id": "0FZcPgWI3BsFQl4rOAGSHT", + "name": "Make Them Suffer", + "type": "artist", + "uri": "spotify:artist:0FZcPgWI3BsFQl4rOAGSHT" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/7J8x3vAHCvP4gKZUEdsLN4" + }, + "href": "https://api.spotify.com/v1/albums/7J8x3vAHCvP4gKZUEdsLN4", + "id": "7J8x3vAHCvP4gKZUEdsLN4", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27346ed2365695de346fa0027e8", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0246ed2365695de346fa0027e8", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485146ed2365695de346fa0027e8", + "width": 64 + }], + "is_playable": true, + "name": "Doomswitch", + "release_date": "2022-10-14", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:7J8x3vAHCvP4gKZUEdsLN4" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0FZcPgWI3BsFQl4rOAGSHT" + }, + "href": "https://api.spotify.com/v1/artists/0FZcPgWI3BsFQl4rOAGSHT", + "id": "0FZcPgWI3BsFQl4rOAGSHT", + "name": "Make Them Suffer", + "type": "artist", + "uri": "spotify:artist:0FZcPgWI3BsFQl4rOAGSHT" + }], + "available_markets": ["AR", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 275205, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "AUNCC2200059" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/6pUUtKVRmODliJWTyY2pet" + }, + "href": "https://api.spotify.com/v1/tracks/6pUUtKVRmODliJWTyY2pet", + "id": "6pUUtKVRmODliJWTyY2pet", + "is_local": false, + "name": "Doomswitch", + "popularity": 56, + "preview_url": "https://p.scdn.co/mp3-preview/1e49e1e6df369bd805c0a6f909f7a064c6726114?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:6pUUtKVRmODliJWTyY2pet" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6qO6LhD6FuXK5e2PtfAIMz" + }, + "href": "https://api.spotify.com/v1/artists/6qO6LhD6FuXK5e2PtfAIMz", + "id": "6qO6LhD6FuXK5e2PtfAIMz", + "name": "We Came As Romans", + "type": "artist", + "uri": "spotify:artist:6qO6LhD6FuXK5e2PtfAIMz" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/15q7078X1sRf9ivhEnv1tm" + }, + "href": "https://api.spotify.com/v1/albums/15q7078X1sRf9ivhEnv1tm", + "id": "15q7078X1sRf9ivhEnv1tm", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2732aaa9372a6922e6e3575d828", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e022aaa9372a6922e6e3575d828", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048512aaa9372a6922e6e3575d828", + "width": 64 + }], + "is_playable": true, + "name": "Darkbloom", + "release_date": "2022-10-14", + "release_date_precision": "day", + "total_tracks": 10, + "type": "album", + "uri": "spotify:album:15q7078X1sRf9ivhEnv1tm" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6qO6LhD6FuXK5e2PtfAIMz" + }, + "href": "https://api.spotify.com/v1/artists/6qO6LhD6FuXK5e2PtfAIMz", + "id": "6qO6LhD6FuXK5e2PtfAIMz", + "name": "We Came As Romans", + "type": "artist", + "uri": "spotify:artist:6qO6LhD6FuXK5e2PtfAIMz" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 209840, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DED832100655" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/6xC8tcFBMMjJIyfPw66lDF" + }, + "href": "https://api.spotify.com/v1/tracks/6xC8tcFBMMjJIyfPw66lDF", + "id": "6xC8tcFBMMjJIyfPw66lDF", + "is_local": false, + "name": "Plagued", + "popularity": 56, + "preview_url": "https://p.scdn.co/mp3-preview/5c6f2aa4d961cb7511501a9695deb7f819bdee28?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 2, + "type": "track", + "uri": "spotify:track:6xC8tcFBMMjJIyfPw66lDF" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7InRNmmQuAi5KGBFtfOkrf" + }, + "href": "https://api.spotify.com/v1/artists/7InRNmmQuAi5KGBFtfOkrf", + "id": "7InRNmmQuAi5KGBFtfOkrf", + "name": "Rising Insane", + "type": "artist", + "uri": "spotify:artist:7InRNmmQuAi5KGBFtfOkrf" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/05KgX2I0e6LKvBWlUmRW0H" + }, + "href": "https://api.spotify.com/v1/albums/05KgX2I0e6LKvBWlUmRW0H", + "id": "05KgX2I0e6LKvBWlUmRW0H", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2733fe36a4e209b3b08d14aba21", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e023fe36a4e209b3b08d14aba21", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048513fe36a4e209b3b08d14aba21", + "width": 64 + }], + "is_playable": true, + "name": "Drag Me Under", + "release_date": "2023-02-03", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:05KgX2I0e6LKvBWlUmRW0H" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7InRNmmQuAi5KGBFtfOkrf" + }, + "href": "https://api.spotify.com/v1/artists/7InRNmmQuAi5KGBFtfOkrf", + "id": "7InRNmmQuAi5KGBFtfOkrf", + "name": "Rising Insane", + "type": "artist", + "uri": "spotify:artist:7InRNmmQuAi5KGBFtfOkrf" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 225666, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QMFME2253674" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2CwBf7BQoztOsPNUszOOv8" + }, + "href": "https://api.spotify.com/v1/tracks/2CwBf7BQoztOsPNUszOOv8", + "id": "2CwBf7BQoztOsPNUszOOv8", + "is_local": false, + "name": "Drag Me Under", + "popularity": 43, + "preview_url": "https://p.scdn.co/mp3-preview/91e126075d5ff7aa3decbfca543faca03e56a0d7?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2CwBf7BQoztOsPNUszOOv8" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4ISeDymLgZtEyx5Dy4BaqD" + }, + "href": "https://api.spotify.com/v1/artists/4ISeDymLgZtEyx5Dy4BaqD", + "id": "4ISeDymLgZtEyx5Dy4BaqD", + "name": "Our Promise", + "type": "artist", + "uri": "spotify:artist:4ISeDymLgZtEyx5Dy4BaqD" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/5aNJN4zGJTPKvie47D56aE" + }, + "href": "https://api.spotify.com/v1/albums/5aNJN4zGJTPKvie47D56aE", + "id": "5aNJN4zGJTPKvie47D56aE", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273a6cfcc33c2802bb5ebd8a500", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02a6cfcc33c2802bb5ebd8a500", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851a6cfcc33c2802bb5ebd8a500", + "width": 64 + }], + "is_playable": true, + "name": "Panic Waves", + "release_date": "2023-02-17", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:5aNJN4zGJTPKvie47D56aE" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4ISeDymLgZtEyx5Dy4BaqD" + }, + "href": "https://api.spotify.com/v1/artists/4ISeDymLgZtEyx5Dy4BaqD", + "id": "4ISeDymLgZtEyx5Dy4BaqD", + "name": "Our Promise", + "type": "artist", + "uri": "spotify:artist:4ISeDymLgZtEyx5Dy4BaqD" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 247399, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEVX62300001" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2UE48m09FyDdc6Ot1sGKqS" + }, + "href": "https://api.spotify.com/v1/tracks/2UE48m09FyDdc6Ot1sGKqS", + "id": "2UE48m09FyDdc6Ot1sGKqS", + "is_local": false, + "name": "Panic Waves", + "popularity": 49, + "preview_url": "https://p.scdn.co/mp3-preview/c2d9a6e7ae26e64bf5d02416987a3c1433214b30?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2UE48m09FyDdc6Ot1sGKqS" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0NbQe5CNgh4YApOCDuHSjb" + }, + "href": "https://api.spotify.com/v1/artists/0NbQe5CNgh4YApOCDuHSjb", + "id": "0NbQe5CNgh4YApOCDuHSjb", + "name": "The Devil Wears Prada", + "type": "artist", + "uri": "spotify:artist:0NbQe5CNgh4YApOCDuHSjb" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/1HqkZxWaoHVC5OPhGlHGa0" + }, + "href": "https://api.spotify.com/v1/albums/1HqkZxWaoHVC5OPhGlHGa0", + "id": "1HqkZxWaoHVC5OPhGlHGa0", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273c782d6cf6c3665c15bb4c18f", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02c782d6cf6c3665c15bb4c18f", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851c782d6cf6c3665c15bb4c18f", + "width": 64 + }], + "is_playable": true, + "name": "Salt", + "release_date": "2022-06-07", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:1HqkZxWaoHVC5OPhGlHGa0" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0NbQe5CNgh4YApOCDuHSjb" + }, + "href": "https://api.spotify.com/v1/artists/0NbQe5CNgh4YApOCDuHSjb", + "id": "0NbQe5CNgh4YApOCDuHSjb", + "name": "The Devil Wears Prada", + "type": "artist", + "uri": "spotify:artist:0NbQe5CNgh4YApOCDuHSjb" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 207400, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QMGVJ2200016" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5Ve3eqZmguw75vcY7iwwZY" + }, + "href": "https://api.spotify.com/v1/tracks/5Ve3eqZmguw75vcY7iwwZY", + "id": "5Ve3eqZmguw75vcY7iwwZY", + "is_local": false, + "name": "Salt", + "popularity": 47, + "preview_url": "https://p.scdn.co/mp3-preview/734e9e8fae6b0dbb3687d08e7c998e37129cc433?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:5Ve3eqZmguw75vcY7iwwZY" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1FcRUsTmnEQfVCH5OIKSpb" + }, + "href": "https://api.spotify.com/v1/artists/1FcRUsTmnEQfVCH5OIKSpb", + "id": "1FcRUsTmnEQfVCH5OIKSpb", + "name": "Attack Attack!", + "type": "artist", + "uri": "spotify:artist:1FcRUsTmnEQfVCH5OIKSpb" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/5vsJsheUwcsiM3O7r5qN0v" + }, + "href": "https://api.spotify.com/v1/albums/5vsJsheUwcsiM3O7r5qN0v", + "id": "5vsJsheUwcsiM3O7r5qN0v", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2732f7a22bb843ec3b9b7c81e3e", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e022f7a22bb843ec3b9b7c81e3e", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048512f7a22bb843ec3b9b7c81e3e", + "width": 64 + }], + "is_playable": true, + "name": "Dark Waves", + "release_date": "2023-02-10", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:5vsJsheUwcsiM3O7r5qN0v" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1FcRUsTmnEQfVCH5OIKSpb" + }, + "href": "https://api.spotify.com/v1/artists/1FcRUsTmnEQfVCH5OIKSpb", + "id": "1FcRUsTmnEQfVCH5OIKSpb", + "name": "Attack Attack!", + "type": "artist", + "uri": "spotify:artist:1FcRUsTmnEQfVCH5OIKSpb" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 222571, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QZRUP2200267" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/3SDcDLF3wwQwnI3Wst38aY" + }, + "href": "https://api.spotify.com/v1/tracks/3SDcDLF3wwQwnI3Wst38aY", + "id": "3SDcDLF3wwQwnI3Wst38aY", + "is_local": false, + "name": "Dark Waves", + "popularity": 53, + "preview_url": "https://p.scdn.co/mp3-preview/262a52c421d101c4fe065b23ba777ed0d163d89a?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:3SDcDLF3wwQwnI3Wst38aY" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7rqJQQxuUOCk052MK5kLsH" + }, + "href": "https://api.spotify.com/v1/artists/7rqJQQxuUOCk052MK5kLsH", + "id": "7rqJQQxuUOCk052MK5kLsH", + "name": "Imminence", + "type": "artist", + "uri": "spotify:artist:7rqJQQxuUOCk052MK5kLsH" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/1CjPzgqkAeSShcb3mQ4iNS" + }, + "href": "https://api.spotify.com/v1/albums/1CjPzgqkAeSShcb3mQ4iNS", + "id": "1CjPzgqkAeSShcb3mQ4iNS", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273d60639197bede016e8c5f974", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02d60639197bede016e8c5f974", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851d60639197bede016e8c5f974", + "width": 64 + }], + "is_playable": true, + "name": "Jaded", + "release_date": "2023-02-10", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:1CjPzgqkAeSShcb3mQ4iNS" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7rqJQQxuUOCk052MK5kLsH" + }, + "href": "https://api.spotify.com/v1/artists/7rqJQQxuUOCk052MK5kLsH", + "id": "7rqJQQxuUOCk052MK5kLsH", + "name": "Imminence", + "type": "artist", + "uri": "spotify:artist:7rqJQQxuUOCk052MK5kLsH" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 267744, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEYO62200235" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/6syEBcinz3tRLPwM9Kdemo" + }, + "href": "https://api.spotify.com/v1/tracks/6syEBcinz3tRLPwM9Kdemo", + "id": "6syEBcinz3tRLPwM9Kdemo", + "is_local": false, + "name": "Jaded", + "popularity": 54, + "preview_url": "https://p.scdn.co/mp3-preview/c59408f0043ce3a1786c9fcd7e512afcee14c36e?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:6syEBcinz3tRLPwM9Kdemo" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6Gnk08ItppARKX1z1EW3Vn" + }, + "href": "https://api.spotify.com/v1/artists/6Gnk08ItppARKX1z1EW3Vn", + "id": "6Gnk08ItppARKX1z1EW3Vn", + "name": "Archetypes Collide", + "type": "artist", + "uri": "spotify:artist:6Gnk08ItppARKX1z1EW3Vn" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/0sx2ImaWkigyLHH45jdIo1" + }, + "href": "https://api.spotify.com/v1/albums/0sx2ImaWkigyLHH45jdIo1", + "id": "0sx2ImaWkigyLHH45jdIo1", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2739444d8e245906f778bca0687", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e029444d8e245906f778bca0687", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048519444d8e245906f778bca0687", + "width": 64 + }], + "is_playable": true, + "name": "Parasite", + "release_date": "2023-02-24", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:0sx2ImaWkigyLHH45jdIo1" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6Gnk08ItppARKX1z1EW3Vn" + }, + "href": "https://api.spotify.com/v1/artists/6Gnk08ItppARKX1z1EW3Vn", + "id": "6Gnk08ItppARKX1z1EW3Vn", + "name": "Archetypes Collide", + "type": "artist", + "uri": "spotify:artist:6Gnk08ItppARKX1z1EW3Vn" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 212802, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "US5262224897" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0sBXPxWJpMlQBnVF2y78Rg" + }, + "href": "https://api.spotify.com/v1/tracks/0sBXPxWJpMlQBnVF2y78Rg", + "id": "0sBXPxWJpMlQBnVF2y78Rg", + "is_local": false, + "name": "Parasite", + "popularity": 47, + "preview_url": null, + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:0sBXPxWJpMlQBnVF2y78Rg" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/28IImD2QqPWTQ2cWgOMQNT" + }, + "href": "https://api.spotify.com/v1/artists/28IImD2QqPWTQ2cWgOMQNT", + "id": "28IImD2QqPWTQ2cWgOMQNT", + "name": "As Everything Unfolds", + "type": "artist", + "uri": "spotify:artist:28IImD2QqPWTQ2cWgOMQNT" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/1gQRMfDzWuQ4J2BCjuvWAS" + }, + "href": "https://api.spotify.com/v1/albums/1gQRMfDzWuQ4J2BCjuvWAS", + "id": "1gQRMfDzWuQ4J2BCjuvWAS", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27341f0e8a8b3c56e47eee403bb", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0241f0e8a8b3c56e47eee403bb", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485141f0e8a8b3c56e47eee403bb", + "width": 64 + }], + "is_playable": true, + "name": "Ultraviolet", + "release_date": "2023-01-19", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:1gQRMfDzWuQ4J2BCjuvWAS" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/28IImD2QqPWTQ2cWgOMQNT" + }, + "href": "https://api.spotify.com/v1/artists/28IImD2QqPWTQ2cWgOMQNT", + "id": "28IImD2QqPWTQ2cWgOMQNT", + "name": "As Everything Unfolds", + "type": "artist", + "uri": "spotify:artist:28IImD2QqPWTQ2cWgOMQNT" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 232608, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEA452300010" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0gukK40IEqCb6arYVQxMtl" + }, + "href": "https://api.spotify.com/v1/tracks/0gukK40IEqCb6arYVQxMtl", + "id": "0gukK40IEqCb6arYVQxMtl", + "is_local": false, + "name": "Ultraviolet", + "popularity": 49, + "preview_url": "https://p.scdn.co/mp3-preview/e33927d72b61d44b57b957b56e6d64802515820d?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:0gukK40IEqCb6arYVQxMtl" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6n5DUGtIWYMurrtVt7IdZr" + }, + "href": "https://api.spotify.com/v1/artists/6n5DUGtIWYMurrtVt7IdZr", + "id": "6n5DUGtIWYMurrtVt7IdZr", + "name": "Elwood Stray", + "type": "artist", + "uri": "spotify:artist:6n5DUGtIWYMurrtVt7IdZr" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/5wYZPVMaVGyrfy8xeJdswt" + }, + "href": "https://api.spotify.com/v1/albums/5wYZPVMaVGyrfy8xeJdswt", + "id": "5wYZPVMaVGyrfy8xeJdswt", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273f81f0bf9f97c9c1098223071", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02f81f0bf9f97c9c1098223071", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851f81f0bf9f97c9c1098223071", + "width": 64 + }], + "is_playable": true, + "name": "Decay", + "release_date": "2023-02-17", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:5wYZPVMaVGyrfy8xeJdswt" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6n5DUGtIWYMurrtVt7IdZr" + }, + "href": "https://api.spotify.com/v1/artists/6n5DUGtIWYMurrtVt7IdZr", + "id": "6n5DUGtIWYMurrtVt7IdZr", + "name": "Elwood Stray", + "type": "artist", + "uri": "spotify:artist:6n5DUGtIWYMurrtVt7IdZr" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 206346, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEBZ72300013" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/188VxGLFQF56eO5o7bOwiC" + }, + "href": "https://api.spotify.com/v1/tracks/188VxGLFQF56eO5o7bOwiC", + "id": "188VxGLFQF56eO5o7bOwiC", + "is_local": false, + "name": "Decay", + "popularity": 41, + "preview_url": "https://p.scdn.co/mp3-preview/31583f3a1cd741c648454c6b013b2e4d4abfaa49?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:188VxGLFQF56eO5o7bOwiC" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3y43zXffnLmhyQD1K4QCmD" + }, + "href": "https://api.spotify.com/v1/artists/3y43zXffnLmhyQD1K4QCmD", + "id": "3y43zXffnLmhyQD1K4QCmD", + "name": "Acres", + "type": "artist", + "uri": "spotify:artist:3y43zXffnLmhyQD1K4QCmD" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4SvwujGdVPbHhAR3DIQCc4" + }, + "href": "https://api.spotify.com/v1/albums/4SvwujGdVPbHhAR3DIQCc4", + "id": "4SvwujGdVPbHhAR3DIQCc4", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273eb1cb37efd5c166d24d31819", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02eb1cb37efd5c166d24d31819", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851eb1cb37efd5c166d24d31819", + "width": 64 + }], + "is_playable": true, + "name": "Burning Throne", + "release_date": "2023-03-03", + "release_date_precision": "day", + "total_tracks": 10, + "type": "album", + "uri": "spotify:album:4SvwujGdVPbHhAR3DIQCc4" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3y43zXffnLmhyQD1K4QCmD" + }, + "href": "https://api.spotify.com/v1/artists/3y43zXffnLmhyQD1K4QCmD", + "id": "3y43zXffnLmhyQD1K4QCmD", + "name": "Acres", + "type": "artist", + "uri": "spotify:artist:3y43zXffnLmhyQD1K4QCmD" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 233076, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "GBAJC2200106" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1Zsy3xy9TvYELEGg1js4yw" + }, + "href": "https://api.spotify.com/v1/tracks/1Zsy3xy9TvYELEGg1js4yw", + "id": "1Zsy3xy9TvYELEGg1js4yw", + "is_local": false, + "name": "My Everything", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/330045fb3097c94940b3c29afcd080297db835ea?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 6, + "type": "track", + "uri": "spotify:track:1Zsy3xy9TvYELEGg1js4yw" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7x3hXpGkI296eBLTbhbND0" + }, + "href": "https://api.spotify.com/v1/artists/7x3hXpGkI296eBLTbhbND0", + "id": "7x3hXpGkI296eBLTbhbND0", + "name": "Oceans", + "type": "artist", + "uri": "spotify:artist:7x3hXpGkI296eBLTbhbND0" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/7lt5GA2p1R951h7cg6IycG" + }, + "href": "https://api.spotify.com/v1/albums/7lt5GA2p1R951h7cg6IycG", + "id": "7lt5GA2p1R951h7cg6IycG", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2734803666bf99b67925c9de368", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e024803666bf99b67925c9de368", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048514803666bf99b67925c9de368", + "width": 64 + }], + "is_playable": true, + "name": "Hell Is Where The Heart Is, Pt. III: Clarity", + "release_date": "2022-11-25", + "release_date_precision": "day", + "total_tracks": 4, + "type": "album", + "uri": "spotify:album:7lt5GA2p1R951h7cg6IycG" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7x3hXpGkI296eBLTbhbND0" + }, + "href": "https://api.spotify.com/v1/artists/7x3hXpGkI296eBLTbhbND0", + "id": "7x3hXpGkI296eBLTbhbND0", + "name": "Oceans", + "type": "artist", + "uri": "spotify:artist:7x3hXpGkI296eBLTbhbND0" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 233533, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "DED832100721" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4jZFmBhYpwwiWjuEYmlEYq" + }, + "href": "https://api.spotify.com/v1/tracks/4jZFmBhYpwwiWjuEYmlEYq", + "id": "4jZFmBhYpwwiWjuEYmlEYq", + "is_local": false, + "name": "Hell Is Where The Heart Is", + "popularity": 41, + "preview_url": "https://p.scdn.co/mp3-preview/0cb3c591c4994aa6c286e5391ecd8291302e05fc?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 4, + "type": "track", + "uri": "spotify:track:4jZFmBhYpwwiWjuEYmlEYq" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/42VxcSRld3QR7Rmv7m97RW" + }, + "href": "https://api.spotify.com/v1/artists/42VxcSRld3QR7Rmv7m97RW", + "id": "42VxcSRld3QR7Rmv7m97RW", + "name": "The Worst of Us", + "type": "artist", + "uri": "spotify:artist:42VxcSRld3QR7Rmv7m97RW" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/65sChHf6etCvSFdXn8NPUO" + }, + "href": "https://api.spotify.com/v1/artists/65sChHf6etCvSFdXn8NPUO", + "id": "65sChHf6etCvSFdXn8NPUO", + "name": "ALEX", + "type": "artist", + "uri": "spotify:artist:65sChHf6etCvSFdXn8NPUO" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/3kwoPkICT4iPkNjr6mL13N" + }, + "href": "https://api.spotify.com/v1/artists/3kwoPkICT4iPkNjr6mL13N", + "id": "3kwoPkICT4iPkNjr6mL13N", + "name": "TOKYO ROSE", + "type": "artist", + "uri": "spotify:artist:3kwoPkICT4iPkNjr6mL13N" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/1Y1gza8GXGUTuwYgZK0EWb" + }, + "href": "https://api.spotify.com/v1/albums/1Y1gza8GXGUTuwYgZK0EWb", + "id": "1Y1gza8GXGUTuwYgZK0EWb", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273e2da27d03552f5984e6a6946", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02e2da27d03552f5984e6a6946", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851e2da27d03552f5984e6a6946", + "width": 64 + }], + "is_playable": true, + "name": "ANTAGONIST RETURNS", + "release_date": "2023-03-03", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:1Y1gza8GXGUTuwYgZK0EWb" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/42VxcSRld3QR7Rmv7m97RW" + }, + "href": "https://api.spotify.com/v1/artists/42VxcSRld3QR7Rmv7m97RW", + "id": "42VxcSRld3QR7Rmv7m97RW", + "name": "The Worst of Us", + "type": "artist", + "uri": "spotify:artist:42VxcSRld3QR7Rmv7m97RW" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/65sChHf6etCvSFdXn8NPUO" + }, + "href": "https://api.spotify.com/v1/artists/65sChHf6etCvSFdXn8NPUO", + "id": "65sChHf6etCvSFdXn8NPUO", + "name": "ALEX", + "type": "artist", + "uri": "spotify:artist:65sChHf6etCvSFdXn8NPUO" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/3kwoPkICT4iPkNjr6mL13N" + }, + "href": "https://api.spotify.com/v1/artists/3kwoPkICT4iPkNjr6mL13N", + "id": "3kwoPkICT4iPkNjr6mL13N", + "name": "TOKYO ROSE", + "type": "artist", + "uri": "spotify:artist:3kwoPkICT4iPkNjr6mL13N" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/20kxwZ3KtZExRwq4s9IXZW" + }, + "href": "https://api.spotify.com/v1/artists/20kxwZ3KtZExRwq4s9IXZW", + "id": "20kxwZ3KtZExRwq4s9IXZW", + "name": "THE AKUMA", + "type": "artist", + "uri": "spotify:artist:20kxwZ3KtZExRwq4s9IXZW" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 217308, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QZFZ62305866" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2tCwpWtQsAFGafn1tZCcfm" + }, + "href": "https://api.spotify.com/v1/tracks/2tCwpWtQsAFGafn1tZCcfm", + "id": "2tCwpWtQsAFGafn1tZCcfm", + "is_local": false, + "name": "ANTAGONIST RETURNS", + "popularity": 42, + "preview_url": "https://p.scdn.co/mp3-preview/794322bc67055ed3281db82fc66d955d1a5075bd?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2tCwpWtQsAFGafn1tZCcfm" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0DJJrg8eUagEWZXFgwKJfM" + }, + "href": "https://api.spotify.com/v1/artists/0DJJrg8eUagEWZXFgwKJfM", + "id": "0DJJrg8eUagEWZXFgwKJfM", + "name": "ENMY", + "type": "artist", + "uri": "spotify:artist:0DJJrg8eUagEWZXFgwKJfM" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/09CZXfat40xo0FMgh9bGc9" + }, + "href": "https://api.spotify.com/v1/albums/09CZXfat40xo0FMgh9bGc9", + "id": "09CZXfat40xo0FMgh9bGc9", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273d219e83dc5e6cc4b7b375189", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02d219e83dc5e6cc4b7b375189", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851d219e83dc5e6cc4b7b375189", + "width": 64 + }], + "is_playable": true, + "name": "Survive", + "release_date": "2022-12-15", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:09CZXfat40xo0FMgh9bGc9" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0DJJrg8eUagEWZXFgwKJfM" + }, + "href": "https://api.spotify.com/v1/artists/0DJJrg8eUagEWZXFgwKJfM", + "id": "0DJJrg8eUagEWZXFgwKJfM", + "name": "ENMY", + "type": "artist", + "uri": "spotify:artist:0DJJrg8eUagEWZXFgwKJfM" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 171486, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QMDA72263058" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/10sNQBSpWrUV1jcyafuw0x" + }, + "href": "https://api.spotify.com/v1/tracks/10sNQBSpWrUV1jcyafuw0x", + "id": "10sNQBSpWrUV1jcyafuw0x", + "is_local": false, + "name": "Survive", + "popularity": 47, + "preview_url": "https://p.scdn.co/mp3-preview/c6d073df09347188621069cca61205923c65a170?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:10sNQBSpWrUV1jcyafuw0x" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6f0FWL5v2c3a5shWKRuiwq" + }, + "href": "https://api.spotify.com/v1/artists/6f0FWL5v2c3a5shWKRuiwq", + "id": "6f0FWL5v2c3a5shWKRuiwq", + "name": "Samurai Pizza Cats", + "type": "artist", + "uri": "spotify:artist:6f0FWL5v2c3a5shWKRuiwq" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/02UmgKnxslxUbrVpHhF9bb" + }, + "href": "https://api.spotify.com/v1/artists/02UmgKnxslxUbrVpHhF9bb", + "id": "02UmgKnxslxUbrVpHhF9bb", + "name": "Nico Sallach", + "type": "artist", + "uri": "spotify:artist:02UmgKnxslxUbrVpHhF9bb" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4NTGoJrPUvdgihClkErxoM" + }, + "href": "https://api.spotify.com/v1/albums/4NTGoJrPUvdgihClkErxoM", + "id": "4NTGoJrPUvdgihClkErxoM", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273832dfd8f652036285cc48d0d", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02832dfd8f652036285cc48d0d", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851832dfd8f652036285cc48d0d", + "width": 64 + }], + "is_playable": true, + "name": "Pizza Homicide", + "release_date": "2023-03-03", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:4NTGoJrPUvdgihClkErxoM" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6f0FWL5v2c3a5shWKRuiwq" + }, + "href": "https://api.spotify.com/v1/artists/6f0FWL5v2c3a5shWKRuiwq", + "id": "6f0FWL5v2c3a5shWKRuiwq", + "name": "Samurai Pizza Cats", + "type": "artist", + "uri": "spotify:artist:6f0FWL5v2c3a5shWKRuiwq" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/02UmgKnxslxUbrVpHhF9bb" + }, + "href": "https://api.spotify.com/v1/artists/02UmgKnxslxUbrVpHhF9bb", + "id": "02UmgKnxslxUbrVpHhF9bb", + "name": "Nico Sallach", + "type": "artist", + "uri": "spotify:artist:02UmgKnxslxUbrVpHhF9bb" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/1WNoKxsp715jez1Td4vthc" + }, + "href": "https://api.spotify.com/v1/artists/1WNoKxsp715jez1Td4vthc", + "id": "1WNoKxsp715jez1Td4vthc", + "name": "Electric Callboy", + "type": "artist", + "uri": "spotify:artist:1WNoKxsp715jez1Td4vthc" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 180947, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QM4TW2362536" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/7vqgYX29LWz74BlsaW9bub" + }, + "href": "https://api.spotify.com/v1/tracks/7vqgYX29LWz74BlsaW9bub", + "id": "7vqgYX29LWz74BlsaW9bub", + "is_local": false, + "name": "Pizza Homicide", + "popularity": 53, + "preview_url": "https://p.scdn.co/mp3-preview/aef916adc1468638dea70e84b60dcfb03b9296f5?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:7vqgYX29LWz74BlsaW9bub" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6koaWXkOOBCzZDCd9GaHsj" + }, + "href": "https://api.spotify.com/v1/artists/6koaWXkOOBCzZDCd9GaHsj", + "id": "6koaWXkOOBCzZDCd9GaHsj", + "name": "Acacia Ridge", + "type": "artist", + "uri": "spotify:artist:6koaWXkOOBCzZDCd9GaHsj" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/22ZNSrE7hmUqmoXtR4uhIl" + }, + "href": "https://api.spotify.com/v1/albums/22ZNSrE7hmUqmoXtR4uhIl", + "id": "22ZNSrE7hmUqmoXtR4uhIl", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273eb80a59e19b306cd5d941938", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02eb80a59e19b306cd5d941938", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851eb80a59e19b306cd5d941938", + "width": 64 + }], + "is_playable": true, + "name": "Hivemind", + "release_date": "2023-02-09", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:22ZNSrE7hmUqmoXtR4uhIl" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6koaWXkOOBCzZDCd9GaHsj" + }, + "href": "https://api.spotify.com/v1/artists/6koaWXkOOBCzZDCd9GaHsj", + "id": "6koaWXkOOBCzZDCd9GaHsj", + "name": "Acacia Ridge", + "type": "artist", + "uri": "spotify:artist:6koaWXkOOBCzZDCd9GaHsj" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 247896, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZFYY2365877" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/7lRciDLcZY0MKaMyakkvu0" + }, + "href": "https://api.spotify.com/v1/tracks/7lRciDLcZY0MKaMyakkvu0", + "id": "7lRciDLcZY0MKaMyakkvu0", + "is_local": false, + "name": "Hivemind", + "popularity": 39, + "preview_url": "https://p.scdn.co/mp3-preview/0f575648a5483a9fafd60531ab8e594b0abbd08a?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:7lRciDLcZY0MKaMyakkvu0" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/70Xhx9yjoKm0t3VmTYkrPp" + }, + "href": "https://api.spotify.com/v1/artists/70Xhx9yjoKm0t3VmTYkrPp", + "id": "70Xhx9yjoKm0t3VmTYkrPp", + "name": "Maelføy", + "type": "artist", + "uri": "spotify:artist:70Xhx9yjoKm0t3VmTYkrPp" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/0TWnG9BOpdFeMZAKTWFVUT" + }, + "href": "https://api.spotify.com/v1/albums/0TWnG9BOpdFeMZAKTWFVUT", + "id": "0TWnG9BOpdFeMZAKTWFVUT", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273f3283ab2f9c9adc5a409c40c", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02f3283ab2f9c9adc5a409c40c", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851f3283ab2f9c9adc5a409c40c", + "width": 64 + }], + "is_playable": true, + "name": "away", + "release_date": "2022-12-16", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:0TWnG9BOpdFeMZAKTWFVUT" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/70Xhx9yjoKm0t3VmTYkrPp" + }, + "href": "https://api.spotify.com/v1/artists/70Xhx9yjoKm0t3VmTYkrPp", + "id": "70Xhx9yjoKm0t3VmTYkrPp", + "name": "Maelføy", + "type": "artist", + "uri": "spotify:artist:70Xhx9yjoKm0t3VmTYkrPp" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 262486, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "DGA052249011" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4rNn6vx1vmzJfr894A5bM7" + }, + "href": "https://api.spotify.com/v1/tracks/4rNn6vx1vmzJfr894A5bM7", + "id": "4rNn6vx1vmzJfr894A5bM7", + "is_local": false, + "name": "away", + "popularity": 41, + "preview_url": "https://p.scdn.co/mp3-preview/fd9b898979b68999baa18e0724bba72eaf2d7570?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:4rNn6vx1vmzJfr894A5bM7" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6BD4lgmnh4vy6kkCaZRDWt" + }, + "href": "https://api.spotify.com/v1/artists/6BD4lgmnh4vy6kkCaZRDWt", + "id": "6BD4lgmnh4vy6kkCaZRDWt", + "name": "Bury Tomorrow", + "type": "artist", + "uri": "spotify:artist:6BD4lgmnh4vy6kkCaZRDWt" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4GuxQZOki4NdCKpn9kW9xn" + }, + "href": "https://api.spotify.com/v1/albums/4GuxQZOki4NdCKpn9kW9xn", + "id": "4GuxQZOki4NdCKpn9kW9xn", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273dc9d9ce634f2abc1ec3298e7", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02dc9d9ce634f2abc1ec3298e7", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851dc9d9ce634f2abc1ec3298e7", + "width": 64 + }], + "is_playable": true, + "name": "Heretic (feat. Loz Taylor)", + "release_date": "2023-02-15", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:4GuxQZOki4NdCKpn9kW9xn" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6BD4lgmnh4vy6kkCaZRDWt" + }, + "href": "https://api.spotify.com/v1/artists/6BD4lgmnh4vy6kkCaZRDWt", + "id": "6BD4lgmnh4vy6kkCaZRDWt", + "name": "Bury Tomorrow", + "type": "artist", + "uri": "spotify:artist:6BD4lgmnh4vy6kkCaZRDWt" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 212878, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "GBCKC2200025" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2mTi7e03FygOF0bds32848" + }, + "href": "https://api.spotify.com/v1/tracks/2mTi7e03FygOF0bds32848", + "id": "2mTi7e03FygOF0bds32848", + "is_local": false, + "name": "Heretic (feat. Loz Taylor)", + "popularity": 56, + "preview_url": "https://p.scdn.co/mp3-preview/06eb0cf0b95091b09a2237ebfc0e85f6b9ab2d8e?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2mTi7e03FygOF0bds32848" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4tususHNaR68xdgLstlGBA" + }, + "href": "https://api.spotify.com/v1/artists/4tususHNaR68xdgLstlGBA", + "id": "4tususHNaR68xdgLstlGBA", + "name": "Of Mice & Men", + "type": "artist", + "uri": "spotify:artist:4tususHNaR68xdgLstlGBA" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/2Gy8PtzODbaenwA7aCI6UG" + }, + "href": "https://api.spotify.com/v1/albums/2Gy8PtzODbaenwA7aCI6UG", + "id": "2Gy8PtzODbaenwA7aCI6UG", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273a58a6c9723a595e05f9d42e3", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02a58a6c9723a595e05f9d42e3", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851a58a6c9723a595e05f9d42e3", + "width": 64 + }], + "is_playable": true, + "name": "Echo (Deluxe Version)", + "release_date": "2022-12-09", + "release_date_precision": "day", + "total_tracks": 20, + "type": "album", + "uri": "spotify:album:2Gy8PtzODbaenwA7aCI6UG" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4tususHNaR68xdgLstlGBA" + }, + "href": "https://api.spotify.com/v1/artists/4tususHNaR68xdgLstlGBA", + "id": "4tususHNaR68xdgLstlGBA", + "name": "Of Mice & Men", + "type": "artist", + "uri": "spotify:artist:4tususHNaR68xdgLstlGBA" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/1CXuuw8HJhyN80HlNzvL1e" + }, + "href": "https://api.spotify.com/v1/artists/1CXuuw8HJhyN80HlNzvL1e", + "id": "1CXuuw8HJhyN80HlNzvL1e", + "name": "Sullivan King", + "type": "artist", + "uri": "spotify:artist:1CXuuw8HJhyN80HlNzvL1e" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 185039, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DED832200466" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/7MUPbvNwlgqY1Sboxe9jJD" + }, + "href": "https://api.spotify.com/v1/tracks/7MUPbvNwlgqY1Sboxe9jJD", + "id": "7MUPbvNwlgqY1Sboxe9jJD", + "is_local": false, + "name": "Obsolete - Sullivan King Remix", + "popularity": 53, + "preview_url": "https://p.scdn.co/mp3-preview/a8ae50d4ca6ab030060e2594b07f5d11d090c3c2?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 12, + "type": "track", + "uri": "spotify:track:7MUPbvNwlgqY1Sboxe9jJD" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/5Vp7LqcfAtx2U1RfIX8i7r" + }, + "href": "https://api.spotify.com/v1/artists/5Vp7LqcfAtx2U1RfIX8i7r", + "id": "5Vp7LqcfAtx2U1RfIX8i7r", + "name": "Point North", + "type": "artist", + "uri": "spotify:artist:5Vp7LqcfAtx2U1RfIX8i7r" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/6kQB2RN7WwryMdJ1MoQh1E" + }, + "href": "https://api.spotify.com/v1/artists/6kQB2RN7WwryMdJ1MoQh1E", + "id": "6kQB2RN7WwryMdJ1MoQh1E", + "name": "The Ghost Inside", + "type": "artist", + "uri": "spotify:artist:6kQB2RN7WwryMdJ1MoQh1E" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3QUEnfQoenkZIyLZDMSegH" + }, + "href": "https://api.spotify.com/v1/albums/3QUEnfQoenkZIyLZDMSegH", + "id": "3QUEnfQoenkZIyLZDMSegH", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27302e76460590f7379afd089cb", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0202e76460590f7379afd089cb", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485102e76460590f7379afd089cb", + "width": 64 + }], + "is_playable": true, + "name": "Safe And Sound", + "release_date": "2023-02-24", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:3QUEnfQoenkZIyLZDMSegH" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/5Vp7LqcfAtx2U1RfIX8i7r" + }, + "href": "https://api.spotify.com/v1/artists/5Vp7LqcfAtx2U1RfIX8i7r", + "id": "5Vp7LqcfAtx2U1RfIX8i7r", + "name": "Point North", + "type": "artist", + "uri": "spotify:artist:5Vp7LqcfAtx2U1RfIX8i7r" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/6kQB2RN7WwryMdJ1MoQh1E" + }, + "href": "https://api.spotify.com/v1/artists/6kQB2RN7WwryMdJ1MoQh1E", + "id": "6kQB2RN7WwryMdJ1MoQh1E", + "name": "The Ghost Inside", + "type": "artist", + "uri": "spotify:artist:6kQB2RN7WwryMdJ1MoQh1E" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 201402, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "USHR22312901" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1LtXoOrqBYS8kcheVUt5Pr" + }, + "href": "https://api.spotify.com/v1/tracks/1LtXoOrqBYS8kcheVUt5Pr", + "id": "1LtXoOrqBYS8kcheVUt5Pr", + "is_local": false, + "name": "Safe And Sound", + "popularity": 58, + "preview_url": "https://p.scdn.co/mp3-preview/ba04d6efdced2e29119a9834316c4406d4fdc7b6?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:1LtXoOrqBYS8kcheVUt5Pr" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/28XopU8Uw6D6Wl7rIgCVNE" + }, + "href": "https://api.spotify.com/v1/artists/28XopU8Uw6D6Wl7rIgCVNE", + "id": "28XopU8Uw6D6Wl7rIgCVNE", + "name": "Villain of the Story", + "type": "artist", + "uri": "spotify:artist:28XopU8Uw6D6Wl7rIgCVNE" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6h7gZv6v0tqGC6Q54v6VY1" + }, + "href": "https://api.spotify.com/v1/albums/6h7gZv6v0tqGC6Q54v6VY1", + "id": "6h7gZv6v0tqGC6Q54v6VY1", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273fd1a52f325d70b0f3203a71f", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02fd1a52f325d70b0f3203a71f", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851fd1a52f325d70b0f3203a71f", + "width": 64 + }], + "is_playable": true, + "name": "No More Sorrow", + "release_date": "2023-01-18", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:6h7gZv6v0tqGC6Q54v6VY1" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/28XopU8Uw6D6Wl7rIgCVNE" + }, + "href": "https://api.spotify.com/v1/artists/28XopU8Uw6D6Wl7rIgCVNE", + "id": "28XopU8Uw6D6Wl7rIgCVNE", + "name": "Villain of the Story", + "type": "artist", + "uri": "spotify:artist:28XopU8Uw6D6Wl7rIgCVNE" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 225095, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEBZ72200363" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2yInTIIIQQ1sYLJIFefzff" + }, + "href": "https://api.spotify.com/v1/tracks/2yInTIIIQQ1sYLJIFefzff", + "id": "2yInTIIIQQ1sYLJIFefzff", + "is_local": false, + "name": "No More Sorrow", + "popularity": 46, + "preview_url": "https://p.scdn.co/mp3-preview/077a4a54afdaa92f357ac5bacada85721da4e6e5?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2yInTIIIQQ1sYLJIFefzff" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3ALVPmg5sZexSVD2m9atEt" + }, + "href": "https://api.spotify.com/v1/artists/3ALVPmg5sZexSVD2m9atEt", + "id": "3ALVPmg5sZexSVD2m9atEt", + "name": "Invent Animate", + "type": "artist", + "uri": "spotify:artist:3ALVPmg5sZexSVD2m9atEt" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/0DumP1DzkNR7b0uIASVDcy" + }, + "href": "https://api.spotify.com/v1/albums/0DumP1DzkNR7b0uIASVDcy", + "id": "0DumP1DzkNR7b0uIASVDcy", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2732a683d3bd167b95bc28cd318", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e022a683d3bd167b95bc28cd318", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048512a683d3bd167b95bc28cd318", + "width": 64 + }], + "is_playable": true, + "name": "Immolation of Night", + "release_date": "2023-02-02", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:0DumP1DzkNR7b0uIASVDcy" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3ALVPmg5sZexSVD2m9atEt" + }, + "href": "https://api.spotify.com/v1/artists/3ALVPmg5sZexSVD2m9atEt", + "id": "3ALVPmg5sZexSVD2m9atEt", + "name": "Invent Animate", + "type": "artist", + "uri": "spotify:artist:3ALVPmg5sZexSVD2m9atEt" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 230400, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "AUI442200164" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/3OOeWlT6cQYNbdJ4qcBipL" + }, + "href": "https://api.spotify.com/v1/tracks/3OOeWlT6cQYNbdJ4qcBipL", + "id": "3OOeWlT6cQYNbdJ4qcBipL", + "is_local": false, + "name": "Immolation of Night", + "popularity": 53, + "preview_url": "https://p.scdn.co/mp3-preview/cc596a9a8402cb06c243fff12275b5c29aed4727?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:3OOeWlT6cQYNbdJ4qcBipL" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1U58LFQaBX4bS0GIiF0dBn" + }, + "href": "https://api.spotify.com/v1/artists/1U58LFQaBX4bS0GIiF0dBn", + "id": "1U58LFQaBX4bS0GIiF0dBn", + "name": "Destroy//Create", + "type": "artist", + "uri": "spotify:artist:1U58LFQaBX4bS0GIiF0dBn" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/60z2i9Azhj1TRXY43VdSAE" + }, + "href": "https://api.spotify.com/v1/albums/60z2i9Azhj1TRXY43VdSAE", + "id": "60z2i9Azhj1TRXY43VdSAE", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273efbedddb78ce8647c94433b9", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02efbedddb78ce8647c94433b9", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851efbedddb78ce8647c94433b9", + "width": 64 + }], + "is_playable": true, + "name": "Your Ghost…(été un)", + "release_date": "2023-01-06", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:60z2i9Azhj1TRXY43VdSAE" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1U58LFQaBX4bS0GIiF0dBn" + }, + "href": "https://api.spotify.com/v1/artists/1U58LFQaBX4bS0GIiF0dBn", + "id": "1U58LFQaBX4bS0GIiF0dBn", + "name": "Destroy//Create", + "type": "artist", + "uri": "spotify:artist:1U58LFQaBX4bS0GIiF0dBn" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 237277, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "FRX762271302" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/67apRpuDfI6vMtl6ZNVbFJ" + }, + "href": "https://api.spotify.com/v1/tracks/67apRpuDfI6vMtl6ZNVbFJ", + "id": "67apRpuDfI6vMtl6ZNVbFJ", + "is_local": false, + "name": "Your Ghost…(été un)", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/563733bd40ac1a715a14f78c39e6d70b075e6368?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:67apRpuDfI6vMtl6ZNVbFJ" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4fnono0JCZFAeeaecrI7kg" + }, + "href": "https://api.spotify.com/v1/artists/4fnono0JCZFAeeaecrI7kg", + "id": "4fnono0JCZFAeeaecrI7kg", + "name": "Solence", + "type": "artist", + "uri": "spotify:artist:4fnono0JCZFAeeaecrI7kg" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/5lq3RYK2UtsoM0KWq0dDNk" + }, + "href": "https://api.spotify.com/v1/albums/5lq3RYK2UtsoM0KWq0dDNk", + "id": "5lq3RYK2UtsoM0KWq0dDNk", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273e57f0ad646af399eef39f942", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02e57f0ad646af399eef39f942", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851e57f0ad646af399eef39f942", + "width": 64 + }], + "is_playable": true, + "name": "Hope is a Cult", + "release_date": "2023-02-17", + "release_date_precision": "day", + "total_tracks": 13, + "type": "album", + "uri": "spotify:album:5lq3RYK2UtsoM0KWq0dDNk" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4fnono0JCZFAeeaecrI7kg" + }, + "href": "https://api.spotify.com/v1/artists/4fnono0JCZFAeeaecrI7kg", + "id": "4fnono0JCZFAeeaecrI7kg", + "name": "Solence", + "type": "artist", + "uri": "spotify:artist:4fnono0JCZFAeeaecrI7kg" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 221347, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "USHR22215702" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0Fa9nx13nJ7CiZLRM3in1S" + }, + "href": "https://api.spotify.com/v1/tracks/0Fa9nx13nJ7CiZLRM3in1S", + "id": "0Fa9nx13nJ7CiZLRM3in1S", + "is_local": false, + "name": "Best For You", + "popularity": 52, + "preview_url": "https://p.scdn.co/mp3-preview/8109003be715b44df8cc41cd93f9af2838fc514f?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 2, + "type": "track", + "uri": "spotify:track:0Fa9nx13nJ7CiZLRM3in1S" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2o6toWFM0eynwdOjVJfoSQ" + }, + "href": "https://api.spotify.com/v1/artists/2o6toWFM0eynwdOjVJfoSQ", + "id": "2o6toWFM0eynwdOjVJfoSQ", + "name": "alt.", + "type": "artist", + "uri": "spotify:artist:2o6toWFM0eynwdOjVJfoSQ" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/76psVqthi8ZmsWCHBwDJxd" + }, + "href": "https://api.spotify.com/v1/albums/76psVqthi8ZmsWCHBwDJxd", + "id": "76psVqthi8ZmsWCHBwDJxd", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2737ed58cae6b825c2d16269065", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e027ed58cae6b825c2d16269065", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048517ed58cae6b825c2d16269065", + "width": 64 + }], + "is_playable": true, + "name": "THE GREAT DEPRESSION", + "release_date": "2023-02-09", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:76psVqthi8ZmsWCHBwDJxd" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2o6toWFM0eynwdOjVJfoSQ" + }, + "href": "https://api.spotify.com/v1/artists/2o6toWFM0eynwdOjVJfoSQ", + "id": "2o6toWFM0eynwdOjVJfoSQ", + "name": "alt.", + "type": "artist", + "uri": "spotify:artist:2o6toWFM0eynwdOjVJfoSQ" + }], + "available_markets": ["AR", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 187428, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "AUUF12301364" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4XLAtJLVLFvSUXRZFc0dqr" + }, + "href": "https://api.spotify.com/v1/tracks/4XLAtJLVLFvSUXRZFc0dqr", + "id": "4XLAtJLVLFvSUXRZFc0dqr", + "is_local": false, + "name": "THE GREAT DEPRESSION", + "popularity": 39, + "preview_url": "https://p.scdn.co/mp3-preview/af35d74354454f5e5335b6b214932fd381139c22?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:4XLAtJLVLFvSUXRZFc0dqr" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1S4xN9nvW5vlFoRBisdxUL" + }, + "href": "https://api.spotify.com/v1/artists/1S4xN9nvW5vlFoRBisdxUL", + "id": "1S4xN9nvW5vlFoRBisdxUL", + "name": "Halocene", + "type": "artist", + "uri": "spotify:artist:1S4xN9nvW5vlFoRBisdxUL" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/1g3ByU8bZ8KclMW1mLVwxz" + }, + "href": "https://api.spotify.com/v1/albums/1g3ByU8bZ8KclMW1mLVwxz", + "id": "1g3ByU8bZ8KclMW1mLVwxz", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273ba34a6672f918c5b71463f1b", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02ba34a6672f918c5b71463f1b", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851ba34a6672f918c5b71463f1b", + "width": 64 + }], + "is_playable": true, + "name": "Hold Me, Help Me", + "release_date": "2022-11-04", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:1g3ByU8bZ8KclMW1mLVwxz" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1S4xN9nvW5vlFoRBisdxUL" + }, + "href": "https://api.spotify.com/v1/artists/1S4xN9nvW5vlFoRBisdxUL", + "id": "1S4xN9nvW5vlFoRBisdxUL", + "name": "Halocene", + "type": "artist", + "uri": "spotify:artist:1S4xN9nvW5vlFoRBisdxUL" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 225418, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QZPJ32206985" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5PonHqoB85p240oUT9AIDj" + }, + "href": "https://api.spotify.com/v1/tracks/5PonHqoB85p240oUT9AIDj", + "id": "5PonHqoB85p240oUT9AIDj", + "is_local": false, + "name": "Hold Me, Help Me", + "popularity": 45, + "preview_url": "https://p.scdn.co/mp3-preview/30e1ec7a1b841cacadde065d5afc9b9bd4a93b22?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:5PonHqoB85p240oUT9AIDj" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/12A5ksM0yYvX6ULrJmIvQN" + }, + "href": "https://api.spotify.com/v1/artists/12A5ksM0yYvX6ULrJmIvQN", + "id": "12A5ksM0yYvX6ULrJmIvQN", + "name": "As The Structure Fails", + "type": "artist", + "uri": "spotify:artist:12A5ksM0yYvX6ULrJmIvQN" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/78jDD0o4blFWZTpo9tHWoh" + }, + "href": "https://api.spotify.com/v1/albums/78jDD0o4blFWZTpo9tHWoh", + "id": "78jDD0o4blFWZTpo9tHWoh", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27375ca687a788267a62e26c874", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0275ca687a788267a62e26c874", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485175ca687a788267a62e26c874", + "width": 64 + }], + "is_playable": true, + "name": "Talk to Me", + "release_date": "2023-01-20", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:78jDD0o4blFWZTpo9tHWoh" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/12A5ksM0yYvX6ULrJmIvQN" + }, + "href": "https://api.spotify.com/v1/artists/12A5ksM0yYvX6ULrJmIvQN", + "id": "12A5ksM0yYvX6ULrJmIvQN", + "name": "As The Structure Fails", + "type": "artist", + "uri": "spotify:artist:12A5ksM0yYvX6ULrJmIvQN" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 196500, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "TCAGR2226469" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4QOuEQBmCJJJhYTkrE5Zy2" + }, + "href": "https://api.spotify.com/v1/tracks/4QOuEQBmCJJJhYTkrE5Zy2", + "id": "4QOuEQBmCJJJhYTkrE5Zy2", + "is_local": false, + "name": "Talk to Me", + "popularity": 41, + "preview_url": "https://p.scdn.co/mp3-preview/f9c56f5c5817ca3214e0f1e04f7f192cceadee81?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:4QOuEQBmCJJJhYTkrE5Zy2" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/12qp69G4vHfQcJUbjONDY1" + }, + "href": "https://api.spotify.com/v1/artists/12qp69G4vHfQcJUbjONDY1", + "id": "12qp69G4vHfQcJUbjONDY1", + "name": "After Hour Animals", + "type": "artist", + "uri": "spotify:artist:12qp69G4vHfQcJUbjONDY1" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4PpW6GVABbHkRxGHnCU0za" + }, + "href": "https://api.spotify.com/v1/albums/4PpW6GVABbHkRxGHnCU0za", + "id": "4PpW6GVABbHkRxGHnCU0za", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273226cf1263f126665a1d7012b", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02226cf1263f126665a1d7012b", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851226cf1263f126665a1d7012b", + "width": 64 + }], + "is_playable": true, + "name": "Dangerous", + "release_date": "2022-12-16", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:4PpW6GVABbHkRxGHnCU0za" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/12qp69G4vHfQcJUbjONDY1" + }, + "href": "https://api.spotify.com/v1/artists/12qp69G4vHfQcJUbjONDY1", + "id": "12qp69G4vHfQcJUbjONDY1", + "name": "After Hour Animals", + "type": "artist", + "uri": "spotify:artist:12qp69G4vHfQcJUbjONDY1" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 198206, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QZTB52203152" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/3E0kmaCVPaxw4D55Nt2cen" + }, + "href": "https://api.spotify.com/v1/tracks/3E0kmaCVPaxw4D55Nt2cen", + "id": "3E0kmaCVPaxw4D55Nt2cen", + "is_local": false, + "name": "Dangerous", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/8487aef9e3ef88495940c90c215b2bddad7c282d?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:3E0kmaCVPaxw4D55Nt2cen" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2WQQRKpu2PMLsHSrUJmyCS" + }, + "href": "https://api.spotify.com/v1/artists/2WQQRKpu2PMLsHSrUJmyCS", + "id": "2WQQRKpu2PMLsHSrUJmyCS", + "name": "The Veer Union", + "type": "artist", + "uri": "spotify:artist:2WQQRKpu2PMLsHSrUJmyCS" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/2N96LsbA1SO5Q6BpjIuY9O" + }, + "href": "https://api.spotify.com/v1/albums/2N96LsbA1SO5Q6BpjIuY9O", + "id": "2N96LsbA1SO5Q6BpjIuY9O", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27363ac5c1e10b35194b226fdf0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0263ac5c1e10b35194b226fdf0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485163ac5c1e10b35194b226fdf0", + "width": 64 + }], + "is_playable": true, + "name": "10:35", + "release_date": "2023-01-20", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:2N96LsbA1SO5Q6BpjIuY9O" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2WQQRKpu2PMLsHSrUJmyCS" + }, + "href": "https://api.spotify.com/v1/artists/2WQQRKpu2PMLsHSrUJmyCS", + "id": "2WQQRKpu2PMLsHSrUJmyCS", + "name": "The Veer Union", + "type": "artist", + "uri": "spotify:artist:2WQQRKpu2PMLsHSrUJmyCS" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 169000, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZSYP2269313" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0F0lT8EmvnKUYZ1YLR6ops" + }, + "href": "https://api.spotify.com/v1/tracks/0F0lT8EmvnKUYZ1YLR6ops", + "id": "0F0lT8EmvnKUYZ1YLR6ops", + "is_local": false, + "name": "10:35", + "popularity": 47, + "preview_url": "https://p.scdn.co/mp3-preview/046ad91b86d4351861baa5c5245ff2e71866e425?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:0F0lT8EmvnKUYZ1YLR6ops" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2x583f2zJEjkiPd6IY4yfW" + }, + "href": "https://api.spotify.com/v1/artists/2x583f2zJEjkiPd6IY4yfW", + "id": "2x583f2zJEjkiPd6IY4yfW", + "name": "The Anchor", + "type": "artist", + "uri": "spotify:artist:2x583f2zJEjkiPd6IY4yfW" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/52ssN73hMqj9cv16Zc0JLp" + }, + "href": "https://api.spotify.com/v1/albums/52ssN73hMqj9cv16Zc0JLp", + "id": "52ssN73hMqj9cv16Zc0JLp", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27312f321dd8902d57dae61ad36", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0212f321dd8902d57dae61ad36", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485112f321dd8902d57dae61ad36", + "width": 64 + }], + "is_playable": true, + "name": "Let Down", + "release_date": "2022-12-16", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:52ssN73hMqj9cv16Zc0JLp" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2x583f2zJEjkiPd6IY4yfW" + }, + "href": "https://api.spotify.com/v1/artists/2x583f2zJEjkiPd6IY4yfW", + "id": "2x583f2zJEjkiPd6IY4yfW", + "name": "The Anchor", + "type": "artist", + "uri": "spotify:artist:2x583f2zJEjkiPd6IY4yfW" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 269777, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZTB22233018" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2JrPhJ74FfygxtRYMXU0Fk" + }, + "href": "https://api.spotify.com/v1/tracks/2JrPhJ74FfygxtRYMXU0Fk", + "id": "2JrPhJ74FfygxtRYMXU0Fk", + "is_local": false, + "name": "Let Down", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/e13d3cbbc220b5ebb86b1d824a4f00d453a0cee4?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2JrPhJ74FfygxtRYMXU0Fk" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/17pjImdVvIja9Es8R436NP" + }, + "href": "https://api.spotify.com/v1/artists/17pjImdVvIja9Es8R436NP", + "id": "17pjImdVvIja9Es8R436NP", + "name": "Foxblood", + "type": "artist", + "uri": "spotify:artist:17pjImdVvIja9Es8R436NP" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/40dWOUbTdbTDHgaRIKc58J" + }, + "href": "https://api.spotify.com/v1/albums/40dWOUbTdbTDHgaRIKc58J", + "id": "40dWOUbTdbTDHgaRIKc58J", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273bb2ac9648d31b0fd6774b3a4", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02bb2ac9648d31b0fd6774b3a4", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851bb2ac9648d31b0fd6774b3a4", + "width": 64 + }], + "is_playable": true, + "name": "Dissociation Vacation", + "release_date": "2022-12-02", + "release_date_precision": "day", + "total_tracks": 7, + "type": "album", + "uri": "spotify:album:40dWOUbTdbTDHgaRIKc58J" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/17pjImdVvIja9Es8R436NP" + }, + "href": "https://api.spotify.com/v1/artists/17pjImdVvIja9Es8R436NP", + "id": "17pjImdVvIja9Es8R436NP", + "name": "Foxblood", + "type": "artist", + "uri": "spotify:artist:17pjImdVvIja9Es8R436NP" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 251330, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "FRX872204825" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5fETISA0KLKcKb8pRHMgqW" + }, + "href": "https://api.spotify.com/v1/tracks/5fETISA0KLKcKb8pRHMgqW", + "id": "5fETISA0KLKcKb8pRHMgqW", + "is_local": false, + "name": "Kingdom Come", + "popularity": 39, + "preview_url": "https://p.scdn.co/mp3-preview/b17be4b07acc8355bb274c87e60a45f09469deb5?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 5, + "type": "track", + "uri": "spotify:track:5fETISA0KLKcKb8pRHMgqW" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1YcOnsBEycC9X5OY6kUzmV" + }, + "href": "https://api.spotify.com/v1/artists/1YcOnsBEycC9X5OY6kUzmV", + "id": "1YcOnsBEycC9X5OY6kUzmV", + "name": "Main-De-Gloire", + "type": "artist", + "uri": "spotify:artist:1YcOnsBEycC9X5OY6kUzmV" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/5K1VQBpd6392NncfwKl6kG" + }, + "href": "https://api.spotify.com/v1/albums/5K1VQBpd6392NncfwKl6kG", + "id": "5K1VQBpd6392NncfwKl6kG", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273f8a4ae3fd59507f9fed01e92", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02f8a4ae3fd59507f9fed01e92", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851f8a4ae3fd59507f9fed01e92", + "width": 64 + }], + "is_playable": true, + "name": "W.A.R", + "release_date": "2023-01-24", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:5K1VQBpd6392NncfwKl6kG" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1YcOnsBEycC9X5OY6kUzmV" + }, + "href": "https://api.spotify.com/v1/artists/1YcOnsBEycC9X5OY6kUzmV", + "id": "1YcOnsBEycC9X5OY6kUzmV", + "name": "Main-De-Gloire", + "type": "artist", + "uri": "spotify:artist:1YcOnsBEycC9X5OY6kUzmV" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 207980, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "TCAGT2367150" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/75ipV1ycKTZuy6CYb6wa0j" + }, + "href": "https://api.spotify.com/v1/tracks/75ipV1ycKTZuy6CYb6wa0j", + "id": "75ipV1ycKTZuy6CYb6wa0j", + "is_local": false, + "name": "W.a.R", + "popularity": 45, + "preview_url": "https://p.scdn.co/mp3-preview/2a3a0d9d5ffc5384c6914a40e028e6209cd90fa6?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:75ipV1ycKTZuy6CYb6wa0j" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2WQQRKpu2PMLsHSrUJmyCS" + }, + "href": "https://api.spotify.com/v1/artists/2WQQRKpu2PMLsHSrUJmyCS", + "id": "2WQQRKpu2PMLsHSrUJmyCS", + "name": "The Veer Union", + "type": "artist", + "uri": "spotify:artist:2WQQRKpu2PMLsHSrUJmyCS" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6nBEVXXXly3MKAgqLz8N8W" + }, + "href": "https://api.spotify.com/v1/albums/6nBEVXXXly3MKAgqLz8N8W", + "id": "6nBEVXXXly3MKAgqLz8N8W", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273352c0026079c3a717fac3c6d", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02352c0026079c3a717fac3c6d", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851352c0026079c3a717fac3c6d", + "width": 64 + }], + "is_playable": true, + "name": "MANIFESTATIONS (DELUXE EDITION)", + "release_date": "2022-12-16", + "release_date_precision": "day", + "total_tracks": 15, + "type": "album", + "uri": "spotify:album:6nBEVXXXly3MKAgqLz8N8W" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2WQQRKpu2PMLsHSrUJmyCS" + }, + "href": "https://api.spotify.com/v1/artists/2WQQRKpu2PMLsHSrUJmyCS", + "id": "2WQQRKpu2PMLsHSrUJmyCS", + "name": "The Veer Union", + "type": "artist", + "uri": "spotify:artist:2WQQRKpu2PMLsHSrUJmyCS" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 180020, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZSYP2298331" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/3lOqKMANmDGUTtTBvCPyKf" + }, + "href": "https://api.spotify.com/v1/tracks/3lOqKMANmDGUTtTBvCPyKf", + "id": "3lOqKMANmDGUTtTBvCPyKf", + "is_local": false, + "name": "In The Light Of Innocence", + "popularity": 42, + "preview_url": "https://p.scdn.co/mp3-preview/319a0e6d9318c5328dfd25ce57b4d8ffd065937c?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 8, + "type": "track", + "uri": "spotify:track:3lOqKMANmDGUTtTBvCPyKf" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/79VoWRyWV2e3rTHm1fb6N0" + }, + "href": "https://api.spotify.com/v1/artists/79VoWRyWV2e3rTHm1fb6N0", + "id": "79VoWRyWV2e3rTHm1fb6N0", + "name": "Morgan Thomaso", + "type": "artist", + "uri": "spotify:artist:79VoWRyWV2e3rTHm1fb6N0" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/2yMgp5XJfvhpTgAg7wZqRF" + }, + "href": "https://api.spotify.com/v1/artists/2yMgp5XJfvhpTgAg7wZqRF", + "id": "2yMgp5XJfvhpTgAg7wZqRF", + "name": "Victor Borba", + "type": "artist", + "uri": "spotify:artist:2yMgp5XJfvhpTgAg7wZqRF" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/6BZE9AyYDPkfejgH7c4DJs" + }, + "href": "https://api.spotify.com/v1/artists/6BZE9AyYDPkfejgH7c4DJs", + "id": "6BZE9AyYDPkfejgH7c4DJs", + "name": "Hugo Bringart", + "type": "artist", + "uri": "spotify:artist:6BZE9AyYDPkfejgH7c4DJs" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4gosCMpbomQ5OGjbnqeiUn" + }, + "href": "https://api.spotify.com/v1/albums/4gosCMpbomQ5OGjbnqeiUn", + "id": "4gosCMpbomQ5OGjbnqeiUn", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2731a830852843fc30cda49f27e", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e021a830852843fc30cda49f27e", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048511a830852843fc30cda49f27e", + "width": 64 + }], + "is_playable": true, + "name": "Majesty", + "release_date": "2022-12-15", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:4gosCMpbomQ5OGjbnqeiUn" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/79VoWRyWV2e3rTHm1fb6N0" + }, + "href": "https://api.spotify.com/v1/artists/79VoWRyWV2e3rTHm1fb6N0", + "id": "79VoWRyWV2e3rTHm1fb6N0", + "name": "Morgan Thomaso", + "type": "artist", + "uri": "spotify:artist:79VoWRyWV2e3rTHm1fb6N0" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/2yMgp5XJfvhpTgAg7wZqRF" + }, + "href": "https://api.spotify.com/v1/artists/2yMgp5XJfvhpTgAg7wZqRF", + "id": "2yMgp5XJfvhpTgAg7wZqRF", + "name": "Victor Borba", + "type": "artist", + "uri": "spotify:artist:2yMgp5XJfvhpTgAg7wZqRF" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/6BZE9AyYDPkfejgH7c4DJs" + }, + "href": "https://api.spotify.com/v1/artists/6BZE9AyYDPkfejgH7c4DJs", + "id": "6BZE9AyYDPkfejgH7c4DJs", + "name": "Hugo Bringart", + "type": "artist", + "uri": "spotify:artist:6BZE9AyYDPkfejgH7c4DJs" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/4UPSjbEaWn0LrLoF4f8ipX" + }, + "href": "https://api.spotify.com/v1/artists/4UPSjbEaWn0LrLoF4f8ipX", + "id": "4UPSjbEaWn0LrLoF4f8ipX", + "name": "Cartoon Theory", + "type": "artist", + "uri": "spotify:artist:4UPSjbEaWn0LrLoF4f8ipX" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 281946, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZTB22248985" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5o9LbFRtoxDRXiJdlPOXSy" + }, + "href": "https://api.spotify.com/v1/tracks/5o9LbFRtoxDRXiJdlPOXSy", + "id": "5o9LbFRtoxDRXiJdlPOXSy", + "is_local": false, + "name": "Majesty", + "popularity": 39, + "preview_url": "https://p.scdn.co/mp3-preview/f0d55f0fdca6673841cde69a7af8fc7d59f73195?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:5o9LbFRtoxDRXiJdlPOXSy" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3kSDOw6bEMSStOjqLR2kVX" + }, + "href": "https://api.spotify.com/v1/artists/3kSDOw6bEMSStOjqLR2kVX", + "id": "3kSDOw6bEMSStOjqLR2kVX", + "name": "Colorblind", + "type": "artist", + "uri": "spotify:artist:3kSDOw6bEMSStOjqLR2kVX" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/29M640Q87avBIyyLC1rWlT" + }, + "href": "https://api.spotify.com/v1/albums/29M640Q87avBIyyLC1rWlT", + "id": "29M640Q87avBIyyLC1rWlT", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27352daea405b73ab7d12d2b5ac", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0252daea405b73ab7d12d2b5ac", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485152daea405b73ab7d12d2b5ac", + "width": 64 + }], + "is_playable": true, + "name": "Colorblind EP", + "release_date": "2022-12-09", + "release_date_precision": "day", + "total_tracks": 5, + "type": "album", + "uri": "spotify:album:29M640Q87avBIyyLC1rWlT" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3kSDOw6bEMSStOjqLR2kVX" + }, + "href": "https://api.spotify.com/v1/artists/3kSDOw6bEMSStOjqLR2kVX", + "id": "3kSDOw6bEMSStOjqLR2kVX", + "name": "Colorblind", + "type": "artist", + "uri": "spotify:artist:3kSDOw6bEMSStOjqLR2kVX" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 222631, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZRUP2101306" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4ADgspuZLhlsiAijC9oDAR" + }, + "href": "https://api.spotify.com/v1/tracks/4ADgspuZLhlsiAijC9oDAR", + "id": "4ADgspuZLhlsiAijC9oDAR", + "is_local": false, + "name": "Everything but Faith", + "popularity": 45, + "preview_url": "https://p.scdn.co/mp3-preview/05d2cd12d291b36b5d01e883dff232a3475826f8?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 3, + "type": "track", + "uri": "spotify:track:4ADgspuZLhlsiAijC9oDAR" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6HXpMYkohJ9wOCdUev8qzS" + }, + "href": "https://api.spotify.com/v1/artists/6HXpMYkohJ9wOCdUev8qzS", + "id": "6HXpMYkohJ9wOCdUev8qzS", + "name": "Vatic", + "type": "artist", + "uri": "spotify:artist:6HXpMYkohJ9wOCdUev8qzS" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6eSyQdEzLe207n5TcOjx88" + }, + "href": "https://api.spotify.com/v1/albums/6eSyQdEzLe207n5TcOjx88", + "id": "6eSyQdEzLe207n5TcOjx88", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273c7e11f46d1dac903fe505bf4", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02c7e11f46d1dac903fe505bf4", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851c7e11f46d1dac903fe505bf4", + "width": 64 + }], + "is_playable": true, + "name": "Mercer 217", + "release_date": "2022-10-21", + "release_date_precision": "day", + "total_tracks": 8, + "type": "album", + "uri": "spotify:album:6eSyQdEzLe207n5TcOjx88" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6HXpMYkohJ9wOCdUev8qzS" + }, + "href": "https://api.spotify.com/v1/artists/6HXpMYkohJ9wOCdUev8qzS", + "id": "6HXpMYkohJ9wOCdUev8qzS", + "name": "Vatic", + "type": "artist", + "uri": "spotify:artist:6HXpMYkohJ9wOCdUev8qzS" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 231999, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "AUBEC2221706" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/6YlXUTJWpYofpMXgfrmks8" + }, + "href": "https://api.spotify.com/v1/tracks/6YlXUTJWpYofpMXgfrmks8", + "id": "6YlXUTJWpYofpMXgfrmks8", + "is_local": false, + "name": "Remember East Mercer", + "popularity": 37, + "preview_url": "https://p.scdn.co/mp3-preview/8819e3373f2909d07787885c165fd995d92d3b38?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 7, + "type": "track", + "uri": "spotify:track:6YlXUTJWpYofpMXgfrmks8" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0rsHKddRhuze38fVL0egOY" + }, + "href": "https://api.spotify.com/v1/artists/0rsHKddRhuze38fVL0egOY", + "id": "0rsHKddRhuze38fVL0egOY", + "name": "For The Fallen Dreams", + "type": "artist", + "uri": "spotify:artist:0rsHKddRhuze38fVL0egOY" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3UDy59MHq2lMzX04LeH6qa" + }, + "href": "https://api.spotify.com/v1/albums/3UDy59MHq2lMzX04LeH6qa", + "id": "3UDy59MHq2lMzX04LeH6qa", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2735e2c71c1fae2d11a6aaf1041", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e025e2c71c1fae2d11a6aaf1041", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048515e2c71c1fae2d11a6aaf1041", + "width": 64 + }], + "is_playable": true, + "name": "No Heaven", + "release_date": "2022-10-21", + "release_date_precision": "day", + "total_tracks": 4, + "type": "album", + "uri": "spotify:album:3UDy59MHq2lMzX04LeH6qa" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0rsHKddRhuze38fVL0egOY" + }, + "href": "https://api.spotify.com/v1/artists/0rsHKddRhuze38fVL0egOY", + "id": "0rsHKddRhuze38fVL0egOY", + "name": "For The Fallen Dreams", + "type": "artist", + "uri": "spotify:artist:0rsHKddRhuze38fVL0egOY" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 204000, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEYO62200079" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5nxZSkMS7VpbjEHaCQ39a1" + }, + "href": "https://api.spotify.com/v1/tracks/5nxZSkMS7VpbjEHaCQ39a1", + "id": "5nxZSkMS7VpbjEHaCQ39a1", + "is_local": false, + "name": "No Heaven", + "popularity": 48, + "preview_url": "https://p.scdn.co/mp3-preview/79ebf42e5bdc83ea9f7363fef621f3bed2d76556?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:5nxZSkMS7VpbjEHaCQ39a1" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "compilation", + "album_type": "compilation", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/52qKfVcIV4GS8A8Vay2xtt" + }, + "href": "https://api.spotify.com/v1/artists/52qKfVcIV4GS8A8Vay2xtt", + "id": "52qKfVcIV4GS8A8Vay2xtt", + "name": "Ice Nine Kills", + "type": "artist", + "uri": "spotify:artist:52qKfVcIV4GS8A8Vay2xtt" + }], + "available_markets": ["AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH", "BO", "BR", "CA", "CH", "CI", "CL", "CM", "CO", "CR", "CW", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FR", "GB", "GH", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JP", "KE", "KH", "KR", "KW", "LB", "LK", "LT", "LU", "LV", "MA", "ME", "MK", "MT", "MX", "MY", "NG", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PT", "PY", "QA", "RO", "RS", "SA", "SE", "SG", "SI", "SK", "SN", "SV", "TH", "TN", "TR", "TT", "TW", "UA", "US", "UY", "VE", "VN", "XK", "ZA"], + "external_urls": { + "spotify": "https://open.spotify.com/album/273LyHQV9St48MzqO73UkX" + }, + "href": "https://api.spotify.com/v1/albums/273LyHQV9St48MzqO73UkX", + "id": "273LyHQV9St48MzqO73UkX", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273939aaba2289ceaae1024a705", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02939aaba2289ceaae1024a705", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851939aaba2289ceaae1024a705", + "width": 64 + }], + "is_playable": true, + "name": "The Shower Scene Playlist", + "release_date": "2022-06-24", + "release_date_precision": "day", + "total_tracks": 7, + "type": "album", + "uri": "spotify:album:273LyHQV9St48MzqO73UkX" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/52qKfVcIV4GS8A8Vay2xtt" + }, + "href": "https://api.spotify.com/v1/artists/52qKfVcIV4GS8A8Vay2xtt", + "id": "52qKfVcIV4GS8A8Vay2xtt", + "name": "Ice Nine Kills", + "type": "artist", + "uri": "spotify:artist:52qKfVcIV4GS8A8Vay2xtt" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/3a0Ol9AaugGXjf1ZQcAs1U" + }, + "href": "https://api.spotify.com/v1/artists/3a0Ol9AaugGXjf1ZQcAs1U", + "id": "3a0Ol9AaugGXjf1ZQcAs1U", + "name": "Jacoby Shaddix", + "type": "artist", + "uri": "spotify:artist:3a0Ol9AaugGXjf1ZQcAs1U" + }], + "available_markets": ["AE", "AL", "AR", "AT", "AU", "BA", "BE", "BG", "BH", "BO", "BR", "CA", "CH", "CI", "CL", "CM", "CO", "CR", "CW", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE", "EG", "ES", "FI", "FR", "GB", "GH", "GR", "GT", "HK", "HN", "HR", "HU", "ID", "IE", "IL", "IN", "IS", "IT", "JP", "KE", "KH", "KR", "KW", "LB", "LK", "LT", "LU", "LV", "MA", "ME", "MK", "MT", "MX", "MY", "NG", "NI", "NL", "NO", "NZ", "OM", "PA", "PE", "PH", "PL", "PT", "PY", "QA", "RO", "RS", "SA", "SE", "SG", "SI", "SK", "SN", "SV", "TH", "TN", "TR", "TT", "TW", "UA", "US", "UY", "VE", "VN", "XK", "ZA"], + "disc_number": 1, + "duration_ms": 205276, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "US5262124132" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4lEbtjtLpF0YxRCFWeswAG" + }, + "href": "https://api.spotify.com/v1/tracks/4lEbtjtLpF0YxRCFWeswAG", + "id": "4lEbtjtLpF0YxRCFWeswAG", + "is_local": false, + "name": "Hip To Be Scared", + "popularity": 39, + "preview_url": null, + "track": true, + "track_number": 2, + "type": "track", + "uri": "spotify:track:4lEbtjtLpF0YxRCFWeswAG" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6DAXLVtNvEBAy0ncBuaQGv" + }, + "href": "https://api.spotify.com/v1/artists/6DAXLVtNvEBAy0ncBuaQGv", + "id": "6DAXLVtNvEBAy0ncBuaQGv", + "name": "Grieve", + "type": "artist", + "uri": "spotify:artist:6DAXLVtNvEBAy0ncBuaQGv" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/0wKIiZrKsOPxqhRxvlWcQ0" + }, + "href": "https://api.spotify.com/v1/albums/0wKIiZrKsOPxqhRxvlWcQ0", + "id": "0wKIiZrKsOPxqhRxvlWcQ0", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2734009a46786fe217474f3f50a", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e024009a46786fe217474f3f50a", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048514009a46786fe217474f3f50a", + "width": 64 + }], + "is_playable": true, + "name": "Empty, Like Me.", + "release_date": "2022-10-28", + "release_date_precision": "day", + "total_tracks": 5, + "type": "album", + "uri": "spotify:album:0wKIiZrKsOPxqhRxvlWcQ0" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6DAXLVtNvEBAy0ncBuaQGv" + }, + "href": "https://api.spotify.com/v1/artists/6DAXLVtNvEBAy0ncBuaQGv", + "id": "6DAXLVtNvEBAy0ncBuaQGv", + "name": "Grieve", + "type": "artist", + "uri": "spotify:artist:6DAXLVtNvEBAy0ncBuaQGv" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/5KrUtVY5gE9p9U52TT42rR" + }, + "href": "https://api.spotify.com/v1/artists/5KrUtVY5gE9p9U52TT42rR", + "id": "5KrUtVY5gE9p9U52TT42rR", + "name": "Joshua Roberts", + "type": "artist", + "uri": "spotify:artist:5KrUtVY5gE9p9U52TT42rR" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 264710, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QZTAS2251535" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1oaRm4ubgYTSlDNM0xGbgR" + }, + "href": "https://api.spotify.com/v1/tracks/1oaRm4ubgYTSlDNM0xGbgR", + "id": "1oaRm4ubgYTSlDNM0xGbgR", + "is_local": false, + "name": "Empty, Like Me.", + "popularity": 34, + "preview_url": "https://p.scdn.co/mp3-preview/b1dcc228490252d49fe209404c9c52de0cd5ab64?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 3, + "type": "track", + "uri": "spotify:track:1oaRm4ubgYTSlDNM0xGbgR" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7iWiAD5LLKyiox2grgfmUT" + }, + "href": "https://api.spotify.com/v1/artists/7iWiAD5LLKyiox2grgfmUT", + "id": "7iWiAD5LLKyiox2grgfmUT", + "name": "Bullet For My Valentine", + "type": "artist", + "uri": "spotify:artist:7iWiAD5LLKyiox2grgfmUT" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AO", "AR", "AU", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KH", "KI", "KM", "KN", "KR", "KW", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UG", "US", "UY", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6FqFZ1gdiCXhCPWhFbF1fF" + }, + "href": "https://api.spotify.com/v1/albums/6FqFZ1gdiCXhCPWhFbF1fF", + "id": "6FqFZ1gdiCXhCPWhFbF1fF", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273417504217838fa0b6eae1061", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02417504217838fa0b6eae1061", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851417504217838fa0b6eae1061", + "width": 64 + }], + "is_playable": true, + "name": "Bullet For My Valentine (Deluxe)", + "release_date": "2022-08-05", + "release_date_precision": "day", + "total_tracks": 15, + "type": "album", + "uri": "spotify:album:6FqFZ1gdiCXhCPWhFbF1fF" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7iWiAD5LLKyiox2grgfmUT" + }, + "href": "https://api.spotify.com/v1/artists/7iWiAD5LLKyiox2grgfmUT", + "id": "7iWiAD5LLKyiox2grgfmUT", + "name": "Bullet For My Valentine", + "type": "artist", + "uri": "spotify:artist:7iWiAD5LLKyiox2grgfmUT" + }], + "available_markets": ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "MD", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 235018, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "GBUM72201809" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4f1Bxzgor1HNbdm2kGl8mL" + }, + "href": "https://api.spotify.com/v1/tracks/4f1Bxzgor1HNbdm2kGl8mL", + "id": "4f1Bxzgor1HNbdm2kGl8mL", + "is_local": false, + "name": "This Means War", + "popularity": 48, + "preview_url": null, + "track": true, + "track_number": 15, + "type": "track", + "uri": "spotify:track:4f1Bxzgor1HNbdm2kGl8mL" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6o8sDniHcZPM1SixvjKiYS" + }, + "href": "https://api.spotify.com/v1/artists/6o8sDniHcZPM1SixvjKiYS", + "id": "6o8sDniHcZPM1SixvjKiYS", + "name": "NOVELISTS", + "type": "artist", + "uri": "spotify:artist:6o8sDniHcZPM1SixvjKiYS" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4aSQ7ZdevivIQFeSMWxPSW" + }, + "href": "https://api.spotify.com/v1/albums/4aSQ7ZdevivIQFeSMWxPSW", + "id": "4aSQ7ZdevivIQFeSMWxPSW", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273076ab8e6857a57b951bf2735", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02076ab8e6857a57b951bf2735", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851076ab8e6857a57b951bf2735", + "width": 64 + }], + "is_playable": true, + "name": "Déjà Vu", + "release_date": "2022-09-23", + "release_date_precision": "day", + "total_tracks": 12, + "type": "album", + "uri": "spotify:album:4aSQ7ZdevivIQFeSMWxPSW" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6G43CiunIxMwb2tQ12vNP6" + }, + "href": "https://api.spotify.com/v1/artists/6G43CiunIxMwb2tQ12vNP6", + "id": "6G43CiunIxMwb2tQ12vNP6", + "name": "LANDMVRKS", + "type": "artist", + "uri": "spotify:artist:6G43CiunIxMwb2tQ12vNP6" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/6o8sDniHcZPM1SixvjKiYS" + }, + "href": "https://api.spotify.com/v1/artists/6o8sDniHcZPM1SixvjKiYS", + "id": "6o8sDniHcZPM1SixvjKiYS", + "name": "NOVELISTS", + "type": "artist", + "uri": "spotify:artist:6o8sDniHcZPM1SixvjKiYS" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 202418, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEBZ72200060" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4whGYZQVkjI7r1hAyc4BFY" + }, + "href": "https://api.spotify.com/v1/tracks/4whGYZQVkjI7r1hAyc4BFY", + "id": "4whGYZQVkjI7r1hAyc4BFY", + "is_local": false, + "name": "Heretic", + "popularity": 51, + "preview_url": "https://p.scdn.co/mp3-preview/67af647c65372db1ccab526d1ad657bea16a7cda?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 3, + "type": "track", + "uri": "spotify:track:4whGYZQVkjI7r1hAyc4BFY" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0OgdRTPItr9dw4XYp4JJUx" + }, + "href": "https://api.spotify.com/v1/artists/0OgdRTPItr9dw4XYp4JJUx", + "id": "0OgdRTPItr9dw4XYp4JJUx", + "name": "Fit For A King", + "type": "artist", + "uri": "spotify:artist:0OgdRTPItr9dw4XYp4JJUx" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6RnuLQwxEgHaHPyWjel051" + }, + "href": "https://api.spotify.com/v1/albums/6RnuLQwxEgHaHPyWjel051", + "id": "6RnuLQwxEgHaHPyWjel051", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273f9993bd0b39d72160c509fbc", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02f9993bd0b39d72160c509fbc", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851f9993bd0b39d72160c509fbc", + "width": 64 + }], + "is_playable": true, + "name": "Reaper", + "release_date": "2022-06-23", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:6RnuLQwxEgHaHPyWjel051" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/0OgdRTPItr9dw4XYp4JJUx" + }, + "href": "https://api.spotify.com/v1/artists/0OgdRTPItr9dw4XYp4JJUx", + "id": "0OgdRTPItr9dw4XYp4JJUx", + "name": "Fit For A King", + "type": "artist", + "uri": "spotify:artist:0OgdRTPItr9dw4XYp4JJUx" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 199500, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QMGVJ2200051" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/6I7ilpVQq4oETOdmHPL5LE" + }, + "href": "https://api.spotify.com/v1/tracks/6I7ilpVQq4oETOdmHPL5LE", + "id": "6I7ilpVQq4oETOdmHPL5LE", + "is_local": false, + "name": "Reaper", + "popularity": 43, + "preview_url": "https://p.scdn.co/mp3-preview/697897163eb7faaf1502f527ef548edad6ba0e6b?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:6I7ilpVQq4oETOdmHPL5LE" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3Zj2B8yAi8gHoR8vpsPatZ" + }, + "href": "https://api.spotify.com/v1/artists/3Zj2B8yAi8gHoR8vpsPatZ", + "id": "3Zj2B8yAi8gHoR8vpsPatZ", + "name": "Gideon", + "type": "artist", + "uri": "spotify:artist:3Zj2B8yAi8gHoR8vpsPatZ" + }], + "available_markets": ["AE", "AG", "AO", "AR", "AU", "AZ", "BB", "BD", "BF", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "DJ", "DM", "DO", "DZ", "EC", "EG", "ET", "FJ", "FM", "GA", "GD", "GH", "GM", "GN", "GQ", "GT", "GW", "GY", "HK", "HN", "HT", "ID", "IN", "IQ", "JM", "JO", "JP", "KE", "KH", "KI", "KM", "KN", "KR", "KW", "LA", "LB", "LC", "LK", "LR", "LS", "LY", "MA", "MG", "MH", "ML", "MN", "MO", "MR", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PS", "PW", "PY", "QA", "RW", "SA", "SB", "SC", "SG", "SL", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TL", "TN", "TO", "TT", "TV", "TW", "TZ", "UG", "US", "UY", "VC", "VE", "VN", "VU", "WS", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4Am9KEEleButgBfQ9rq6Gh" + }, + "href": "https://api.spotify.com/v1/albums/4Am9KEEleButgBfQ9rq6Gh", + "id": "4Am9KEEleButgBfQ9rq6Gh", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2730f713d1120eb2a6a5bed5f23", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e020f713d1120eb2a6a5bed5f23", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048510f713d1120eb2a6a5bed5f23", + "width": 64 + }], + "is_playable": true, + "name": "Take Off", + "release_date": "2023-02-17", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:4Am9KEEleButgBfQ9rq6Gh" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3Zj2B8yAi8gHoR8vpsPatZ" + }, + "href": "https://api.spotify.com/v1/artists/3Zj2B8yAi8gHoR8vpsPatZ", + "id": "3Zj2B8yAi8gHoR8vpsPatZ", + "name": "Gideon", + "type": "artist", + "uri": "spotify:artist:3Zj2B8yAi8gHoR8vpsPatZ" + }], + "available_markets": ["AR", "AU", "BO", "BR", "CA", "CL", "CO", "CR", "DO", "EC", "SV", "GT", "HN", "HK", "MY", "MX", "NZ", "NI", "PA", "PY", "PE", "PH", "SG", "TW", "UY", "US", "ID", "JP", "TH", "VN", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "VE", "ET"], + "disc_number": 1, + "duration_ms": 208880, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "US3X52246306" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0TSz9TsaZXc6I6yKAa4xCD" + }, + "href": "https://api.spotify.com/v1/tracks/0TSz9TsaZXc6I6yKAa4xCD", + "id": "0TSz9TsaZXc6I6yKAa4xCD", + "is_local": false, + "name": "Take Off", + "popularity": 37, + "preview_url": "https://p.scdn.co/mp3-preview/d2cae38b8cdb50bf336f2b19de06b08f01e576c4?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:0TSz9TsaZXc6I6yKAa4xCD" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4pCVGaLWxDe4d8bsjsnmUM" + }, + "href": "https://api.spotify.com/v1/artists/4pCVGaLWxDe4d8bsjsnmUM", + "id": "4pCVGaLWxDe4d8bsjsnmUM", + "name": "coldrain", + "type": "artist", + "uri": "spotify:artist:4pCVGaLWxDe4d8bsjsnmUM" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/2XA78l6T2geC3hfxcnOs6V" + }, + "href": "https://api.spotify.com/v1/albums/2XA78l6T2geC3hfxcnOs6V", + "id": "2XA78l6T2geC3hfxcnOs6V", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2734fc2b816166db68ba62424ca", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e024fc2b816166db68ba62424ca", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048514fc2b816166db68ba62424ca", + "width": 64 + }], + "is_playable": true, + "name": "Nonnegative", + "release_date": "2022-07-06", + "release_date_precision": "day", + "total_tracks": 12, + "type": "album", + "uri": "spotify:album:2XA78l6T2geC3hfxcnOs6V" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4pCVGaLWxDe4d8bsjsnmUM" + }, + "href": "https://api.spotify.com/v1/artists/4pCVGaLWxDe4d8bsjsnmUM", + "id": "4pCVGaLWxDe4d8bsjsnmUM", + "name": "coldrain", + "type": "artist", + "uri": "spotify:artist:4pCVGaLWxDe4d8bsjsnmUM" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 233678, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "JPWP02270484" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/7qLbPd5yhm0Vne45PXPabV" + }, + "href": "https://api.spotify.com/v1/tracks/7qLbPd5yhm0Vne45PXPabV", + "id": "7qLbPd5yhm0Vne45PXPabV", + "is_local": false, + "name": "From Today", + "popularity": 46, + "preview_url": "https://p.scdn.co/mp3-preview/ae37c73d9ef381046ca76873f02d46d7d74be757?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 12, + "type": "track", + "uri": "spotify:track:7qLbPd5yhm0Vne45PXPabV" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/10Z7WzKMeIdNBKexi1YarP" + }, + "href": "https://api.spotify.com/v1/artists/10Z7WzKMeIdNBKexi1YarP", + "id": "10Z7WzKMeIdNBKexi1YarP", + "name": "Fame on Fire", + "type": "artist", + "uri": "spotify:artist:10Z7WzKMeIdNBKexi1YarP" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/7IJVzIr5F8Vq0Qe50PGwke" + }, + "href": "https://api.spotify.com/v1/albums/7IJVzIr5F8Vq0Qe50PGwke", + "id": "7IJVzIr5F8Vq0Qe50PGwke", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273471038c9bf8d1af038ca83d0", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02471038c9bf8d1af038ca83d0", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851471038c9bf8d1af038ca83d0", + "width": 64 + }], + "is_playable": true, + "name": "Ketamine", + "release_date": "2022-06-24", + "release_date_precision": "day", + "total_tracks": 4, + "type": "album", + "uri": "spotify:album:7IJVzIr5F8Vq0Qe50PGwke" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/10Z7WzKMeIdNBKexi1YarP" + }, + "href": "https://api.spotify.com/v1/artists/10Z7WzKMeIdNBKexi1YarP", + "id": "10Z7WzKMeIdNBKexi1YarP", + "name": "Fame on Fire", + "type": "artist", + "uri": "spotify:artist:10Z7WzKMeIdNBKexi1YarP" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 172019, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "USHR22212706" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/37vKzukXbXcJiA3TMmGptj" + }, + "href": "https://api.spotify.com/v1/tracks/37vKzukXbXcJiA3TMmGptj", + "id": "37vKzukXbXcJiA3TMmGptj", + "is_local": false, + "name": "Ketamine", + "popularity": 42, + "preview_url": "https://p.scdn.co/mp3-preview/b4c3ff5f4b9f1b5a9a62c6493cfe752b65532022?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:37vKzukXbXcJiA3TMmGptj" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2UoOdQyBGyzrEfxcY77ce0" + }, + "href": "https://api.spotify.com/v1/artists/2UoOdQyBGyzrEfxcY77ce0", + "id": "2UoOdQyBGyzrEfxcY77ce0", + "name": "ERRA", + "type": "artist", + "uri": "spotify:artist:2UoOdQyBGyzrEfxcY77ce0" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/2KElNfghT2G7tHLaOCMqFe" + }, + "href": "https://api.spotify.com/v1/albums/2KElNfghT2G7tHLaOCMqFe", + "id": "2KElNfghT2G7tHLaOCMqFe", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27394875e23212e1eca7354b02a", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0294875e23212e1eca7354b02a", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485194875e23212e1eca7354b02a", + "width": 64 + }], + "is_playable": true, + "name": "Pull From The Ghost", + "release_date": "2022-07-07", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:2KElNfghT2G7tHLaOCMqFe" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2UoOdQyBGyzrEfxcY77ce0" + }, + "href": "https://api.spotify.com/v1/artists/2UoOdQyBGyzrEfxcY77ce0", + "id": "2UoOdQyBGyzrEfxcY77ce0", + "name": "ERRA", + "type": "artist", + "uri": "spotify:artist:2UoOdQyBGyzrEfxcY77ce0" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 251191, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "AUI442200129" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/5X0o92ihmXE7KP5fcmNSFv" + }, + "href": "https://api.spotify.com/v1/tracks/5X0o92ihmXE7KP5fcmNSFv", + "id": "5X0o92ihmXE7KP5fcmNSFv", + "is_local": false, + "name": "Pull From The Ghost", + "popularity": 50, + "preview_url": "https://p.scdn.co/mp3-preview/8a80c5af5bdd8f6f9297ffeda6e41197c66640d2?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:5X0o92ihmXE7KP5fcmNSFv" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7GNTvmIi6DDF2XDJKYKoUk" + }, + "href": "https://api.spotify.com/v1/artists/7GNTvmIi6DDF2XDJKYKoUk", + "id": "7GNTvmIi6DDF2XDJKYKoUk", + "name": "Chaosbay", + "type": "artist", + "uri": "spotify:artist:7GNTvmIi6DDF2XDJKYKoUk" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/2Fig0Wysa46RMtW7JyNAc9" + }, + "href": "https://api.spotify.com/v1/albums/2Fig0Wysa46RMtW7JyNAc9", + "id": "2Fig0Wysa46RMtW7JyNAc9", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273a1410b5e7b3de50d9a9f64ca", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02a1410b5e7b3de50d9a9f64ca", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851a1410b5e7b3de50d9a9f64ca", + "width": 64 + }], + "is_playable": true, + "name": "What Is War", + "release_date": "2022-05-26", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:2Fig0Wysa46RMtW7JyNAc9" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/7GNTvmIi6DDF2XDJKYKoUk" + }, + "href": "https://api.spotify.com/v1/artists/7GNTvmIi6DDF2XDJKYKoUk", + "id": "7GNTvmIi6DDF2XDJKYKoUk", + "name": "Chaosbay", + "type": "artist", + "uri": "spotify:artist:7GNTvmIi6DDF2XDJKYKoUk" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/0Hx4gv3eoiodtu6XYHF1X0" + }, + "href": "https://api.spotify.com/v1/artists/0Hx4gv3eoiodtu6XYHF1X0", + "id": "0Hx4gv3eoiodtu6XYHF1X0", + "name": "Siamese", + "type": "artist", + "uri": "spotify:artist:0Hx4gv3eoiodtu6XYHF1X0" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 239975, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEXN92239727" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/3qPDkJVT3nTadE0DowU2w5" + }, + "href": "https://api.spotify.com/v1/tracks/3qPDkJVT3nTadE0DowU2w5", + "id": "3qPDkJVT3nTadE0DowU2w5", + "is_local": false, + "name": "What Is War", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/0f8789873890117e2de3c368f1aedf092de96c80?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:3qPDkJVT3nTadE0DowU2w5" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1AYs2fxCu0pV8iKaguz4po" + }, + "href": "https://api.spotify.com/v1/artists/1AYs2fxCu0pV8iKaguz4po", + "id": "1AYs2fxCu0pV8iKaguz4po", + "name": "Eyes Wide Open", + "type": "artist", + "uri": "spotify:artist:1AYs2fxCu0pV8iKaguz4po" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/5ByL1dXjgnjKAEF6H63e5p" + }, + "href": "https://api.spotify.com/v1/albums/5ByL1dXjgnjKAEF6H63e5p", + "id": "5ByL1dXjgnjKAEF6H63e5p", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2730ea4fb34e281c92128799e31", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e020ea4fb34e281c92128799e31", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048510ea4fb34e281c92128799e31", + "width": 64 + }], + "is_playable": true, + "name": "Cross My Heart", + "release_date": "2022-05-13", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:5ByL1dXjgnjKAEF6H63e5p" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/1AYs2fxCu0pV8iKaguz4po" + }, + "href": "https://api.spotify.com/v1/artists/1AYs2fxCu0pV8iKaguz4po", + "id": "1AYs2fxCu0pV8iKaguz4po", + "name": "Eyes Wide Open", + "type": "artist", + "uri": "spotify:artist:1AYs2fxCu0pV8iKaguz4po" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 198000, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEYO62200027" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2icamhwuMDLOPIGcTq3qxg" + }, + "href": "https://api.spotify.com/v1/tracks/2icamhwuMDLOPIGcTq3qxg", + "id": "2icamhwuMDLOPIGcTq3qxg", + "is_local": false, + "name": "Cross My Heart", + "popularity": 41, + "preview_url": "https://p.scdn.co/mp3-preview/d6607212017049734987c6bd86c80fa748f295a5?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2icamhwuMDLOPIGcTq3qxg" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2vhrwzjf9H3icunkVFi9tq" + }, + "href": "https://api.spotify.com/v1/artists/2vhrwzjf9H3icunkVFi9tq", + "id": "2vhrwzjf9H3icunkVFi9tq", + "name": "Smash Into Pieces", + "type": "artist", + "uri": "spotify:artist:2vhrwzjf9H3icunkVFi9tq" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/66snwEHAdTrN5gw7z3mpoA" + }, + "href": "https://api.spotify.com/v1/albums/66snwEHAdTrN5gw7z3mpoA", + "id": "66snwEHAdTrN5gw7z3mpoA", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27302d45ed91e80f93a6aa4b118", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0202d45ed91e80f93a6aa4b118", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485102d45ed91e80f93a6aa4b118", + "width": 64 + }], + "is_playable": true, + "name": "Throne", + "release_date": "2022-06-24", + "release_date_precision": "day", + "total_tracks": 7, + "type": "album", + "uri": "spotify:album:66snwEHAdTrN5gw7z3mpoA" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2vhrwzjf9H3icunkVFi9tq" + }, + "href": "https://api.spotify.com/v1/artists/2vhrwzjf9H3icunkVFi9tq", + "id": "2vhrwzjf9H3icunkVFi9tq", + "name": "Smash Into Pieces", + "type": "artist", + "uri": "spotify:artist:2vhrwzjf9H3icunkVFi9tq" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 207936, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "QM6MZ2289849" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1IIHG2cRp9PBYSGLSKAdgD" + }, + "href": "https://api.spotify.com/v1/tracks/1IIHG2cRp9PBYSGLSKAdgD", + "id": "1IIHG2cRp9PBYSGLSKAdgD", + "is_local": false, + "name": "Throne", + "popularity": 48, + "preview_url": "https://p.scdn.co/mp3-preview/54b267540f236780fa243600e3a622f1b298650d?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:1IIHG2cRp9PBYSGLSKAdgD" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6drAKOLWO1vzBrdmJmg5SE" + }, + "href": "https://api.spotify.com/v1/artists/6drAKOLWO1vzBrdmJmg5SE", + "id": "6drAKOLWO1vzBrdmJmg5SE", + "name": "Outline In Color", + "type": "artist", + "uri": "spotify:artist:6drAKOLWO1vzBrdmJmg5SE" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/3YMpkFfYLXaD8eZlQalBHC" + }, + "href": "https://api.spotify.com/v1/artists/3YMpkFfYLXaD8eZlQalBHC", + "id": "3YMpkFfYLXaD8eZlQalBHC", + "name": "Foxera", + "type": "artist", + "uri": "spotify:artist:3YMpkFfYLXaD8eZlQalBHC" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3vo077XHNBeAEVlnWGQUCG" + }, + "href": "https://api.spotify.com/v1/albums/3vo077XHNBeAEVlnWGQUCG", + "id": "3vo077XHNBeAEVlnWGQUCG", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b27319e4fe3e1a34cd0f238e0ede", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e0219e4fe3e1a34cd0f238e0ede", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d0000485119e4fe3e1a34cd0f238e0ede", + "width": 64 + }], + "is_playable": true, + "name": "Quicksand", + "release_date": "2022-07-01", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:3vo077XHNBeAEVlnWGQUCG" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/6drAKOLWO1vzBrdmJmg5SE" + }, + "href": "https://api.spotify.com/v1/artists/6drAKOLWO1vzBrdmJmg5SE", + "id": "6drAKOLWO1vzBrdmJmg5SE", + "name": "Outline In Color", + "type": "artist", + "uri": "spotify:artist:6drAKOLWO1vzBrdmJmg5SE" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/3YMpkFfYLXaD8eZlQalBHC" + }, + "href": "https://api.spotify.com/v1/artists/3YMpkFfYLXaD8eZlQalBHC", + "id": "3YMpkFfYLXaD8eZlQalBHC", + "name": "Foxera", + "type": "artist", + "uri": "spotify:artist:3YMpkFfYLXaD8eZlQalBHC" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/1p4l2x4EUENGm1VCQfBkuu" + }, + "href": "https://api.spotify.com/v1/artists/1p4l2x4EUENGm1VCQfBkuu", + "id": "1p4l2x4EUENGm1VCQfBkuu", + "name": "Michael Swank", + "type": "artist", + "uri": "spotify:artist:1p4l2x4EUENGm1VCQfBkuu" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 152000, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QM6N22231680" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/3B2lC0tHokLJuPOhKaLycU" + }, + "href": "https://api.spotify.com/v1/tracks/3B2lC0tHokLJuPOhKaLycU", + "id": "3B2lC0tHokLJuPOhKaLycU", + "is_local": false, + "name": "Quicksand (feat. Michael Swank)", + "popularity": 37, + "preview_url": "https://p.scdn.co/mp3-preview/8c72c71a21c2c39c4d330681a03afc7c386a5054?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:3B2lC0tHokLJuPOhKaLycU" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3f3CYDS0i8Z0Egxp9gwD1Z" + }, + "href": "https://api.spotify.com/v1/artists/3f3CYDS0i8Z0Egxp9gwD1Z", + "id": "3f3CYDS0i8Z0Egxp9gwD1Z", + "name": "Execution Day", + "type": "artist", + "uri": "spotify:artist:3f3CYDS0i8Z0Egxp9gwD1Z" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/6KXqyVNZsxl7NwgQVvtZ4C" + }, + "href": "https://api.spotify.com/v1/albums/6KXqyVNZsxl7NwgQVvtZ4C", + "id": "6KXqyVNZsxl7NwgQVvtZ4C", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273d2bb0cb91686f9b0c8625812", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02d2bb0cb91686f9b0c8625812", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851d2bb0cb91686f9b0c8625812", + "width": 64 + }], + "is_playable": true, + "name": "Suffocate", + "release_date": "2022-05-13", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:6KXqyVNZsxl7NwgQVvtZ4C" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3f3CYDS0i8Z0Egxp9gwD1Z" + }, + "href": "https://api.spotify.com/v1/artists/3f3CYDS0i8Z0Egxp9gwD1Z", + "id": "3f3CYDS0i8Z0Egxp9gwD1Z", + "name": "Execution Day", + "type": "artist", + "uri": "spotify:artist:3f3CYDS0i8Z0Egxp9gwD1Z" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 227272, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "usdy42205848" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/7aIKpaMchQAKcNv7W8GQhv" + }, + "href": "https://api.spotify.com/v1/tracks/7aIKpaMchQAKcNv7W8GQhv", + "id": "7aIKpaMchQAKcNv7W8GQhv", + "is_local": false, + "name": "Suffocate", + "popularity": 39, + "preview_url": "https://p.scdn.co/mp3-preview/efe34df0893f7e115cc04297afdcba686f102bab?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:7aIKpaMchQAKcNv7W8GQhv" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4GnK2zRFtw1gBoiFORWHsA" + }, + "href": "https://api.spotify.com/v1/artists/4GnK2zRFtw1gBoiFORWHsA", + "id": "4GnK2zRFtw1gBoiFORWHsA", + "name": "Of Virtue", + "type": "artist", + "uri": "spotify:artist:4GnK2zRFtw1gBoiFORWHsA" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4Qiu3xzymfFETMN7yEDCP3" + }, + "href": "https://api.spotify.com/v1/albums/4Qiu3xzymfFETMN7yEDCP3", + "id": "4Qiu3xzymfFETMN7yEDCP3", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273f56fe4dc140893ee3a285b9d", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02f56fe4dc140893ee3a285b9d", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851f56fe4dc140893ee3a285b9d", + "width": 64 + }], + "is_playable": true, + "name": "A.N.X.I.E.T.Y.", + "release_date": "2023-02-09", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:4Qiu3xzymfFETMN7yEDCP3" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4GnK2zRFtw1gBoiFORWHsA" + }, + "href": "https://api.spotify.com/v1/artists/4GnK2zRFtw1gBoiFORWHsA", + "id": "4GnK2zRFtw1gBoiFORWHsA", + "name": "Of Virtue", + "type": "artist", + "uri": "spotify:artist:4GnK2zRFtw1gBoiFORWHsA" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 179275, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEYO62200240" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/2FlSBOa7In5PcpL5SXFwkW" + }, + "href": "https://api.spotify.com/v1/tracks/2FlSBOa7In5PcpL5SXFwkW", + "id": "2FlSBOa7In5PcpL5SXFwkW", + "is_local": false, + "name": "A.N.X.I.E.T.Y.", + "popularity": 43, + "preview_url": "https://p.scdn.co/mp3-preview/342fb0a2d5faf2e3b4f6b6950cde89e2cca53dc0?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:2FlSBOa7In5PcpL5SXFwkW" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2tjnvrUmP46XNjFh9V0NGc" + }, + "href": "https://api.spotify.com/v1/artists/2tjnvrUmP46XNjFh9V0NGc", + "id": "2tjnvrUmP46XNjFh9V0NGc", + "name": "Alpha Wolf", + "type": "artist", + "uri": "spotify:artist:2tjnvrUmP46XNjFh9V0NGc" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3GdgTYJ6MCD7nsQ8uZZly5" + }, + "href": "https://api.spotify.com/v1/albums/3GdgTYJ6MCD7nsQ8uZZly5", + "id": "3GdgTYJ6MCD7nsQ8uZZly5", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2735ae606698677e51d8528f06d", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e025ae606698677e51d8528f06d", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048515ae606698677e51d8528f06d", + "width": 64 + }], + "is_playable": true, + "name": "Hotel Underground", + "release_date": "2022-06-23", + "release_date_precision": "day", + "total_tracks": 2, + "type": "album", + "uri": "spotify:album:3GdgTYJ6MCD7nsQ8uZZly5" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2tjnvrUmP46XNjFh9V0NGc" + }, + "href": "https://api.spotify.com/v1/artists/2tjnvrUmP46XNjFh9V0NGc", + "id": "2tjnvrUmP46XNjFh9V0NGc", + "name": "Alpha Wolf", + "type": "artist", + "uri": "spotify:artist:2tjnvrUmP46XNjFh9V0NGc" + }], + "available_markets": ["AR", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 166181, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "DED832200123" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0CoxiZuaRFycPJ0Xl1oSOJ" + }, + "href": "https://api.spotify.com/v1/tracks/0CoxiZuaRFycPJ0Xl1oSOJ", + "id": "0CoxiZuaRFycPJ0Xl1oSOJ", + "is_local": false, + "name": "Hotel Underground", + "popularity": 43, + "preview_url": "https://p.scdn.co/mp3-preview/5bc4b961000d6331dd5bbb0d933cdb3f8b500dbf?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:0CoxiZuaRFycPJ0Xl1oSOJ" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/28XopU8Uw6D6Wl7rIgCVNE" + }, + "href": "https://api.spotify.com/v1/artists/28XopU8Uw6D6Wl7rIgCVNE", + "id": "28XopU8Uw6D6Wl7rIgCVNE", + "name": "Villain of the Story", + "type": "artist", + "uri": "spotify:artist:28XopU8Uw6D6Wl7rIgCVNE" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3y8C86Pm7N3YWAohYNAmjY" + }, + "href": "https://api.spotify.com/v1/albums/3y8C86Pm7N3YWAohYNAmjY", + "id": "3y8C86Pm7N3YWAohYNAmjY", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2731cbbbe8452940b15715c1a47", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e021cbbbe8452940b15715c1a47", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048511cbbbe8452940b15715c1a47", + "width": 64 + }], + "is_playable": true, + "name": "Divided", + "release_date": "2022-07-22", + "release_date_precision": "day", + "total_tracks": 8, + "type": "album", + "uri": "spotify:album:3y8C86Pm7N3YWAohYNAmjY" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/28XopU8Uw6D6Wl7rIgCVNE" + }, + "href": "https://api.spotify.com/v1/artists/28XopU8Uw6D6Wl7rIgCVNE", + "id": "28XopU8Uw6D6Wl7rIgCVNE", + "name": "Villain of the Story", + "type": "artist", + "uri": "spotify:artist:28XopU8Uw6D6Wl7rIgCVNE" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 208920, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEBZ72100155" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/10K74dbHDqw7hmtSmLfs7t" + }, + "href": "https://api.spotify.com/v1/tracks/10K74dbHDqw7hmtSmLfs7t", + "id": "10K74dbHDqw7hmtSmLfs7t", + "is_local": false, + "name": "Losing Control", + "popularity": 58, + "preview_url": "https://p.scdn.co/mp3-preview/1c292635d52d6ba0f70081cd304dd22d4dea8b77?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 5, + "type": "track", + "uri": "spotify:track:10K74dbHDqw7hmtSmLfs7t" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2tl280wIokrLjabzrSKTgU" + }, + "href": "https://api.spotify.com/v1/artists/2tl280wIokrLjabzrSKTgU", + "id": "2tl280wIokrLjabzrSKTgU", + "name": "Holding Absence", + "type": "artist", + "uri": "spotify:artist:2tl280wIokrLjabzrSKTgU" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/4qPVQisdRPip6QzcBXP7Xz" + }, + "href": "https://api.spotify.com/v1/albums/4qPVQisdRPip6QzcBXP7Xz", + "id": "4qPVQisdRPip6QzcBXP7Xz", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273c19398c5c5e6908bfdf77355", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02c19398c5c5e6908bfdf77355", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851c19398c5c5e6908bfdf77355", + "width": 64 + }], + "is_playable": true, + "name": "Coffin", + "release_date": "2022-08-03", + "release_date_precision": "day", + "total_tracks": 3, + "type": "album", + "uri": "spotify:album:4qPVQisdRPip6QzcBXP7Xz" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/2tl280wIokrLjabzrSKTgU" + }, + "href": "https://api.spotify.com/v1/artists/2tl280wIokrLjabzrSKTgU", + "id": "2tl280wIokrLjabzrSKTgU", + "name": "Holding Absence", + "type": "artist", + "uri": "spotify:artist:2tl280wIokrLjabzrSKTgU" + }, { + "external_urls": { + "spotify": "https://open.spotify.com/artist/2tjnvrUmP46XNjFh9V0NGc" + }, + "href": "https://api.spotify.com/v1/artists/2tjnvrUmP46XNjFh9V0NGc", + "id": "2tjnvrUmP46XNjFh9V0NGc", + "name": "Alpha Wolf", + "type": "artist", + "uri": "spotify:artist:2tjnvrUmP46XNjFh9V0NGc" + }], + "available_markets": ["AR", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XC", "XK"], + "disc_number": 1, + "duration_ms": 264306, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DED832200124" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/49UQKQom802JUWPq63lxEb" + }, + "href": "https://api.spotify.com/v1/tracks/49UQKQom802JUWPq63lxEb", + "id": "49UQKQom802JUWPq63lxEb", + "is_local": false, + "name": "Aching Longing", + "popularity": 43, + "preview_url": "https://p.scdn.co/mp3-preview/a7a36386693cf651291a37bd781c3c4cccb436e9?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 3, + "type": "track", + "uri": "spotify:track:49UQKQom802JUWPq63lxEb" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/04LbaB3D3XOMbfPnWmObAi" + }, + "href": "https://api.spotify.com/v1/artists/04LbaB3D3XOMbfPnWmObAi", + "id": "04LbaB3D3XOMbfPnWmObAi", + "name": "Ocean Sleeper", + "type": "artist", + "uri": "spotify:artist:04LbaB3D3XOMbfPnWmObAi" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/17yymNfb1oyI5bBn0BvXv2" + }, + "href": "https://api.spotify.com/v1/albums/17yymNfb1oyI5bBn0BvXv2", + "id": "17yymNfb1oyI5bBn0BvXv2", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2734ed2b5055689f160989b7f1d", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e024ed2b5055689f160989b7f1d", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048514ed2b5055689f160989b7f1d", + "width": 64 + }], + "is_playable": true, + "name": "Your Love I'll Never Need", + "release_date": "2022-06-28", + "release_date_precision": "day", + "total_tracks": 1, + "type": "album", + "uri": "spotify:album:17yymNfb1oyI5bBn0BvXv2" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/04LbaB3D3XOMbfPnWmObAi" + }, + "href": "https://api.spotify.com/v1/artists/04LbaB3D3XOMbfPnWmObAi", + "id": "04LbaB3D3XOMbfPnWmObAi", + "name": "Ocean Sleeper", + "type": "artist", + "uri": "spotify:artist:04LbaB3D3XOMbfPnWmObAi" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 200843, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "AUOXM2200369" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/228ijND7JwCIpNt8sYlHYW" + }, + "href": "https://api.spotify.com/v1/tracks/228ijND7JwCIpNt8sYlHYW", + "id": "228ijND7JwCIpNt8sYlHYW", + "is_local": false, + "name": "Your Love I'll Never Need", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/be89c6958811f2bf29d27e5ddb42a7e077cce994?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:228ijND7JwCIpNt8sYlHYW" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/50YmW8f4U5IxTIwYI9mGAe" + }, + "href": "https://api.spotify.com/v1/artists/50YmW8f4U5IxTIwYI9mGAe", + "id": "50YmW8f4U5IxTIwYI9mGAe", + "name": "Hollow Front", + "type": "artist", + "uri": "spotify:artist:50YmW8f4U5IxTIwYI9mGAe" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/7y1KzLYE9ws4vN3vP6OZh4" + }, + "href": "https://api.spotify.com/v1/albums/7y1KzLYE9ws4vN3vP6OZh4", + "id": "7y1KzLYE9ws4vN3vP6OZh4", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273d8a1f224d1e52b9bf338a7d4", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02d8a1f224d1e52b9bf338a7d4", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851d8a1f224d1e52b9bf338a7d4", + "width": 64 + }], + "is_playable": true, + "name": "The Price Of Dreaming", + "release_date": "2022-05-27", + "release_date_precision": "day", + "total_tracks": 12, + "type": "album", + "uri": "spotify:album:7y1KzLYE9ws4vN3vP6OZh4" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/50YmW8f4U5IxTIwYI9mGAe" + }, + "href": "https://api.spotify.com/v1/artists/50YmW8f4U5IxTIwYI9mGAe", + "id": "50YmW8f4U5IxTIwYI9mGAe", + "name": "Hollow Front", + "type": "artist", + "uri": "spotify:artist:50YmW8f4U5IxTIwYI9mGAe" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 280579, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "AUI442100091" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/1ALVr49q6IjFtzMajHvaU9" + }, + "href": "https://api.spotify.com/v1/tracks/1ALVr49q6IjFtzMajHvaU9", + "id": "1ALVr49q6IjFtzMajHvaU9", + "is_local": false, + "name": "Thick As Blood", + "popularity": 42, + "preview_url": "https://p.scdn.co/mp3-preview/ddf07c882de9f9a39d7cef33d27e49f2a9349c35?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 4, + "type": "track", + "uri": "spotify:track:1ALVr49q6IjFtzMajHvaU9" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "album", + "album_type": "album", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4QnuZOyl4C9d1keyOZXJ21" + }, + "href": "https://api.spotify.com/v1/artists/4QnuZOyl4C9d1keyOZXJ21", + "id": "4QnuZOyl4C9d1keyOZXJ21", + "name": "Future Palace", + "type": "artist", + "uri": "spotify:artist:4QnuZOyl4C9d1keyOZXJ21" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3PsbQWb1jzu1TieGQwvjd7" + }, + "href": "https://api.spotify.com/v1/albums/3PsbQWb1jzu1TieGQwvjd7", + "id": "3PsbQWb1jzu1TieGQwvjd7", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2736d6b13d1fc6d3af5ae92f61e", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e026d6b13d1fc6d3af5ae92f61e", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048516d6b13d1fc6d3af5ae92f61e", + "width": 64 + }], + "is_playable": true, + "name": "Run", + "release_date": "2022-06-10", + "release_date_precision": "day", + "total_tracks": 12, + "type": "album", + "uri": "spotify:album:3PsbQWb1jzu1TieGQwvjd7" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/4QnuZOyl4C9d1keyOZXJ21" + }, + "href": "https://api.spotify.com/v1/artists/4QnuZOyl4C9d1keyOZXJ21", + "id": "4QnuZOyl4C9d1keyOZXJ21", + "name": "Future Palace", + "type": "artist", + "uri": "spotify:artist:4QnuZOyl4C9d1keyOZXJ21" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 204040, + "episode": false, + "explicit": false, + "external_ids": { + "isrc": "DEYO62100129" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4hZIolup6cgYhrzzGq46aq" + }, + "href": "https://api.spotify.com/v1/tracks/4hZIolup6cgYhrzzGq46aq", + "id": "4hZIolup6cgYhrzzGq46aq", + "is_local": false, + "name": "Dead Inside", + "popularity": 54, + "preview_url": "https://p.scdn.co/mp3-preview/4d4adc339aed709c8e3bad499e679745a406f23d?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 2, + "type": "track", + "uri": "spotify:track:4hZIolup6cgYhrzzGq46aq" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3CMyREgx8ZErRUydXlmCDX" + }, + "href": "https://api.spotify.com/v1/artists/3CMyREgx8ZErRUydXlmCDX", + "id": "3CMyREgx8ZErRUydXlmCDX", + "name": "Dark Divine", + "type": "artist", + "uri": "spotify:artist:3CMyREgx8ZErRUydXlmCDX" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/48yuoZ91DAKQGAvfPwNYF0" + }, + "href": "https://api.spotify.com/v1/albums/48yuoZ91DAKQGAvfPwNYF0", + "id": "48yuoZ91DAKQGAvfPwNYF0", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b2732259cd7294f13d62772198b9", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e022259cd7294f13d62772198b9", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d000048512259cd7294f13d62772198b9", + "width": 64 + }], + "is_playable": true, + "name": "Circles", + "release_date": "2022-06-24", + "release_date_precision": "day", + "total_tracks": 4, + "type": "album", + "uri": "spotify:album:48yuoZ91DAKQGAvfPwNYF0" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/3CMyREgx8ZErRUydXlmCDX" + }, + "href": "https://api.spotify.com/v1/artists/3CMyREgx8ZErRUydXlmCDX", + "id": "3CMyREgx8ZErRUydXlmCDX", + "name": "Dark Divine", + "type": "artist", + "uri": "spotify:artist:3CMyREgx8ZErRUydXlmCDX" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 182057, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QM6MZ2284348" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/0JIEEyj0EsqTZORin5bxnM" + }, + "href": "https://api.spotify.com/v1/tracks/0JIEEyj0EsqTZORin5bxnM", + "id": "0JIEEyj0EsqTZORin5bxnM", + "is_local": false, + "name": "Circles", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/c5c7e9ab73e31da5930a9ca70db3508460431b33?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:0JIEEyj0EsqTZORin5bxnM" + }, + "video_thumbnail": { + "url": null + } + }, { + "added_at": "2023-03-10T05:39:11Z", + "added_by": { + "external_urls": { + "spotify": "https://open.spotify.com/user/" + }, + "href": "https://api.spotify.com/v1/users/", + "id": "", + "type": "user", + "uri": "spotify:user:" + }, + "is_local": false, + "primary_color": null, + "track": { + "album": { + "album_group": "single", + "album_type": "single", + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/567L1a4812VuMSRrbCqdo4" + }, + "href": "https://api.spotify.com/v1/artists/567L1a4812VuMSRrbCqdo4", + "id": "567L1a4812VuMSRrbCqdo4", + "name": "Stain the Canvas", + "type": "artist", + "uri": "spotify:artist:567L1a4812VuMSRrbCqdo4" + }], + "available_markets": ["AD", "AE", "AG", "AL", "AM", "AO", "AR", "AT", "AU", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BN", "BO", "BR", "BS", "BT", "BW", "BY", "BZ", "CA", "CD", "CG", "CH", "CI", "CL", "CM", "CO", "CR", "CV", "CW", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "ES", "ET", "FI", "FJ", "FM", "FR", "GA", "GB", "GD", "GE", "GH", "GM", "GN", "GQ", "GR", "GT", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KR", "KW", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MG", "MH", "MK", "ML", "MN", "MO", "MR", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NE", "NG", "NI", "NL", "NO", "NP", "NR", "NZ", "OM", "PA", "PE", "PG", "PH", "PK", "PL", "PS", "PT", "PW", "PY", "QA", "RO", "RS", "RW", "SA", "SB", "SC", "SE", "SG", "SI", "SK", "SL", "SM", "SN", "SR", "ST", "SV", "SZ", "TD", "TG", "TH", "TJ", "TL", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "US", "UY", "UZ", "VC", "VE", "VN", "VU", "WS", "XK", "ZA", "ZM", "ZW"], + "external_urls": { + "spotify": "https://open.spotify.com/album/3Z7HDWGhP7QV3mML7pEIVY" + }, + "href": "https://api.spotify.com/v1/albums/3Z7HDWGhP7QV3mML7pEIVY", + "id": "3Z7HDWGhP7QV3mML7pEIVY", + "images": [{ + "height": 640, + "url": "https://i.scdn.co/image/ab67616d0000b273392ddeb33fcd0cf1e19b2c9a", + "width": 640 + }, { + "height": 300, + "url": "https://i.scdn.co/image/ab67616d00001e02392ddeb33fcd0cf1e19b2c9a", + "width": 300 + }, { + "height": 64, + "url": "https://i.scdn.co/image/ab67616d00004851392ddeb33fcd0cf1e19b2c9a", + "width": 64 + }], + "is_playable": true, + "name": "Dead Circus", + "release_date": "2022-05-06", + "release_date_precision": "day", + "total_tracks": 5, + "type": "album", + "uri": "spotify:album:3Z7HDWGhP7QV3mML7pEIVY" + }, + "artists": [{ + "external_urls": { + "spotify": "https://open.spotify.com/artist/567L1a4812VuMSRrbCqdo4" + }, + "href": "https://api.spotify.com/v1/artists/567L1a4812VuMSRrbCqdo4", + "id": "567L1a4812VuMSRrbCqdo4", + "name": "Stain the Canvas", + "type": "artist", + "uri": "spotify:artist:567L1a4812VuMSRrbCqdo4" + }], + "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"], + "disc_number": 1, + "duration_ms": 190250, + "episode": false, + "explicit": true, + "external_ids": { + "isrc": "QM4TX2233916" + }, + "external_urls": { + "spotify": "https://open.spotify.com/track/4RJ2TLSVhIyHFaEVYKygGh" + }, + "href": "https://api.spotify.com/v1/tracks/4RJ2TLSVhIyHFaEVYKygGh", + "id": "4RJ2TLSVhIyHFaEVYKygGh", + "is_local": false, + "name": "Dead Circus", + "popularity": 40, + "preview_url": "https://p.scdn.co/mp3-preview/3d1f27384501b933985a802ca48d6edf6d200928?cid=3c5328c75f1f44c086b25e73608c453b", + "track": true, + "track_number": 1, + "type": "track", + "uri": "spotify:track:4RJ2TLSVhIyHFaEVYKygGh" + }, + "video_thumbnail": { + "url": null + } + }], + "limit": 100, + "next": null, + "offset": 0, + "previous": null, + "total": 74 + }, + "type": "playlist", + "uri": "spotify:playlist:37i9dQZF1DWXIcbzpLauPS" + }; +} \ No newline at end of file diff --git a/src/test/data/validShow.ts b/src/test/data/validShow.ts new file mode 100644 index 0000000..0e4aaea --- /dev/null +++ b/src/test/data/validShow.ts @@ -0,0 +1,2224 @@ +export function validShow() { + return { + "available_markets": [ + "AD", + "AE", + "AG", + "AL", + "AM", + "AO", + "AR", + "AT", + "AU", + "AZ", + "BA", + "BB", + "BE", + "BF", + "BG", + "BH", + "BI", + "BJ", + "BN", + "BO", + "BR", + "BS", + "BT", + "BW", + "BZ", + "CA", + "CH", + "CI", + "CL", + "CM", + "CO", + "CR", + "CV", + "CW", + "CY", + "CZ", + "DE", + "DJ", + "DK", + "DM", + "DO", + "DZ", + "EC", + "EE", + "EG", + "ES", + "FI", + "FJ", + "FM", + "FR", + "GA", + "GB", + "GD", + "GE", + "GH", + "GM", + "GN", + "GQ", + "GR", + "GT", + "GW", + "GY", + "HK", + "HN", + "HR", + "HT", + "HU", + "ID", + "IE", + "IL", + "IN", + "IS", + "IT", + "JM", + "JO", + "JP", + "KE", + "KH", + "KI", + "KM", + "KN", + "KR", + "KW", + "LA", + "LB", + "LC", + "LI", + "LR", + "LS", + "LT", + "LU", + "LV", + "MA", + "MC", + "ME", + "MG", + "MH", + "MK", + "ML", + "MN", + "MO", + "MR", + "MT", + "MU", + "MV", + "MW", + "MX", + "MY", + "MZ", + "NA", + "NE", + "NG", + "NI", + "NL", + "NO", + "NP", + "NR", + "NZ", + "OM", + "PA", + "PE", + "PG", + "PH", + "PL", + "PS", + "PT", + "PW", + "PY", + "QA", + "RO", + "RS", + "RW", + "SA", + "SB", + "SC", + "SE", + "SG", + "SI", + "SK", + "SL", + "SM", + "SN", + "SR", + "ST", + "SV", + "SZ", + "TD", + "TG", + "TH", + "TL", + "TN", + "TO", + "TR", + "TT", + "TV", + "TW", + "TZ", + "UA", + "US", + "UY", + "UZ", + "VC", + "VN", + "VU", + "WS", + "XC", + "XK", + "ZA", + "ZM", + "ZW" + ], + "copyrights": [ + + ], + "description": "A podcast looking back at The Simpsons, episode by episode, discussing and analyzing its importance, history, and greatness.", + "episodes": { + "href": "https://api.spotify.com/v1/shows/4ZbloPxqlAqHbbP4EnivIB/episodes?offset=0&limit=50&market=GB", + "items": [ + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/0b467e7870140b2ffcc0717d28b7a88b370ba05d", + "description": "Tonight, Robbie and Matt are joined by Ryan Rogers (of the Juras-sick Park-cast) to discuss Episode MABF07, Stealing First Base, the fifteenth episode of Season Twenty-One. They talk about Michelle Obama, Sarah Silverman, and Nelson. Listen to the Juras-sick Park-Cast! Support the show on Patreon! Listener Question of the Week: What is your favorite MartinContinue Reading…", + "duration_ms": 6077465, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/2CKKmFPsAHBvsQTAvMi11R" + }, + "href": "https://api.spotify.com/v1/episodes/2CKKmFPsAHBvsQTAvMi11R", + "html_description": "

Tonight, Robbie and Matt are joined by Ryan Rogers (of the Juras-sick Park-cast) to discuss Episode MABF07, Stealing First Base, the fifteenth episode of Season Twenty-One. They talk about Michelle Obama, Sarah Silverman, and Nelson.


Listen to the Juras-sick Park-Cast!


Support the show on Patreon!


Listener Question of the Week: What is your favorite Martin Prince quote?

", + "id": "2CKKmFPsAHBvsQTAvMi11R", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "460 – Stealing First Base (w Ryan Rogers)", + "release_date": "2023-03-13", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:2CKKmFPsAHBvsQTAvMi11R" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/b2ef78d486fe92b389e59f05c7d88be19c41c0e8", + "description": "Tonight, Matt and Robbie discuss Episode MABF04, Postcards from the Wedge, the fourteenth episode of Season Twenty-One. They talk about homework, abandoned subways, and being better than last week. Support the show on Patreon! Listener Question of the Week: What’s your go-to comfort episode of The Simpsons?", + "duration_ms": 4210070, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/426wSvCcbTdPRIGSzcZSfM" + }, + "href": "https://api.spotify.com/v1/episodes/426wSvCcbTdPRIGSzcZSfM", + "html_description": "

Tonight, Matt and Robbie discuss Episode MABF04, Postcards from the Wedge, the fourteenth episode of Season Twenty-One. They talk about homework, abandoned subways, and being better than last week.


Support the show on Patreon!


Listener Question of the Week: What’s your go-to comfort episode of The Simpsons?

", + "id": "426wSvCcbTdPRIGSzcZSfM", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "459 – Postcards from the Wedge", + "release_date": "2023-03-06", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:426wSvCcbTdPRIGSzcZSfM" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/a0603530486d039da110f45a02811a7c88312f3a", + "description": "Tonight, Matt and Robbie talk about Episode MABF06, The Color Yellow, the thirteenth episode of Season Twenty-One. They talk about racism, nonsense, and how easy is it to not write an episode about slavery. Support the show on Patreon! Listener Question of the Week: What episode have you seen the most?", + "duration_ms": 4345628, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/7CXdz8vL5XEjFkAa4p5MgP" + }, + "href": "https://api.spotify.com/v1/episodes/7CXdz8vL5XEjFkAa4p5MgP", + "html_description": "

Tonight, Matt and Robbie talk about Episode MABF06, The Color Yellow, the thirteenth episode of Season Twenty-One. They talk about racism, nonsense, and how easy is it to not write an episode about slavery.


Support the show on Patreon!


Listener Question of the Week: What episode have you seen the most?

", + "id": "7CXdz8vL5XEjFkAa4p5MgP", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "458 – The Color Yellow", + "release_date": "2023-02-27", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:7CXdz8vL5XEjFkAa4p5MgP" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/f50319865f6a2dc39a9c47a5446e198dc55f5ef8", + "description": "Tonight, Matt and Robbie discuss Episode MABF05, Boy Meets Curl, the twelfth episode of Season Twenty-One. They talk about curling, the Olympics, and pins. Support the show on Patreon! Listener Question of the Week: What’s your favorite Olympic sport?", + "duration_ms": 4306533, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/0Kmq0q8zZDqskTwaVmcIas" + }, + "href": "https://api.spotify.com/v1/episodes/0Kmq0q8zZDqskTwaVmcIas", + "html_description": "

Tonight, Matt and Robbie discuss Episode MABF05, Boy Meets Curl, the twelfth episode of Season Twenty-One. They talk about curling, the Olympics, and pins.


Support the show on Patreon!


Listener Question of the Week: What’s your favorite Olympic sport?

", + "id": "0Kmq0q8zZDqskTwaVmcIas", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "457 – Boy Meets Curl", + "release_date": "2023-02-20", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:0Kmq0q8zZDqskTwaVmcIas" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/c1fb3d28c34f11f53ad8e497f94c04e1090d297d", + "description": "Tonight, Matt and Robbie discuss Episode MABF03, Million Dollar Maybe, the eleventh episode of Season Twenty-One. They talk about filler, nothing, and emptiness. Support the show on Patreon! Listener Question of the Week: What’s your favorite video game console?", + "duration_ms": 4253932, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/3aFCnxPbr8xHIJMfQdi0xO" + }, + "href": "https://api.spotify.com/v1/episodes/3aFCnxPbr8xHIJMfQdi0xO", + "html_description": "

Tonight, Matt and Robbie discuss Episode MABF03, Million Dollar Maybe, the eleventh episode of Season Twenty-One. They talk about filler, nothing, and emptiness.


Support the show on Patreon!


Listener Question of the Week: What’s your favorite video game console?

", + "id": "3aFCnxPbr8xHIJMfQdi0xO", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "456 – Million Dollar Maybe", + "release_date": "2023-02-13", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:3aFCnxPbr8xHIJMfQdi0xO" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/97bed0c184b3d34da0f366c89a1ef1fb2878bc2b", + "description": "Tonight, Matt and Robbie discuss Episode LABF20, Once Upon a Time in Springfield, the tenth episode of Season Twenty-One. They talk about princesses, gross relationship dynamics, and Krusty. Support the show on Patreon! Listener Question of the Week: What’s your favorite comic strip (including webcomics)?", + "duration_ms": 5457988, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/1ckeE9usaNWKds3YwmRhFy" + }, + "href": "https://api.spotify.com/v1/episodes/1ckeE9usaNWKds3YwmRhFy", + "html_description": "

Tonight, Matt and Robbie discuss Episode LABF20, Once Upon a Time in Springfield, the tenth episode of Season Twenty-One. They talk about princesses, gross relationship dynamics, and Krusty.


Support the show on Patreon!


Listener Question of the Week: What’s your favorite comic strip (including webcomics)?

", + "id": "1ckeE9usaNWKds3YwmRhFy", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "455 – Once Upon a Time in Springfield", + "release_date": "2023-02-06", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:1ckeE9usaNWKds3YwmRhFy" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/509146643ca8f5c20dbc710b9cdb6f40683aada3", + "description": "Tonight, Matt and Robbie discuss Episode MABF02, Thursdays with Abie, the ninth episode of Season Twenty-One. They talk about Mitch Albom, human behavior, and Abe Simpson. Support the show on Patreon Listener Question of the Week: What’s your favorite non-fiction book?", + "duration_ms": 4600074, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/58mHyrYTwkoA5InfBtUHCN" + }, + "href": "https://api.spotify.com/v1/episodes/58mHyrYTwkoA5InfBtUHCN", + "html_description": "

Tonight, Matt and Robbie discuss Episode MABF02, Thursdays with Abie, the ninth episode of Season Twenty-One. They talk about Mitch Albom, human behavior, and Abe Simpson.


Support the show on Patreon


Listener Question of the Week: What’s your favorite non-fiction book?

", + "id": "58mHyrYTwkoA5InfBtUHCN", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "454 – Thursdays with Abie", + "release_date": "2023-01-30", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:58mHyrYTwkoA5InfBtUHCN" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/c2aa2f3b2a778576deddbcff798381bd1ab64bb2", + "description": "Tonight, Matt and Robbie discuss Episode MABF01, Oh Brother, Where Bart Thou?, the eighth episode of Season Twenty-One. They talk about Bart, brothers, and the Smothers Brothers. Support the show on Patreon! Listener Question of the Week: What is your idea for a new reoccurring, supporting character?", + "duration_ms": 5266555, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/2GQ0oFj0cHsHDBOvCad5Tt" + }, + "href": "https://api.spotify.com/v1/episodes/2GQ0oFj0cHsHDBOvCad5Tt", + "html_description": "

Tonight, Matt and Robbie discuss Episode MABF01, Oh Brother, Where Bart Thou?, the eighth episode of Season Twenty-One. They talk about Bart, brothers, and the Smothers Brothers.


Support the show on Patreon!


Listener Question of the Week: What is your idea for a new reoccurring, supporting character?

", + "id": "2GQ0oFj0cHsHDBOvCad5Tt", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "453 – O Brother, Where Bart Thou?", + "release_date": "2023-01-23", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:2GQ0oFj0cHsHDBOvCad5Tt" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/325178fa6f65d0b1b9d66451d7153d81be99194c", + "description": "Tonight, Matt and Robbie discuss Episode LABF19, Rednecks and Broomsticks, the seventh episode of Season Twenty-One. They talk about wiccans, hillbilly jokes, and nothing. Support the show on Patreon! Listener Question of the Week: What’s your favorite Neve Campbell movie?", + "duration_ms": 3474787, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/7GXFYdxl04boIhfqlSAWV5" + }, + "href": "https://api.spotify.com/v1/episodes/7GXFYdxl04boIhfqlSAWV5", + "html_description": "

Tonight, Matt and Robbie discuss Episode LABF19, Rednecks and Broomsticks, the seventh episode of Season Twenty-One. They talk about wiccans, hillbilly jokes, and nothing.


Support the show on Patreon!


Listener Question of the Week: What’s your favorite Neve Campbell movie?

", + "id": "7GXFYdxl04boIhfqlSAWV5", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "452 – Rednecks and Broomsticks", + "release_date": "2023-01-16", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:7GXFYdxl04boIhfqlSAWV5" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/51adaa18e802250655f871631848f7685b17e1d8", + "description": "Tonight, Matt and Robbie discuss Episode LABF18, Pranks and Greens, the sixth episode of Season Twenty-One. They talk about pranks, Bart, and health food. Support the show on Patreon! Listener Question of the Week: What’s your favorite Jonah Hill movie?", + "duration_ms": 4293032, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/4dVtv6iW21M5Zuav1GBJdj" + }, + "href": "https://api.spotify.com/v1/episodes/4dVtv6iW21M5Zuav1GBJdj", + "html_description": "

Tonight, Matt and Robbie discuss Episode LABF18, Pranks and Greens, the sixth episode of Season Twenty-One. They talk about pranks, Bart, and health food.


Support the show on Patreon!


Listener Question of the Week: What’s your favorite Jonah Hill movie?

", + "id": "4dVtv6iW21M5Zuav1GBJdj", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "451 – Pranks and Greens", + "release_date": "2023-01-09", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:4dVtv6iW21M5Zuav1GBJdj" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/b1dc8eb7357c93ec9df8f59d7889a8f29743156e", + "description": "Matt and Robbie answer YOUR burning questions in this year’s holiday mailbag!", + "duration_ms": 4461592, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/7xlydBzzACKztXDa3P96cd" + }, + "href": "https://api.spotify.com/v1/episodes/7xlydBzzACKztXDa3P96cd", + "html_description": "Matt and Robbie answer YOUR burning questions in this year’s holiday mailbag!", + "id": "7xlydBzzACKztXDa3P96cd", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "450 – Holiday Mailbag 2022", + "release_date": "2022-12-26", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:7xlydBzzACKztXDa3P96cd" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/23a3363c11ccb346b443624ad90ef0db9c82e068", + "description": "Tonight, Matt and Robbie discuss Episode LABF17, The Devil Wears Nada, the fifth episode of Season Twenty-One. They talk about pin-up calendars, Fission Week, and cooking with Flanders. Support the show on Patreon! Listener Question of the Week: What’s your favorite Carl quote?", + "duration_ms": 4477470, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/7szZ1mRnhn5NBx9uraxzHP" + }, + "href": "https://api.spotify.com/v1/episodes/7szZ1mRnhn5NBx9uraxzHP", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF17, The Devil Wears Nada, the fifth episode of Season Twenty-One. They talk about pin-up calendars, Fission Week, and cooking with Flanders. Support the show on Patreon! Listener Question of the Week: What’s your favorite Carl quote?", + "id": "7szZ1mRnhn5NBx9uraxzHP", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "449 – The Devil Wears Nada", + "release_date": "2022-12-19", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:7szZ1mRnhn5NBx9uraxzHP" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/f1937d98a8ad13835ea6eba2d5e5d6e120c5ae5f", + "description": "Tonight, Matt and Robbie discuss Episode LABF14, Treehouse of Horror XX, the fourth episode of Season Twenty-One. They talk about Hitchcock, zombies, and strange songs. Support the show on Patreon! Listener Question of the Week: What’s your favorite Hitchcock film?", + "duration_ms": 4172766, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/57yXA2phndXGP7gaznzNKQ" + }, + "href": "https://api.spotify.com/v1/episodes/57yXA2phndXGP7gaznzNKQ", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF14, Treehouse of Horror XX, the fourth episode of Season Twenty-One. They talk about Hitchcock, zombies, and strange songs. Support the show on Patreon! Listener Question of the Week: What’s your favorite Hitchcock film?", + "id": "57yXA2phndXGP7gaznzNKQ", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "448 – Treehouse of Horror XX", + "release_date": "2022-12-12", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:57yXA2phndXGP7gaznzNKQ" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/c6fc5f1a0d4bfd2277936ba36c23c8c4b4a6bf6d", + "description": "Tonight, Matt and Robbie discuss Episode LABF16, The Great Wife Hope, the third episode of Season Twenty-One. They talk about MMA, Marge’s kindness, and a complete and total lack of sincerity from The Simpsons. Support the show on Patreon! Listener Question of the Week: What is your favorite moment of cartoon violence in The Simpsons?", + "duration_ms": 5075550, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/3GiZhhkiXymJZ32sCFnttp" + }, + "href": "https://api.spotify.com/v1/episodes/3GiZhhkiXymJZ32sCFnttp", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF16, The Great Wife Hope, the third episode of Season Twenty-One. They talk about MMA, Marge’s kindness, and a complete and total lack of sincerity from The Simpsons. Support the show on Patreon! Listener Question of the Week: What is your favorite moment of cartoon violence in The Simpsons?", + "id": "3GiZhhkiXymJZ32sCFnttp", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "447 – The Great Wife Hope", + "release_date": "2022-12-05", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:3GiZhhkiXymJZ32sCFnttp" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/eec0e49847bab1bd5f5cf94544b12f29ada37651", + "description": "Tonight, Matt and Robbie discuss Episode LABF15, Bart Gets a Z, the second episode of Season Twenty-One. They talk about Edna, cell phones, and muffin stores. Buy Robbie’s new book, The Other! Support the show on Patreon Listener Question of the Week: What’s your favorite Edna Krabappel quote?", + "duration_ms": 4947785, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/4N0govIwm1jIKL6M3Sp5Fs" + }, + "href": "https://api.spotify.com/v1/episodes/4N0govIwm1jIKL6M3Sp5Fs", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF15, Bart Gets a Z, the second episode of Season Twenty-One. They talk about Edna, cell phones, and muffin stores. Buy Robbie’s new book, The Other! Support the show on Patreon Listener Question of the Week: What’s your favorite Edna Krabappel quote?", + "id": "4N0govIwm1jIKL6M3Sp5Fs", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "446 – Bart Gets a Z", + "release_date": "2022-11-28", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:4N0govIwm1jIKL6M3Sp5Fs" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/6bdf6e6dc0dd47fcc26aebd07fca5a6b58796d0a", + "description": "Tonight, Matt and Robbie discuss Episode LABF13, Homer the Whopper, the first episode of Season Twenty-One. They talk about superhero movies, better episodes, and sincerity. Get your copy of Robbie’s new book, THE OTHER Support the show on Patreon Listener Question of the Week: What’s your favorite Comic Book Guy quote?", + "duration_ms": 4751469, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/2zCmjk3ze0sga405IA51BZ" + }, + "href": "https://api.spotify.com/v1/episodes/2zCmjk3ze0sga405IA51BZ", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF13, Homer the Whopper, the first episode of Season Twenty-One. They talk about superhero movies, better episodes, and sincerity. Get your copy of Robbie’s new book, THE OTHER Support the show on Patreon Listener Question of the Week: What’s your favorite Comic Book Guy quote?", + "id": "2zCmjk3ze0sga405IA51BZ", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "445 – Homer the Whopper", + "release_date": "2022-11-21", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:2zCmjk3ze0sga405IA51BZ" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/f381f9ececcea862f39fcfd708807aa7aa1c1455", + "description": "Tonight, Matt and Robbie discuss Episode LABF12, Coming to Homerica, the final episode of Season Twenty. They talk about immigration, walls, and barley farming. Pre-Order The Other Support the show on the Patreon! Listener Question of the Week: What’s your favorite moment from Season Twenty?", + "duration_ms": 5243613, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/6gQCBJFhvMTZ6YEYhORGEV" + }, + "href": "https://api.spotify.com/v1/episodes/6gQCBJFhvMTZ6YEYhORGEV", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF12, Coming to Homerica, the final episode of Season Twenty. They talk about immigration, walls, and barley farming. Pre-Order The Other Support the show on the Patreon! Listener Question of the Week: What’s your favorite moment from Season Twenty?", + "id": "6gQCBJFhvMTZ6YEYhORGEV", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "444 – Coming to Homerica", + "release_date": "2022-11-14", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:6gQCBJFhvMTZ6YEYhORGEV" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/fb862043f884ea5f5549bbae1d82761a48b98c3c", + "description": "Tonight, Matt and Robbie discuss Episode LABF09, Four Great Women and a Manicure, the twentieth episode of Season Twenty. They talk about themes in anthology, Jodie Foster, and Macbeth. Pre-Order The Other Support the show on Patreon Listener Question of the Week: What theme would you use for a Simpsons anthology episode?", + "duration_ms": 5514327, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/7jvNyEBCzTdbn1BBqvOPA1" + }, + "href": "https://api.spotify.com/v1/episodes/7jvNyEBCzTdbn1BBqvOPA1", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF09, Four Great Women and a Manicure, the twentieth episode of Season Twenty. They talk about themes in anthology, Jodie Foster, and Macbeth. Pre-Order The Other Support the show on Patreon Listener Question of the Week: What theme would you use for a Simpsons anthology episode?", + "id": "7jvNyEBCzTdbn1BBqvOPA1", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "443 – Four Great Women and a Manicure", + "release_date": "2022-11-07", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:7jvNyEBCzTdbn1BBqvOPA1" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/f948cd307edf9cfcccd04a5362d062361afba734", + "description": "Tonight, Matt and Robbie discuss Episode LABF10, Waverly Hills, 9-0-2-1-D’oh, the nineteenth episode of Season Twenty. They talk about apartments, popularity, and Alaska Nebraska. Pre-Order The Other Support the show on Patreon Listener Question of the Week: What’s your favorite fictional setting that isn’t Springfield?", + "duration_ms": 4771412, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/5GfNpo7CSz0gMkEgfosWkj" + }, + "href": "https://api.spotify.com/v1/episodes/5GfNpo7CSz0gMkEgfosWkj", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF10, Waverly Hills, 9-0-2-1-D’oh, the nineteenth episode of Season Twenty. They talk about apartments, popularity, and Alaska Nebraska. Pre-Order The Other Support the show on Patreon Listener Question of the Week: What’s your favorite fictional setting that isn’t Springfield?", + "id": "5GfNpo7CSz0gMkEgfosWkj", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "442 – Waverly Hills, 9-0-2-1-D’oh", + "release_date": "2022-10-31", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:5GfNpo7CSz0gMkEgfosWkj" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/b909b456bfa3e042ff5589f44318b137f9936211", + "description": "Tonight, Matt and Robbie discuss Episode LABF08, Father Knows Worst, the eighteenth episode of Season Twenty. They talk about lucky rolls, the realism curve, and water heaters. Support the show on Patreon! Listener Question of the Week: What’s your favorite movie about parenting?", + "duration_ms": 5525889, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/03OwMkCzlkckDiYpqMfab2" + }, + "href": "https://api.spotify.com/v1/episodes/03OwMkCzlkckDiYpqMfab2", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF08, Father Knows Worst, the eighteenth episode of Season Twenty. They talk about lucky rolls, the realism curve, and water heaters. Support the show on Patreon! Listener Question of the Week: What’s your favorite movie about parenting?", + "id": "03OwMkCzlkckDiYpqMfab2", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "441 – Father Knows Worst", + "release_date": "2022-10-24", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:03OwMkCzlkckDiYpqMfab2" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/0fd3ee00584c2c5762876ffeb1a2613567a4ac8f", + "description": "Tonight, Matt and Robbie discuss Episode LABF07, The Good, the Sad, and the Drugly, the seventeenth episode of Season Twenty. They talk about Bart’s girlfriends, drugs, and friendships. Support the show on the Patreon! Listener Question of the Week: What’s your favorite Anne Hathaway movie?", + "duration_ms": 4712837, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/4269D6LLvYZZLWu2qLS2kg" + }, + "href": "https://api.spotify.com/v1/episodes/4269D6LLvYZZLWu2qLS2kg", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF07, The Good, the Sad, and the Drugly, the seventeenth episode of Season Twenty. They talk about Bart’s girlfriends, drugs, and friendships. Support the show on the Patreon! Listener Question of the Week: What’s your favorite Anne Hathaway movie?", + "id": "4269D6LLvYZZLWu2qLS2kg", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "440 – The Good, the Sad, and the Drugly", + "release_date": "2022-10-17", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:4269D6LLvYZZLWu2qLS2kg" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/61ad3201ab1ce5d24364ec5142ef6c38d0354f80", + "description": "Tonight, Matt and Robbie discuss Episode LABF06, Eeny Teeny Maya Moe, the sixteenth episode of Season Twenty. They talk about Maya, easy jokes, and giant Kearney babies beating up Homer. Support the show on Patreon! Listener Question of the Week: What’s your favorite movie with a baby in it?", + "duration_ms": 5738518, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/3Stp9u0dQP703fTUEYnfSX" + }, + "href": "https://api.spotify.com/v1/episodes/3Stp9u0dQP703fTUEYnfSX", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF06, Eeny Teeny Maya Moe, the sixteenth episode of Season Twenty. They talk about Maya, easy jokes, and giant Kearney babies beating up Homer. Support the show on Patreon! Listener Question of the Week: What’s your favorite movie with a baby in it?", + "id": "3Stp9u0dQP703fTUEYnfSX", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "439 – Eeny Teeny Maya Moe", + "release_date": "2022-10-10", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:3Stp9u0dQP703fTUEYnfSX" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/6aeae772776de9fdb5ad9d5dfa17fe9c905b2a49", + "description": "Tonight, Matt and Robbie discuss Episode LABF05, Wedding for Disaster, the fifteenth episode of Season Twenty. They talk about weddings, kidnappings, and Sideshow Bob bait and switches. Support the show on Patreon! Listener Question of the Week: What’s your favorite movie featuring a wedding?", + "duration_ms": 5105229, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/7ISxmLZ2flOUxO892dSawz" + }, + "href": "https://api.spotify.com/v1/episodes/7ISxmLZ2flOUxO892dSawz", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF05, Wedding for Disaster, the fifteenth episode of Season Twenty. They talk about weddings, kidnappings, and Sideshow Bob bait and switches. Support the show on Patreon! Listener Question of the Week: What’s your favorite movie featuring a wedding?", + "id": "7ISxmLZ2flOUxO892dSawz", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "438 – Wedding for Disaster", + "release_date": "2022-10-03", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:7ISxmLZ2flOUxO892dSawz" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/fa6401ca737883068a9872d140addae9fbde6486", + "description": "Tonight, Matt and Robbie discuss Episode LABF11, In the Name of the Grandfather, the fourteenth episode of Season Twenty. They talk about Ireland, leprechauns, and literally no story. Support the show on Patreon! Listener Question of the Week: Who’s your favorite Irish actor and what’s your favorite thing they’ve been in?", + "duration_ms": 3965640, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/1a4XIlwN3HHfEKzbPK9PB1" + }, + "href": "https://api.spotify.com/v1/episodes/1a4XIlwN3HHfEKzbPK9PB1", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF11, In the Name of the Grandfather, the fourteenth episode of Season Twenty. They talk about Ireland, leprechauns, and literally no story. Support the show on Patreon! Listener Question of the Week: Who’s your favorite Irish actor and what’s your favorite thing they’ve been in?", + "id": "1a4XIlwN3HHfEKzbPK9PB1", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "437 – In the Name of the Grandfather", + "release_date": "2022-09-26", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:1a4XIlwN3HHfEKzbPK9PB1" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/3a4d3cf9041b422d5f8f7ab9f076acf1388bddc6", + "description": "Tonight, Matt and Robbie are joined by Andrew Bloom to discuss Episode LABF04, Gone Maggie Gone, the thirteenth episode of Season Twenty. They talk about magic gem babies, The Da Vinci Code, and Robbie losing his mind. Support the show on Patreon! Listener Question of the Week – What’s your favorite thriller?", + "duration_ms": 7193938, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/3jNBIR7m6YeF2iMqL0jlON" + }, + "href": "https://api.spotify.com/v1/episodes/3jNBIR7m6YeF2iMqL0jlON", + "html_description": "Tonight, Matt and Robbie are joined by Andrew Bloom to discuss Episode LABF04, Gone Maggie Gone, the thirteenth episode of Season Twenty. They talk about magic gem babies, The Da Vinci Code, and Robbie losing his mind. Support the show on Patreon! Listener Question of the Week – What’s your favorite thriller?", + "id": "3jNBIR7m6YeF2iMqL0jlON", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "436 – Gone Maggie Gone (w Andrew Bloom)", + "release_date": "2022-09-19", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:3jNBIR7m6YeF2iMqL0jlON" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/0db8819730dc2a42256d9cbbfb3ff2f0d883cee0", + "description": "Tonight, Matt and Robbie discuss Episode LABF03, No Loan Again, Naturally, the twelfth episode of Season Twenty. They talk about loans, mortgages, and things that should just not be Simpsons episodes. Support the show on Patreon! Listener Question of the Week: What’s your favorite Flanders quote?", + "duration_ms": 4834689, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/2Fvyyerd234Yn8xUL9I3sQ" + }, + "href": "https://api.spotify.com/v1/episodes/2Fvyyerd234Yn8xUL9I3sQ", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF03, No Loan Again, Naturally, the twelfth episode of Season Twenty. They talk about loans, mortgages, and things that should just not be Simpsons episodes. Support the show on Patreon! Listener Question of the Week: What’s your favorite Flanders quote?", + "id": "2Fvyyerd234Yn8xUL9I3sQ", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "435 – No Loan Again, Naturally", + "release_date": "2022-09-12", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:2Fvyyerd234Yn8xUL9I3sQ" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/3d8e7235df0748ab0fb79df8226dcdd40b942d91", + "description": "Tonight, Matt and Robbie discuss Episode LABF02, How the Test Was Won, the eleventh episode of Season Twenty. They talk about standardized testing, Ralph’s powers, and insurance. Support the show on Patreon! Listener Question of the Week: What is your favorite sitcom that isn’t The Simpsons?", + "duration_ms": 5042440, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/4EcP2j1JsLrMKA4Rb0w2Ei" + }, + "href": "https://api.spotify.com/v1/episodes/4EcP2j1JsLrMKA4Rb0w2Ei", + "html_description": "Tonight, Matt and Robbie discuss Episode LABF02, How the Test Was Won, the eleventh episode of Season Twenty. They talk about standardized testing, Ralph’s powers, and insurance. Support the show on Patreon! Listener Question of the Week: What is your favorite sitcom that isn’t The Simpsons?", + "id": "4EcP2j1JsLrMKA4Rb0w2Ei", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "434 – How the Test Was Won", + "release_date": "2022-09-05", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:4EcP2j1JsLrMKA4Rb0w2Ei" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/d203bbe753262cab04ae82d44452a595a8b2b7da", + "description": "Tonight, Matt and Robbie are joined by Bryan Green to discuss Episode LABF01, Take My Life, Please, tenth episode of Season Twenty. They talk about magic pasta sauce, magical realism, and flashbacks. Support the show on Patreon! Listener Question of the Week: What’s your favorite quote from a flashback?", + "duration_ms": 6517465, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/146yb2i6DtTp9cEqwHoDje" + }, + "href": "https://api.spotify.com/v1/episodes/146yb2i6DtTp9cEqwHoDje", + "html_description": "Tonight, Matt and Robbie are joined by Bryan Green to discuss Episode LABF01, Take My Life, Please, tenth episode of Season Twenty. They talk about magic pasta sauce, magical realism, and flashbacks. Support the show on Patreon! Listener Question of the Week: What’s your favorite quote from a flashback?", + "id": "146yb2i6DtTp9cEqwHoDje", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "433 – Take My Life, Please (w Bryan Green)", + "release_date": "2022-08-29", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:146yb2i6DtTp9cEqwHoDje" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/d7d299ee531398f86084337bcaa4d4774bdf07f4", + "description": "Tonight, Matt and Robbie discuss Episode KABF22, Lisa the Drama Queen, the ninth episode of Season Twenty. They talk about fantasy worlds, zero jokes, and John Grisham. Support the show on Patreon! Listener Question of the Week: What’s your favorite quote from the bullies?", + "duration_ms": 4894414, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/408FVh0BcpDWgoRZGFGnef" + }, + "href": "https://api.spotify.com/v1/episodes/408FVh0BcpDWgoRZGFGnef", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF22, Lisa the Drama Queen, the ninth episode of Season Twenty. They talk about fantasy worlds, zero jokes, and John Grisham. Support the show on Patreon! Listener Question of the Week: What’s your favorite quote from the bullies?", + "id": "408FVh0BcpDWgoRZGFGnef", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "432 – Lisa the Drama Queen", + "release_date": "2022-08-22", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:408FVh0BcpDWgoRZGFGnef" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/25ae4c3bd7a93116657d48647e5e1fb19aad65d9", + "description": "Tonight, Matt and Robbie discuss Episode KABF21, The Burns and the Bees, the eighth episode of Season Twenty. They talk about bee plots, billionaires, and racist bees. Support the show on Patreon! Listener Question of the Week: Who is your least favorite guest?", + "duration_ms": 5233003, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/5VUBtPTCQf6POQmopNa3ty" + }, + "href": "https://api.spotify.com/v1/episodes/5VUBtPTCQf6POQmopNa3ty", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF21, The Burns and the Bees, the eighth episode of Season Twenty. They talk about bee plots, billionaires, and racist bees. Support the show on Patreon! Listener Question of the Week: Who is your least favorite guest?", + "id": "5VUBtPTCQf6POQmopNa3ty", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "431 – The Burns and the Bees", + "release_date": "2022-08-15", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:5VUBtPTCQf6POQmopNa3ty" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/74f8055c5ba544779b7d26dd4e7bbaf0e8522789", + "description": "Tonight, Matt and Robbie discuss Episode KABF20, MyPods and Boomsticks, the seventh episode of Season Twenty. They talk about racism, racist jokes, and inexplicable awards. Support us on Patreon! Listener Question of the Week: Who is your favorite female guest star?", + "duration_ms": 6780268, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/5TILQd4YyyzIqOsHAbD3fL" + }, + "href": "https://api.spotify.com/v1/episodes/5TILQd4YyyzIqOsHAbD3fL", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF20, MyPods and Boomsticks, the seventh episode of Season Twenty. They talk about racism, racist jokes, and inexplicable awards. Support us on Patreon! Listener Question of the Week: Who is your favorite female guest star?", + "id": "5TILQd4YyyzIqOsHAbD3fL", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "430 – Mypods and Boomsticks", + "release_date": "2022-08-08", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:5TILQd4YyyzIqOsHAbD3fL" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/06b23069ebeec2f8d6914ba27f3a235d0b1c3e98", + "description": "Tonight, Matt and Robbie discuss Episode KABF19, Homer and Lisa Exchange Cross Words, the sixth episode of Season Twenty. They talk about crossword puzzles, pointless B plots, and Homer infecting the A plot. Support us on Patreon! Listener Question of the Week: Who is your favorite lesser-known guess star?", + "duration_ms": 4832065, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/6S7wsQUOYL961XOa5UvItx" + }, + "href": "https://api.spotify.com/v1/episodes/6S7wsQUOYL961XOa5UvItx", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF19, Homer and Lisa Exchange Cross Words, the sixth episode of Season Twenty. They talk about crossword puzzles, pointless B plots, and Homer infecting the A plot. Support us on Patreon! Listener Question of the Week: Who is your favorite lesser-known guess star?", + "id": "6S7wsQUOYL961XOa5UvItx", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "429 – Homer and Lisa Exchange Cross Words", + "release_date": "2022-08-01", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:6S7wsQUOYL961XOa5UvItx" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/966f3d71dfd7986457109b9f26d73fa4e61ae8dc", + "description": "Tonight, Matt and Robbie discuss Episode KABF18, Dangerous Curves, the fifth episode of Season Twenty. They talk about non-linear storytelling, unrecognizable characters, and relationship episodes. Order Killer Hockey Mascot! Support us on Patreon! Listener Question of the Week: What’s your favorite quote from a flashback episode?", + "duration_ms": 5417533, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/3oENRT0e2sFSVfEuwgXSPK" + }, + "href": "https://api.spotify.com/v1/episodes/3oENRT0e2sFSVfEuwgXSPK", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF18, Dangerous Curves, the fifth episode of Season Twenty. They talk about non-linear storytelling, unrecognizable characters, and relationship episodes. Order Killer Hockey Mascot! Support us on Patreon! Listener Question of the Week: What’s your favorite quote from a flashback episode?", + "id": "3oENRT0e2sFSVfEuwgXSPK", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "428 – Dangerous Curves", + "release_date": "2022-07-25", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:3oENRT0e2sFSVfEuwgXSPK" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/840b2b51b25293e7101557b7e6a0918f23880d86", + "description": "Tonight, Matt and Robbie discuss Episode KABF16, Treehouse of Horror XIX, the fourth episode of Season Twenty. They talk about tepid parodies, zero jokes, and Charlie Brown. Pre-Order Killer Hockey Mascot! Support us on Patreon! Listener Question of the Week: What’s your favorite TOH quote?", + "duration_ms": 4235332, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/227cdrDgjbfeGVmQuz0Zne" + }, + "href": "https://api.spotify.com/v1/episodes/227cdrDgjbfeGVmQuz0Zne", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF16, Treehouse of Horror XIX, the fourth episode of Season Twenty. They talk about tepid parodies, zero jokes, and Charlie Brown. Pre-Order Killer Hockey Mascot! Support us on Patreon! Listener Question of the Week: What’s your favorite TOH quote?", + "id": "227cdrDgjbfeGVmQuz0Zne", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "427 – Treehouse of Horror XIX", + "release_date": "2022-07-18", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:227cdrDgjbfeGVmQuz0Zne" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/a7457f825eb62fb0eb21201c00059f1cd5a37d1e", + "description": "Tonight, Matt and Robbie discuss Episode KABF14, Double, Double, Boy in Trouble, the third episode of Season Twenty. They talk about doppelgangers, logistics, and robot vacuums. Pre-Order Killer Hockey Mascot! Support us on Patreon! Listener Question of the Week: What’s your favorite Lenny moment?", + "duration_ms": 5101478, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/1zrTXAm02Yom4UigtjhbO7" + }, + "href": "https://api.spotify.com/v1/episodes/1zrTXAm02Yom4UigtjhbO7", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF14, Double, Double, Boy in Trouble, the third episode of Season Twenty. They talk about doppelgangers, logistics, and robot vacuums. Pre-Order Killer Hockey Mascot! Support us on Patreon! Listener Question of the Week: What’s your favorite Lenny moment?", + "id": "1zrTXAm02Yom4UigtjhbO7", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "426 – Double, Double, Boy in Trouble", + "release_date": "2022-07-11", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:1zrTXAm02Yom4UigtjhbO7" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/df69d034e44d488b4b7d8550efe4f5907d98c712", + "description": "Tonight, Matt and Robbie discuss Episode KABF15, Lost Verizon, the second episode of Season Twenty. They talk about nonsense, filler, and Incan dieties. Pre-Order Killer Hockey Mascot Support us on Patreon! Listener Question of the Week: What’s your favorite Groundskeeper Willie quote?", + "duration_ms": 5100805, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/4Y8Hch3ayqTVXYOukIX2b5" + }, + "href": "https://api.spotify.com/v1/episodes/4Y8Hch3ayqTVXYOukIX2b5", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF15, Lost Verizon, the second episode of Season Twenty. They talk about nonsense, filler, and Incan dieties. Pre-Order Killer Hockey Mascot Support us on Patreon! Listener Question of the Week: What’s your favorite Groundskeeper Willie quote?", + "id": "4Y8Hch3ayqTVXYOukIX2b5", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "425 – Lost Verizon", + "release_date": "2022-07-04", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:4Y8Hch3ayqTVXYOukIX2b5" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/d35b0bd15b61b335d46cf3fc369cf22332c76fdc", + "description": "Tonight, we are joined by cartoonist Jeff Martin to discuss Episode KABF17, Sex, Pies, and Idiot Scrapes, the first episode of Season Twenty. They talk about erotic bakeries, bounty hunting, and parkour. Crowdfund Jeff’s new book, Hockeypocalypse: Slashers! Listen to Robbie’s appearance on the Juras-Sick Park-cast! Support us on Patreon! Listener Question of the Week:Continue Reading…", + "duration_ms": 7440614, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/1bviTTWtuWZ4xdPQms9Cc4" + }, + "href": "https://api.spotify.com/v1/episodes/1bviTTWtuWZ4xdPQms9Cc4", + "html_description": "Tonight, we are joined by cartoonist Jeff Martin to discuss Episode KABF17, Sex, Pies, and Idiot Scrapes, the first episode of Season Twenty. They talk about erotic bakeries, bounty hunting, and parkour. Crowdfund Jeff’s new book, Hockeypocalypse: Slashers! Listen to Robbie’s appearance on the Juras-Sick Park-cast! Support us on Patreon! Listener Question of the Week:

Continue Reading…

", + "id": "1bviTTWtuWZ4xdPQms9Cc4", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "424 – Sex, Pies, and Idiot Scrapes (w Jeff Martin)", + "release_date": "2022-06-27", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:1bviTTWtuWZ4xdPQms9Cc4" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/9a21ac014ead3cc9c04d334f8f7c7dc3aa1a2175", + "description": "Tonight, Matt and Robbie discuss Episode KABF13, All About Lisa, the twentieth and final episode of Season Nineteen. They talk about Hollywood, fame, and coin collecting. Support us on Patreon! Listener Question of the Week: What’s your favorite moment from Season 19?", + "duration_ms": 5028162, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/37V6zfOgwvGR4vZ8sk2Acj" + }, + "href": "https://api.spotify.com/v1/episodes/37V6zfOgwvGR4vZ8sk2Acj", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF13, All About Lisa, the twentieth and final episode of Season Nineteen. They talk about Hollywood, fame, and coin collecting. Support us on Patreon! Listener Question of the Week: What’s your favorite moment from Season 19?", + "id": "37V6zfOgwvGR4vZ8sk2Acj", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "423 – All About Lisa", + "release_date": "2022-06-20", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:37V6zfOgwvGR4vZ8sk2Acj" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/898289e7fd723dc4851aaeb50494038e5d859214", + "description": "Tonight, Matt and Robbie discuss Episode KABF12, Mona Leaves-a, the nineteenth episode of Season Nineteen. They talk about Mona, missile silos, and processing grief. Support us on Patreon! Listener Question of the Week: What’s your favorite fictional death?", + "duration_ms": 6383419, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/19j7F0IUnLhye0a6OIoFbp" + }, + "href": "https://api.spotify.com/v1/episodes/19j7F0IUnLhye0a6OIoFbp", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF12, Mona Leaves-a, the nineteenth episode of Season Nineteen. They talk about Mona, missile silos, and processing grief. Support us on Patreon! Listener Question of the Week: What’s your favorite fictional death?", + "id": "19j7F0IUnLhye0a6OIoFbp", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "422 – Mona Leaves-a", + "release_date": "2022-06-13", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:19j7F0IUnLhye0a6OIoFbp" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/d258e9ec584677f17441228967a2dc5df6a0ad55", + "description": "Tonight, Matt and Robbie discuss Episode KABF11, Any Given Sundance, the eighteenth episode of Season Nineteen. They talk about indie film, Lisa, and Jim Jarmusch. Support us on Patreon! Listener Question of the Week: What’s your favorite John C Reilly performance?", + "duration_ms": 4397683, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/3zwHZvhqrLJD4lSsyFKUkz" + }, + "href": "https://api.spotify.com/v1/episodes/3zwHZvhqrLJD4lSsyFKUkz", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF11, Any Given Sundance, the eighteenth episode of Season Nineteen. They talk about indie film, Lisa, and Jim Jarmusch. Support us on Patreon! Listener Question of the Week: What’s your favorite John C Reilly performance?", + "id": "3zwHZvhqrLJD4lSsyFKUkz", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "421 – Any Given Sundance", + "release_date": "2022-06-06", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:3zwHZvhqrLJD4lSsyFKUkz" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/cecba35750250a1a2af5a6ba717f83def439cdd8", + "description": "Tonight, Matt and Robbie discuss Episode KABF10, Apocalypse Cow, the seventeenth episode of Season Nineteen. They talk about cows, endless montages, and hilbilly jokes. Support us on Patreon! Listener Question of the Week: What’s your favorite Cletus quote?", + "duration_ms": 5936513, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/6AInd3aWXeEqE5mu7GNxaL" + }, + "href": "https://api.spotify.com/v1/episodes/6AInd3aWXeEqE5mu7GNxaL", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF10, Apocalypse Cow, the seventeenth episode of Season Nineteen. They talk about cows, endless montages, and hilbilly jokes. Support us on Patreon! Listener Question of the Week: What’s your favorite Cletus quote?", + "id": "6AInd3aWXeEqE5mu7GNxaL", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "420 – Apocalypse Cow", + "release_date": "2022-05-30", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:6AInd3aWXeEqE5mu7GNxaL" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/481c378cb83bf43b8062b1cdc3167db1b4105b5c", + "description": "Tonight, Matt and Robbie discuss Episode KABF09, Papa Don’t Leech, the sixteenth episode of Season Nineteen. They talk about Lurleen, murderous Homer, and deadbeat dads. Support us on Patreon! Listener Question of the Week: What one-off guest character would you bring back?", + "duration_ms": 5732647, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/6b8a3VEBTu4bnyt7JNv2p6" + }, + "href": "https://api.spotify.com/v1/episodes/6b8a3VEBTu4bnyt7JNv2p6", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF09, Papa Don’t Leech, the sixteenth episode of Season Nineteen. They talk about Lurleen, murderous Homer, and deadbeat dads. Support us on Patreon! Listener Question of the Week: What one-off guest character would you bring back?", + "id": "6b8a3VEBTu4bnyt7JNv2p6", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "419 – Papa Don’t Leech", + "release_date": "2022-05-23", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:6b8a3VEBTu4bnyt7JNv2p6" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/b75357e3597023fe91db307d2bb7a73b007be151", + "description": "Tonight, Matt and Robbie discuss Episode KABF08, Smoke on the Daughter, the fifteenth episode of Season Nineteen. Support us on Patreon! Listener Question of the Week: What is your favorite fictional animal character?", + "duration_ms": 5874123, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/37zETjNvuIZoNI0fEWdFdn" + }, + "href": "https://api.spotify.com/v1/episodes/37zETjNvuIZoNI0fEWdFdn", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF08, Smoke on the Daughter, the fifteenth episode of Season Nineteen. Support us on Patreon! Listener Question of the Week: What is your favorite fictional animal character?", + "id": "37zETjNvuIZoNI0fEWdFdn", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "418 – Smoke on the Daughter", + "release_date": "2022-05-16", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:37zETjNvuIZoNI0fEWdFdn" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/f06bb0fd8df0bab4d6ea932ce183d877cba86e6e", + "description": "Tonight, Matt and Robbie discuss Episode KABF07, Dial N for Nerder, the fourteenth episode of Season Nineteen. They talk about Columbo, murder mysteries, and terrible, terrible B plots. Support us on Patreon! Listener Question of the Week: What’s your favorite fictional detective?", + "duration_ms": 5677321, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/13G46dEM8suYGazAdauj3g" + }, + "href": "https://api.spotify.com/v1/episodes/13G46dEM8suYGazAdauj3g", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF07, Dial N for Nerder, the fourteenth episode of Season Nineteen. They talk about Columbo, murder mysteries, and terrible, terrible B plots. Support us on Patreon! Listener Question of the Week: What’s your favorite fictional detective?", + "id": "13G46dEM8suYGazAdauj3g", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "417 – Dial N for Nerder", + "release_date": "2022-05-09", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:13G46dEM8suYGazAdauj3g" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/b0fde1455761b2cbb911063a82e8b8b8ceda9cde", + "description": "Tonight, Matt and Robbie discuss Episode KABF06, The Debarted, the thirteenth episode of Season Nineteen. They talk about bad B plots, good pastiches, and enjoyable episodes. Support us on Patreon! Listener Question of the Week: What’s your favorite ending to a movie?", + "duration_ms": 4630760, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/10zCZJKgKEerI6edwYTWvR" + }, + "href": "https://api.spotify.com/v1/episodes/10zCZJKgKEerI6edwYTWvR", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF06, The Debarted, the thirteenth episode of Season Nineteen. They talk about bad B plots, good pastiches, and enjoyable episodes. Support us on Patreon! Listener Question of the Week: What’s your favorite ending to a movie?", + "id": "10zCZJKgKEerI6edwYTWvR", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "416 – The Debarted", + "release_date": "2022-05-02", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:10zCZJKgKEerI6edwYTWvR" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/e44ca9c05ee5bdab9f809a053b28050f6b768748", + "description": "Tonight, Matt and Robbie discuss Episode KABF05, Love, Springfieldian Style, the twelfth episode of Season Nineteen. They talk about love, connecting stories, and filler. Support the show on Patreon! Listener Question of the Week: What’s your favorite romantic comedy?", + "duration_ms": 4655665, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/7BsvYKgXQlvqd3RmHEOuCx" + }, + "href": "https://api.spotify.com/v1/episodes/7BsvYKgXQlvqd3RmHEOuCx", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF05, Love, Springfieldian Style, the twelfth episode of Season Nineteen. They talk about love, connecting stories, and filler. Support the show on Patreon! Listener Question of the Week: What’s your favorite romantic comedy?", + "id": "7BsvYKgXQlvqd3RmHEOuCx", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "415 – Love, Springfieldian Style", + "release_date": "2022-04-25", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:7BsvYKgXQlvqd3RmHEOuCx" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/a01f769652c5e52e24fac24b303899594c46c18f", + "description": "Tonight, Matt and Robbie are joined by Andrew Bloom to discuss Episode KABF04, That 90’s Show, the eleventh episode of Season Nineteen. They talk about references, retcons, and reckoning with The Simpsons timeline. Andrew’s Review Support the show on Patreon! Listener Question of the Week: What’s the plot of your Simpsons retcon episode?", + "duration_ms": 8427645, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/09F4uX1Bo6nh0ibfcScTZg" + }, + "href": "https://api.spotify.com/v1/episodes/09F4uX1Bo6nh0ibfcScTZg", + "html_description": "Tonight, Matt and Robbie are joined by Andrew Bloom to discuss Episode KABF04, That 90’s Show, the eleventh episode of Season Nineteen. They talk about references, retcons, and reckoning with The Simpsons timeline. Andrew’s Review Support the show on Patreon! Listener Question of the Week: What’s the plot of your Simpsons retcon episode?", + "id": "09F4uX1Bo6nh0ibfcScTZg", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "414 – That 90’s Show (w Andrew Bloom)", + "release_date": "2022-04-18", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:09F4uX1Bo6nh0ibfcScTZg" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/e94cf661b2b41b0725c72a5e42358db7a36c2ddf", + "description": "Tonight, Matt and Robbie discuss Episode KABF03, E Pluribus Wiggum, the tenth episode of Season Nineteen. They talk about politics, Ralph Wiggum, and caring. Order Burial! Support the Show on Patreon! Listener Question of the Week: What Simpsons character would make the best President?", + "duration_ms": 6736116, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/5reN7mii9N0QgU9qvWl8T2" + }, + "href": "https://api.spotify.com/v1/episodes/5reN7mii9N0QgU9qvWl8T2", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF03, E Pluribus Wiggum, the tenth episode of Season Nineteen. They talk about politics, Ralph Wiggum, and caring. Order Burial! Support the Show on Patreon! Listener Question of the Week: What Simpsons character would make the best President?", + "id": "5reN7mii9N0QgU9qvWl8T2", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "413 – E Pluribus Wiggum", + "release_date": "2022-04-11", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:5reN7mii9N0QgU9qvWl8T2" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/f34342f5df38db60a36bbca9323a79a68c57d4fb", + "description": "Tonight, Matt and Robbie discuss Episode KABF02, Eternal Moonshine of the Simpson Mind, the ninth episode of Season Nineteen. They talk about mysteries, Patty & Selma, and contrivances. Pre-Order Burial! Support The Simpsons Show on Patreon! Listener Question of the Week: What’s your favorite drink?", + "duration_ms": 5700961, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/5qIyxVAq36uDTElceC9U5O" + }, + "href": "https://api.spotify.com/v1/episodes/5qIyxVAq36uDTElceC9U5O", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF02, Eternal Moonshine of the Simpson Mind, the ninth episode of Season Nineteen. They talk about mysteries, Patty & Selma, and contrivances. Pre-Order Burial! Support The Simpsons Show on Patreon! Listener Question of the Week: What’s your favorite drink?", + "id": "5qIyxVAq36uDTElceC9U5O", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "412 – Eternal Moonshine of the Simpson Mind", + "release_date": "2022-04-04", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:5qIyxVAq36uDTElceC9U5O" + }, + { + "audio_preview_url": "https://p.scdn.co/mp3-preview/2fa02c266275c2258dbb5642c5159dd77490e164", + "description": "Tonight, Matt and Robbie discuss Episode KABF01, Funeral for a Fiend, the eighth episode of Season Nineteen. They talk about Sideshow Bob, goodwill, and layer after layer of absolute nonsense. Pre-Order Burial! Support us on Patreon! Listener Question of the Week: What’s your favorite mystery film?", + "duration_ms": 5786517, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/episode/6xBvS4qd2K39a1p1C26tsD" + }, + "href": "https://api.spotify.com/v1/episodes/6xBvS4qd2K39a1p1C26tsD", + "html_description": "Tonight, Matt and Robbie discuss Episode KABF01, Funeral for a Fiend, the eighth episode of Season Nineteen. They talk about Sideshow Bob, goodwill, and layer after layer of absolute nonsense. Pre-Order Burial! Support us on Patreon! Listener Question of the Week: What’s your favorite mystery film?", + "id": "6xBvS4qd2K39a1p1C26tsD", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "is_playable": true, + "language": "en-US", + "languages": [ + "en-US" + ], + "name": "411 – Funeral for a Fiend", + "release_date": "2022-03-28", + "release_date_precision": "day", + "type": "episode", + "uri": "spotify:episode:6xBvS4qd2K39a1p1C26tsD" + } + ], + "limit": 50, + "next": "https://api.spotify.com/v1/shows/4ZbloPxqlAqHbbP4EnivIB/episodes?offset=50&limit=50&market=GB", + "offset": 0, + "previous": null, + "total": 300 + }, + "explicit": false, + "external_urls": { + "spotify": "https://open.spotify.com/show/4ZbloPxqlAqHbbP4EnivIB" + }, + "href": "https://api.spotify.com/v1/shows/4ZbloPxqlAqHbbP4EnivIB", + "html_description": "A podcast looking back at The Simpsons, episode by episode, discussing and analyzing its importance, history, and greatness.", + "id": "4ZbloPxqlAqHbbP4EnivIB", + "images": [ + { + "height": 640, + "url": "https://i.scdn.co/image/5dc7540613c82103d1445e54fa66e52710dfcde2", + "width": 640 + }, + { + "height": 300, + "url": "https://i.scdn.co/image/6cf91224bd8b08b19a02090df8559a6c76416d07", + "width": 300 + }, + { + "height": 64, + "url": "https://i.scdn.co/image/d2696a8fd331c62cad28d7d38e463e96691e7a18", + "width": 64 + } + ], + "is_externally_hosted": false, + "languages": [ + "en" + ], + "media_type": "audio", + "name": "The Simpsons Show", + "publisher": "The Simpsons Show", + "total_episodes": 300, + "type": "show", + "uri": "spotify:show:4ZbloPxqlAqHbbP4EnivIB" + }; +} \ No newline at end of file diff --git a/src/test/data/validTrack.ts b/src/test/data/validTrack.ts new file mode 100644 index 0000000..99f12f0 --- /dev/null +++ b/src/test/data/validTrack.ts @@ -0,0 +1,68 @@ +export function validTrack() { + return { + album: + { + album_group: 'album', + album_type: 'album', + artists: + [{ + external_urls: { spotify: 'https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm' }, + href: 'https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm', + id: '2CWWgbxApjbyByxBBCvGTm', + name: 'Katatonia', + type: 'artist', + uri: 'spotify:artist:2CWWgbxApjbyByxBBCvGTm' + }], + available_markets: ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + external_urls: { spotify: 'https://open.spotify.com/album/4EcfbzCtbJDk2wMwhT4D1h' }, + href: 'https://api.spotify.com/v1/albums/4EcfbzCtbJDk2wMwhT4D1h', + id: '4EcfbzCtbJDk2wMwhT4D1h', + images: + [{ + height: 640, + url: 'https://i.scdn.co/image/ab67616d0000b2731465df104ab9c7772fe0da9b', + width: 640 + }, + { + height: 300, + url: 'https://i.scdn.co/image/ab67616d00001e021465df104ab9c7772fe0da9b', + width: 300 + }, + { + height: 64, + url: 'https://i.scdn.co/image/ab67616d000048511465df104ab9c7772fe0da9b', + width: 64 + }], + name: 'Sky Void of Stars', + release_date: '2023-01-20', + release_date_precision: 'day', + total_tracks: 11, + type: 'album', + uri: 'spotify:album:4EcfbzCtbJDk2wMwhT4D1h' + }, + artists: + [{ + external_urls: { spotify: 'https://open.spotify.com/artist/2CWWgbxApjbyByxBBCvGTm' }, + href: 'https://api.spotify.com/v1/artists/2CWWgbxApjbyByxBBCvGTm', + id: '2CWWgbxApjbyByxBBCvGTm', + name: 'Katatonia', + type: 'artist', + uri: 'spotify:artist:2CWWgbxApjbyByxBBCvGTm' + }], + available_markets: ["AR", "AU", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET"], + disc_number: 1, + duration_ms: 221200, + explicit: false, + external_ids: { isrc: 'ATN262320801' }, + external_urls: { spotify: 'https://open.spotify.com/track/2RM5Lx7VIp6GrLRsg2yXwW' }, + href: 'https://api.spotify.com/v1/tracks/2RM5Lx7VIp6GrLRsg2yXwW', + id: '2RM5Lx7VIp6GrLRsg2yXwW', + is_local: false, + name: 'Austerity', + popularity: 47, + preview_url: 'https://p.scdn.co/mp3-preview/92060dafd9885ae188be4b7bb3640ad41bf221b3?cid=3c5328c75f1f44c086b25e73608c453b', + track_number: 1, + type: 'track', + uri: 'spotify:track:2RM5Lx7VIp6GrLRsg2yXwW' + }; +} \ No newline at end of file diff --git a/src/test/data/validUser.ts b/src/test/data/validUser.ts new file mode 100644 index 0000000..377bb51 --- /dev/null +++ b/src/test/data/validUser.ts @@ -0,0 +1,23 @@ +export function validUser() { + return { + "display_name": "Jo Franchetti", + "external_urls": { + "spotify": "https://open.spotify.com/user/11124066204" + }, + "followers": { + "href": null, + "total": 30 + }, + "href": "https://api.spotify.com/v1/users/11124066204", + "id": "11124066204", + "images": [ + { + "height": null, + "url": "https://scontent-ams2-1.xx.fbcdn.net/v/t1.6435-1/69809582_10102088511738144_5412754542196424704_n.jpg?stp=c0.0.320.320a_dst-jpg_p320x320&_nc_cat=104&ccb=1-7&_nc_sid=0c64ff&_nc_ohc=uxmfdDkbS_YAX9AmJ3H&_nc_ht=scontent-ams2-1.xx&edm=AP4hL3IEAAAA&oh=00_AfArHPzppyUooSmM8EjW_yeJ9plpPJTh3QKEV2MInSStfw&oe=64395EB9", + "width": null + } + ], + "type": "user", + "uri": "spotify:user:11124066204" + }; +} \ No newline at end of file diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000..63a0882 --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,609 @@ +// Configuration types + +type RequestImplementation = (input: RequestInfo | URL, init?: RequestInit | undefined) => Promise; + +interface SdkOptions { + fetch?: RequestImplementation; + beforeRequest?: (url: string, options: RequestInit) => void; + afterRequest?: (url: string, options: RequestInit, response: Response) => void; + deserializer?: IResponseDeserializer; + responseValidator?: IValidateResponses; + errorHandler?: IHandleErrors; + redirectionStrategy?: IRedirectionStrategy; + cachingStrategy?: ICachingStrategy; +} + +interface SdkConfiguration extends SdkOptions { + fetch: RequestImplementation; + beforeRequest: (url: string, options: RequestInit) => void; + afterRequest: (url: string, options: RequestInit, response: Response) => void; + deserializer: IResponseDeserializer; + responseValidator: IValidateResponses; + errorHandler: IHandleErrors; + redirectionStrategy: IRedirectionStrategy; + cachingStrategy: ICachingStrategy; +} + +interface IRedirectionStrategy { + redirect(targetUrl: string | URL): Promise; + onReturnFromRedirect(): Promise; +} + +interface IHandleErrors { + handleErrors(error: any): Promise; +} + +interface IValidateResponses { + validateResponse: (response: Response) => Promise; +} + +interface IResponseDeserializer { + deserialize(response: Response): Promise; +} + +interface ICachingStrategy { + getOrCreate( + cacheKey: string, + createFunction: () => Promise, + updateFunction?: (item: T) => Promise + ): Promise; + + get(cacheKey: string): Promise; + setCacheItem(cacheKey: string, item: T & ICachable): void; + remove(cacheKey: string): void; +} + +interface ICachable { + expires?: number; + expiresOnAccess?: boolean; +} + +// API return types + +type MaxInt = number extends T ? number : _Range; +type _Range = R['length'] extends T ? R[number] : _Range; + +type ItemTypes = 'artist' | 'album' | 'playlist' | 'track' | 'show' | 'episode' | 'audiobook'; +type Market = "AD" | "AE" | "AG" | "AL" | "AM" | "AO" | "AR" | "AT" | "AU" | "AZ" | "BA" | "BB" | "BD" | "BE" | "BF" | "BG" | "BH" | "BI" | "BJ" | "BN" | "BO" | "BR" | "BS" | "BT" | "BW" | "BY" | "BZ" | "CA" | "CD" | "CG" | "CH" | "CI" | "CL" | "CM" | "CO" | "CR" | "CV" | "CW" | "CY" | "CZ" | "DE" | "DJ" | "DK" | "DM" | "DO" | "DZ" | "EC" | "EE" | "EG" | "ES" | "ET" | "FI" | "FJ" | "FM" | "FR" | "GA" | "GB" | "GD" | "GE" | "GH" | "GM" | "GN" | "GQ" | "GR" | "GT" | "GW" | "GY" | "HK" | "HN" | "HR" | "HT" | "HU" | "ID" | "IE" | "IL" | "IN" | "IQ" | "IS" | "IT" | "JM" | "JO" | "JP" | "KE" | "KG" | "KH" | "KI" | "KM" | "KN" | "KR" | "KW" | "KZ" | "LA" | "LB" | "LC" | "LI" | "LK" | "LR" | "LS" | "LT" | "LU" | "LV" | "LY" | "MA" | "MC" | "MD" | "ME" | "MG" | "MH" | "MK" | "ML" | "MN" | "MO" | "MR" | "MT" | "MU" | "MV" | "MW" | "MX" | "MY" | "MZ" | "NA" | "NE" | "NG" | "NI" | "NL" | "NO" | "NP" | "NR" | "NZ" | "OM" | "PA" | "PE" | "PG" | "PH" | "PK" | "PL" | "PS" | "PT" | "PW" | "PY" | "QA" | "RO" | "RS" | "RW" | "SA" | "SB" | "SC" | "SE" | "SG" | "SI" | "SK" | "SL" | "SM" | "SN" | "SR" | "ST" | "SV" | "SZ" | "TD" | "TG" | "TH" | "TJ" | "TL" | "TN" | "TO" | "TR" | "TT" | "TV" | "TW" | "TZ" | "UA" | "UG" | "US" | "UY" | "UZ" | "VC" | "VE" | "VN" | "VU" | "WS" | "XK" | "ZA" | "ZM" | "ZW"; +type CountryCodeA2 = 'AD' | 'AE' | 'AF' | 'AG' | 'AI' | 'AL' | 'AM' | 'AO' | 'AQ' | 'AR' | 'AS' | 'AT' | 'AU' | 'AW' | 'AX' | 'AZ' | 'BA' | 'BB' | 'BD' | 'BE' | 'BF' | 'BG' | 'BH' | 'BI' | 'BJ' | 'BL' | 'BM' | 'BN' | 'BO' | 'BQ' | 'BR' | 'BS' | 'BT' | 'BV' | 'BW' | 'BY' | 'BZ' | 'CA' | 'CC' | 'CD' | 'CF' | 'CG' | 'CH' | 'CI' | 'CK' | 'CL' | 'CM' | 'CN' | 'CO' | 'CR' | 'CU' | 'CV' | 'CW' | 'CX' | 'CY' | 'CZ' | 'DE' | 'DJ' | 'DK' | 'DM' | 'DO' | 'DZ' | 'EC' | 'EE' | 'EG' | 'EH' | 'ER' | 'ES' | 'ET' | 'FI' | 'FJ' | 'FK' | 'FM' | 'FO' | 'FR' | 'GA' | 'GB' | 'GD' | 'GE' | 'GF' | 'GG' | 'GH' | 'GI' | 'GL' | 'GM' | 'GN' | 'GP' | 'GQ' | 'GR' | 'GS' | 'GT' | 'GU' | 'GW' | 'GY' | 'HK' | 'HM' | 'HN' | 'HR' | 'HT' | 'HU' | 'ID' | 'IE' | 'IL' | 'IM' | 'IN' | 'IO' | 'IQ' | 'IR' | 'IS' | 'IT' | 'JE' | 'JM' | 'JO' | 'JP' | 'KE' | 'KG' | 'KH' | 'KI' | 'KM' | 'KN' | 'KP' | 'KR' | 'KW' | 'KY' | 'KZ' | 'LA' | 'LB' | 'LC' | 'LI' | 'LK' | 'LR' | 'LS' | 'LT' | 'LU' | 'LV' | 'LY' | 'MA' | 'MC' | 'MD' | 'ME' | 'MF' | 'MG' | 'MH' | 'MK' | 'ML' | 'MM' | 'MN' | 'MO' | 'MP' | 'MQ' | 'MR' | 'MS' | 'MT' | 'MU' | 'MV' | 'MW' | 'MX' | 'MY' | 'MZ' | 'NA' | 'NC' | 'NE' | 'NF' | 'NG' | 'NI' | 'NL' | 'NO' | 'NP' | 'NR' | 'NU' | 'NZ' | 'OM' | 'PA' | 'PE' | 'PF' | 'PG' | 'PH' | 'PK' | 'PL' | 'PM' | 'PN' | 'PR' | 'PS' | 'PT' | 'PW' | 'PY' | 'QA' | 'RE' | 'RO' | 'RS' | 'RU' | 'RW' | 'SA' | 'SB' | 'SC' | 'SD' | 'SE' | 'SG' | 'SH' | 'SI' | 'SJ' | 'SK' | 'SL' | 'SM' | 'SN' | 'SO' | 'SR' | 'SS' | 'ST' | 'SV' | 'SX' | 'SY' | 'SZ' | 'TC' | 'TD' | 'TF' | 'TG' | 'TH' | 'TJ' | 'TK' | 'TL' | 'TM' | 'TN' | 'TO' | 'TR' | 'TT' | 'TV' | 'TW' | 'TZ' | 'UA' | 'UG' | 'UM' | 'US' | 'UY' | 'UZ' | 'VA' | 'VC' | 'VE' | 'VG' | 'VI' | 'VN' | 'VU' | 'WF' | 'WS' | 'YE' | 'YT' | 'ZA' | 'ZM' | 'ZW'; + +interface AccessToken { + access_token: string; + token_type: string; + expires_in: number; + refresh_token: string; +} + +interface Album { + album_group: string + album_type: string + artists: ArtistReference[] + available_markets: string[] + copyrights: Copyright[] + external_ids: ExternalIds + external_urls: ExternalUrls + genres: any[] + href: string + id: string + images: Image[] + label: string + name: string + popularity: number + release_date: string + release_date_precision: string + total_tracks: number + type: string + uri: string + +} + +interface SavedAlbum { + added_at: string + album: AlbumWithTracks +} + +interface AlbumWithTracks extends Album { + tracks: Page +} + +interface Albums { + albums: AlbumWithTracks[] +} + +interface NewReleases { + albums: Page +} + +interface Copyright { + text: string + type: string +} + +interface ExternalIds { + upc: string +} + +interface Page { + href: string + items: TItemType[] + limit: number + next: any + offset: number + previous: any + total: number +} + +interface PlaylistedTrack { + added_at: string + added_by: AddedBy + is_local: boolean + primary_color: any + track: TrackWithAlbum +} + +interface AddedBy { + external_urls: ExternalUrls + href: string + id: string + type: string + uri: string +} + +interface Track { + artists: ArtistReference[] + available_markets: string[] + disc_number: number + duration_ms: number + explicit: boolean + external_urls: ExternalUrls + href: string + id: string + is_local: boolean + name: string + preview_url: string + track_number: number + type: string + uri: string +} + +interface TrackWithAlbum extends Track { + album: Album +} + +interface Tracks { + tracks: TrackWithAlbum[] +} + +interface ArtistReference { + external_urls: ExternalUrls + href: string + id: string + name: string + type: string + uri: string +} + +interface Artist { + external_urls: ExternalUrls + followers: Followers + genres: string[] + href: string + id: string + images: Image[] + name: string + popularity: number + type: string + uri: string +} + +interface Artists { + artists: Artist[] +} + +interface FollowedArtists { + artists: Page +} + +interface Followers { + href: any + total: number +} + +interface ExternalUrls { + spotify: string +} + +interface SearchResults { + tracks: Page + artists: Page + albums: Page + playlists: Page + shows: Page + episodes: Page + audiobooks: Page +} + +interface ArtistSearchResult { + href: string; + items: ArtistSearchResultItem[]; +} + +interface ArtistSearchResultItem { + id: string; + name: string; + popularity: number; + genres: string[]; +} + +interface TopTracksResult { + tracks: Track[]; +} + +interface UserResponse { + country: string; + display_name: string; + email: string; + explicit_content: { + filter_enabled: boolean, + filter_locked: boolean + }, + external_urls: ExternalUrls; + followers: { href: string; total: number; }; + href: string; + id: string; + images: Image[]; + product: string; + type: string; + uri: string; +} + +interface Image { + url: string; + height: number; + width: number; +} + +interface PlaylistCreationResult { + id: string; + name: string; + href: string; + external_urls: ExternalUrls; +} + +interface Audiobook { + authors: Author[] + available_markets: string[] + copyrights: any[] + description: string + edition: string + explicit: boolean + external_urls: ExternalUrls + href: string + html_description: string + id: string + images: Image[] + languages: string[] + media_type: string + name: string + narrators: Narrator[] + publisher: string + total_chapters: number + type: string + uri: string +} + +interface AudiobookWithChapters extends Audiobook { + chapters: Page +} + +interface Audiobooks { + audiobooks: AudiobookWithChapters[] +} + +interface Categories { + categories: Page +} + +interface Episodes { + episodes: Episode[] +} + +interface Genres { + genres: string[] +} + +interface Markets { + markets: string[] +} + +interface Shows { + shows: ShowWithEpisodes[] +} + +interface Category { + href: string + icons: Icon[] + id: string + name: string +} + +interface Icon { + height?: number + url: string + width?: number +} + +interface Author { + name: string +} + +interface Chapter { + id: string + description: string + chapter_number: number + duration_ms: number + explicit: boolean + images: Image[] + languages: string[] + name: string + audio_preview_url: any + release_date: string + release_date_precision: string + resume_point: ResumePoint + html_description: string + available_markets: Market[] + type: string + uri: string + external_urls: ExternalUrls + href: string +} + +interface Chapters { + chapters: ChapterWithAudiobookAndRestrictions[]; +} + +interface ChapterWithAudiobookAndRestrictions extends Chapter { + restrictions?: Restrictions + audiobook: Audiobook +} + +interface Restrictions { + reason: string +} + +interface ResumePoint { + fully_played: boolean + resume_position_ms: number +} + +interface Narrator { + name: string +} + +interface Episode { + audio_preview_url: string + description: string + html_description: string + duration_ms: number + explicit: boolean + external_urls: ExternalUrls + href: string + id: string + images: Image[] + is_externally_hosted: boolean + is_playable: boolean + language: string + languages: string[] + name: string + release_date: string + release_date_precision: string + resume_point: ResumePoint + type: string + uri: string + restrictions: Restrictions + + // If fetched from Episode API, show included + show?: Show +} + +interface Show { + available_markets: string[] + copyrights: Copyright[] + description: string + html_description: string + explicit: boolean + external_urls: ExternalUrls + href: string + id: string + images: Image[] + is_externally_hosted: boolean + languages: string[] + media_type: string + name: string + publisher: string + type: string + uri: string + total_episodes: number +} + +interface ShowWithEpisodes extends Show { + episodes: Page +} + +interface SnapshotReference { + snapshot_id: string +} + +interface Playlist { + collaborative: boolean + description: string + external_urls: ExternalUrls + followers: Followers + href: string + id: string + images: Image[] + name: string + owner: UserReference + primary_color: string + public: boolean + snapshot_id: string + type: string + uri: string +} + +interface PlaylistWithTracks extends Playlist { + tracks: Page +} + +interface PlaylistsWithTrackReferences { + message: string; + playlists: Page +} + +interface PlaylistWithTrackReferences extends Playlist { + tracks: TrackReference +} + +interface TrackReference { + href: string; + total: number; +} + +interface UserReference { + display_name: string + external_urls: ExternalUrls + href: string + id: string + type: string + uri: string +} + +interface User { + display_name: string + external_urls: ExternalUrls + followers: Followers + href: string + id: string + images: Image[] + type: string + uri: string +} + +interface AudioFeatures { + danceability: number + energy: number + key: number + loudness: number + mode: number + speechiness: number + acousticness: number + instrumentalness: number + liveness: number + valence: number + tempo: number + type: string + id: string + uri: string + track_href: string + analysis_url: string + duration_ms: number + time_signature: number +} + +interface AudioFeaturesCollection { + audio_features: AudioFeatures[] +} + +interface AudioAnalysis { + meta: Meta + track: TrackAnalysis + bars: Bar[] + beats: Beat[] + sections: Section[] + segments: Segment[] + tatums: Tatum[] +} + +interface Meta { + analyzer_version: string + platform: string + detailed_status: string + status_code: number + timestamp: number + analysis_time: number + input_process: string +} + +interface TrackAnalysis { + num_samples: number + duration: number + sample_md5: string + offset_seconds: number + window_seconds: number + analysis_sample_rate: number + analysis_channels: number + end_of_fade_in: number + start_of_fade_out: number + loudness: number + tempo: number + tempo_confidence: number + time_signature: number + time_signature_confidence: number + key: number + key_confidence: number + mode: number + mode_confidence: number + codestring: string + code_version: number + echoprintstring: string + echoprint_version: number + synchstring: string + synch_version: number + rhythmstring: string + rhythm_version: number +} + +interface Bar { + start: number + duration: number + confidence: number +} + +interface Beat { + start: number + duration: number + confidence: number +} + +interface Section { + start: number + duration: number + confidence: number + loudness: number + tempo: number + tempo_confidence: number + key: number + key_confidence: number + mode: number + mode_confidence: number + time_signature: number + time_signature_confidence: number +} + +interface Segment { + start: number + duration: number + confidence: number + loudness_start: number + loudness_max: number + loudness_max_time: number + loudness_end: number + pitches: number[] + timbre: number[] +} + +interface Tatum { + start: number + duration: number + confidence: number +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..78553b3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": [ + "DOM", + "DOM.Iterable", + "ESNext" + ], + "allowJs": true, + "skipLibCheck": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "module": "ESNext", + "moduleResolution": "Node", + "outDir": "dist", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": false, + "strict": true + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..762409c --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + root: "example", + server: { + port: 3000, + strictPort: true, + host: true, + }, + plugins: [], + test: { + globals: true, + environment: 'jsdom', + }, +}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..c4c7223 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + root: "src", + plugins: [], + test: { + globals: true, + environment: 'jsdom', + }, +});