mirror of
https://github.com/devfake/flox.git
synced 2024-11-14 22:22:39 +01:00
search by media type (#45)
* search only for media_type for file-parser * typos * remove 'add' button if it's an empty item * fix relations for searching * add tests for search * fix missing media type * fix media type for strict search * fix test
This commit is contained in:
parent
89eb67f85a
commit
04d34440df
@ -65,11 +65,11 @@
|
||||
$title = Input::get('q');
|
||||
|
||||
if(config('scout.driver')) {
|
||||
return $this->item->search($title)->get();
|
||||
return $this->item->search($title)->with('latestEpisode')->get();
|
||||
}
|
||||
|
||||
// We don't have an smart search driver and return an simple 'like' query.
|
||||
return $this->item->findByTitle($title)->get();
|
||||
return $this->item->findByTitle($title)->with('latestEpisode')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,11 +102,14 @@
|
||||
return $query->where('tmdb_id', $tmdbId);
|
||||
}
|
||||
|
||||
public function scopeFindByFPName($query, $item)
|
||||
public function scopeFindByFPName($query, $item, $mediaType)
|
||||
{
|
||||
$changed = isset($item->changed->name) ? $item->changed->name : $item->name;
|
||||
|
||||
return $query->where('media_type', $mediaType)
|
||||
->where(function($query) use ($item, $changed) {
|
||||
return $query->where('fp_name', $item->name)->orWhere('fp_name', $changed);
|
||||
});
|
||||
}
|
||||
|
||||
public function scopeFindBySrc($query, $src)
|
||||
@ -114,22 +117,32 @@
|
||||
return $query->where('src', $src);
|
||||
}
|
||||
|
||||
public function scopeFindByTitle($query, $title)
|
||||
public function scopeFindByTitle($query, $title, $mediaType = null)
|
||||
{
|
||||
// Only necessarily if we search from file-parser.
|
||||
if($mediaType) {
|
||||
$query->where('media_type', $mediaType);
|
||||
}
|
||||
|
||||
return $query->where(function($query) use ($title) {
|
||||
return $query->where('title', 'like', '%' . $title . '%')
|
||||
->orWhere('original_title', 'like', '%' . $title . '%')
|
||||
->orWhereHas('alternativeTitles', function($query) use ($title) {
|
||||
$query->where('title', 'like', '%' . $title . '%');
|
||||
return $query->where('title', 'like', '%' . $title . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public function scopeFindByTitleStrict($query, $title)
|
||||
public function scopeFindByTitleStrict($query, $title, $mediaType)
|
||||
{
|
||||
return $query->where('title', $title)
|
||||
return $query->where('media_type', $mediaType)
|
||||
->where(function($query) use ($title) {
|
||||
$query->where('title', $title)
|
||||
->orWhere('original_title', $title)
|
||||
->orWhere('fp_name', $title)
|
||||
->orWhereHas('alternativeTitles', function($query) use ($title) {
|
||||
$query->where('title', $title);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* See if it can find the item in our database.
|
||||
* See if it can find the item in our database, filtered by media_type.
|
||||
* Otherwise search in TMDb or create an empty item.
|
||||
*
|
||||
* @param $item
|
||||
@ -116,7 +116,7 @@
|
||||
private function validateStore($item)
|
||||
{
|
||||
// See if file is already in our database.
|
||||
if($found = $this->itemService->findBy('title_strict', $item->name)) {
|
||||
if($found = $this->itemService->findBy('title_strict', $item->name, $this->itemCategory)) {
|
||||
return $this->store($item, $found->tmdb_id);
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* See if it can find the item in our database.
|
||||
* See if it can find the item in our database, filtered by media_type.
|
||||
* Check if it is an empty item and search against TMDb and update them.
|
||||
* Otherwise create an empty item.
|
||||
*
|
||||
@ -142,7 +142,7 @@
|
||||
private function validateUpdate($item)
|
||||
{
|
||||
// See if file is already in our database.
|
||||
if($found = $this->itemService->findBy('fp_name', $item)) {
|
||||
if($found = $this->itemService->findBy('fp_name', $item, $this->itemCategory)) {
|
||||
if( ! $found->tmdb_id) {
|
||||
return $this->searchTmdbAndUpdateEmptyItem($found, $item);
|
||||
}
|
||||
@ -194,7 +194,7 @@
|
||||
*/
|
||||
private function searchTmdb($item)
|
||||
{
|
||||
$found = $this->tmdb->search($this->getFileName($item));
|
||||
$found = $this->tmdb->search($this->getFileName($item), $this->itemCategory);
|
||||
|
||||
if( ! $found) {
|
||||
return false;
|
||||
@ -207,7 +207,6 @@
|
||||
* If TMDb can't find anything, create a simple item with data from local file.
|
||||
*
|
||||
* @param $item
|
||||
* @param $mediaType
|
||||
* @return mixed
|
||||
*/
|
||||
private function createEmptyItem($item)
|
||||
|
@ -134,21 +134,29 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* See if we can find a item by title, tmdb_id or src in our database.
|
||||
* See if we can find a item by title, fp_name, tmdb_id or src in our database.
|
||||
*
|
||||
* If we search from file-parser, we also need to filter the results by media_type.
|
||||
* If we have e.g. 'Avatar' as tv show, we don't want results like the 'Avatar' movie.
|
||||
*
|
||||
* @param $type
|
||||
* @param $value
|
||||
* @param $mediaType
|
||||
* @return mixed
|
||||
*/
|
||||
public function findBy($type, $value)
|
||||
public function findBy($type, $value, $mediaType = null)
|
||||
{
|
||||
if($mediaType) {
|
||||
$mediaType = $mediaType == 'movies' ? 'movie' : 'tv';
|
||||
}
|
||||
|
||||
switch($type) {
|
||||
case 'title':
|
||||
return $this->model->findByTitle($value)->first();
|
||||
return $this->model->findByTitle($value, $mediaType)->first();
|
||||
case 'title_strict':
|
||||
return $this->model->findByTitleStrict($value)->first();
|
||||
return $this->model->findByTitleStrict($value, $mediaType)->first();
|
||||
case 'fp_name':
|
||||
return $this->model->findByFPName($value)->first();
|
||||
return $this->model->findByFPName($value, $mediaType)->first();
|
||||
case 'tmdb_id':
|
||||
return $this->model->findByTmdbId($value)->first();
|
||||
case 'src':
|
||||
|
@ -19,7 +19,7 @@
|
||||
private $base = 'http://api.themoviedb.org';
|
||||
|
||||
/**
|
||||
* Get the API Key for TMDB and create an instance of Guzzle.
|
||||
* Get the API Key for TMDb and create an instance of Guzzle.
|
||||
*
|
||||
* @param Client $client
|
||||
*/
|
||||
@ -31,22 +31,38 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Search TMDB by 'title'.
|
||||
* Search TMDb by 'title'.
|
||||
*
|
||||
* @param $title
|
||||
* @return array
|
||||
* @param null $mediaType
|
||||
* @return Collection
|
||||
*/
|
||||
public function search($title)
|
||||
public function search($title, $mediaType = null)
|
||||
{
|
||||
$response = $this->requestTmdb($this->base . '/3/search/multi', [
|
||||
'query' => $title
|
||||
]);
|
||||
$tv = collect();
|
||||
$movies = collect();
|
||||
|
||||
return $this->createItems($response);
|
||||
if( ! $mediaType || $mediaType == 'tv') {
|
||||
$response = $this->fetchSearch($title, 'tv');
|
||||
$tv = collect($this->createItems($response, 'tv'));
|
||||
}
|
||||
|
||||
if( ! $mediaType || $mediaType == 'movies') {
|
||||
$response = $this->fetchSearch($title, 'movie');
|
||||
$movies = collect($this->createItems($response, 'movie'));
|
||||
}
|
||||
|
||||
return $tv->merge($movies)->toArray();
|
||||
}
|
||||
|
||||
private function fetchSearch($title, $mediaType) {
|
||||
return $this->requestTmdb($this->base . '/3/search/' . $mediaType, [
|
||||
'query' => $title,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search TMDB for recommendations and similar movies.
|
||||
* Search TMDb for recommendations and similar movies.
|
||||
*
|
||||
* @param $mediaType
|
||||
* @param $tmdbID
|
||||
@ -82,7 +98,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Search TMDB for upcoming movies.
|
||||
* Search TMDb for upcoming movies.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@ -98,7 +114,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Search TMDB for current popular movies and tv shows.
|
||||
* Search TMDb for current popular movies and tv shows.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@ -148,21 +164,16 @@
|
||||
|
||||
/**
|
||||
* @param $response
|
||||
* @param null $type
|
||||
*
|
||||
* @param $mediaType
|
||||
* @return array
|
||||
*
|
||||
*/
|
||||
private function createItems($response, $type = null)
|
||||
private function createItems($response, $mediaType)
|
||||
{
|
||||
$items = [];
|
||||
$response = json_decode($response->getBody());
|
||||
|
||||
foreach($response->results as $result) {
|
||||
// Suggestions doesn't deliver 'media type' by default
|
||||
$mediaType = $type ?: $result->media_type;
|
||||
|
||||
if($mediaType == 'person') continue;
|
||||
|
||||
$dtime = DateTime::createFromFormat('Y-m-d', (array_key_exists('release_date', $result)
|
||||
? ($result->release_date ?: '1970-12-1')
|
||||
: ($result->first_air_date ?: '1970-12-1')
|
||||
|
@ -67,7 +67,7 @@
|
||||
{
|
||||
$this->createMovie();
|
||||
|
||||
$itemFromTitle = $this->itemService->findBy('title', 'craft');
|
||||
$itemFromTitle = $this->itemService->findBy('title', 'craft', 'movies');
|
||||
$itemFromId = $this->itemService->findBy('tmdb_id', 68735);
|
||||
|
||||
$this->assertEquals(68735, $itemFromTitle->tmdb_id);
|
||||
@ -79,8 +79,8 @@
|
||||
{
|
||||
$this->createMovie();
|
||||
|
||||
$notFound = $this->itemService->findBy('title_strict', 'craft');
|
||||
$found = $this->itemService->findBy('title_strict', 'Warcraft: The Beginning');
|
||||
$notFound = $this->itemService->findBy('title_strict', 'craft', 'movies');
|
||||
$found = $this->itemService->findBy('title_strict', 'Warcraft: The Beginning', 'movies');
|
||||
|
||||
$this->assertNull($notFound);
|
||||
$this->assertEquals(68735, $found->tmdb_id);
|
||||
|
@ -11,6 +11,48 @@
|
||||
|
||||
use DatabaseMigrations;
|
||||
|
||||
/** @test */
|
||||
public function it_should_search_and_merge_movies_and_tv()
|
||||
{
|
||||
$this->createGuzzleMock($this->tmdbFixtures('tv/search'), $this->tmdbFixtures('movie/search'));
|
||||
|
||||
$result = $this->callSearch();
|
||||
|
||||
$hasTv = $this->in_array_r('Avatar: The Last Airbender', $result);
|
||||
$hasMovie = $this->in_array_r('Avatar: Aufbruch nach Pandora', $result);
|
||||
|
||||
$this->assertTrue($hasTv);
|
||||
$this->assertTrue($hasMovie);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_should_only_search_for_tv()
|
||||
{
|
||||
$this->createGuzzleMock($this->tmdbFixtures('tv/search'), $this->tmdbFixtures('movie/search'));
|
||||
|
||||
$result = $this->callSearch('tv');
|
||||
|
||||
$hasTv = $this->in_array_r('Avatar: The Last Airbender', $result);
|
||||
$hasMovie = $this->in_array_r('Avatar: Aufbruch nach Pandora', $result);
|
||||
|
||||
$this->assertTrue($hasTv);
|
||||
$this->assertFalse($hasMovie);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_should_only_search_for_movies()
|
||||
{
|
||||
$this->createGuzzleMock($this->tmdbFixtures('movie/search'), $this->tmdbFixtures('tv/search'));
|
||||
|
||||
$result = $this->callSearch('movies');
|
||||
|
||||
$hasTv = $this->in_array_r('Avatar: The Last Airbender', $result);
|
||||
$hasMovie = $this->in_array_r('Avatar: Aufbruch nach Pandora', $result);
|
||||
|
||||
$this->assertFalse($hasTv);
|
||||
$this->assertTrue($hasMovie);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_should_fetch_and_merge_movies_and_tv_in_trending()
|
||||
{
|
||||
@ -70,17 +112,24 @@
|
||||
$this->app->instance(Client::class, new Client(['handler' => $handler]));
|
||||
|
||||
$tmdb = app(TMDB::class);
|
||||
$result = $tmdb->search('Avatar - Legend of Korra');
|
||||
$result = $tmdb->search('Avatar - Legend of Korra', 'tv');
|
||||
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertArrayHasKey('tmdb_id', $result[0]);
|
||||
}
|
||||
|
||||
private function callSearch($type = null)
|
||||
{
|
||||
$tmdb = app(TMDB::class);
|
||||
|
||||
return $tmdb->search('Avatar', $type);
|
||||
}
|
||||
|
||||
private function in_array_r($item , $array){
|
||||
return (bool) preg_match('/"' . $item . '"/i' , json_encode($array));
|
||||
}
|
||||
|
||||
private function createGuzzleMock($fixture, $fixture2 = null)
|
||||
private function createGuzzleMock($fixture, $fixture2)
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(200, ['X-RateLimit-Remaining' => [40]], $fixture),
|
||||
|
46
backend/tests/fixtures/tmdb/movie/search.json
vendored
Normal file
46
backend/tests/fixtures/tmdb/movie/search.json
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"page": 1,
|
||||
"results": [
|
||||
{
|
||||
"poster_path": "/kmcqlZGaSh20zpTbuoF0Cdn07dT.jpg",
|
||||
"adult": false,
|
||||
"overview": "overview",
|
||||
"release_date": "2009-12-10",
|
||||
"genre_ids": [
|
||||
28,
|
||||
12,
|
||||
14,
|
||||
878
|
||||
],
|
||||
"id": 19995,
|
||||
"original_title": "Avatar",
|
||||
"original_language": "en",
|
||||
"title": "Avatar: Aufbruch nach Pandora",
|
||||
"backdrop_path": "/5XPPB44RQGfkBrbJxmtdndKz05n.jpg",
|
||||
"popularity": 13.117401,
|
||||
"vote_count": 8721,
|
||||
"video": false,
|
||||
"vote_average": 7.1
|
||||
},
|
||||
{
|
||||
"poster_path": "/famiFiwZPQ3A8WVjKFhCplKrZgr.jpg",
|
||||
"adult": false,
|
||||
"overview": "overview",
|
||||
"release_date": "2011-04-30",
|
||||
"genre_ids": [
|
||||
27
|
||||
],
|
||||
"id": 282908,
|
||||
"original_title": "Abataa",
|
||||
"original_language": "ja",
|
||||
"title": "Avatar",
|
||||
"backdrop_path": null,
|
||||
"popularity": 1.001713,
|
||||
"vote_count": 0,
|
||||
"video": false,
|
||||
"vote_average": 0
|
||||
}
|
||||
],
|
||||
"total_results": 29,
|
||||
"total_pages": 2
|
||||
}
|
51
backend/tests/fixtures/tmdb/tv/search.json
vendored
Normal file
51
backend/tests/fixtures/tmdb/tv/search.json
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"page": 1,
|
||||
"results": [
|
||||
{
|
||||
"poster_path": "/4KgScXaTeVZWgsBDJNbDYbeqRjF.jpg",
|
||||
"popularity": 3.04828,
|
||||
"id": 246,
|
||||
"backdrop_path": "/14UEjm0MDQ8C22BqYqdzn3gsAiX.jpg",
|
||||
"vote_average": 7.8,
|
||||
"overview": "overview",
|
||||
"first_air_date": "2005-02-21",
|
||||
"origin_country": [
|
||||
"US"
|
||||
],
|
||||
"genre_ids": [
|
||||
28,
|
||||
12,
|
||||
16,
|
||||
14
|
||||
],
|
||||
"original_language": "en",
|
||||
"vote_count": 67,
|
||||
"name": "Avatar: The Last Airbender",
|
||||
"original_name": "Avatar: The Last Airbender"
|
||||
},
|
||||
{
|
||||
"poster_path": "/8uOOycL6r4vqOT8tgw4behO5MmB.jpg",
|
||||
"popularity": 3.52741,
|
||||
"id": 33880,
|
||||
"backdrop_path": "/r1oTzR9Ke7pICxe1eiP8ZjoGJju.jpg",
|
||||
"vote_average": 7.52,
|
||||
"overview": "overview",
|
||||
"first_air_date": "2012-04-14",
|
||||
"origin_country": [
|
||||
"US"
|
||||
],
|
||||
"genre_ids": [
|
||||
10765,
|
||||
16,
|
||||
18,
|
||||
10751
|
||||
],
|
||||
"original_language": "en",
|
||||
"vote_count": 44,
|
||||
"name": "The Legend of Korra",
|
||||
"original_name": "The Legend of Korra"
|
||||
}
|
||||
],
|
||||
"total_results": 2,
|
||||
"total_pages": 1
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<span v-if="localItem.rating" :class="'item-rating rating-' + localItem.rating" @click="changeRating()">
|
||||
<i class="icon-rating"></i>
|
||||
</span>
|
||||
<span v-if=" ! localItem.rating" class="item-rating item-new" :class="{disabled: disabled}" @click="addNewItem()">
|
||||
<span v-if=" ! localItem.rating && localItem.tmdb_id" class="item-rating item-new" :class="{disabled: disabled}" @click="addNewItem()">
|
||||
<span class="loader smallsize-loader" v-if="rated"><i></i></span>
|
||||
<i class="icon-add" v-if=" ! rated"></i>
|
||||
</span>
|
||||
|
Loading…
Reference in New Issue
Block a user