mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
feat: use Saloon for Last.fm integration
This commit is contained in:
parent
9238ecfd44
commit
06dfe8a1db
15 changed files with 559 additions and 96 deletions
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Values\Concerns;
|
||||
namespace App\Http\Integrations\Concerns;
|
||||
|
||||
trait FormatsLastFmText
|
||||
{
|
16
app/Http/Integrations/Lastfm/LastfmConnector.php
Normal file
16
app/Http/Integrations/Lastfm/LastfmConnector.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm;
|
||||
|
||||
use Saloon\Http\Connector;
|
||||
use Saloon\Traits\Plugins\AcceptsJson;
|
||||
|
||||
class LastfmConnector extends Connector
|
||||
{
|
||||
use AcceptsJson;
|
||||
|
||||
public function resolveBaseUrl(): string
|
||||
{
|
||||
return config('koel.lastfm.endpoint');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm\Requests;
|
||||
|
||||
use App\Http\Integrations\Concerns\FormatsLastFmText;
|
||||
use App\Models\Album;
|
||||
use App\Values\AlbumInformation;
|
||||
use Illuminate\Support\Arr;
|
||||
use Saloon\Enums\Method;
|
||||
use Saloon\Http\Request;
|
||||
use Saloon\Http\Response;
|
||||
|
||||
final class GetAlbumInfoRequest extends Request
|
||||
{
|
||||
use FormatsLastFmText;
|
||||
|
||||
protected Method $method = Method::GET;
|
||||
|
||||
public function __construct(private Album $album)
|
||||
{
|
||||
}
|
||||
|
||||
public function resolveEndpoint(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
protected function defaultQuery(): array
|
||||
{
|
||||
return [
|
||||
'api_key' => config('koel.lastfm.key'),
|
||||
'method' => 'album.getInfo',
|
||||
'artist' => $this->album->artist->name,
|
||||
'album' => $this->album->name,
|
||||
'autocorrect' => 1,
|
||||
'format' => 'json',
|
||||
];
|
||||
}
|
||||
|
||||
public function createDtoFromResponse(Response $response): ?AlbumInformation
|
||||
{
|
||||
$album = object_get($response->object(), 'album');
|
||||
|
||||
if (!$album) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return AlbumInformation::make(
|
||||
url: object_get($album, 'url'),
|
||||
cover: Arr::get(object_get($album, 'image', []), '0.#text'),
|
||||
wiki: [
|
||||
'summary' => self::formatLastFmText(object_get($album, 'wiki.summary')),
|
||||
'full' => self::formatLastFmText(object_get($album, 'wiki.content')),
|
||||
],
|
||||
tracks: array_map(static fn ($track): array => [
|
||||
'title' => $track->name,
|
||||
'length' => (int) $track->duration,
|
||||
'url' => $track->url,
|
||||
], object_get($album, 'tracks.track', []))
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm\Requests;
|
||||
|
||||
use App\Http\Integrations\Concerns\FormatsLastFmText;
|
||||
use App\Models\Artist;
|
||||
use App\Values\ArtistInformation;
|
||||
use Saloon\Enums\Method;
|
||||
use Saloon\Http\Request;
|
||||
use Saloon\Http\Response;
|
||||
|
||||
final class GetArtistInfoRequest extends Request
|
||||
{
|
||||
use FormatsLastFmText;
|
||||
|
||||
protected Method $method = Method::GET;
|
||||
|
||||
public function __construct(private Artist $artist)
|
||||
{
|
||||
}
|
||||
|
||||
public function resolveEndpoint(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
protected function defaultQuery(): array
|
||||
{
|
||||
return [
|
||||
'api_key' => config('koel.lastfm.key'),
|
||||
'method' => 'artist.getInfo',
|
||||
'artist' => $this->artist->name,
|
||||
'autocorrect' => 1,
|
||||
'format' => 'json',
|
||||
];
|
||||
}
|
||||
|
||||
public function createDtoFromResponse(Response $response): ?ArtistInformation
|
||||
{
|
||||
$artist = object_get($response->object(), 'artist');
|
||||
|
||||
if (!$artist) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ArtistInformation::make(
|
||||
url: object_get($artist, 'url'),
|
||||
bio: [
|
||||
'summary' => self::formatLastFmText(object_get($artist, 'bio.summary')),
|
||||
'full' => self::formatLastFmText(object_get($artist, 'bio.content')),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm\Requests;
|
||||
|
||||
use Saloon\Enums\Method;
|
||||
|
||||
final class GetSessionKeyRequest extends SignedRequest
|
||||
{
|
||||
protected Method $method = Method::GET;
|
||||
|
||||
public function __construct(private string $token)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function resolveEndpoint(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
protected function defaultQuery(): array
|
||||
{
|
||||
return [
|
||||
'api_key' => config('koel.lastfm.key'),
|
||||
'method' => 'auth.getSession',
|
||||
'token' => $this->token,
|
||||
'format' => 'json',
|
||||
];
|
||||
}
|
||||
}
|
46
app/Http/Integrations/Lastfm/Requests/ScrobbleRequest.php
Normal file
46
app/Http/Integrations/Lastfm/Requests/ScrobbleRequest.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm\Requests;
|
||||
|
||||
use App\Models\Album;
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use Saloon\Contracts\Body\HasBody;
|
||||
use Saloon\Enums\Method;
|
||||
use Saloon\Traits\Body\HasFormBody;
|
||||
|
||||
final class ScrobbleRequest extends SignedRequest implements HasBody
|
||||
{
|
||||
use HasFormBody;
|
||||
|
||||
protected Method $method = Method::POST;
|
||||
|
||||
public function __construct(private Song $song, private User $user, private int $timestamp)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function resolveEndpoint(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
protected function defaultBody(): array
|
||||
{
|
||||
$body = [
|
||||
'api_key' => config('koel.lastfm.key'),
|
||||
'method' => 'track.scrobble',
|
||||
'artist' => $this->song->artist->name,
|
||||
'track' => $this->song->title,
|
||||
'timestamp' => $this->timestamp,
|
||||
'sk' => $this->user->preferences->lastFmSessionKey,
|
||||
];
|
||||
|
||||
if ($this->song->album->name !== Album::UNKNOWN_NAME) {
|
||||
$body['album'] = $this->song->album->name;
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
}
|
48
app/Http/Integrations/Lastfm/Requests/SignedRequest.php
Normal file
48
app/Http/Integrations/Lastfm/Requests/SignedRequest.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm\Requests;
|
||||
|
||||
use Saloon\Http\PendingRequest;
|
||||
use Saloon\Http\Request;
|
||||
use Saloon\Repositories\Body\FormBodyRepository;
|
||||
|
||||
abstract class SignedRequest extends Request
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware()->onRequest(fn (PendingRequest $request) => $this->sign($request));
|
||||
}
|
||||
|
||||
protected function sign(PendingRequest $request): void
|
||||
{
|
||||
if ($request->body() instanceof FormBodyRepository) {
|
||||
$request->body()->add('api_sig', self::createSignature($request->body()->all()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$request->query()->add('api_sig', self::createSignature($request->query()->all()));
|
||||
}
|
||||
|
||||
private static function createSignature(array $parameters): string
|
||||
{
|
||||
ksort($parameters);
|
||||
|
||||
// Generate the API signature.
|
||||
// @link http://www.last.fm/api/webauth#6
|
||||
$str = '';
|
||||
|
||||
foreach ($parameters as $name => $value) {
|
||||
if ($name === 'format') {
|
||||
// The format parameter is not part of the signature.
|
||||
continue;
|
||||
}
|
||||
|
||||
$str .= $name . $value;
|
||||
}
|
||||
|
||||
$str .= config('koel.lastfm.secret');
|
||||
|
||||
return md5($str);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm\Requests;
|
||||
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use Saloon\Contracts\Body\HasBody;
|
||||
use Saloon\Enums\Method;
|
||||
use Saloon\Traits\Body\HasFormBody;
|
||||
|
||||
final class ToggleLoveTrackRequest extends SignedRequest implements HasBody
|
||||
{
|
||||
use HasFormBody;
|
||||
|
||||
protected Method $method = Method::POST;
|
||||
|
||||
public function __construct(private Song $song, private User $user, private bool $love)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function resolveEndpoint(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
protected function defaultBody(): array
|
||||
{
|
||||
return [
|
||||
'api_key' => config('koel.lastfm.key'),
|
||||
'method' => $this->love ? 'track.love' : 'track.unlove',
|
||||
'sk' => $this->user->preferences->lastFmSessionKey,
|
||||
'artist' => $this->song->artist->name,
|
||||
'track' => $this->song->title,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Integrations\Lastfm\Requests;
|
||||
|
||||
use App\Models\Album;
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use Saloon\Contracts\Body\HasBody;
|
||||
use Saloon\Enums\Method;
|
||||
use Saloon\Traits\Body\HasFormBody;
|
||||
|
||||
final class UpdateNowPlayingRequest extends SignedRequest implements HasBody
|
||||
{
|
||||
use HasFormBody;
|
||||
|
||||
protected Method $method = Method::POST;
|
||||
|
||||
public function __construct(private Song $song, private User $user)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function resolveEndpoint(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
protected function defaultBody(): array
|
||||
{
|
||||
$parameters = [
|
||||
'api_key' => config('koel.lastfm.key'),
|
||||
'method' => 'track.updateNowPlaying',
|
||||
'artist' => $this->song->artist->name,
|
||||
'track' => $this->song->title,
|
||||
'duration' => $this->song->length,
|
||||
'sk' => $this->user->preferences->lastFmSessionKey,
|
||||
];
|
||||
|
||||
if ($this->song->album->name !== Album::UNKNOWN_NAME) {
|
||||
$parameters['album'] = $this->song->album->name;
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
}
|
|
@ -2,21 +2,26 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Http\Integrations\Lastfm\LastfmConnector;
|
||||
use App\Http\Integrations\Lastfm\Requests\GetAlbumInfoRequest;
|
||||
use App\Http\Integrations\Lastfm\Requests\GetArtistInfoRequest;
|
||||
use App\Http\Integrations\Lastfm\Requests\GetSessionKeyRequest;
|
||||
use App\Http\Integrations\Lastfm\Requests\ScrobbleRequest;
|
||||
use App\Http\Integrations\Lastfm\Requests\ToggleLoveTrackRequest;
|
||||
use App\Http\Integrations\Lastfm\Requests\UpdateNowPlayingRequest;
|
||||
use App\Models\Album;
|
||||
use App\Models\Artist;
|
||||
use App\Models\Song;
|
||||
use App\Models\User;
|
||||
use App\Services\ApiClients\LastfmClient;
|
||||
use App\Services\Contracts\MusicEncyclopedia;
|
||||
use App\Values\AlbumInformation;
|
||||
use App\Values\ArtistInformation;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\Utils;
|
||||
use Generator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class LastfmService implements MusicEncyclopedia
|
||||
{
|
||||
public function __construct(private LastfmClient $client)
|
||||
public function __construct(private LastfmConnector $connector)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -43,10 +48,7 @@ class LastfmService implements MusicEncyclopedia
|
|||
}
|
||||
|
||||
return attempt_if(static::enabled(), function () use ($artist): ?ArtistInformation {
|
||||
$name = urlencode($artist->name);
|
||||
$response = $this->client->get("?method=artist.getInfo&autocorrect=1&artist=$name&format=json");
|
||||
|
||||
return isset($response?->artist) ? ArtistInformation::fromLastFmData($response->artist) : null;
|
||||
return $this->connector->send(new GetArtistInfoRequest($artist))->dto();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -57,41 +59,18 @@ class LastfmService implements MusicEncyclopedia
|
|||
}
|
||||
|
||||
return attempt_if(static::enabled(), function () use ($album): ?AlbumInformation {
|
||||
$albumName = urlencode($album->name);
|
||||
$artistName = urlencode($album->artist->name);
|
||||
|
||||
$response = $this->client
|
||||
->get("?method=album.getInfo&autocorrect=1&album=$albumName&artist=$artistName&format=json");
|
||||
|
||||
return isset($response?->album) ? AlbumInformation::fromLastFmData($response->album) : null;
|
||||
return $this->connector->send(new GetAlbumInfoRequest($album))->dto();
|
||||
});
|
||||
}
|
||||
|
||||
public function scrobble(Song $song, User $user, int $timestamp): void
|
||||
{
|
||||
$params = [
|
||||
'artist' => $song->artist->name,
|
||||
'track' => $song->title,
|
||||
'timestamp' => $timestamp,
|
||||
'sk' => $user->preferences->lastFmSessionKey,
|
||||
'method' => 'track.scrobble',
|
||||
];
|
||||
|
||||
if ($song->album->name !== Album::UNKNOWN_NAME) {
|
||||
$params['album'] = $song->album->name;
|
||||
}
|
||||
|
||||
attempt(fn () => $this->client->post('/', $params, false));
|
||||
attempt(fn () => $this->connector->send(new ScrobbleRequest($song, $user, $timestamp)));
|
||||
}
|
||||
|
||||
public function toggleLoveTrack(Song $song, User $user, bool $love): void
|
||||
{
|
||||
attempt(fn () => $this->client->post('/', [
|
||||
'track' => $song->title,
|
||||
'artist' => $song->artist->name,
|
||||
'sk' => $user->preferences->lastFmSessionKey,
|
||||
'method' => $love ? 'track.love' : 'track.unlove',
|
||||
], false));
|
||||
attempt(fn () => $this->connector->send(new ToggleLoveTrackRequest($song, $user, $love)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,40 +78,26 @@ class LastfmService implements MusicEncyclopedia
|
|||
*/
|
||||
public function batchToggleLoveTracks(Collection $songs, User $user, bool $love): void
|
||||
{
|
||||
$promises = $songs->map(
|
||||
function (Song $song) use ($user, $love): Promise {
|
||||
return $this->client->postAsync('/', [
|
||||
'track' => $song->title,
|
||||
'artist' => $song->artist->name,
|
||||
'sk' => $user->preferences->lastFmSessionKey,
|
||||
'method' => $love ? 'track.love' : 'track.unlove',
|
||||
], false);
|
||||
$generatorCallback = static function () use ($songs, $user, $love): Generator {
|
||||
foreach ($songs as $song) {
|
||||
yield new ToggleLoveTrackRequest($song, $user, $love);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
attempt(static fn () => Utils::unwrap($promises));
|
||||
$this->connector
|
||||
->pool($generatorCallback)
|
||||
->send()
|
||||
->wait();
|
||||
}
|
||||
|
||||
public function updateNowPlaying(Song $song, User $user): void
|
||||
{
|
||||
$params = [
|
||||
'artist' => $song->artist->name,
|
||||
'track' => $song->title,
|
||||
'duration' => $song->length,
|
||||
'sk' => $user->preferences->lastFmSessionKey,
|
||||
'method' => 'track.updateNowPlaying',
|
||||
];
|
||||
|
||||
if ($song->album->name !== Album::UNKNOWN_NAME) {
|
||||
$params['album'] = $song->album->name;
|
||||
}
|
||||
|
||||
attempt(fn () => $this->client->post('/', $params, false));
|
||||
attempt(fn () => $this->connector->send(new UpdateNowPlayingRequest($song, $user)));
|
||||
}
|
||||
|
||||
public function getSessionKey(string $token): ?string
|
||||
{
|
||||
return $this->client->getSessionKey($token);
|
||||
return object_get($this->connector->send(new GetSessionKeyRequest($token))->object(), 'session.key');
|
||||
}
|
||||
|
||||
public function setUserSessionKey(User $user, ?string $sessionKey): void
|
||||
|
|
|
@ -2,14 +2,10 @@
|
|||
|
||||
namespace App\Values;
|
||||
|
||||
use App\Values\Concerns\FormatsLastFmText;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
final class AlbumInformation implements Arrayable
|
||||
{
|
||||
use FormatsLastFmText;
|
||||
|
||||
public const JSON_STRUCTURE = [
|
||||
'url',
|
||||
'cover',
|
||||
|
@ -39,23 +35,6 @@ final class AlbumInformation implements Arrayable
|
|||
return new self($url, $cover, $wiki, $tracks);
|
||||
}
|
||||
|
||||
public static function fromLastFmData(object $data): self
|
||||
{
|
||||
return self::make(
|
||||
url: $data->url,
|
||||
cover: Arr::get($data->image, '0.#text'),
|
||||
wiki: [
|
||||
'summary' => isset($data->wiki) ? self::formatLastFmText($data->wiki->summary) : '',
|
||||
'full' => isset($data->wiki) ? self::formatLastFmText($data->wiki->content) : '',
|
||||
],
|
||||
tracks: array_map(static fn ($track): array => [
|
||||
'title' => $track->name,
|
||||
'length' => (int) $track->duration,
|
||||
'url' => $track->url,
|
||||
], $data->tracks?->track ?? []),
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
|
|
|
@ -2,13 +2,10 @@
|
|||
|
||||
namespace App\Values;
|
||||
|
||||
use App\Values\Concerns\FormatsLastFmText;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
|
||||
final class ArtistInformation implements Arrayable
|
||||
{
|
||||
use FormatsLastFmText;
|
||||
|
||||
public const JSON_STRUCTURE = [
|
||||
'url',
|
||||
'image',
|
||||
|
@ -30,17 +27,6 @@ final class ArtistInformation implements Arrayable
|
|||
return new self($url, $image, $bio);
|
||||
}
|
||||
|
||||
public static function fromLastFmData(object $data): self
|
||||
{
|
||||
return self::make(
|
||||
url: $data->url,
|
||||
bio: [
|
||||
'summary' => isset($data->bio) ? self::formatLastFmText($data->bio->summary) : '',
|
||||
'full' => isset($data->bio) ? self::formatLastFmText($data->bio->content) : '',
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
"meilisearch/meilisearch-php": "^0.24.0",
|
||||
"http-interop/http-factory-guzzle": "^1.2",
|
||||
"league/flysystem-aws-s3-v3": "^3.0",
|
||||
"spatie/flysystem-dropbox": "^3.0"
|
||||
"spatie/flysystem-dropbox": "^3.0",
|
||||
"saloonphp/saloon": "^3.8",
|
||||
"saloonphp/laravel-plugin": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.0",
|
||||
|
|
152
composer.lock
generated
152
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "7cf7d2bb1b51df5f49ca061698b6c4be",
|
||||
"content-hash": "05ad56210e2f5ed90da83428f2777175",
|
||||
"packages": [
|
||||
{
|
||||
"name": "algolia/algoliasearch-client-php",
|
||||
|
@ -5359,6 +5359,156 @@
|
|||
],
|
||||
"time": "2023-01-12T18:13:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "saloonphp/laravel-plugin",
|
||||
"version": "v3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/saloonphp/laravel-plugin.git",
|
||||
"reference": "017fc93a2af15ccb94840b9ea772c9f4e95e2917"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/saloonphp/laravel-plugin/zipball/017fc93a2af15ccb94840b9ea772c9f4e95e2917",
|
||||
"reference": "017fc93a2af15ccb94840b9ea772c9f4e95e2917",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/console": "^9.52 || ^10.0",
|
||||
"illuminate/http": "^9.52 || ^10.0",
|
||||
"illuminate/support": "^9.52 || ^10.0",
|
||||
"php": "^8.1",
|
||||
"saloonphp/saloon": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.5",
|
||||
"orchestra/testbench": "^v7.30 || ^v8.10",
|
||||
"pestphp/pest": "^v1.23",
|
||||
"phpstan/phpstan": "^1.9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Saloon": "Saloon\\Laravel\\Facades\\Saloon"
|
||||
},
|
||||
"providers": [
|
||||
"Saloon\\Laravel\\SaloonServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Saloon\\Laravel\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sam Carré",
|
||||
"email": "29132017+Sammyjo20@users.noreply.github.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Laravel plugin for Saloon",
|
||||
"homepage": "https://github.com/saloonphp/laravel-plugin",
|
||||
"keywords": [
|
||||
"api",
|
||||
"api-integrations",
|
||||
"saloon",
|
||||
"sammyjo20",
|
||||
"sdk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/saloonphp/laravel-plugin/issues",
|
||||
"source": "https://github.com/saloonphp/laravel-plugin/tree/v3.0.0"
|
||||
},
|
||||
"time": "2023-10-02T16:28:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "saloonphp/saloon",
|
||||
"version": "v3.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/saloonphp/saloon.git",
|
||||
"reference": "e669e8554f275c83aaa0b7d9d219b442e269f75f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/saloonphp/saloon/zipball/e669e8554f275c83aaa0b7d9d219b442e269f75f",
|
||||
"reference": "e669e8554f275c83aaa0b7d9d219b442e269f75f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^7.6",
|
||||
"guzzlehttp/promises": "^1.5 || ^2.0",
|
||||
"guzzlehttp/psr7": "^2.0",
|
||||
"php": "^8.1",
|
||||
"psr/http-factory": "^1.0",
|
||||
"psr/http-message": "^1.1 || ^2.0"
|
||||
},
|
||||
"conflict": {
|
||||
"sammyjo20/saloon": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-simplexml": "*",
|
||||
"friendsofphp/php-cs-fixer": "^3.5",
|
||||
"illuminate/collections": "^9.39 || ^10.0",
|
||||
"league/flysystem": "^3.0",
|
||||
"pestphp/pest": "^2.6",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"saloonphp/xml-wrangler": "^1.1",
|
||||
"spatie/ray": "^1.33",
|
||||
"symfony/dom-crawler": "^6.0 || ^7.0",
|
||||
"symfony/var-dumper": "^6.3 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/collections": "Required for the response collect() method.",
|
||||
"saloonphp/xml-wrangler": "Required for the response xmlReader() method.",
|
||||
"symfony/dom-crawler": "Required for the response dom() method.",
|
||||
"symfony/var-dumper": "Required for default debugging drivers."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Saloon\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sam Carré",
|
||||
"email": "29132017+Sammyjo20@users.noreply.github.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Build beautiful API integrations and SDKs with Saloon",
|
||||
"homepage": "https://github.com/saloonphp/saloon",
|
||||
"keywords": [
|
||||
"api",
|
||||
"api-integrations",
|
||||
"saloon",
|
||||
"sammyjo20",
|
||||
"sdk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/saloonphp/saloon/issues",
|
||||
"source": "https://github.com/saloonphp/saloon/tree/v3.8.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sammyjo20",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-20T23:14:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/dropbox-api",
|
||||
"version": "1.22.0",
|
||||
|
|
38
config/saloon.php
Normal file
38
config/saloon.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Saloon\Http\Senders\GuzzleSender;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Saloon Sender
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value specifies the "sender" class that Saloon should use by
|
||||
| default on all connectors. You can change this sender if you
|
||||
| would like to use your own. You may also specify your own
|
||||
| sender on a per-connector basis.
|
||||
|
|
||||
*/
|
||||
|
||||
'default_sender' => GuzzleSender::class,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Integrations Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, this package will create any classes within
|
||||
| `/app/Http/Integrations` directory. If you're using
|
||||
| a different design approach, then your classes
|
||||
| may be in a different place. You can change
|
||||
| that location so that the saloon:list
|
||||
| command will still find your files
|
||||
|
|
||||
*/
|
||||
|
||||
'integrations_path' => base_path('App/Http/Integrations'),
|
||||
];
|
Loading…
Reference in a new issue