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; } }