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;
use App\Episode;
use App\Item;
use App\Services\Storage;
use App\Services\TMDB;
@ -27,16 +28,33 @@
}
/**
* Return all items for home with pagination.
* Return all items with pagination.
*
* @param $orderBy
* @return mixed
*/
public function items($orderBy)
public function items($type, $orderBy)
{
$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
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
@ -107,8 +125,13 @@
}
$this->storage->removePosterFile($item->poster);
$tmdb_id = $item->tmdb_id;
$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
* @return Item
*/
private function createItem($data)
private function createItem($data, TMDB $tmdb)
{
return $this->item->create([
'tmdb_id' => $data['tmdb_id'],
$tmdbId = $data['tmdb_id'];
$mediaType = $data['media_type'];
$item = $this->item->create([
'tmdb_id' => $tmdbId,
'title' => $data['title'],
'media_type' => $mediaType,
'original_title' => $data['original_title'],
'poster' => $data['poster'],
'rating' => 1,
@ -129,5 +156,45 @@
'genre' => $data['genre'],
'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',
'poster',
'media_type',
'tv_data',
'rating',
'released',
'created_at',
'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 $apiKey;
private $translation;
/**
* Get the API Key for TMDB and create an instance of Guzzle.
@ -17,24 +18,23 @@
public function __construct()
{
$this->apiKey = config('app.TMDB_API_KEY');
$this->translation = config('app.TRANSLATION');
$this->client = new Client(['base_uri' => 'http://api.themoviedb.org/']);
}
/**
* Search TMDB for an movie by 'title'.
* Search TMDB by 'title'.
*
* @param $title
* @return array
*/
public function search($title)
{
$translation = config('app.TRANSLATION');
$response = $this->client->get('/3/search/movie', [
$response = $this->client->get('/3/search/multi', [
'query' => [
'api_key' => $this->apiKey,
'query' => $title,
'language' => strtolower($translation)
'language' => strtolower($this->translation)
]
]);
@ -54,13 +54,14 @@
/**
* Search TMDB for recommendations and similar movies.
*
* @param $mediaType
* @param $tmdbID
* @return \Illuminate\Support\Collection
*/
public function suggestions($tmdbID)
public function suggestions($mediaType, $tmdbID)
{
$recommendations = $this->searchSuggestions($tmdbID, 'recommendations');
$similar = $this->searchSuggestions($tmdbID, 'similar');
$recommendations = $this->searchSuggestions($mediaType, $tmdbID, 'recommendations');
$similar = $this->searchSuggestions($mediaType, $tmdbID, 'similar');
$items = $recommendations->merge($similar);
@ -73,16 +74,22 @@
}
/**
* @param $mediaType
* @param $tmdbID
* @param $type
*
* @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)
{
$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));
$allID = $items->pluck('tmdb_id');
@ -116,20 +128,32 @@
* @param $response
* @return array
*/
private function createItems($response)
private function createItems($response, $type = null)
{
$items = [];
$response = json_decode($response->getBody());
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[] = [
'tmdb_id' => $result->id,
'title' => $result->title,
'original_title' => $result->original_title,
'title' => array_key_exists('name', $result) ? $result->name : $result->title,
'original_title' => array_key_exists('name', $result) ? $result->original_name : $result->original_title,
'poster' => $result->poster_path,
'media_type' => $mediaType,
'released' => $dtime->getTimestamp(),
'genre' => $this->parseGenre($result->genre_ids),
'episodes' => [],
];
}
@ -144,11 +168,69 @@
*/
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());
}
/**
* 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.
*

View File

@ -4,10 +4,10 @@
Route::post('/login', 'UserController@login');
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('/suggestions/{tmdbID}', 'TMDBController@suggestions');
Route::get('/suggestions/{tmdbID}/{mediaType}', 'TMDBController@suggestions');
Route::get('/trending', 'TMDBController@trending');
Route::get('/upcoming', 'TMDBController@upcoming');
@ -22,6 +22,8 @@
Route::patch('/settings', 'SettingController@changeSettings');
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::post('/add', 'ItemController@add');

View File

@ -10,15 +10,15 @@
<i class="icon-add" v-if=" ! rated"></i>
</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>
<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">
<span class="show-episode" @click="changeEpisode()" v-if="localItem.type == 'tv'">
<span class="season-item"><i>S</i>1/2</span>
<span class="episode-item"><i>E</i>03/10</span>
<span class="show-episode" @click="editEpisodes()" v-if="localItem.media_type == 'tv' && localItem.rating">
<span class="season-item"><i>S</i>{{ season }}</span>
<span class="episode-item"><i>E</i>{{ episode }}</span>
</span>
</div>
@ -35,6 +35,8 @@
import http from 'axios';
import Helper from '../../helper';
import { mapMutations, mapActions } from 'vuex';
export default {
mixins: [Helper],
@ -43,6 +45,7 @@
data() {
return {
localItem: this.item,
latestEpisode: this.item.latest_episode,
saveTimeout: null,
auth: config.auth,
prevRating: null,
@ -83,14 +86,46 @@
youtube() {
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: {
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) {
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 => {
this.localItem = value.data;
this.disabled = false;
this.rated = false;
}, error => {
if(error.status == 409) {
alert(this.localItem.title + ' already exists!');