Update online docs

This commit is contained in:
Jonas Dellinger 2020-06-03 17:44:13 +02:00
parent 2a9b0338f5
commit d31a9e4ea1
26 changed files with 630 additions and 428 deletions

View File

@ -0,0 +1,6 @@
---
id: auth_introduction
title: Introduction
---
Hello

View File

@ -0,0 +1,48 @@
---
id: configuration
title: Configuration
---
To configure the spotify client functionality, the `SpotifyClientConfig` class exists.
```csharp
var config = SpotifyClientConfig.CreateDefault("YourAccessToken");
var spotify = new SpotifyClient(config);
// is the same as
var spotify = new SpotifyClient("YourAccessToken");
```
We won't cover every possible configuration in this part, head over to the specific guides for that:
* ...
## HTTPClient Notes
One important part of the configuration is the used HTTPClient. By default, every time when a `SpotifyClientConfig` is instantiated, a new `HTTPClient` is created in the background. For Web Applications which require a lot of different configs due to user based access tokens, it is **not** advised to create a new config from scratch with every HTTP call. Instead, a default (static) config should be used to create a new config with a new access token.
Consider the following HTTP Endpoint:
```csharp
public HttpResult Get()
{
var config = SpotifyClientConfig.CreateDefault("YourAccessToken")
var spotify = new SpotifyClient(config);
}
```
This creates a new `HTTPClient` every time a request is made, which can be quite bad for the performance. Instead we should use a base config and use `WithToken`:
```csharp
// somewhere global/static
public static SpotifyClientConfig DefaultConfig = SpotifyClientConfig.CreateDefault();
public HttpResult Get()
{
var config = DefaultConfig.WithToken("YourAccessToken");
var spotify = new SpotifyClient(config);
}
```
This way, a single `HTTPClient` will be used. For a real world example, checkout the [ASP.NET Example](example_aspnet)

View File

@ -0,0 +1,46 @@
---
id: error_handling
title: Error Handling
---
API calls can fail when input data is malformed or the server detects issues with the request. As an example, the following request obviously fails:
```csharp
var track = await spotify.Tracks.Get("NotExistingTrackId");
Console.WriteLine(track.Name);
```
When a request fails an `APIException` is thrown. Specific errors may throw a child exception of `APIException`.
## APIException
A very general API error. The message is parsed from the API response JSON body and the response is available as public property.
```csharp
try {
var track = await spotify.Tracks.Get("NotExistingTrackId");
} catch(APIException e) {
// Prints: invalid id
Console.WriteLine(e.Message);
// Prints: BadRequest
Console.WriteLine(e.Response?.StatusCode);
}
```
## APIUnauthorizedException
Provides the same properties as `APIException` and occurs, when the access token is expired or not provided. Notice that an access token has to be included in **every** request. Spotify does not allow unauthorized API access.
## APITooManyRequestsException
Provides the same properties as `APIException` and occurs, when too many requests has been sent by your application. It also provides the property `TimeSpan RetryAfter`, which maps to the received `Retry-After` Header.
```csharp
try {
// call it very often?
var track = await spotify.Tracks.Get("1s6ux0lNiTziSrd7iUAADH");
} catch(APITooManyRequestsException e) {
// Prints: seconds to wait, often 1 or 2
Console.WriteLine(e.RetryAfter);
}
```

View File

@ -2,3 +2,107 @@
id: getting_started id: getting_started
title: Getting Started title: Getting Started
--- ---
import InstallInstructions from '../src/install_instructions'
## Adding SpotifyAPI-NET to your project
The library can be added to your project via the following methods:
### Package Managers
<InstallInstructions />
### Add DLL Manually
You can also grab the latest compiled DLL from our [GitHub Releases Page](https://github.com/johnnycrazy/spotifyapi-net/releases). It can be added to your project via Visual Studio or directly in your `.csproj`:
```xml
<ItemGroup>
<Reference Include="SpotifyAPI.Web">
<HintPath>..\Dlls\SpotifyAPI.Web.dll</HintPath>
</Reference>
</ItemGroup>
```
### Compile Yourself
```sh
git clone https://github.com/JohnnyCrazy/SpotifyAPI-NET.git
cd SpotifyAPI-NET
dotnet restore
dotnet build
ls -la SpotifyAPI.Web/bin/Debug/netstandard2.1/SpotifyAPI.Web.dll
```
## First API Calls
You're now ready to issue your first calls to the Spotify API, a small console example:
```csharp
using System;
using SpotifyAPI.Web;
class Program
{
static async Task Main()
{
var spotify = new SpotifyClient("YourAccessToken");
var track = await spotify.Tracks.Get("1s6ux0lNiTziSrd7iUAADH");
Console.WriteLine(track.Name);
}
}
```
:::tip
Notice that the spotify api does not allow unauthorized API access. Wondering where you should get an access token from? For a quick test, head over to the [Spotify Developer Console](https://developer.spotify.com/console/get-album/) and generate an access token with the required scopes! For a permanent solution, head over to the [authentication guides](auth_introduction).
:::
There is no online documentation for every available API call, but XML inline docs are available:
* [UserProfile](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IUserProfileClient.cs)
* [Browse](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IBrowseClient.cs)
* [Shows](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IShowsClient.cs)
* [Playlists](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IPlaylistsClient.cs)
* [Search](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/ISearchClient.cs)
* [Follow](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IFollowClient.cs)
* [Tracks](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/ITracksClient.cs)
* [Player](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IPlayerClient.cs)
* [Albums](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IAlbumsClient.cs)
* [Artists](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IArtistsClient.cs)
* [Personalization](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IPersonalizationClient.cs)
* [Episodes](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IEpisodesClient.cs)
* [Library](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/ILibraryClient.cs)
All calls have the [Spotify Web API documentation reference](https://developer.spotify.com/documentation/web-api/reference-beta/) attached as a remark.
## Query/Body Parameters
If an API endpoint has query or body parameters, a request model can be supplied to the method
```csharp
// No optional or required query/body parameters
// The track ID is part of the request path --> it's not treated as query/body parameter
var track = await spotify.Tracks.Get("1s6ux0lNiTziSrd7iUAADH");
// Optional query/body parameter
var track = await spotify.Tracks.Get("1s6ux0lNiTziSrd7iUAADH", new TrackRequest{
Market = "DE"
});
// Sometimes, query/body parameters are also required!
var tracks = await spotify.Tracks.GetSeveral(new TracksRequest(new List<string> {
"1s6ux0lNiTziSrd7iUAADH",
"6YlOxoHWLjH6uVQvxUIUug"
}));
```
If a query/body parameter is required, it has to be supplied in the constructor of the request model. In the background, empty/null checks are also performed to make sure required parameters are not empty/null. If it is optional, it can be supplied as a property to the request model.
## Guides
All other relevant topics are covered in the "Guides" and [Authentication Guides](auth_introduction) section in the sidebar!

View File

@ -1,4 +0,0 @@
---
id: installation
title: Installation
---

View File

@ -3,199 +3,22 @@ id: introduction
title: Introduction title: Introduction
--- ---
You can write content using [GitHub-flavored Markdown syntax](https://github.github.com/gfm/). This open source library for the Spotify Web API provides an easy to use interface for .NET based languages, like C# and VisualBasic .NET. By using it you can query general spotify catalog information (tracks, albums and playlists), manage user-related content ("My Library", create and edit playlists) and control the users music players (play, stop, transfer playback, play specific track).
## Markdown Syntax ## Features
To serve as an example page when styling markdown based Docusaurus sites. From version 6 onwards, the library was built with the following features included:
## Headers * ✅ Typed responses and requests to over 74 endpoints. Complete and always up to date.
* ✅ Supports `.NET Standard 2.X`, which includes all major platforms, including mobile:
# H1 - Create the best documentation * `.NET Framework`
* `UWP`
## H2 - Create the best documentation * `.NET Core`
* `Xamarin.Forms`
### H3 - Create the best documentation * ✅ Included `HTTPClient`, but feel free to bring your own!
* ✅ Logging supported
#### H4 - Create the best documentation * ✅ Retry Handlers supported
* ✅ Proxy support
##### H5 - Create the best documentation * ✅ Pagination support
* ✅ All OAuth2 Authentications supported for use in `ASP .NET` **and** `CLI` apps
###### H6 - Create the best documentation * ✅ Modular structure, for easy unit testing
---
## Emphasis
Emphasis, aka italics, with _asterisks_ or _underscores_.
Strong emphasis, aka bold, with **asterisks** or **underscores**.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
---
## Lists
1. First ordered list item
1. Another item ⋅⋅\* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number ⋅⋅1. Ordered sub-list
1. And another item.
⋅⋅⋅You can have properly indented paragraphs within list items. Notice the blank line above, and the leading spaces (at least one, but we'll use three here to also align the raw Markdown).
⋅⋅⋅To have a line break without a paragraph, you will need to use two trailing spaces.⋅⋅ ⋅⋅⋅Note that this line is separate, but within the same paragraph.⋅⋅ ⋅⋅⋅(This is contrary to the typical GFM line break behaviour, where trailing spaces are not required.)
- Unordered list can use asterisks
* Or minuses
- Or pluses
---
## Links
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][arbitrary case-insensitive reference text]
[I'm a relative reference to a repository file](../blob/master/LICENSE)
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or <http://www.example.com> and sometimes example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
---
## Images
Here's our logo (hover to see the title text):
Inline-style: ![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 1')
Reference-style: ![alt text][logo]
[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 2'
---
## Code
```javascript
var s = 'JavaScript syntax highlighting';
alert(s);
```
```python
s = "Python syntax highlighting"
print(s)
```
```
No language indicated, so no syntax highlighting.
But let's throw in a <b>tag</b>.
```
```js {2}
function highlightMe() {
console.log('This line can be highlighted!');
}
```
---
## Tables
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- | :-----------: | -----: |
| col 3 is | right-aligned | \$1600 |
| col 2 is | centered | \$12 |
| zebra stripes | are neat | \$1 |
There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown.
| Markdown | Less | Pretty |
| -------- | --------- | ---------- |
| _Still_ | `renders` | **nicely** |
| 1 | 2 | 3 |
---
## Blockquotes
> Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can _put_ **Markdown** into a blockquote.
---
## Inline HTML
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
---
## Line Breaks
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a _separate paragraph_.
This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the _same paragraph_.
---
## Admonitions
:::note
This is a note
:::
:::tip
This is a tip
:::
:::important
This is important
:::
:::caution
This is a caution
:::
:::warning
This is a warning
:::

View File

@ -0,0 +1,38 @@
---
id: logging
title: Logging
---
The library provides a way to inject your own, custom HTTP Logger. By default, no logging is performed.
```csharp
var config = SpotifyClientConfig
.CreateDefault("YourAccessToken")
.WithHTTPLogger(new YourHTTPLogger());
var spotify = new SpotifyClient(config);
```
The `IHTTPLogger` interface can be found [here](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Http/Interfaces/IHTTPLogger.cs).
## SimpleConsoleHTTPLogger
The library ships with a simple console-based logger
```csharp
var config = SpotifyClientConfig
.CreateDefault("YourAccessToken")
.WithHTTPLogger(new SimpleConsoleHTTPLogger());
var spotify = new SpotifyClient(config);
```
This logger produces a simple console output for debugging purposes:
```text
GET tracks/NotAnid []
--> BadRequest application/json { "error" : { "status" : 400, "message" : "
GET tracks/6YlOxoHWLjH6uVQvxUIUug []
--> OK application/json { "album" : { "album_type" : "album", "arti
```

View File

@ -3,199 +3,78 @@ id: pagination
title: Pagination title: Pagination
--- ---
You can write content using [GitHub-flavored Markdown syntax](https://github.github.com/gfm/). When working with spotify responses, you will often encounter the `Paging<T>` type.
## Markdown Syntax > The offset-based paging object is a container for a set of objects. It contains a key called items (whose value is an array of the requested objects) along with other keys like previous, next and limit that can be useful in future calls.
To serve as an example page when styling markdown based Docusaurus sites. It allows to receive only a subset of all available data and dynamically check if more requests are required. The library supports `Paging<T>` responses in two ways:
## Headers ## PaginateAll
# H1 - Create the best documentation `PaginateAll` will query all remaining elements based on a first page and return all of them in a `IList`. This method should not be used for a huge amount of pages (e.g `Search` Endpoint), since it stores every response in memory.
## H2 - Create the best documentation ```csharp
// we need the first page, every syntax can be used for pagination
var page = await spotify.Playlists.CurrentUsers();
var page = spotify.Playlists.CurrentUsers();
var page = () => spotify.Playlists.CurrentUsers();
### H3 - Create the best documentation // allPages will include the first page retrived before
var allPages = await spotify.PaginateAll(page);
#### H4 - Create the best documentation
##### H5 - Create the best documentation
###### H6 - Create the best documentation
---
## Emphasis
Emphasis, aka italics, with _asterisks_ or _underscores_.
Strong emphasis, aka bold, with **asterisks** or **underscores**.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
---
## Lists
1. First ordered list item
1. Another item ⋅⋅\* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number ⋅⋅1. Ordered sub-list
1. And another item.
⋅⋅⋅You can have properly indented paragraphs within list items. Notice the blank line above, and the leading spaces (at least one, but we'll use three here to also align the raw Markdown).
⋅⋅⋅To have a line break without a paragraph, you will need to use two trailing spaces.⋅⋅ ⋅⋅⋅Note that this line is separate, but within the same paragraph.⋅⋅ ⋅⋅⋅(This is contrary to the typical GFM line break behaviour, where trailing spaces are not required.)
- Unordered list can use asterisks
* Or minuses
- Or pluses
---
## Links
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][arbitrary case-insensitive reference text]
[I'm a relative reference to a repository file](../blob/master/LICENSE)
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or <http://www.example.com> and sometimes example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
---
## Images
Here's our logo (hover to see the title text):
Inline-style: ![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 1')
Reference-style: ![alt text][logo]
[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 2'
---
## Code
```javascript
var s = 'JavaScript syntax highlighting';
alert(s);
``` ```
```python ## Paginate
s = "Python syntax highlighting"
print(s)
```
``` :::info .NET Standard >= 2.1 required
No language indicated, so no syntax highlighting. :::
But let's throw in a <b>tag</b>.
```
```js {2} `Paginate` is based on `IAsyncEnumerable` and streams pages instead of returning them all in one list. This allows to break the fetching early and keeps only 1 page in memory at a time. This method should always be preferred to `PaginateAll`
function highlightMe() {
console.log('This line can be highlighted!'); ```csharp
// we need the first page, every syntax can be used for pagination
var page = await spotify.Playlists.CurrentUsers();
var page = spotify.Playlists.CurrentUsers();
var page = () => spotify.Playlists.CurrentUsers();
await foreach(var item in spotify.Paginate(page))
{
Console.WriteLine(item.Name);
// you can use "break" here!
} }
``` ```
--- Some endpoints have nested and/or multiple paginations objects. When requesting the next page, it will not return the actual paging object but rather the root level endpoint object. A good example is the `Search` endpoint, which contains up to 5 Paging objects. Requesting the next page of the nested `Artists` paging object will return another `Search` response, instead of just `Artists`. You will need to supply a mapper function to the `Paginate` call, which returns the correct paging object:
## Tables ```csharp
var search = await spotify.Search.Item(new SearchRequest(
SearchRequest.Types.All, "Jake"
));
Colons can be used to align columns. await foreach(var item in spotify.Paginate(search.Albums, (s) => s.Albums))
{
Console.WriteLine(item.Name);
// you can use "break" here!
}
```
| Tables | Are | Cool | ## Paginators
| ------------- | :-----------: | -----: |
| col 3 is | right-aligned | \$1600 |
| col 2 is | centered | \$12 |
| zebra stripes | are neat | \$1 |
There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown. Via the interface [`IPaginator`](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/Interfaces/IPaginator.cs), it can be configured how pages are fetched. It can be configured on a global level:
| Markdown | Less | Pretty | ```csharp
| -------- | --------- | ---------- | var config = SpotifyClientConfig
| _Still_ | `renders` | **nicely** | .CreateDefault()
| 1 | 2 | 3 | .WithPaginator(new YourCustomPaginator());
```
--- or on method level:
## Blockquotes ```csharp
await foreach(var item in spotify.Paginate(page, new YourCustomPaginator()))
{
Console.WriteLine(item.Name);
// you can use "break" here!
}
```
> Blockquotes are very handy in email to emulate reply text. This line is part of the same quote. By default, [`SimplePaginator`](https://github.com/JohnnyCrazy/SpotifyAPI-NET/blob/master/SpotifyAPI.Web/Clients/SimplePaginator.cs) is used. It fetches pages without any delay.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can _put_ **Markdown** into a blockquote.
---
## Inline HTML
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
---
## Line Breaks
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a _separate paragraph_.
This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the _same paragraph_.
---
## Admonitions
:::note
This is a note
:::
:::tip
This is a tip
:::
:::important
This is important
:::
:::caution
This is a caution
:::
:::warning
This is a warning
:::

View File

@ -0,0 +1,25 @@
---
id: proxy
title: Proxy
---
The included `HTTPClient` has full proxy configuration support:
```csharp
var httpClient = new NetHttpClient(new ProxyConfig("localhost", 8080)
{
User = "",
Password = "",
SkipSSLCheck = false,
});
var config = SpotifyClientConfig
.CreateDefault()
.WithHTTPClient(httpClient);
var spotify = new SpotifyClient(config);
```
As an example, [mitmproxy](https://mitmproxy.org/) can be used to inspect the requests and responses:
![mitmproxy](/img/mitmproxy.png)

View File

@ -9,7 +9,7 @@ module.exports = {
organizationName: 'JohnnyCrazy', // Usually your GitHub org/user name. organizationName: 'JohnnyCrazy', // Usually your GitHub org/user name.
projectName: 'SpotifyAPI-NET', // Usually your repo name. projectName: 'SpotifyAPI-NET', // Usually your repo name.
themeConfig: { themeConfig: {
sidebarCollapsible: false, sidebarCollapsible: true,
prism: { prism: {
additionalLanguages: ['csharp'], additionalLanguages: ['csharp'],
}, },

View File

@ -0,0 +1,196 @@
You can write content using [GitHub-flavored Markdown syntax](https://github.github.com/gfm/).
## Markdown Syntax
To serve as an example page when styling markdown based Docusaurus sites.
## Headers
# H1 - Create the best documentation
## H2 - Create the best documentation
### H3 - Create the best documentation
#### H4 - Create the best documentation
##### H5 - Create the best documentation
###### H6 - Create the best documentation
---
## Emphasis
Emphasis, aka italics, with _asterisks_ or _underscores_.
Strong emphasis, aka bold, with **asterisks** or **underscores**.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
---
## Lists
1. First ordered list item
1. Another item ⋅⋅\* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number ⋅⋅1. Ordered sub-list
1. And another item.
⋅⋅⋅You can have properly indented paragraphs within list items. Notice the blank line above, and the leading spaces (at least one, but we'll use three here to also align the raw Markdown).
⋅⋅⋅To have a line break without a paragraph, you will need to use two trailing spaces.⋅⋅ ⋅⋅⋅Note that this line is separate, but within the same paragraph.⋅⋅ ⋅⋅⋅(This is contrary to the typical GFM line break behaviour, where trailing spaces are not required.)
- Unordered list can use asterisks
* Or minuses
- Or pluses
---
## Links
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][arbitrary case-insensitive reference text]
[I'm a relative reference to a repository file](../blob/master/LICENSE)
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or <http://www.example.com> and sometimes example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
---
## Images
Here's our logo (hover to see the title text):
Inline-style: ![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 1')
Reference-style: ![alt text][logo]
[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 2'
---
## Code
```javascript
var s = 'JavaScript syntax highlighting';
alert(s);
```
```python
s = "Python syntax highlighting"
print(s)
```
```
No language indicated, so no syntax highlighting.
But let's throw in a <b>tag</b>.
```
```js {2}
function highlightMe() {
console.log('This line can be highlighted!');
}
```
---
## Tables
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- | :-----------: | -----: |
| col 3 is | right-aligned | \$1600 |
| col 2 is | centered | \$12 |
| zebra stripes | are neat | \$1 |
There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown.
| Markdown | Less | Pretty |
| -------- | --------- | ---------- |
| _Still_ | `renders` | **nicely** |
| 1 | 2 | 3 |
---
## Blockquotes
> Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can _put_ **Markdown** into a blockquote.
---
## Inline HTML
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
---
## Line Breaks
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a _separate paragraph_.
This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the _same paragraph_.
---
## Admonitions
:::note
This is a note
:::
:::tip
This is a tip
:::
:::important
This is important
:::
:::caution
This is a caution
:::
:::warning
This is a warning
:::

View File

@ -1,16 +1,26 @@
module.exports = { module.exports = {
docs: { docs: {
'Spotify-API': [ 'SpotifyAPI.NET': [
'introduction', 'introduction',
'installation',
'getting_started', 'getting_started',
{ {
type: 'category', type: 'category',
label: 'Guides', label: 'Guides',
items: [ items: [
'error_handling',
'configuration',
'logging',
'proxy',
'pagination', 'pagination',
] ]
}, },
{
type: 'category',
label: 'Authentication Guides',
items: [
'auth_introduction',
]
},
{ {
type: 'category', type: 'category',
label: 'Examples', label: 'Examples',

View File

@ -0,0 +1,52 @@
import React from "react";
import CodeBlock from '@theme/CodeBlock'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
const installCodeNuget =
`Install-Package SpotifyAPI.Web -Version 6.0.0-beta.1
# Optional Auth module, which includes an embedded HTTP Server for OAuth2
Install-Package SpotifyAPI.Web.Auth -Version 6.0.0-beta.1
`;
const installReference =
`<PackageReference Include="SpotifyAPI.Web" Version="6.0.0-beta.1" />
<!-- Optional Auth module, which includes an embedded HTTP Server for OAuth2 -->
<PackageReference Include="SpotifyAPI.Web.Auth" Version="6.0.0-beta.1" />
`;
const installCodeCLI =
`dotnet add package SpotifyAPI.Web --version 6.0.0-beta.1
# Optional Auth module, which includes an embedded HTTP Server for OAuth2
dotnet add package SpotifyAPI.Web.Auth --version 6.0.0-beta.1
`;
const InstallInstructions = () => {
return (<div style={{ padding: '30px' }}>
<Tabs
defaultValue="cli"
values={[
{ label: '.NET CLI', value: 'cli' },
{ label: 'Package Manager', value: 'nuget' },
{ label: 'Package Reference', value: 'reference' }
]}>
<TabItem value="cli">
<CodeBlock metastring="shell" className="shell">
{installCodeCLI}
</CodeBlock>
</TabItem>
<TabItem value="nuget">
<CodeBlock metastring="shell" className="shell">
{installCodeNuget}
</CodeBlock>
</TabItem>
<TabItem value="reference">
<CodeBlock metastring="xml" className="xml">
{installReference}
</CodeBlock>
</TabItem>
</Tabs>
</div>);
}
export default InstallInstructions;

View File

@ -9,6 +9,7 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import styles from './styles.module.css'; import styles from './styles.module.css';
import GitHubButton from 'react-github-btn' import GitHubButton from 'react-github-btn'
import InstallInstructions from '../install_instructions';
const exampleCode = const exampleCode =
`var spotify = new SpotifyClient("YourAccessToken"); `var spotify = new SpotifyClient("YourAccessToken");
@ -23,16 +24,6 @@ await foreach(
Console.WriteLine(playlist.Name); Console.WriteLine(playlist.Name);
}`; }`;
const installCodeNuget =
`# Core Package
Install-Package SpotifyAPI.Web
`;
const installCodeCLI =
`# Core Package
dotnet add package SpotifyAPI.Web
`;
const features = [ const features = [
{ {
title: <>Sane Defaults - Easy To Configure</>, title: <>Sane Defaults - Easy To Configure</>,
@ -125,6 +116,10 @@ function Home() {
</div> </div>
</header> </header>
<main> <main>
<div className="container">
<h2 style={{ textAlign: 'center', marginTop: '30px' }}>Try it out now</h2>
<InstallInstructions />
</div>
{features && features.length && ( {features && features.length && (
<section className={styles.features}> <section className={styles.features}>
<div className="container"> <div className="container">
@ -136,28 +131,6 @@ function Home() {
</div> </div>
</section> </section>
)} )}
<div className="container">
<h2 style={{ textAlign: 'center' }}>Try it out now</h2>
<div style={{ padding: '50px' }}>
<Tabs
defaultValue="cli"
values={[
{ label: 'dotnet CLI', value: 'cli' },
{ label: 'NuGET Console', value: 'nuget' },
]}>
<TabItem value="cli">
<CodeBlock metastring="csharp" className="bash">
{installCodeCLI}
</CodeBlock>
</TabItem>
<TabItem value="nuget">
<CodeBlock metastring="csharp" className="bash">
{installCodeNuget}
</CodeBlock>
</TabItem>
</Tabs>
</div>
</div>
</main> </main>
</Layout> </Layout>
); );

View File

@ -1,4 +0,0 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://convertio.co/de/download/e5c0c141d0809a93b2a78a795d803e3503d4c2/
HostUrl=https://s183.convertio.me/p/YXorEnOzkE_qAdQbVudFOg/e5c0c141d0809a93b2a78a795d803e35/logo.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -1 +0,0 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@ -32,7 +32,7 @@ namespace SpotifyAPI.Web.Tests
r.HandleRetry( r.HandleRetry(
It.IsAny<IRequest>(), It.IsAny<IRequest>(),
It.IsAny<IResponse>(), It.IsAny<IResponse>(),
It.IsAny<Func<IRequest, Task<IResponse>>>() It.IsAny<IRetryHandler.RetryFunc>()
) )
).Returns(Task.FromResult(response.Object)); ).Returns(Task.FromResult(response.Object));
@ -74,9 +74,9 @@ namespace SpotifyAPI.Web.Tests
r.HandleRetry( r.HandleRetry(
It.IsAny<IRequest>(), It.IsAny<IRequest>(),
It.IsAny<IResponse>(), It.IsAny<IResponse>(),
It.IsAny<Func<IRequest, Task<IResponse>>>() It.IsAny<IRetryHandler.RetryFunc>()
) )
).Returns((IRequest request, IResponse response, Func<IRequest, Task<IResponse>> retry) => retry(request)); ).Returns((IRequest request, IResponse response, IRetryHandler.RetryFunc retry) => retry(request));
var apiConnector = new APIConnector( var apiConnector = new APIConnector(
new Uri("https://spotify.com"), new Uri("https://spotify.com"),

View File

@ -157,7 +157,7 @@ namespace SpotifyAPI.Web
public Mock<Func<int, Task>> Sleep { get; set; } = new Mock<Func<int, Task>>(); public Mock<Func<int, Task>> Sleep { get; set; } = new Mock<Func<int, Task>>();
public Mock<IResponse> Response { get; set; } = new Mock<IResponse>(); public Mock<IResponse> Response { get; set; } = new Mock<IResponse>();
public Mock<IRequest> Request { get; set; } = new Mock<IRequest>(); public Mock<IRequest> Request { get; set; } = new Mock<IRequest>();
public Func<IRequest, Task<IResponse>> Retry { get; set; } public IRetryHandler.RetryFunc Retry { get; set; }
} }
} }
} }

View File

@ -1,7 +1,8 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web.Http namespace SpotifyAPI.Web
{ {
/// <summary> /// <summary>
/// This Authenticator requests new credentials token on demand and stores them into memory. /// This Authenticator requests new credentials token on demand and stores them into memory.

View File

@ -1,6 +1,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web.Http namespace SpotifyAPI.Web
{ {
/// <summary> /// <summary>
/// This Authenticator requests new credentials token on demand and stores them into memory. /// This Authenticator requests new credentials token on demand and stores them into memory.

View File

@ -1,6 +1,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web.Http namespace SpotifyAPI.Web
{ {
public interface IAuthenticator public interface IAuthenticator
{ {

View File

@ -1,6 +1,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web.Http namespace SpotifyAPI.Web
{ {
public class TokenAuthenticator : IAuthenticator public class TokenAuthenticator : IAuthenticator
{ {

View File

@ -283,7 +283,7 @@ namespace SpotifyAPI.Web.Http
{ {
case HttpStatusCode.Unauthorized: case HttpStatusCode.Unauthorized:
throw new APIUnauthorizedException(response); throw new APIUnauthorizedException(response);
case HttpStatusCode.TooManyRequests: case (HttpStatusCode)429: // TODO: Remove hack once .netstandard 2.0 is not supported
throw new APITooManyRequestsException(response); throw new APITooManyRequestsException(response);
default: default:
throw new APIException(response); throw new APIException(response);

View File

@ -8,6 +8,8 @@ namespace SpotifyAPI.Web.Http
/// </summary> /// </summary>
public interface IRetryHandler public interface IRetryHandler
{ {
Task<IResponse> HandleRetry(IRequest request, IResponse response, Func<IRequest, Task<IResponse>> retry); delegate Task<IResponse> RetryFunc(IRequest request);
Task<IResponse> HandleRetry(IRequest request, IResponse response, RetryFunc retry);
} }
} }

View File

@ -3,8 +3,9 @@ using System.Net;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic; using System.Collections.Generic;
using SpotifyAPI.Web.Http;
namespace SpotifyAPI.Web.Http namespace SpotifyAPI.Web
{ {
public class SimpleRetryHandler : IRetryHandler public class SimpleRetryHandler : IRetryHandler
{ {
@ -64,14 +65,18 @@ namespace SpotifyAPI.Web.Http
throw new APIException("429 received, but unable to parse Retry-After Header. This should not happen!"); throw new APIException("429 received, but unable to parse Retry-After Header. This should not happen!");
} }
public Task<IResponse> HandleRetry(IRequest request, IResponse response, Func<IRequest, Task<IResponse>> retry) public Task<IResponse> HandleRetry(IRequest request, IResponse response, IRetryHandler.RetryFunc retry)
{ {
Ensure.ArgumentNotNull(response, nameof(response)); Ensure.ArgumentNotNull(response, nameof(response));
return HandleRetryInternally(request, response, retry, RetryTimes); return HandleRetryInternally(request, response, retry, RetryTimes);
} }
private async Task<IResponse> HandleRetryInternally(IRequest request, IResponse response, Func<IRequest, Task<IResponse>> retry, int triesLeft) private async Task<IResponse> HandleRetryInternally(
IRequest request,
IResponse response,
IRetryHandler.RetryFunc retry,
int triesLeft)
{ {
var secondsToWait = ParseTooManyRetriesToMs(response); var secondsToWait = ParseTooManyRetriesToMs(response);
if (secondsToWait != null && (!TooManyRequestsConsumesARetry || triesLeft > 0)) if (secondsToWait != null && (!TooManyRequestsConsumesARetry || triesLeft > 0))