From 5b0cf89391d207a6786ecdcf8767481793c532fc Mon Sep 17 00:00:00 2001 From: OwsleyJr Date: Tue, 8 Apr 2025 01:13:36 -0500 Subject: [PATCH] fix: correctly set seasons status when using the manual button --- server/entity/Season.ts | 57 ++++++------ server/routes/media.ts | 22 ++++- src/components/ManageSlideOver/index.tsx | 1 + .../RequestModal/TvRequestModal.tsx | 3 +- src/components/TvDetails/index.tsx | 86 ++++++++++++------- 5 files changed, 108 insertions(+), 61 deletions(-) diff --git a/server/entity/Season.ts b/server/entity/Season.ts index 170f8a0d6..80f442309 100644 --- a/server/entity/Season.ts +++ b/server/entity/Season.ts @@ -2,6 +2,7 @@ import { MediaRequestStatus, MediaStatus } from '@server/constants/media'; import { getRepository } from '@server/datasource'; import SeasonRequest from '@server/entity/SeasonRequest'; import { + AfterInsert, AfterUpdate, Column, CreateDateColumn, @@ -39,35 +40,43 @@ class Season { Object.assign(this, init); } + @AfterInsert() @AfterUpdate() public async updateSeasonRequests(): Promise { const seasonRequestRepository = getRepository(SeasonRequest); - const relatedSeasonRequests = await seasonRequestRepository.find({ - relations: { - request: true, - }, - where: { - request: { media: { id: (await this.media).id } }, - seasonNumber: this.seasonNumber, - }, - }); + if ( + this.status === MediaStatus.AVAILABLE || + this.status === MediaStatus.DELETED || + this.status4k === MediaStatus.AVAILABLE || + this.status4k === MediaStatus.DELETED + ) { + const relatedSeasonRequests = await seasonRequestRepository.find({ + relations: { + request: true, + }, + where: { + request: { media: { id: (await this.media).id } }, + seasonNumber: this.seasonNumber, + }, + }); - // Check seasons when/if they become available or deleted, - // then set the related season request to completed - relatedSeasonRequests.forEach((seasonRequest) => { - if ( - this.seasonNumber === seasonRequest.seasonNumber && - ((!seasonRequest.request.is4k && - (this.status === MediaStatus.AVAILABLE || - this.status === MediaStatus.DELETED)) || - (seasonRequest.request.is4k && - this.status4k === MediaStatus.AVAILABLE) || - this.status4k === MediaStatus.DELETED) - ) - seasonRequest.status = MediaRequestStatus.COMPLETED; - }); - seasonRequestRepository.save(relatedSeasonRequests); + // Check seasons when/if they become available or deleted, + // then set the related season request to completed + relatedSeasonRequests.forEach((seasonRequest) => { + if ( + this.seasonNumber === seasonRequest.seasonNumber && + ((!seasonRequest.request.is4k && + (this.status === MediaStatus.AVAILABLE || + this.status === MediaStatus.DELETED)) || + (seasonRequest.request.is4k && + this.status4k === MediaStatus.AVAILABLE) || + this.status4k === MediaStatus.DELETED) + ) + seasonRequest.status = MediaRequestStatus.COMPLETED; + }); + seasonRequestRepository.save(relatedSeasonRequests); + } } } diff --git a/server/routes/media.ts b/server/routes/media.ts index 8f93116c0..4862ee6d9 100644 --- a/server/routes/media.ts +++ b/server/routes/media.ts @@ -2,6 +2,7 @@ import TautulliAPI from '@server/api/tautulli'; import { MediaStatus, MediaType } from '@server/constants/media'; import { getRepository } from '@server/datasource'; import Media from '@server/entity/Media'; +import Season from '@server/entity/Season'; import { User } from '@server/entity/User'; import type { MediaResultsResponse, @@ -98,6 +99,7 @@ mediaRoutes.post< isAuthenticated(Permission.MANAGE_REQUESTS), async (req, res, next) => { const mediaRepository = getRepository(Media); + const seasonRepository = getRepository(Season); const media = await mediaRepository.findOne({ where: { id: Number(req.params.id) }, @@ -112,11 +114,25 @@ mediaRoutes.post< switch (req.params.status) { case 'available': media[is4k ? 'status4k' : 'status'] = MediaStatus.AVAILABLE; + if (media.mediaType === MediaType.TV) { - // Mark all seasons available - media.seasons.forEach((season) => { + const expectedSeasons = req.body.seasons ?? []; + + for (const expectedSeason of expectedSeasons) { + let season = media.seasons.find( + (s) => s.seasonNumber === expectedSeason?.seasonNumber + ); + + if (!season) { + // Create the season if it doesn't exist + season = seasonRepository.create({ + seasonNumber: expectedSeason?.seasonNumber, + }); + media.seasons.push(season); + } + season[is4k ? 'status4k' : 'status'] = MediaStatus.AVAILABLE; - }); + } } break; case 'partial': diff --git a/src/components/ManageSlideOver/index.tsx b/src/components/ManageSlideOver/index.tsx index 103781d1c..01af2e2f2 100644 --- a/src/components/ManageSlideOver/index.tsx +++ b/src/components/ManageSlideOver/index.tsx @@ -96,6 +96,7 @@ const ManageSlideOver = ({ if (data.mediaInfo) { await axios.post(`/api/v1/media/${data.mediaInfo?.id}/available`, { is4k, + ...(mediaType === 'tv' && { seasons: data.seasons }), }); revalidate(); } diff --git a/src/components/RequestModal/TvRequestModal.tsx b/src/components/RequestModal/TvRequestModal.tsx index 88f5fab3d..d5c7ec824 100644 --- a/src/components/RequestModal/TvRequestModal.tsx +++ b/src/components/RequestModal/TvRequestModal.tsx @@ -342,7 +342,8 @@ const TvRequestModal = ({ (data.mediaInfo.requests || []).filter( (request) => request.is4k === is4k && - request.status !== MediaRequestStatus.DECLINED + request.status !== MediaRequestStatus.DECLINED && + request.status !== MediaRequestStatus.COMPLETED ).length > 0 ) { data.mediaInfo.requests diff --git a/src/components/TvDetails/index.tsx b/src/components/TvDetails/index.tsx index cb4e8a89b..6d07fa326 100644 --- a/src/components/TvDetails/index.tsx +++ b/src/components/TvDetails/index.tsx @@ -235,7 +235,8 @@ const TvDetails = ({ tv }: TvDetailsProps) => { .filter( (request) => request.is4k === is4k && - request.status !== MediaRequestStatus.DECLINED + request.status !== MediaRequestStatus.DECLINED && + request.status !== MediaRequestStatus.COMPLETED ) .reduce((requestedSeasons, request) => { return [ @@ -554,23 +555,37 @@ const TvDetails = ({ tv }: TvDetailsProps) => { season.seasonNumber === s.seasonNumber && s.status4k !== MediaStatus.UNKNOWN ); - const request = (data.mediaInfo?.requests ?? []).find( - (r) => - !!r.seasons.find( - (s) => s.seasonNumber === season.seasonNumber - ) && !r.is4k - ); - const request4k = (data.mediaInfo?.requests ?? []).find( - (r) => - !!r.seasons.find( - (s) => s.seasonNumber === season.seasonNumber - ) && r.is4k - ); + const request = (data.mediaInfo?.requests ?? []) + .filter( + (r) => + !!r.seasons.find( + (s) => s.seasonNumber === season.seasonNumber + ) && !r.is4k + ) + .sort( + (a, b) => + new Date(b.createdAt).getTime() - + new Date(a.createdAt).getTime() + )[0]; + const request4k = (data.mediaInfo?.requests ?? []) + .filter( + (r) => + !!r.seasons.find( + (s) => s.seasonNumber === season.seasonNumber + ) && r.is4k + ) + .sort( + (a, b) => + new Date(b.createdAt).getTime() - + new Date(a.createdAt).getTime() + )[0]; if (season.episodeCount === 0) { return null; } + console.log({ request }); + return ( {({ open }) => ( @@ -597,10 +612,10 @@ const TvDetails = ({ tv }: TvDetailsProps) => { {((!mSeason && - (request?.status === MediaRequestStatus.APPROVED || - request?.status === - MediaRequestStatus.COMPLETED)) || - mSeason?.status === MediaStatus.PROCESSING) && ( + request?.status === MediaRequestStatus.APPROVED) || + mSeason?.status === MediaStatus.PROCESSING || + (request?.status === MediaRequestStatus.APPROVED && + mSeason?.status === MediaStatus.DELETED)) && ( <>
@@ -659,24 +674,28 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
)} - {mSeason?.status === MediaStatus.DELETED && ( - <> -
- - {intl.formatMessage(globalMessages.deleted)} - -
-
- -
- - )} + {mSeason?.status === MediaStatus.DELETED && + request?.status !== MediaRequestStatus.APPROVED && ( + <> +
+ + {intl.formatMessage(globalMessages.deleted)} + +
+
+ +
+ + )} {((!mSeason4k && + request4k?.status === + MediaRequestStatus.APPROVED) || + mSeason4k?.status4k === MediaStatus.PROCESSING || (request4k?.status === - MediaRequestStatus.APPROVED || - request4k?.status === - MediaRequestStatus.COMPLETED)) || - mSeason4k?.status4k === MediaStatus.PROCESSING) && + MediaRequestStatus.APPROVED && + mSeason4k?.status4k === MediaStatus.DELETED)) && show4k && ( <>
@@ -760,6 +779,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => { )} {mSeason4k?.status4k === MediaStatus.DELETED && + request4k?.status !== MediaRequestStatus.APPROVED && show4k && ( <>