Skip to content

Commit

Permalink
Merge pull request #48 from leepeuker/add-trakt-client-id-to-user-set…
Browse files Browse the repository at this point in the history
…tings-page

Set trakt client per user and make it configurable via settings page
  • Loading branch information
leepeuker authored Jul 13, 2022
2 parents 2ee11b7 + 0ef106b commit 7481ec5
Show file tree
Hide file tree
Showing 25 changed files with 259 additions and 83 deletions.
4 changes: 0 additions & 4 deletions .env.development.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ DATABASE_CHARSET=utf8
# Tmdb api
TMDB_API_KEY=

# Trakt.tv api
TRAKT_USERNAME=
TRAKT_CLIENT_ID=

# Letterboxed
LETTERBOXD_RATINGS_CSV_PATH="tmp/ratings.csv"

Expand Down
4 changes: 0 additions & 4 deletions .env.production.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ DATABASE_CHARSET=utf8
# Tmdb api
TMDB_API_KEY=

# Trakt.tv api
TRAKT_USERNAME=
TRAKT_CLIENT_ID=

# Logging
LOG_FILE="tmp/app.log"
LOG_LEVEL=warning
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ DATABASE_CHARSET=utf8
# https://www.themoviedb.org/settings/api
TMDB_API_KEY=

# https://trakt.tv/oauth/applications
TRAKT_USERNAME=
TRAKT_CLIENT_ID=

TIMEZONE="Europe/Berlin"

LOG_FILE="tmp/app.log"
Expand All @@ -129,12 +125,13 @@ Add the generated url as a [webhook to plex](https://support.plex.tv/articles/11
<a name="#trakttv-sync"></a>
### trakt.tv sync
You can sync your watchhistory and ratings from trakt.tv.
Make sure you have added the variables `TRAKT_USERNAME` and `TRAKT_CLIENT_ID` to the environment.
You can sync your watch history and ratings from trakt.tv.
Example:
The user used in the sync process must have a trakt client id set (can be set via web UI on the settings page or via cli `movary:user:change-trakt-client-id`).
Example (syncing history and ratings for user with id 1):
`docker exec movary php bin/console.php movary:sync-trakt --ratings --history`
`docker exec movary php bin/console.php movary:sync-trakt --ratings --history --userId=1`
**Flags:**
Expand Down
1 change: 1 addition & 0 deletions bin/console.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
$application->add($container->get(Movary\Command\CreateUser::class));
$application->add($container->get(Movary\Command\ChangeUserPassword::class));
$application->add($container->get(Movary\Command\DatabaseMigration::class));
$application->add($container->get(Movary\Command\ChangeUserTraktId::class));

$application->run();
1 change: 0 additions & 1 deletion bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
[
\Movary\ValueObject\Config::class => DI\factory([Factory::class, 'createConfig']),
\Movary\Api\Trakt\Api::class => DI\factory([Factory::class, 'createTraktApi']),
\Movary\Api\Trakt\Client::class => DI\factory([Factory::class, 'createTraktApiClient']),
\Movary\Api\Tmdb\Client::class => DI\factory([Factory::class, 'createTmdbApiClient']),
\Movary\HttpController\SettingsController::class => DI\factory([Factory::class, 'createSettingsController']),
\Movary\ValueObject\Http\Request::class => DI\factory([Factory::class, 'createCurrentHttpRequest']),
Expand Down
24 changes: 24 additions & 0 deletions db/migrations/20220713163724_AddTraktClientIdToUserTable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

use Phinx\Migration\AbstractMigration;

final class AddTraktClientIdToUserTable extends AbstractMigration
{
public function down() : void
{
$this->execute(
<<<SQL
ALTER TABLE user DROP COLUMN trakt_client_id;
SQL
);
}

public function up() : void
{
$this->execute(
<<<SQL
ALTER TABLE user ADD COLUMN trakt_client_id VARCHAR(255) DEFAULT NULL AFTER plex_webhook_uuid;
SQL
);
}
}
2 changes: 0 additions & 2 deletions docker-compose.override.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,3 @@ services:
DATABASE_USER: "${DATABASE_USER}"
DATABASE_PASSWORD: "${DATABASE_PASSWORD}"
TMDB_API_KEY: "${TMDB_API_KEY}"
TRAKT_USERNAME: "${TRAKT_USERNAME}"
TRAKT_CLIENT_ID: "${TRAKT_CLIENT_ID}"
5 changes: 5 additions & 0 deletions settings/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@
'/user/plex-webhook-id',
[\Movary\HttpController\PlexController::class, 'regeneratePlexWebhookId']
);
$routeCollector->addRoute(
'POST',
'/user/trakt',
[\Movary\HttpController\SettingsController::class, 'updateTrakt']
);
$routeCollector->addRoute(
'DELETE',
'/user/plex-webhook-id',
Expand Down
12 changes: 6 additions & 6 deletions src/Api/Trakt/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ public function fetchUniqueCachedTraktIds(int $userId) : array
return $this->cacheWatchedService->fetchAllUniqueTraktIds($userId);
}

public function fetchUserMovieHistoryByMovieId(TraktId $traktId) : User\Movie\History\DtoList
public function fetchUserMovieHistoryByMovieId(string $clientId, TraktId $traktId) : User\Movie\History\DtoList
{
$responseData = $this->client->get(sprintf('/users/%s/history/movies/%d', $this->username, $traktId->asInt()));
$responseData = $this->client->get($clientId, sprintf('/users/%s/history/movies/%d', $this->username, $traktId->asInt()));

return User\Movie\History\DtoList::createFromArray($responseData);
}

public function fetchUserMoviesRatings() : User\Movie\Rating\DtoList
public function fetchUserMoviesRatings(string $clientId,) : User\Movie\Rating\DtoList
{
$responseData = $this->client->get(sprintf('/users/%s/ratings/movies', $this->username));
$responseData = $this->client->get($clientId, sprintf('/users/%s/ratings/movies', $this->username));

return User\Movie\Rating\DtoList::createFromArray($responseData);
}

public function fetchUserMoviesWatched() : User\Movie\Watched\DtoList
public function fetchUserMoviesWatched(string $clientId) : User\Movie\Watched\DtoList
{
$responseData = $this->client->get(sprintf('/users/%s/watched/movies', $this->username));
$responseData = $this->client->get($clientId, sprintf('/users/%s/watched/movies', $this->username));

return User\Movie\Watched\DtoList::createFromArray($responseData);
}
Expand Down
5 changes: 2 additions & 3 deletions src/Api/Trakt/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,18 @@ class Client

public function __construct(
private readonly ClientInterface $httpClient,
private readonly string $clientId
) {
}

public function get(string $relativeUrl) : array
public function get(string $clientId, string $relativeUrl) : array
{
$request = new Request(
'GET',
self::BASE_URL . $relativeUrl,
[
'Content-Type' => 'application/json',
'trakt-api-version' => self::TRAKT_API_VERSION,
'trakt-api-key' => $this->clientId,
'trakt-api-key' => $clientId,
]
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Movary\Application\Service\Trakt\Exception;

class TraktClientIdNotSet extends \Exception
{
}
4 changes: 2 additions & 2 deletions src/Application/Service/Trakt/PlaysPerDateFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public function __construct(private readonly Api $traktApi)
{
}

public function fetchTraktPlaysPerDate(TraktId $traktId) : PlaysPerDateDtoList
public function fetchTraktPlaysPerDate(string $traktClientId, TraktId $traktId) : PlaysPerDateDtoList
{
$playsPerDates = PlaysPerDateDtoList::create();

foreach ($this->traktApi->fetchUserMovieHistoryByMovieId($traktId) as $movieHistoryEntry) {
foreach ($this->traktApi->fetchUserMovieHistoryByMovieId($traktClientId, $traktId) as $movieHistoryEntry) {
$watchDate = Date::createFromDateTime($movieHistoryEntry->getWatchedAt());

$playsPerDates->incrementPlaysForDate($watchDate);
Expand Down
11 changes: 9 additions & 2 deletions src/Application/Service/Trakt/SyncRatings.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Movary\Api;
use Movary\Application;
use Movary\Application\Service\Trakt\Exception\TraktClientIdNotSet;
use Movary\ValueObject\PersonalRating;

class SyncRatings
Expand All @@ -12,13 +13,19 @@ public function __construct(
private readonly Application\Movie\Api $movieApi,
private readonly Api\Trakt\Api $traktApi,
private readonly Api\Trakt\Cache\User\Movie\Rating\Service $traktApiCacheUserMovieRatingService,
private readonly Application\SyncLog\Repository $scanLogRepository
private readonly Application\SyncLog\Repository $scanLogRepository,
private readonly Application\User\Api $userApi,
) {
}

public function execute(int $userId, bool $overwriteExistingData = false) : void
{
$this->traktApiCacheUserMovieRatingService->set($userId, $this->traktApi->fetchUserMoviesRatings());
$traktClientId = $this->userApi->findTraktClientId($userId);
if ($traktClientId === null) {
throw new TraktClientIdNotSet();
}

$this->traktApiCacheUserMovieRatingService->set($userId, $this->traktApi->fetchUserMoviesRatings($traktClientId));

foreach ($this->movieApi->fetchAll() as $movie) {
$traktId = $movie->getTraktId();
Expand Down
15 changes: 11 additions & 4 deletions src/Application/Service/Trakt/SyncWatchedMovies.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Movary\Api;
use Movary\Api\Trakt\ValueObject\Movie\TraktId;
use Movary\Application;
use Movary\Application\Service\Trakt\Exception\TraktClientIdNotSet;
use Movary\ValueObject\Date;
use Psr\Log\LoggerInterface;

Expand All @@ -18,12 +19,18 @@ public function __construct(
private readonly PlaysPerDateFetcher $playsPerDateFetcher,
private readonly Application\Service\Tmdb\SyncMovie $tmdbMovieSync,
private readonly Application\SyncLog\Repository $scanLogRepository,
private readonly Application\User\Api $userApi
) {
}

public function execute(int $userId, bool $overwriteExistingData = false, bool $ignoreCache = false) : void
{
$watchedMovies = $this->traktApi->fetchUserMoviesWatched();
$traktClientId = $this->userApi->findTraktClientId($userId);
if ($traktClientId === null) {
throw new TraktClientIdNotSet();
}

$watchedMovies = $this->traktApi->fetchUserMoviesWatched($traktClientId);

foreach ($watchedMovies as $watchedMovie) {
$traktId = $watchedMovie->getMovie()->getTraktId();
Expand All @@ -34,7 +41,7 @@ public function execute(int $userId, bool $overwriteExistingData = false, bool $
continue;
}

$this->syncMovieHistory($userId, $traktId, $movie, $overwriteExistingData);
$this->syncMovieHistory($traktClientId, $userId, $traktId, $movie, $overwriteExistingData);

$this->traktApiCacheUserMovieWatchedService->setOne($userId, $traktId, $watchedMovie->getLastUpdated());
}
Expand Down Expand Up @@ -88,9 +95,9 @@ private function isWatchedCacheUpToDate(int $userId, Api\Trakt\ValueObject\User\
return $cacheLastUpdated !== null && $watchedMovie->getLastUpdated()->isEqual($cacheLastUpdated) === true;
}

private function syncMovieHistory(int $userId, TraktId $traktId, Application\Movie\Entity $movie, bool $overwriteExistingData) : void
private function syncMovieHistory(string $traktClientId, int $userId, TraktId $traktId, Application\Movie\Entity $movie, bool $overwriteExistingData) : void
{
$traktHistoryEntries = $this->playsPerDateFetcher->fetchTraktPlaysPerDate($traktId);
$traktHistoryEntries = $this->playsPerDateFetcher->fetchTraktPlaysPerDate($traktClientId, $traktId);

foreach ($this->movieApi->fetchHistoryByMovieId($movie->getId(), $userId) as $localHistoryEntry) {
$localHistoryEntryDate = Date::createFromString($localHistoryEntry['watched_at']);
Expand Down
14 changes: 12 additions & 2 deletions src/Application/User/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ public function deletePlexWebhookId(int $userId) : void
$this->repository->setPlexWebhookId($userId, null);
}

public function findPlexWebhookIdByUserId(int $userId) : ?string
public function findPlexWebhookId(int $userId) : ?string
{
return $this->repository->findPlexWebhookIdByUserId($userId);
return $this->repository->findPlexWebhookId($userId);
}

public function findTraktClientId(int $userId) : ?string
{
return $this->repository->findTraktClientId($userId);
}

public function findUserIdByPlexWebhookId(string $webhookId) : ?int
Expand All @@ -49,4 +54,9 @@ public function updatePassword(int $userId, string $newPassword) : void

$this->repository->updatePassword($userId, $passwordHash);
}

public function updateTraktClientId(int $userId, ?string $traktClientId) : void
{
$this->repository->updateTraktClientId($userId, $traktClientId);
}
}
26 changes: 25 additions & 1 deletion src/Application/User/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function findAuthTokenExpirationDate(string $token) : ?DateTime
return DateTime::createFromString($expirationDate);
}

public function findPlexWebhookIdByUserId(int $userId) : ?string
public function findPlexWebhookId(int $userId) : ?string
{
$plexWebhookId = $this->dbConnection->fetchOne('SELECT `plex_webhook_uuid` FROM `user` WHERE `id` = ?', [$userId]);

Expand All @@ -67,6 +67,17 @@ public function findPlexWebhookIdByUserId(int $userId) : ?string
return $plexWebhookId;
}

public function findTraktClientId(int $userId) : ?string
{
$plexWebhookId = $this->dbConnection->fetchOne('SELECT `trakt_client_id` FROM `user` WHERE `id` = ?', [$userId]);

if ($plexWebhookId === false) {
return null;
}

return $plexWebhookId;
}

public function findUserByEmail(string $email) : ?Entity
{
$data = $this->dbConnection->fetchAssociative('SELECT * FROM `user` WHERE `email` = ?', [$email]);
Expand Down Expand Up @@ -136,4 +147,17 @@ public function updatePassword(int $userId, string $passwordHash) : void
]
);
}

public function updateTraktClientId(int $userId, ?string $traktClientId) : void
{
$this->dbConnection->update(
'user',
[
'trakt_client_id' => $traktClientId,
],
[
'id' => $userId,
]
);
}
}
7 changes: 4 additions & 3 deletions src/Command/ChangeUserPassword.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,15 @@ protected function execute(InputInterface $input, OutputInterface $output) : int
try {
$this->userApi->updatePassword($userId, $password);
} catch (\Throwable $t) {
$this->logger->error('Could not change admin password.', ['exception' => $t]);
$this->logger->error('Could not change password.', ['exception' => $t]);

$this->generateOutput($output, 'Could not update password');
$this->generateOutput($output, 'Could not update password.');

return Command::FAILURE;
}

$this->generateOutput($output, 'Updated password');
$this->generateOutput($output, 'Updated password.');

return Command::SUCCESS;
}
}
Loading

0 comments on commit 7481ec5

Please sign in to comment.