Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/packages/twig.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
twig:
globals:
watchStatsProvider: '@tracky\watchstats\WatchStatsProvider'

when@test:
twig:
strict_variables: true
76 changes: 76 additions & 0 deletions src/main/php/tracky/HistoryEntry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
namespace tracky;

use tracky\model\Episode;
use tracky\model\Movie;
use tracky\model\View;
use tracky\orm\EpisodeRepository;
use tracky\orm\MovieRepository;
use tracky\watchstats\WatchStatsProvider;

class HistoryEntry
{
public function __construct(
private readonly View $view,
private readonly Episode|Movie $item,
private readonly WatchStatsProvider $watchStatsProvider
) {}

public function getView(): View
{
return $this->view;
}

public function getItem(): Episode|Movie
{
return $this->item;
}

public function getViewCount(): int
{
return $this->watchStatsProvider->getItemStatsByView($this->view)->getCount();
}

/**
* @return list<HistoryEntry>
*/
public static function getFromViews(array $views, EpisodeRepository $episodeRepository, MovieRepository $movieRepository, WatchStatsProvider $watchStatsProvider): array
{
$perTypeItems = [];

// Split up list of views to list of items per type
foreach ($views as $view) {
$type = $view->getType()->value;

if (!isset($perTypeItems[$type])) {
$perTypeItems[$type] = [];
}

$perTypeItems[$type][] = $view->getItem();
}

// Fetch items per type
foreach ($perTypeItems as $type => $items) {
$items = array_unique($items);

switch ($type) {
case ViewType::EPISODE->value:
$items = $episodeRepository->findByIds($items);
break;
case ViewType::MOVIE->value:
$items = $movieRepository->findByIds($items);
break;
}

$perTypeItems[$type] = array_combine(array_map(fn(Episode|Movie $item) => $item->getId(), $items), $items);
}

$historyEntries = [];

foreach ($views as $view) {
$historyEntries[] = new HistoryEntry($view, $perTypeItems[$view->getType()->value][$view->getItem()], $watchStatsProvider);
}

return $historyEntries;
}
}
35 changes: 10 additions & 25 deletions src/main/php/tracky/controller/HistoryController.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<?php
namespace tracky\controller;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;
use tracky\datetime\Date;
use tracky\datetime\DateRange;
use tracky\model\EpisodeView;
use tracky\model\MovieView;
use tracky\HistoryEntry;
use tracky\model\User;
use tracky\model\ViewEntry;
use tracky\orm\EpisodeRepository;
use tracky\orm\MovieRepository;
use tracky\orm\ViewRepository;
use tracky\Pagination;
use tracky\ViewType;
use tracky\watchstats\WatchStatsProvider;

class HistoryController extends AbstractController
{
Expand All @@ -25,7 +25,7 @@ public function __construct(
}

#[Route("/users/{username}/history", name: "user_profile_history_page")]
public function getPage(Request $request, User $user, EntityManagerInterface $entityManager, ViewRepository $viewRepository)
public function getPage(Request $request, User $user, ViewRepository $viewRepository, EpisodeRepository $episodeRepository, MovieRepository $movieRepository)
{
$page = $request->query->getInt("page", 1);

Expand All @@ -47,11 +47,9 @@ public function getPage(Request $request, User $user, EntityManagerInterface $en
switch ($type) {
case ViewType::EPISODE:
$criteria["item"] = $item;
$viewRepository = $entityManager->getRepository(EpisodeView::class);
break;
case ViewType::MOVIE:
$criteria["item"] = $item;
$viewRepository = $entityManager->getRepository(MovieView::class);
break;
}

Expand All @@ -60,14 +58,16 @@ public function getPage(Request $request, User $user, EntityManagerInterface $en
$pagination = new Pagination($page, $count, $this->itemsPerPage, $this->maxPreviousNextPages);

if ($dateRange === null) {
$firstPage = $this->sorted($viewRepository->getPaged($criteria, 1, $this->itemsPerPage, $type, $dateRange));
$lastPage = $this->sorted($viewRepository->getPaged($criteria, $pagination->getLastPage(), $this->itemsPerPage, $type, $dateRange));
$firstPage = $viewRepository->getPaged($criteria, 1, $this->itemsPerPage, $type, $dateRange);
$lastPage = $viewRepository->getPaged($criteria, $pagination->getLastPage(), $this->itemsPerPage, $type, $dateRange);

if (!empty($firstPage) and !empty($lastPage)) {
$dateRange = new DateRange($lastPage[count($lastPage) - 1]->getDateTime()->toDate(), $firstPage[0]->getDateTime()->toDate());
}
}

$views = $viewRepository->getPaged($criteria, $page, $this->itemsPerPage, $type, $dateRange);

return $this->render("user/history.twig", [
"user" => $user,
"dateRange" => $dateRange,
Expand All @@ -76,22 +76,7 @@ public function getPage(Request $request, User $user, EntityManagerInterface $en
"item" => $item
],
"pagination" => $pagination,
"entries" => $this->sorted($viewRepository->getPaged($criteria, $page, $this->itemsPerPage, $type, $dateRange))
"entries" => HistoryEntry::getFromViews($views, $episodeRepository, $movieRepository, new WatchStatsProvider($viewRepository, $user))
]);
}

private function sorted(array $entries): array
{
usort($entries, function (ViewEntry $entry1, ViewEntry $entry2) {
if ($entry1->getDateTime() < $entry2->getDateTime()) {
return 1;
} elseif ($entry1->getDateTime() > $entry2->getDateTime()) {
return -1;
} else {
return 0;
}
});

return $entries;
}
}
62 changes: 28 additions & 34 deletions src/main/php/tracky/controller/HomeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use tracky\model\Episode;
use tracky\model\User;
use tracky\HistoryEntry;
use tracky\orm\EpisodeRepository;
use tracky\orm\MovieRepository;
use tracky\orm\ShowRepository;
use tracky\orm\ViewRepository;
use tracky\scrobbler\Scrobbler;
use tracky\ViewType;
use tracky\watchstats\WatchStatsProvider;

class HomeController extends AbstractController
{
Expand All @@ -24,7 +24,7 @@ public function __construct(
}

#[Route("/", name: "home_page")]
public function home(ShowRepository $showRepository, EpisodeRepository $episodeRepository, MovieRepository $movieRepository, ViewRepository $viewRepository, Scrobbler $scrobbler): Response
public function home(ShowRepository $showRepository, EpisodeRepository $episodeRepository, MovieRepository $movieRepository, ViewRepository $viewRepository, WatchStatsProvider $watchStatsProvider, Scrobbler $scrobbler): Response
{
$nowWatching = null;
$latestWatchedEpisodes = null;
Expand All @@ -34,9 +34,14 @@ public function home(ShowRepository $showRepository, EpisodeRepository $episodeR
$user = $this->getUser();
if ($user !== null) {
$nowWatching = $scrobbler->getNowWatching($user);
$latestWatchedEpisodes = $viewRepository->findBy(["user" => $user->getId()], ["dateTime" => "desc"], $this->maxEpisodes, type: ViewType::EPISODE);
$latestWatchedMovies = $viewRepository->findBy(["user" => $user->getId()], ["dateTime" => "desc"], $this->maxMovies, type: ViewType::MOVIE);
$nextEpisodes = $this->getNextEpisodes($showRepository, $user);

$episodeViews = $viewRepository->findBy(["user" => $user->getId()], ["dateTime" => "desc"], $this->maxEpisodes, type: ViewType::EPISODE);
$movieViews = $viewRepository->findBy(["user" => $user->getId()], ["dateTime" => "desc"], $this->maxMovies, type: ViewType::MOVIE);

$latestWatchedEpisodes = HistoryEntry::getFromViews($episodeViews, $episodeRepository, $movieRepository, $watchStatsProvider);
$latestWatchedMovies = HistoryEntry::getFromViews($movieViews, $episodeRepository, $movieRepository, $watchStatsProvider);

$nextEpisodes = $this->getNextEpisodes($showRepository, $watchStatsProvider);
}

return $this->render("index.twig", [
Expand All @@ -49,41 +54,30 @@ public function home(ShowRepository $showRepository, EpisodeRepository $episodeR
]);
}

private function getNextEpisodes(ShowRepository $showRepository, User $user)
private function getNextEpisodes(ShowRepository $showRepository, WatchStatsProvider $watchStatsProvider)
{
$latestEpisodes = [];
$nextEpisodes = [];

foreach ($showRepository->findAllWithEpisodesAndViews($user->getId()) as $show) {
$latestWatchedEpisodes = $show->getLatestWatchedEpisodes($user, 1, true);
if (!empty($latestWatchedEpisodes)) {
$latestEpisodes[] = $latestWatchedEpisodes[0];
}
}

usort($latestEpisodes, function ($item1, $item2) {
list(, $item1Timestamp) = $item1;
list(, $item2Timestamp) = $item2;
/**
* @var list<array{Episode, DateTime}>
*/
$episodes = [];

foreach ($showRepository->findAllWithEpisodes() as $show) {
$latestWatchedEpisode = $show->getLatestWatchedEpisodes($watchStatsProvider, 1)[0] ?? null;

if ($item1Timestamp === $item2Timestamp) {
return 0;
if ($latestWatchedEpisode === null) {
continue;
}

return ($item1Timestamp > $item2Timestamp) ? -1 : 1;
});

foreach ($latestEpisodes as $item) {
/**
* @var Episode
*/
$episode = $item[0];
$nextEpisode = $episode->getNextEpisode();
if ($nextEpisode !== null) {
$nextEpisodes[] = $nextEpisode;
$nextEpisode = $latestWatchedEpisode[0]->getNextEpisode();
if ($nextEpisode === null) {
continue;
}

$episodes[] = [$nextEpisode, $latestWatchedEpisode[1]->getLastWatched()];
}

return array_slice($nextEpisodes, 0, $this->maxNextEpisodeShows);
usort($episodes, fn($item1, $item2) => $item2[1] <=> $item1[1]);

return array_map(fn($item) => $item[0], array_slice($episodes, 0, $this->maxNextEpisodeShows));
}
}
Loading
Loading