mirror of
https://github.com/koel/koel
synced 2025-02-17 13:58:28 +00:00
feat: modify the response format for search
This commit is contained in:
parent
cacca23c02
commit
588b30d9bb
4 changed files with 118 additions and 25 deletions
|
@ -2,7 +2,7 @@ openapi: 3.0.0
|
||||||
info:
|
info:
|
||||||
title: Koel API
|
title: Koel API
|
||||||
version: 5.0.0
|
version: 5.0.0
|
||||||
description: 'The API for [Koel](http://koel.dev), the music streaming application that works.'
|
description: 'The API for [Koel](https://koel.dev), the music streaming application that works.'
|
||||||
contact:
|
contact:
|
||||||
name: An Phan
|
name: An Phan
|
||||||
url: 'https://phanan.net'
|
url: 'https://phanan.net'
|
||||||
|
@ -11,7 +11,7 @@ info:
|
||||||
name: MIT
|
name: MIT
|
||||||
url: 'https://github.com/koel/koel/blob/master/LICENSE.md'
|
url: 'https://github.com/koel/koel/blob/master/LICENSE.md'
|
||||||
servers:
|
servers:
|
||||||
- url: 'http://localhost:8000'
|
- url: 'https://koel.test'
|
||||||
description: Local
|
description: Local
|
||||||
tags:
|
tags:
|
||||||
- name: interaction
|
- name: interaction
|
||||||
|
@ -852,8 +852,7 @@ paths:
|
||||||
$ref: '#/components/schemas/Song'
|
$ref: '#/components/schemas/Song'
|
||||||
operationId: post-os-s3-song
|
operationId: post-os-s3-song
|
||||||
description: Create a new song or update an existing one with data sent from AWS
|
description: Create a new song or update an existing one with data sent from AWS
|
||||||
security:
|
security: []
|
||||||
- appKey: []
|
|
||||||
requestBody:
|
requestBody:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
|
@ -908,8 +907,7 @@ paths:
|
||||||
'204':
|
'204':
|
||||||
description: No Content
|
description: No Content
|
||||||
description: Remove a song whose information matches the data sent from AWS S3 (`bucket` and `key`)
|
description: Remove a song whose information matches the data sent from AWS S3 (`bucket` and `key`)
|
||||||
security:
|
security: []
|
||||||
- appKey: []
|
|
||||||
requestBody:
|
requestBody:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
|
@ -1103,6 +1101,84 @@ paths:
|
||||||
description: Download a whole playlist. This is NOT an XmlHttpRequest. The response will be a download response of either one media file or a zip file containg multiple media files.
|
description: Download a whole playlist. This is NOT an XmlHttpRequest. The response will be a download response of either one media file or a zip file containg multiple media files.
|
||||||
security:
|
security:
|
||||||
- api-token: []
|
- api-token: []
|
||||||
|
/api/search:
|
||||||
|
get:
|
||||||
|
summary: 'Search for songs, albums, and artists'
|
||||||
|
tags:
|
||||||
|
- search
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: OK
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
results:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- songs
|
||||||
|
- artists
|
||||||
|
- albums
|
||||||
|
properties:
|
||||||
|
songs:
|
||||||
|
type: array
|
||||||
|
description: An array of max 6 best-matching songs' IDs
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
artists:
|
||||||
|
type: array
|
||||||
|
description: An array of max 6 best-matching artists' IDs
|
||||||
|
items:
|
||||||
|
type: integer
|
||||||
|
albums:
|
||||||
|
type: array
|
||||||
|
description: An array of max 6 best-matching albums' IDs
|
||||||
|
items:
|
||||||
|
type: number
|
||||||
|
required:
|
||||||
|
- results
|
||||||
|
operationId: get-api-search
|
||||||
|
description: 'Seach for songs, albums, and artists, with a maximum of {count} results each.'
|
||||||
|
security:
|
||||||
|
- Bearer Token: []
|
||||||
|
parameters:
|
||||||
|
- schema:
|
||||||
|
type: string
|
||||||
|
in: query
|
||||||
|
name: q
|
||||||
|
description: The keywords to search
|
||||||
|
required: true
|
||||||
|
- schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
default: 6
|
||||||
|
in: query
|
||||||
|
name: count
|
||||||
|
description: 'The maximum number of results for songs, artists, and albums'
|
||||||
|
parameters: []
|
||||||
|
/api/search/songs:
|
||||||
|
get:
|
||||||
|
summary: Search for songs
|
||||||
|
tags:
|
||||||
|
- search
|
||||||
|
responses: {}
|
||||||
|
operationId: get-api-search-songs
|
||||||
|
description: Get all songs that matches a search query.
|
||||||
|
security:
|
||||||
|
- Bearer Token: []
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
songs:
|
||||||
|
type: array
|
||||||
|
description: An array of matching songs' IDs
|
||||||
|
items: {}
|
||||||
|
required:
|
||||||
|
- songs
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
User:
|
User:
|
||||||
|
@ -1638,10 +1714,6 @@ components:
|
||||||
Bearer Token:
|
Bearer Token:
|
||||||
type: http
|
type: http
|
||||||
scheme: bearer
|
scheme: bearer
|
||||||
appKey:
|
|
||||||
name: The applcation key (APP_KEY in .env)
|
|
||||||
type: apiKey
|
|
||||||
in: query
|
|
||||||
api-token:
|
api-token:
|
||||||
name: The API token as a query parameter
|
name: The API token as a query parameter
|
||||||
type: apiKey
|
type: apiKey
|
|
@ -22,8 +22,14 @@ class ExcerptSearchController extends Controller
|
||||||
throw new InvalidArgumentException('A search query is required.');
|
throw new InvalidArgumentException('A search query is required.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$count = (int) $request->get('count', SearchService::DEFAULT_EXCERPT_RESULT_COUNT);
|
||||||
|
|
||||||
|
if ($count < 0) {
|
||||||
|
throw new InvalidArgumentException('Invalid count parameter.');
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'results' => $this->searchService->excerptSearch($request->get('q')),
|
'results' => $this->searchService->excerptSearch($request->get('q'), $count),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
namespace App\Http\Controllers\API\Search;
|
namespace App\Http\Controllers\API\Search;
|
||||||
|
|
||||||
use App\Http\Controllers\API\Controller;
|
use App\Http\Controllers\API\Controller;
|
||||||
use App\Models\Song;
|
|
||||||
use App\Services\SearchService;
|
use App\Services\SearchService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
@ -24,11 +23,7 @@ class SongSearchController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'songs' => $this->searchService->searchSongs($request->get('q'))
|
'songs' => $this->searchService->searchSongs($request->get('q')),
|
||||||
->get()
|
|
||||||
->map(static function (Song $song): string {
|
|
||||||
return $song->id;
|
|
||||||
}),
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,20 @@
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Album;
|
||||||
|
use App\Models\Artist;
|
||||||
|
use App\Models\Song;
|
||||||
use App\Repositories\AlbumRepository;
|
use App\Repositories\AlbumRepository;
|
||||||
use App\Repositories\ArtistRepository;
|
use App\Repositories\ArtistRepository;
|
||||||
use App\Repositories\SongRepository;
|
use App\Repositories\SongRepository;
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Laravel\Scout\Builder;
|
use Laravel\Scout\Builder;
|
||||||
|
|
||||||
class SearchService
|
class SearchService
|
||||||
{
|
{
|
||||||
|
public const DEFAULT_EXCERPT_RESULT_COUNT = 6;
|
||||||
|
|
||||||
private $songRepository;
|
private $songRepository;
|
||||||
private $albumRepository;
|
private $albumRepository;
|
||||||
private $artistRepository;
|
private $artistRepository;
|
||||||
|
@ -26,23 +31,38 @@ class SearchService
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<mixed> */
|
/** @return array<mixed> */
|
||||||
public function excerptSearch(string $keywords): array
|
public function excerptSearch(string $keywords, int $count): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'songs' => self::getTopResults($this->songRepository->search($keywords)),
|
'songs' => self::getTopResults($this->songRepository->search($keywords), $count)
|
||||||
'artists' => self::getTopResults($this->artistRepository->search($keywords)),
|
->map(static function (Song $song): string {
|
||||||
'albums' => self::getTopResults($this->albumRepository->search($keywords)),
|
return $song->id;
|
||||||
|
}),
|
||||||
|
'artists' => self::getTopResults($this->artistRepository->search($keywords), $count)
|
||||||
|
->map(static function (Artist $artist): int {
|
||||||
|
return $artist->id;
|
||||||
|
}),
|
||||||
|
'albums' => self::getTopResults($this->albumRepository->search($keywords), $count)
|
||||||
|
->map(static function (Album $album): int {
|
||||||
|
return $album->id;
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return Collection|array<Model> */
|
/** @return Collection|array<Model> */
|
||||||
private static function getTopResults(Builder $query, int $count = 6): Collection
|
private static function getTopResults(Builder $query, int $count): Collection
|
||||||
{
|
{
|
||||||
return $query->take($count)->get();
|
return $query->take($count)->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function searchSongs(string $keywords): Builder
|
/** @return Collection|array<string> */
|
||||||
|
public function searchSongs(string $keywords): Collection
|
||||||
{
|
{
|
||||||
return $this->songRepository->search($keywords);
|
return $this->songRepository
|
||||||
|
->search($keywords)
|
||||||
|
->get()
|
||||||
|
->map(static function (Song $song): string {
|
||||||
|
return $song->id;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue