284 lines
9.7 KiB
PHP
Executable File
284 lines
9.7 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Actions\People;
|
|
|
|
use App\Models\Person;
|
|
use App\Models\Title;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Str;
|
|
|
|
class GetPersonCredits
|
|
{
|
|
private ?int $titleId;
|
|
|
|
public function execute(Person $person, $options = []): array
|
|
{
|
|
$this->titleId = Arr::get($options, 'titleId');
|
|
$credits = $this->titleId ? [] : $this->getTitleCredits($person);
|
|
$seasonCredits = $this->getSeasonCredits($person);
|
|
$episodeCredits = $this->getEpisodeCredits($person);
|
|
|
|
$mergedCredits = $this->mergeCredits(
|
|
Arr::get($credits, 'all', []),
|
|
$seasonCredits,
|
|
$episodeCredits,
|
|
);
|
|
$mergedCredits = $this->separateSelfCreditsAndSort($mergedCredits);
|
|
|
|
return [
|
|
'credits' => $mergedCredits,
|
|
'knownFor' => Arr::get($credits, 'knownFor', []),
|
|
'total_credits_count' => array_reduce(
|
|
$mergedCredits,
|
|
fn($carry, $item) => $carry + count($item),
|
|
0,
|
|
),
|
|
];
|
|
}
|
|
|
|
private function mergeCredits($credits1, $credits2, $credits3): array
|
|
{
|
|
$mergedCredits = array_merge_recursive($credits1, $credits2, $credits3);
|
|
|
|
return array_map(function ($titles) {
|
|
// sort titles by year
|
|
usort($titles, fn($a, $b) => $b['year'] - $a['year']);
|
|
|
|
$unique = [];
|
|
|
|
// if this title already exists and existing
|
|
// title has episodes property, continue,
|
|
// otherwise push title into 'unique' array
|
|
foreach ($titles as $title) {
|
|
$existing = Arr::get($unique, $title['id']);
|
|
if ($existing) {
|
|
$existing['credited_episode_count'] =
|
|
Arr::get($existing, 'credited_episode_count', 0) +
|
|
Arr::get($title, 'credited_episode_count', 0);
|
|
$existing['episodes'] = collect(
|
|
array_merge(
|
|
Arr::get($existing, 'episodes', []),
|
|
Arr::get($title, 'episodes', []),
|
|
),
|
|
)
|
|
->unique('id')
|
|
->toArray();
|
|
if (!$this->titleId) {
|
|
$existing['episodes'] = array_slice(
|
|
$existing['episodes'],
|
|
0,
|
|
5,
|
|
);
|
|
}
|
|
$unique[$title['id']] = $existing;
|
|
} else {
|
|
$unique[$title['id']] = $title;
|
|
}
|
|
}
|
|
|
|
return array_values($unique);
|
|
}, $mergedCredits);
|
|
}
|
|
|
|
private function getTitleCredits(Person $person): array
|
|
{
|
|
$credits = $person->credits()->get();
|
|
|
|
// generate known for list for actors "known_for" department.
|
|
$allKnownFor = $credits
|
|
->filter(function (Title $credit) use ($person) {
|
|
$knownFor =
|
|
strtolower($person->known_for) === 'acting'
|
|
? 'actors'
|
|
: $person->known_for;
|
|
return $credit->pivot->department === strtolower($knownFor);
|
|
})
|
|
->unique();
|
|
|
|
$knownFor = $allKnownFor->where('pivot.order', '<', 10);
|
|
|
|
if ($knownFor->count() < 4) {
|
|
$knownFor = $allKnownFor;
|
|
}
|
|
|
|
// sort by person credit "order" for title as well as title popularity
|
|
$knownFor = $knownFor
|
|
->sortBy(function ($title) {
|
|
$order = $title->pivot->order;
|
|
$popularity = $title->popularity;
|
|
return $order - $popularity;
|
|
})
|
|
->slice(0, 6)
|
|
->values();
|
|
|
|
// cast to array, so poster/backdrop is not removed later.
|
|
$knownFor = $knownFor->load(['primaryVideo'])->toArray();
|
|
|
|
// remove any data not needed to render person filmography
|
|
$credits = $credits
|
|
->map(function (Title $credit) {
|
|
unset($credit['backdrop']);
|
|
return $credit;
|
|
})
|
|
->groupBy('pivot.department');
|
|
|
|
return ['all' => $credits->toArray(), 'knownFor' => $knownFor];
|
|
}
|
|
|
|
/**
|
|
* Get credits for all series seasons person is attached to.
|
|
*/
|
|
private function getSeasonCredits(Person $person): array
|
|
{
|
|
$seasons = $person
|
|
->seasonCredits($this->titleId)
|
|
->with([
|
|
'title' => fn($query) => $query->select(
|
|
'id',
|
|
'name',
|
|
'release_date',
|
|
'poster',
|
|
),
|
|
'episodes' => fn($query) => $query
|
|
->select(
|
|
'id',
|
|
'name',
|
|
'release_date',
|
|
'season_id',
|
|
'season_number',
|
|
'episode_number',
|
|
'title_id',
|
|
)
|
|
->orderBy('season_number', 'desc')
|
|
->orderBy('episode_number', 'desc'),
|
|
])
|
|
->get();
|
|
|
|
// group all seasons by department, for example "production"
|
|
$groupedSeasons = $seasons->groupBy('pivot.department');
|
|
|
|
return $groupedSeasons
|
|
->map(function (Collection $departmentGroup) {
|
|
$seasonsGroupedByTitle = $departmentGroup->groupBy('title.id');
|
|
|
|
// attach episodes from all seasons to title
|
|
return $seasonsGroupedByTitle
|
|
->map(function (Collection $titleSeasons) {
|
|
$title = $titleSeasons
|
|
->first(fn($s) => $s->title)
|
|
->title->toArray();
|
|
|
|
//get episodes from each season and move season "pivot" data to each episode
|
|
$episodesFromAllSeasons = $titleSeasons
|
|
->pluck('episodes')
|
|
->flatten()
|
|
->values()
|
|
->map(function ($episode) use ($titleSeasons) {
|
|
$episode->pivot = $titleSeasons
|
|
->first()
|
|
->pivot->toArray();
|
|
return $episode;
|
|
});
|
|
$title[
|
|
'credited_episode_count'
|
|
] = $episodesFromAllSeasons->count();
|
|
if (!$this->titleId) {
|
|
$episodesFromAllSeasons = $episodesFromAllSeasons->take(
|
|
5,
|
|
);
|
|
}
|
|
$title['episodes'] = $episodesFromAllSeasons->toArray();
|
|
return $title;
|
|
})
|
|
->values();
|
|
})
|
|
->toArray();
|
|
}
|
|
|
|
/**
|
|
* Get all individual episodes person is credited for.
|
|
*
|
|
* This will return array grouped by department, and
|
|
* series with all episodes person is credited for attached
|
|
* to that series.
|
|
*
|
|
* @param Person $person
|
|
* @return array
|
|
*/
|
|
private function getEpisodeCredits(Person $person)
|
|
{
|
|
$episodes = $person
|
|
->episodeCredits($this->titleId)
|
|
->with([
|
|
'title' => function (BelongsTo $query) {
|
|
$query->select('id', 'name', 'release_date', 'poster');
|
|
},
|
|
])
|
|
->get();
|
|
|
|
$groupedByDep = $episodes->groupBy('pivot.department');
|
|
|
|
return $groupedByDep
|
|
->map(
|
|
fn(Collection $episodes) => $episodes
|
|
->groupBy('title.id')
|
|
->map(function (Collection $episodes) {
|
|
if (!$episodes->first()->title) {
|
|
return null;
|
|
}
|
|
$title = $episodes->first()->title->toArray();
|
|
$episodes = $episodes->map(function ($episode) {
|
|
unset($episode->title);
|
|
return $episode;
|
|
});
|
|
$title['credited_episode_count'] = $episodes->count();
|
|
if (!$this->titleId) {
|
|
$episodes = $episodes->take(5);
|
|
}
|
|
$title['episodes'] = $episodes->toArray();
|
|
return $title;
|
|
})
|
|
->filter()
|
|
->values(),
|
|
)
|
|
->toArray();
|
|
}
|
|
|
|
private function separateSelfCreditsAndSort(array $credits): array
|
|
{
|
|
if (!isset($credits['cast'])) {
|
|
return $credits;
|
|
}
|
|
|
|
$cast = [];
|
|
$self = [];
|
|
foreach ($credits['cast'] as $credit) {
|
|
$char = isset($credit['pivot']['character'])
|
|
? strtolower($credit['pivot']['character'])
|
|
: null;
|
|
if (
|
|
$char &&
|
|
($char === 'self' || Str::contains($char, 'himself'))
|
|
) {
|
|
$self[] = $credit;
|
|
} else {
|
|
$cast[] = $credit;
|
|
}
|
|
}
|
|
$credits['cast'] = $cast;
|
|
|
|
// sort before adding "self" to array as that should be last always
|
|
uksort(
|
|
$credits,
|
|
fn($a, $b) => (is_countable($credits[$b])
|
|
? count($credits[$b])
|
|
: 0) - (is_countable($credits[$a]) ? count($credits[$a]) : 0),
|
|
);
|
|
|
|
$credits['self'] = $self;
|
|
return $credits;
|
|
}
|
|
}
|