Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: filter to hide already available media
Browse files Browse the repository at this point in the history
This allows users to hide media that is already available, in the discover pages

fix sct#3779
leejayhsu committed Jul 17, 2024
1 parent 14cf43d commit 700efb4
Showing 4 changed files with 57 additions and 3 deletions.
10 changes: 10 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
@@ -4244,6 +4244,11 @@ paths:
schema:
type: string
example: 8|9
- in: query
name: hideAvailable
schema:
type: boolean
example: true
responses:
'200':
description: Results
@@ -4533,6 +4538,11 @@ paths:
schema:
type: string
example: 8|9
- in: query
name: hideAvailable
schema:
type: boolean
example: true
responses:
'200':
description: Results
29 changes: 26 additions & 3 deletions server/routes/discover.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import PlexTvAPI from '@server/api/plextv';
import type { SortOptions } from '@server/api/themoviedb';
import TheMovieDb from '@server/api/themoviedb';
import type { TmdbKeyword } from '@server/api/themoviedb/interfaces';
import { MediaType } from '@server/constants/media';
import { MediaStatus, MediaType } from '@server/constants/media';
import { getRepository } from '@server/datasource';
import Media from '@server/entity/Media';
import { User } from '@server/entity/User';
@@ -70,6 +70,7 @@ const QueryFilterOptions = z.object({
network: z.coerce.string().optional(),
watchProviders: z.coerce.string().optional(),
watchRegion: z.coerce.string().optional(),
hideAvailable: z.coerce.boolean().optional(),
});

export type FilterOptions = z.infer<typeof QueryFilterOptions>;
@@ -108,6 +109,17 @@ discoverRoutes.get('/movies', async (req, res, next) => {
data.results.map((result) => result.id)
);

let filteredResults = data.results;

if (query.hideAvailable) {
filteredResults = data.results.filter((result) => {
const mediaItem = media.find((req) => req.tmdbId === result.id);
return !(mediaItem?.status === MediaStatus.AVAILABLE);
});
} else {
filteredResults = data.results;
}

let keywordData: TmdbKeyword[] = [];
if (keywords) {
const splitKeywords = keywords.split(',');
@@ -124,7 +136,7 @@ discoverRoutes.get('/movies', async (req, res, next) => {
totalPages: data.total_pages,
totalResults: data.total_results,
keywords: keywordData,
results: data.results.map((result) =>
results: filteredResults.map((result) =>
mapMovieResult(
result,
media.find(
@@ -385,6 +397,17 @@ discoverRoutes.get('/tv', async (req, res, next) => {
data.results.map((result) => result.id)
);

let filteredResults = data.results;

if (query.hideAvailable) {
filteredResults = data.results.filter((result) => {
const mediaItem = media.find((req) => req.tmdbId === result.id);
return !(mediaItem?.status === MediaStatus.AVAILABLE);
});
} else {
filteredResults = data.results;
}

let keywordData: TmdbKeyword[] = [];
if (keywords) {
const splitKeywords = keywords.split(',');
@@ -401,7 +424,7 @@ discoverRoutes.get('/tv', async (req, res, next) => {
totalPages: data.total_pages,
totalResults: data.total_results,
keywords: keywordData,
results: data.results.map((result) =>
results: filteredResults.map((result) =>
mapTvResult(
result,
media.find(
16 changes: 16 additions & 0 deletions src/components/Discover/FilterSlideover/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Button from '@app/components/Common/Button';
import MultiRangeSlider from '@app/components/Common/MultiRangeSlider';
import SlideCheckbox from '@app/components/Common/SlideCheckbox';
import SlideOver from '@app/components/Common/SlideOver';
import type { FilterOptions } from '@app/components/Discover/constants';
import { countActiveFilters } from '@app/components/Discover/constants';
@@ -39,6 +40,7 @@ const messages = defineMessages({
runtime: 'Runtime',
streamingservices: 'Streaming Services',
voteCount: 'Number of votes between {minValue} and {maxValue}',
hideAvailable: 'Hide available titles',
});

type FilterSlideoverProps = {
@@ -287,6 +289,20 @@ const FilterSlideover = ({
})}
/>
</div>
<div className="flex items-center justify-between">
<span className="text-lg font-semibold">
{intl.formatMessage(messages.hideAvailable)}
</span>
<SlideCheckbox
checked={currentFilters.hideAvailable === 'true'}
onClick={() => {
updateQueryParams(
'hideAvailable',
currentFilters.hideAvailable === 'true' ? undefined : 'true'
);
}}
/>
</div>
<span className="text-lg font-semibold">
{intl.formatMessage(messages.streamingservices)}
</span>
5 changes: 5 additions & 0 deletions src/components/Discover/constants.ts
Original file line number Diff line number Diff line change
@@ -108,6 +108,7 @@ export const QueryFilterOptions = z.object({
voteCountGte: z.string().optional(),
watchRegion: z.string().optional(),
watchProviders: z.string().optional(),
hideAvailable: z.string().optional(),
});

export type FilterOptions = z.infer<typeof QueryFilterOptions>;
@@ -187,6 +188,10 @@ export const prepareFilterValues = (
filterValues.watchRegion = values.watchRegion;
}

if (values.hideAvailable) {
filterValues.hideAvailable = values.hideAvailable;
}

return filterValues;
};

0 comments on commit 700efb4

Please sign in to comment.