Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional position to watch dates #548

Merged
merged 12 commits into from
Dec 11, 2023
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 AddPositionToUserWatchDatesTable extends AbstractMigration
{
public function down() : void
{
$this->execute(
<<<SQL
ALTER TABLE movie_user_watch_dates DROP COLUMN position;
SQL,
);
}

public function up() : void
{
$this->execute(
<<<SQL
ALTER TABLE movie_user_watch_dates ADD COLUMN position SMALLINT DEFAULT 1 NOT NULL AFTER comment;
SQL,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php declare(strict_types=1);

use Phinx\Migration\AbstractMigration;

final class AddPositionToUserWatchDatesTable extends AbstractMigration
{
public function down() : void
{
$this->execute(
<<<SQL
CREATE TABLE `movie_user_watch_dates_tmp` (
`movie_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`watched_at` TEXT NOT NULL,
`plays` INTEGER DEFAULT 1,
`comment` TEXT DEFAULT NULL,
FOREIGN KEY (`user_id`) REFERENCES user (`id`) ON DELETE CASCADE,
FOREIGN KEY (`movie_id`) REFERENCES movie (`id`) ON DELETE CASCADE
)
SQL,
);
$this->execute(
'INSERT INTO `movie_user_watch_dates_tmp` (movie_id, user_id, watched_at, plays, comment)
SELECT movie_id, user_id, watched_at, plays, comment FROM movie_user_watch_dates',
);
$this->execute('DROP TABLE `movie_user_watch_dates`');
$this->execute('ALTER TABLE `movie_user_watch_dates_tmp` RENAME TO `movie_user_watch_dates`');
}

public function up() : void
{
$this->execute(
<<<SQL
CREATE TABLE `movie_user_watch_dates_tmp` (
`movie_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
`watched_at` TEXT,
`plays` INTEGER DEFAULT 1,
`comment` TEXT DEFAULT NULL,
`position` INTEGER NOT NULL DEFAULT 1,
FOREIGN KEY (`user_id`) REFERENCES user (`id`) ON DELETE CASCADE,
FOREIGN KEY (`movie_id`) REFERENCES movie (`id`) ON DELETE CASCADE
)
SQL,
);
$this->execute(
'INSERT INTO `movie_user_watch_dates_tmp` (movie_id, user_id, watched_at, plays, comment)
SELECT * FROM movie_user_watch_dates',
);
$this->execute('DROP TABLE `movie_user_watch_dates`');
$this->execute('ALTER TABLE `movie_user_watch_dates_tmp` RENAME TO `movie_user_watch_dates`');
}
}
18 changes: 18 additions & 0 deletions docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
},
"comment": {
"$ref": "#/components/schemas/commentOptional"
},
"position": {
"$ref": "#/components/schemas/positionOptional"
}
}
}
Expand Down Expand Up @@ -211,6 +214,9 @@
},
"comment": {
"$ref": "#/components/schemas/comment"
},
"position": {
"$ref": "#/components/schemas/position"
}
}
}
Expand Down Expand Up @@ -1199,6 +1205,18 @@
"default": null,
"required": false
},
"position": {
"type": "number",
"example": 1,
"nullable": false
},
"positionOptional": {
"type": "number",
"example": 1,
"nullable": true,
"default": 1,
"required": false
},
"date": {
"type": "string",
"example": "2023-07-02"
Expand Down
38 changes: 36 additions & 2 deletions public/js/movie.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@ function deleteWatchDate() {
})
}

function toggleWatchDateAdvancedMode() {
if (document.getElementById('advancedWatchDateDetails').classList.contains('d-none')) {
enableWatchDateAdvancedMode()

return
}

disableWatchDateAdvancedMode()
}

function disableWatchDateAdvancedMode() {
const advancedWatchDateDetails = document.getElementById('advancedWatchDateDetails');
const advancedWatchDateModeButton = document.getElementById('advancedWatchDateModeButton');

advancedWatchDateModeButton.innerHTML = 'Advanced mode'
advancedWatchDateDetails.classList.add('d-none')
}

function enableWatchDateAdvancedMode() {
const advancedWatchDateDetails = document.getElementById('advancedWatchDateDetails');
const advancedWatchDateModeButton = document.getElementById('advancedWatchDateModeButton');

advancedWatchDateDetails.classList.remove('d-none')
advancedWatchDateModeButton.innerHTML = 'Simple mode'
}

function getMovieId() {
return document.getElementById('movieId').value
}
Expand Down Expand Up @@ -77,10 +103,13 @@ function loadWatchDateModal(watchDateListElement) {
document.getElementById('editWatchDateModalInput').value = watchDateListElement.dataset.watchDate;
document.getElementById('editWatchDateModalPlaysInput').value = watchDateListElement.dataset.plays;
document.getElementById('editWatchDateModalCommentInput').value = watchDateListElement.dataset.comment;
document.getElementById('editWatchDateModalPositionInput').value = watchDateListElement.dataset.position;

document.getElementById('originalWatchDate').value = watchDateListElement.dataset.watchDate;
document.getElementById('originalWatchDatePlays').value = watchDateListElement.dataset.plays;

disableWatchDateAdvancedMode()

new Datepicker(document.getElementById('editWatchDateModalInput'), {
format: document.getElementById('dateFormatJavascript').value,
title: 'Watch date',
Expand All @@ -94,6 +123,7 @@ function editWatchDate() {

const newWatchDate = document.getElementById('editWatchDateModalInput').value;
const newWatchDatePlays = document.getElementById('editWatchDateModalPlaysInput').value;
const newPositionPlays = document.getElementById('editWatchDateModalPositionInput').value;
const comment = document.getElementById('editWatchDateModalCommentInput').value;

const apiUrl = '/users/' + getRouteUsername() + '/movies/' + getMovieId() + '/history'
Expand All @@ -106,6 +136,7 @@ function editWatchDate() {
'originalWatchDate': originalWatchDate,
'plays': newWatchDatePlays,
'comment': comment,
'position': newPositionPlays,
'dateFormat': document.getElementById('dateFormatPhp').value
}),
success: function (data, textStatus, xhr) {
Expand Down Expand Up @@ -344,8 +375,8 @@ function isTruncated(el) {
return el.scrollWidth > el.clientWidth
}

const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => {
const tooltipTriggerListCast = document.querySelectorAll('[data-bs-toggle="tooltip"]#castMemberName, [data-bs-toggle="tooltip"]#castCharacterName')
const tooltipCastList = [...tooltipTriggerListCast].map(tooltipTriggerEl => {
if (isTruncated(tooltipTriggerEl) === false) {
return
}
Expand All @@ -357,3 +388,6 @@ const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => {

new bootstrap.Tooltip(tooltipTriggerEl, {'placement': placement})
})

const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]#editWatchDateModalPlays, [data-bs-toggle="tooltip"]#editWatchDateModalPlaysInput1')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
77 changes: 43 additions & 34 deletions src/Domain/Movie/History/MovieHistoryApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ public function __construct(
) {
}

public function create(int $movieId, int $userId, ?Date $watchedAt, int $plays, ?string $comment = null) : void
public function create(int $movieId, int $userId, ?Date $watchedAt, int $plays, ?int $position = null, ?string $comment = null) : void
{
$this->repository->create($movieId, $userId, $watchedAt, $plays, $comment);
if ($position === null) {
$position = $this->findHighestPositionForWatchDate($movieId, $userId, $watchedAt);
}

$this->repository->create($movieId, $userId, $watchedAt, $plays, $comment, (int)$position + 1);

if ($this->userApi->fetchUser($userId)->hasJellyfinSyncEnabled() === false) {
return;
Expand All @@ -35,6 +39,11 @@ public function create(int $movieId, int $userId, ?Date $watchedAt, int $plays,
$this->jobQueueApi->addJellyfinExportMoviesJob($userId, [$movieId]);
}

public function findHighestPositionForWatchDate(int $movieIdToIgnore, int $userId, ?Date $watchedAt) : ?int
{
return $this->repository->fetchHighestPositionForWatchDate($movieIdToIgnore, $userId, $watchedAt);
}

public function deleteByUserAndMovieId(int $userId, int $movieId) : void
{
$this->repository->deleteByUserAndMovieId($userId, $movieId);
Expand Down Expand Up @@ -241,6 +250,36 @@ public function fetchMovieIdsWithWatchDatesByUserId(int $userId) : array
return $this->movieRepository->fetchMovieIdsWithWatchDatesByUserId($userId);
}

public function fetchPlayedMoviesPaginated(
int $userId,
int $limit,
int $page,
?string $searchTerm = null,
string $sortBy = 'title',
?SortOrder $sortOrder = null,
?Year $releaseYear = null,
?string $language = null,
?string $genre = null,
) : array {
if ($sortOrder === null) {
$sortOrder = SortOrder::createAsc();
}

$movies = $this->movieRepository->fetchUniqueWatchedMoviesPaginated(
$userId,
$limit,
$page,
$searchTerm,
$sortBy,
$sortOrder,
$releaseYear,
$language,
$genre,
);

return $this->urlGenerator->replacePosterPathWithImageSrcUrl($movies);
}

public function fetchTmdbIdsToLastWatchDatesMap(int $userId, array $tmdbIds) : array
{
$map = [];
Expand Down Expand Up @@ -386,36 +425,6 @@ public function fetchUniqueWatchedMoviesPaginated(
return $this->urlGenerator->replacePosterPathWithImageSrcUrl($movies);
}

public function fetchPlayedMoviesPaginated(
int $userId,
int $limit,
int $page,
?string $searchTerm = null,
string $sortBy = 'title',
?SortOrder $sortOrder = null,
?Year $releaseYear = null,
?string $language = null,
?string $genre = null,
) : array {
if ($sortOrder === null) {
$sortOrder = SortOrder::createAsc();
}

$movies = $this->movieRepository->fetchUniqueWatchedMoviesPaginated(
$userId,
$limit,
$page,
$searchTerm,
$sortBy,
$sortOrder,
$releaseYear,
$language,
$genre,
);

return $this->urlGenerator->replacePosterPathWithImageSrcUrl($movies);
}

public function fetchWatchDatesForMovieIds(int $userId, array $movieIds) : array
{
$watchDates = [];
Expand All @@ -440,9 +449,9 @@ public function findHistoryEntryForMovieByUserOnDate(int $movieId, int $userId,
return $this->movieRepository->findHistoryEntryForMovieByUserOnDate($movieId, $userId, $watchedAt);
}

public function update(int $movieId, int $userId, ?Date $watchedAt, int $plays, ?string $comment = null) : void
public function update(int $movieId, int $userId, ?Date $watchedAt, int $plays, int $position, ?string $comment = null) : void
{
$this->repository->update($movieId, $userId, $watchedAt, $plays, $comment);
$this->repository->update($movieId, $userId, $watchedAt, $plays, $position, $comment);
}

public function updateHistoryComment(int $movieId, int $userId, ?Date $watchAt, ?string $comment) : void
Expand Down
7 changes: 7 additions & 0 deletions src/Domain/Movie/History/MovieHistoryEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ private function __construct(
private readonly int $movieId,
private readonly ?Date $watchedAt,
private readonly int $plays,
private readonly int $position,
private readonly ?string $comment,
) {
}
Expand All @@ -20,6 +21,7 @@ public static function createFromArray(array $data) : self
(int)$data['movie_id'],
$data['watched_at'] == null ? null : Date::createFromString($data['watched_at']),
$data['plays'],
$data['position'],
$data['comment'],
);
}
Expand All @@ -39,6 +41,11 @@ public function getPlays() : int
return $this->plays;
}

public function getPosition() : int
{
return $this->position;
}

public function getWatchedAt() : ?Date
{
return $this->watchedAt;
Expand Down
Loading