1
0
mirror of https://github.com/devfake/flox.git synced 2024-11-14 22:22:39 +01:00

search and create episodes

This commit is contained in:
devfake 2016-11-28 08:48:12 +01:00
parent 0bf58b12f6
commit 5cc5802231
5 changed files with 233 additions and 34 deletions

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Episode;
use App\Item; use App\Item;
use App\Services\Storage; use App\Services\Storage;
use App\Services\TMDB; use App\Services\TMDB;
@ -27,16 +28,33 @@
} }
/** /**
* Return all items for home with pagination. * Return all items with pagination.
* *
* @param $orderBy * @param $orderBy
* @return mixed * @return mixed
*/ */
public function items($orderBy) public function items($type, $orderBy)
{ {
$orderType = $orderBy == 'rating' ? 'asc' : 'desc'; $orderType = $orderBy == 'rating' ? 'asc' : 'desc';
return $this->item->orderBy($orderBy, $orderType)->simplePaginate($this->loadingItems); $item = $this->item->orderBy($orderBy, $orderType)->with('latestEpisode');
if($type != 'home') {
$item = $item->where('media_type', $type);
}
return $item->simplePaginate($this->loadingItems);
}
/**
* Get all Episodes of an tv show.
*
* @param $tmdb_id
* @return mixed
*/
public function episodes($tmdb_id)
{
return Episode::where('tmdb_id', $tmdb_id)->get()->groupBy('season_number');
} }
/** /**
@ -93,7 +111,7 @@
} }
/** /**
* Delete movie in database and delete the poster image file. * Delete movie or tv show (with episodes) and remove the poster image file.
* *
* @param $itemID * @param $itemID
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
@ -107,8 +125,13 @@
} }
$this->storage->removePosterFile($item->poster); $this->storage->removePosterFile($item->poster);
$tmdb_id = $item->tmdb_id;
$item->delete(); $item->delete();
// Delete all related episodes
// todo: Make this possible in migrations
Episode::where('tmdb_id', $tmdb_id)->delete();
} }
/** /**
@ -117,11 +140,15 @@
* @param $data * @param $data
* @return Item * @return Item
*/ */
private function createItem($data) private function createItem($data, TMDB $tmdb)
{ {
return $this->item->create([ $tmdbId = $data['tmdb_id'];
'tmdb_id' => $data['tmdb_id'], $mediaType = $data['media_type'];
$item = $this->item->create([
'tmdb_id' => $tmdbId,
'title' => $data['title'], 'title' => $data['title'],
'media_type' => $mediaType,
'original_title' => $data['original_title'], 'original_title' => $data['original_title'],
'poster' => $data['poster'], 'poster' => $data['poster'],
'rating' => 1, 'rating' => 1,
@ -129,5 +156,45 @@
'genre' => $data['genre'], 'genre' => $data['genre'],
'created_at' => time(), 'created_at' => time(),
]); ]);
if($mediaType == 'tv') {
$this->createEpisodes($tmdbId, $tmdb);
}
return $item;
}
public function setSeen($id)
{
$episode = Episode::find($id);
$episode->seen = ! $episode->seen;
if( ! $episode->save()) {
return response('Server Error', 500);
}
}
/**
* Save all episodes of each season.
*
* @param $seasons
* @param $tmdbId
*/
private function createEpisodes($tmdbId, TMDB $tmdb)
{
$seasons = $tmdb->tvEpisodes($tmdbId);
foreach($seasons as $season) {
foreach($season->episodes as $episode) {
$new = new Episode();
$new->season_tmdb_id = $season->id;
$new->episode_tmdb_id = $episode->id;
$new->season_number = $episode->season_number;
$new->episode_number = $episode->episode_number;
$new->name = $episode->name;
$new->tmdb_id = $tmdbId;
$new->save();
}
}
} }
} }

View File

@ -18,10 +18,22 @@
'original_title', 'original_title',
'poster', 'poster',
'media_type', 'media_type',
'tv_data',
'rating', 'rating',
'released', 'released',
'created_at', 'created_at',
'genre', 'genre',
]; ];
public function episodes()
{
return $this->hasMany(Episode::class, 'tmdb_id', 'tmdb_id');
}
public function latestEpisode()
{
return $this->hasOne(Episode::class, 'tmdb_id', 'tmdb_id')
->orderBy('id', 'desc')
->where('seen', true)
->latest();
}
} }

View File

@ -10,6 +10,7 @@
private $client; private $client;
private $apiKey; private $apiKey;
private $translation;
/** /**
* Get the API Key for TMDB and create an instance of Guzzle. * Get the API Key for TMDB and create an instance of Guzzle.
@ -17,24 +18,23 @@
public function __construct() public function __construct()
{ {
$this->apiKey = config('app.TMDB_API_KEY'); $this->apiKey = config('app.TMDB_API_KEY');
$this->translation = config('app.TRANSLATION');
$this->client = new Client(['base_uri' => 'http://api.themoviedb.org/']); $this->client = new Client(['base_uri' => 'http://api.themoviedb.org/']);
} }
/** /**
* Search TMDB for an movie by 'title'. * Search TMDB by 'title'.
* *
* @param $title * @param $title
* @return array * @return array
*/ */
public function search($title) public function search($title)
{ {
$translation = config('app.TRANSLATION'); $response = $this->client->get('/3/search/multi', [
$response = $this->client->get('/3/search/movie', [
'query' => [ 'query' => [
'api_key' => $this->apiKey, 'api_key' => $this->apiKey,
'query' => $title, 'query' => $title,
'language' => strtolower($translation) 'language' => strtolower($this->translation)
] ]
]); ]);
@ -54,13 +54,14 @@
/** /**
* Search TMDB for recommendations and similar movies. * Search TMDB for recommendations and similar movies.
* *
* @param $mediaType
* @param $tmdbID * @param $tmdbID
* @return \Illuminate\Support\Collection * @return \Illuminate\Support\Collection
*/ */
public function suggestions($tmdbID) public function suggestions($mediaType, $tmdbID)
{ {
$recommendations = $this->searchSuggestions($tmdbID, 'recommendations'); $recommendations = $this->searchSuggestions($mediaType, $tmdbID, 'recommendations');
$similar = $this->searchSuggestions($tmdbID, 'similar'); $similar = $this->searchSuggestions($mediaType, $tmdbID, 'similar');
$items = $recommendations->merge($similar); $items = $recommendations->merge($similar);
@ -73,16 +74,22 @@
} }
/** /**
* @param $mediaType
* @param $tmdbID * @param $tmdbID
* @param $type * @param $type
* *
* @return \Illuminate\Support\Collection * @return \Illuminate\Support\Collection
*/ */
private function searchSuggestions($tmdbID, $type) private function searchSuggestions($mediaType, $tmdbID, $type)
{ {
$response = $this->client->get('/3/movie/' . $tmdbID . '/' . $type, ['query' => ['api_key' => $this->apiKey]]); $response = $this->client->get('/3/' . $mediaType . '/' . $tmdbID . '/' . $type, [
'query' => [
'api_key' => $this->apiKey,
'language' => strtolower($this->translation)
]
]);
return collect($this->createItems($response)); return collect($this->createItems($response, $mediaType));
} }
/** /**
@ -93,7 +100,12 @@
*/ */
private function searchTrendingOrUpcoming($type) private function searchTrendingOrUpcoming($type)
{ {
$response = $this->client->get('/3/movie/' . $type, ['query' => ['api_key' => $this->apiKey]]); $response = $this->client->get('/3/movie/' . $type, [
'query' => [
'api_key' => $this->apiKey,
'language' => strtolower($this->translation)
]
]);
$items = collect($this->createItems($response)); $items = collect($this->createItems($response));
$allID = $items->pluck('tmdb_id'); $allID = $items->pluck('tmdb_id');
@ -116,20 +128,32 @@
* @param $response * @param $response
* @return array * @return array
*/ */
private function createItems($response) private function createItems($response, $type = null)
{ {
$items = []; $items = [];
$response = json_decode($response->getBody()); $response = json_decode($response->getBody());
foreach($response->results as $result) { foreach($response->results as $result) {
$dtime = DateTime::createFromFormat('Y-m-d', ($result->release_date ?: '1970-12-1')); // 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')
));
// 'name' is from tv, 'title' from movies
$items[] = [ $items[] = [
'tmdb_id' => $result->id, 'tmdb_id' => $result->id,
'title' => $result->title, 'title' => array_key_exists('name', $result) ? $result->name : $result->title,
'original_title' => $result->original_title, 'original_title' => array_key_exists('name', $result) ? $result->original_name : $result->original_title,
'poster' => $result->poster_path, 'poster' => $result->poster_path,
'media_type' => $mediaType,
'released' => $dtime->getTimestamp(), 'released' => $dtime->getTimestamp(),
'genre' => $this->parseGenre($result->genre_ids), 'genre' => $this->parseGenre($result->genre_ids),
'episodes' => [],
]; ];
} }
@ -144,11 +168,69 @@
*/ */
public function movie($tmdb_id) public function movie($tmdb_id)
{ {
$response = $this->client->get('/3/movie/' . $tmdb_id, ['query' => ['api_key' => $this->apiKey]]); $response = $this->client->get('/3/movie/' . $tmdb_id, [
'query' => [
'api_key' => $this->apiKey,
'language' => strtolower($this->translation)
]
]);
return json_decode($response->getBody()); return json_decode($response->getBody());
} }
/**
* Get current count of seasons.
*
* @param $result
* @return integer | null
*/
private function tvSeasonsCount($id, $mediaType)
{
if($mediaType == 'tv') {
$response = $this->client->get('/3/tv/' . $id, [
'query' => [
'api_key' => $this->apiKey,
'language' => strtolower($this->translation)
]
]);
$seasons = collect(json_decode($response->getBody())->seasons);
return $seasons->filter(function ($season) {
// We don't need pilots
return $season->season_number > 0;
})->count();
}
return null;
}
/**
* Get all episodes of each season.
*
* @param $id
* @param $seasons
* @return array
*/
public function tvEpisodes($id)
{
$seasons = $this->tvSeasonsCount($id, 'tv');
$data = [];
for($i = 1; $i <= $seasons; $i++) {
$response = $this->client->get('/3/tv/' . $id . '/season/' . $i, [
'query' => [
'api_key' => $this->apiKey,
'language' => strtolower($this->translation)
]
]);
$data[$i] = json_decode($response->getBody());
}
return $data;
}
/** /**
* Create genre string from genre_ids. * Create genre string from genre_ids.
* *

View File

@ -4,10 +4,10 @@
Route::post('/login', 'UserController@login'); Route::post('/login', 'UserController@login');
Route::get('/logout', 'UserController@logout'); Route::get('/logout', 'UserController@logout');
Route::get('/items/{orderBy}', 'ItemController@items'); Route::get('/items/{type}/{orderBy}', 'ItemController@items');
Route::get('/search-items', 'ItemController@search'); Route::get('/search-items', 'ItemController@search');
Route::get('/suggestions/{tmdbID}', 'TMDBController@suggestions'); Route::get('/suggestions/{tmdbID}/{mediaType}', 'TMDBController@suggestions');
Route::get('/trending', 'TMDBController@trending'); Route::get('/trending', 'TMDBController@trending');
Route::get('/upcoming', 'TMDBController@upcoming'); Route::get('/upcoming', 'TMDBController@upcoming');
@ -22,6 +22,8 @@
Route::patch('/settings', 'SettingController@changeSettings'); Route::patch('/settings', 'SettingController@changeSettings');
Route::patch('/userdata', 'UserController@changeUserData'); Route::patch('/userdata', 'UserController@changeUserData');
Route::patch('/set-seen/{id}', 'ItemController@setSeen');
Route::get('/episodes/{tmdb_id}', 'ItemController@episodes');
Route::get('/search-tmdb', 'TMDBController@search'); Route::get('/search-tmdb', 'TMDBController@search');
Route::post('/add', 'ItemController@add'); Route::post('/add', 'ItemController@add');

View File

@ -10,15 +10,15 @@
<i class="icon-add" v-if=" ! rated"></i> <i class="icon-add" v-if=" ! rated"></i>
</span> </span>
<router-link :to="'/suggestions?for=' + localItem.tmdb_id" class="recommend-item">{{ lang('suggestions') }}</router-link> <router-link :to="'/suggestions?for=' + localItem.tmdb_id + '&type=' + localItem.media_type" class="recommend-item">{{ lang('suggestions') }}</router-link>
<span class="remove-item" v-if="localItem.rating && auth" @click="removeItem()">{{ lang('delete movie') }}</span> <span class="remove-item" v-if="localItem.rating && auth" @click="removeItem()">{{ lang('delete movie') }}</span>
<img v-if="localItem.poster" :src="poster" class="item-image" width="185" height="278"> <img v-if="localItem.poster" :src="poster" class="item-image" width="185" height="278">
<img v-if=" ! localItem.poster" :src="noImage" class="item-image" width="185" height="278"> <img v-if=" ! localItem.poster" :src="noImage" class="item-image" width="185" height="278">
<span class="show-episode" @click="changeEpisode()" v-if="localItem.type == 'tv'"> <span class="show-episode" @click="editEpisodes()" v-if="localItem.media_type == 'tv' && localItem.rating">
<span class="season-item"><i>S</i>1/2</span> <span class="season-item"><i>S</i>{{ season }}</span>
<span class="episode-item"><i>E</i>03/10</span> <span class="episode-item"><i>E</i>{{ episode }}</span>
</span> </span>
</div> </div>
@ -35,6 +35,8 @@
import http from 'axios'; import http from 'axios';
import Helper from '../../helper'; import Helper from '../../helper';
import { mapMutations, mapActions } from 'vuex';
export default { export default {
mixins: [Helper], mixins: [Helper],
@ -43,6 +45,7 @@
data() { data() {
return { return {
localItem: this.item, localItem: this.item,
latestEpisode: this.item.latest_episode,
saveTimeout: null, saveTimeout: null,
auth: config.auth, auth: config.auth,
prevRating: null, prevRating: null,
@ -83,14 +86,46 @@
youtube() { youtube() {
return `https://www.youtube.com/results?search_query=${this.localItem.title} ${this.released} Trailer`; return `https://www.youtube.com/results?search_query=${this.localItem.title} ${this.released} Trailer`;
},
season() {
if(this.latestEpisode) {
return this.addZero(this.latestEpisode.season_number);
}
return '01';
},
episode() {
if(this.latestEpisode) {
return this.addZero(this.latestEpisode.episode_number);
}
return '0';
} }
}, },
methods: { methods: {
changeEpisode() ...mapMutations([ 'OPEN_MODAL' ]),
{ ...mapActions([ 'fetchEpisodes' ]),
editEpisodes() {
this.fetchEpisodes({
tmdb_id: this.localItem.tmdb_id,
title: this.localItem.title
});
this.openModal();
},
openModal() {
if(this.auth) { if(this.auth) {
console.log("changed"); this.OPEN_MODAL({
type: 'season',
data: {
tmdb_id: this.localItem.tmdb_id,
title: this.localItem.title
}
});
} }
}, },
@ -122,6 +157,7 @@
http.post(`${config.api}/add`, {item: this.localItem}).then(value => { http.post(`${config.api}/add`, {item: this.localItem}).then(value => {
this.localItem = value.data; this.localItem = value.data;
this.disabled = false; this.disabled = false;
this.rated = false;
}, error => { }, error => {
if(error.status == 409) { if(error.status == 409) {
alert(this.localItem.title + ' already exists!'); alert(this.localItem.title + ' already exists!');