Skip to content

Commit

Permalink
refactor(blacklist): change all instances of blacktag to blacklistedT…
Browse files Browse the repository at this point in the history
…ag and update doc to match
  • Loading branch information
benbeauchamp7 committed Feb 1, 2025
1 parent 7dec05b commit 971cadf
Show file tree
Hide file tree
Showing 18 changed files with 144 additions and 124 deletions.
4 changes: 2 additions & 2 deletions cypress/config/settings.cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"discoverRegion": "",
"streamingRegion": "",
"originalLanguage": "",
"blacktags": "",
"blacktagsLimit": 50,
"blacklistedTags": "",
"blacklistedTagsLimit": 50,
"trustProxy": false,
"mediaServerType": 1,
"partialRequestsEnabled": true,
Expand Down
4 changes: 2 additions & 2 deletions docs/using-jellyseerr/settings/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ These settings filter content shown on the "Discover" home page based on regiona

## Blacklist Content with Tags and Limit Content Blacklisted per Tag

These settings blacklist any TV shows or movies that have one of the entered tags. Entries are added to the blacklist using the "Process Blacktags" job. Removing blacktags will remove media from the blacklist if it was blacklisted for that blacktag. To clear all blacklist entries created with blacktags, remove all blacktags in the setting and run the "Process Blacktags" job.
These settings blacklist any TV shows or movies that have one of the entered tags. Entries are added to the blacklist using the "Process Blacklisted Tags" job. Removing blacklisted tags will remove media from the blacklist if it was blacklisted for that tag. To clear all blacklist entries created with tag, remove all tags in the setting and run the "Process Blacklisted Tags" job.
The limit configures the number of pages per tag the job will blacklist, where each page is 20 entires. The job cycles through each of the 16 available discovery sort options and queries the defined number of pages to blacklist media most likely to appear at the top of a sort. Increasing the limit will create a more accurate blacklist, but will use more space.
Blacktags are disabled until tags to blacklist are entered. These settings cannot be overriden in user settings.
Blacklisted tags are disabled until tags to blacklist are entered. These settings cannot be overriden in user settings.

## Hide Available Media

Expand Down
2 changes: 1 addition & 1 deletion overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4126,7 +4126,7 @@ paths:
name: filter
schema:
type: string
enum: [all, manual, blacktags]
enum: [all, manual, blacklistedTags]
default: manual
responses:
'200':
Expand Down
4 changes: 2 additions & 2 deletions server/entity/Blacklist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class Blacklist implements BlacklistItem {
public media: Media;

@Column({ nullable: true, type: 'varchar' })
public blacktags?: string;
public blacklistedTags?: string;

@CreateDateColumn()
public createdAt: Date;
Expand All @@ -62,7 +62,7 @@ export class Blacklist implements BlacklistItem {
mediaType: MediaType;
title?: ZodOptional<ZodString>['_output'];
tmdbId: ZodNumber['_output'];
blacktags?: string;
blacklistedTags?: string;
};
},
entityManager?: EntityManager
Expand Down
2 changes: 1 addition & 1 deletion server/interfaces/api/blacklistInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface BlacklistItem {
title?: string;
createdAt?: Date;
user?: User;
blacktags?: string;
blacklistedTags?: string;
}

export interface BlacklistResultsResponse extends PaginatedResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type { EntityManager } from 'typeorm';
const TMDB_API_DELAY_MS = 250;
class AbortTransaction extends Error {}

class BlacktagProcessor implements RunnableScanner<StatusBase> {
class BlacklistedTagProcessor implements RunnableScanner<StatusBase> {
private running = false;
private progress = 0;
private total = 0;
Expand All @@ -35,7 +35,7 @@ class BlacktagProcessor implements RunnableScanner<StatusBase> {
});
} catch (err) {
if (err instanceof AbortTransaction) {
logger.info('Aborting job: Process Blacktags', {
logger.info('Aborting job: Process Blacklisted Tags', {
label: 'Jobs',
});
} else {
Expand Down Expand Up @@ -68,25 +68,25 @@ class BlacktagProcessor implements RunnableScanner<StatusBase> {
const tmdb = createTmdbWithRegionLanguage();

const settings = getSettings();
const blacktags = settings.main.blacktags;
const blacktagsArr = blacktags.split(',');
const blacklistedTags = settings.main.blacklistedTags;
const blacklistedTagsArr = blacklistedTags.split(',');

const pageLimit = settings.main.blacktagsLimit;
const pageLimit = settings.main.blacklistedTagsLimit;

if (blacktags.length === 0) {
if (blacklistedTags.length === 0) {
return;
}

// The maximum number of queries we're expected to execute
this.total =
2 * blacktagsArr.length * pageLimit * SortOptionsIterable.length;
2 * blacklistedTagsArr.length * pageLimit * SortOptionsIterable.length;

for (const type of [MediaType.MOVIE, MediaType.TV]) {
const getDiscover =
type == MediaType.MOVIE ? tmdb.getDiscoverMovies : tmdb.getDiscoverTv;

// Iterate for each tag
for (const tag of blacktagsArr) {
for (const tag of blacklistedTagsArr) {
let queryMax = pageLimit * SortOptionsIterable.length;
let fixedSortMode = false; // Set to true when the page limit allows for getting every page of tag

Expand Down Expand Up @@ -139,11 +139,11 @@ class BlacktagProcessor implements RunnableScanner<StatusBase> {
// Don't mark manual blacklists with tags
// If media wasn't previously blacklisted for this tag, add the tag to the media's blacklist
if (
blacklistEntry.blacktags != null &&
!blacklistEntry.blacktags.includes(`,${keywordId},`)
blacklistEntry.blacklistedTags != null &&
!blacklistEntry.blacklistedTags.includes(`,${keywordId},`)
) {
await blacklistRepository.update(blacklistEntry.id, {
blacktags: `${blacklistEntry.blacktags}${keywordId},`,
blacklistedTags: `${blacklistEntry.blacklistedTags}${keywordId},`,
});
}

Expand All @@ -157,7 +157,7 @@ class BlacktagProcessor implements RunnableScanner<StatusBase> {
mediaType,
title: 'title' in entry ? entry.title : entry.name,
tmdbId: entry.id,
blacktags: `,${keywordId},`,
blacklistedTags: `,${keywordId},`,
},
},
em
Expand All @@ -166,12 +166,12 @@ class BlacktagProcessor implements RunnableScanner<StatusBase> {
}

private async cleanBlacklist(em: EntityManager) {
// Remove blacklist and media entries blacklisted by blacktags
// Remove blacklist and media entries blacklisted by tags
const mediaRepository = em.getRepository(Media);
const mediaToRemove = await mediaRepository
.createQueryBuilder('media')
.innerJoinAndSelect(Blacklist, 'blist', 'blist.tmdbId = media.tmdbId')
.where(`blist.blacktags IS NOT NULL`)
.where(`blist.blacklistedTags IS NOT NULL`)
.getMany();

// Batch removes so the query doesn't get too large
Expand All @@ -181,6 +181,6 @@ class BlacktagProcessor implements RunnableScanner<StatusBase> {
}
}

const blacktagsProcessor = new BlacktagProcessor();
const blacklistedTagsProcessor = new BlacklistedTagProcessor();

export default blacktagsProcessor;
export default blacklistedTagsProcessor;
12 changes: 6 additions & 6 deletions server/job/schedule.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MediaServerType } from '@server/constants/server';
import blacktagsProcessor from '@server/job/blacktagsProcessor';
import blacklistedTagsProcessor from '@server/job/blacklistedTagsProcessor';
import availabilitySync from '@server/lib/availabilitySync';
import downloadTracker from '@server/lib/downloadtracker';
import ImageProxy from '@server/lib/imageproxy';
Expand Down Expand Up @@ -227,18 +227,18 @@ export const startJobs = (): void => {
// Generate blacklist based on keywords weekly at 1:30 am
scheduledJobs.push({
id: 'process-blacklisted-tags',
name: 'Process Blacktags',
name: 'Process Blacklisted Tags',
type: 'process',
interval: 'days',
cronSchedule: jobs['process-blacklisted-tags'].schedule,
job: schedule.scheduleJob(jobs['process-blacklisted-tags'].schedule, () => {
logger.info('Starting scheduled job: Process Blacktags', {
logger.info('Starting scheduled job: Process Blacklisted Tags', {
label: 'Jobs',
});
blacktagsProcessor.run();
blacklistedTagsProcessor.run();
}),
running: () => blacktagsProcessor.status().running,
cancelFn: () => blacktagsProcessor.cancel(),
running: () => blacklistedTagsProcessor.status().running,
cancelFn: () => blacklistedTagsProcessor.cancel(),
});

// Refresh plex token everyday at 01:00 am
Expand Down
8 changes: 4 additions & 4 deletions server/lib/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ export interface MainSettings {
discoverRegion: string;
streamingRegion: string;
originalLanguage: string;
blacktags: string;
blacktagsLimit: number;
blacklistedTags: string;
blacklistedTagsLimit: number;
trustProxy: boolean;
mediaServerType: number;
partialRequestsEnabled: boolean;
Expand Down Expand Up @@ -347,8 +347,8 @@ class Settings {
discoverRegion: '',
streamingRegion: '',
originalLanguage: '',
blacktags: '',
blacktagsLimit: 50,
blacklistedTags: '',
blacklistedTagsLimit: 50,
trustProxy: false,
mediaServerType: MediaServerType.NOT_CONFIGURED,
partialRequestsEnabled: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ export class AddBlacklistTagsColumn1737320080282 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "blacklist" ADD blacktags character varying`
`ALTER TABLE "blacklist" ADD blacklistedTags character varying`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "blacklist" DROP COLUMN blacktags`);
await queryRunner.query(
`ALTER TABLE "blacklist" DROP COLUMN blacklistedTags`
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ export class AddBlacklistTagsColumn1737320080282 implements MigrationInterface {

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "temporary_blacklist" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "mediaType" varchar NOT NULL, "title" varchar, "tmdbId" integer NOT NULL, "blacktags" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer, "mediaId" integer, CONSTRAINT "UQ_6bbafa28411e6046421991ea21c" UNIQUE ("tmdbId"), CONSTRAINT "REL_62b7ade94540f9f8d8bede54b9" UNIQUE ("mediaId"), CONSTRAINT "FK_53c1ab62c3e5875bc3ac474823e" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_62b7ade94540f9f8d8bede54b99" FOREIGN KEY ("mediaId") REFERENCES "media" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
`CREATE TABLE "temporary_blacklist" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "mediaType" varchar NOT NULL, "title" varchar, "tmdbId" integer NOT NULL, "blacklistedTags" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "userId" integer, "mediaId" integer, CONSTRAINT "UQ_6bbafa28411e6046421991ea21c" UNIQUE ("tmdbId"), CONSTRAINT "REL_62b7ade94540f9f8d8bede54b9" UNIQUE ("mediaId"), CONSTRAINT "FK_53c1ab62c3e5875bc3ac474823e" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT "FK_62b7ade94540f9f8d8bede54b99" FOREIGN KEY ("mediaId") REFERENCES "media" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`
);
await queryRunner.query(
`INSERT INTO "temporary_blacklist"("id", "mediaType", "title", "tmdbId", "blacktags", "createdAt", "userId", "mediaId") SELECT "id", "mediaType", "title", "tmdbId", "blacktags", "createdAt", "userId", "mediaId" FROM "blacklist"`
`INSERT INTO "temporary_blacklist"("id", "mediaType", "title", "tmdbId", "blacklistedTags", "createdAt", "userId", "mediaId") SELECT "id", "mediaType", "title", "tmdbId", "blacklistedTags", "createdAt", "userId", "mediaId" FROM "blacklist"`
);
await queryRunner.query(`DROP TABLE "blacklist"`);
await queryRunner.query(
Expand Down
8 changes: 4 additions & 4 deletions server/routes/blacklist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const blacklistGet = z.object({
take: z.coerce.number().int().positive().default(25),
skip: z.coerce.number().int().nonnegative().default(0),
search: z.string().optional(),
filter: z.enum(['all', 'manual', 'blacktags']).optional(),
filter: z.enum(['all', 'manual', 'blacklistedTags']).optional(),
});

blacklistRoutes.get(
Expand All @@ -42,10 +42,10 @@ blacklistRoutes.get(

switch (filter) {
case 'manual':
query = query.andWhere('blacklist.blacktags IS NULL');
query = query.andWhere('blacklist.blacklistedTags IS NULL');
break;
case 'blacktags':
query = query.andWhere('blacklist.blacktags IS NOT NULL');
case 'blacklistedTags':
query = query.andWhere('blacklist.blacklistedTags IS NOT NULL');
break;
}

Expand Down
14 changes: 7 additions & 7 deletions src/components/Blacklist/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BlacktagsBadge from '@app/components/BlacktagsBadge';
import BlacklistedTagsBadge from '@app/components/BlacklistedTagsBadge';
import Badge from '@app/components/Common/Badge';
import Button from '@app/components/Common/Button';
import CachedImage from '@app/components/Common/CachedImage';
Expand Down Expand Up @@ -44,14 +44,14 @@ const messages = defineMessages('components.Blacklist', {
blacklistedby: '{date} by {user}',
blacklistNotFoundError: '<strong>{title}</strong> is not blacklisted.',
filterManual: 'Manual',
filterBlacktags: 'Blacktags',
filterBlacklistedTags: 'Blacklisted Tags',
showAllBlacklisted: 'Show All Blacklisted Media',
});

enum Filter {
ALL = 'all',
MANUAL = 'manual',
BLACKTAGS = 'blacktags',
BLACKLISTEDTAGS = 'blacklistedTags',
}

const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => {
Expand Down Expand Up @@ -136,8 +136,8 @@ const Blacklist = () => {
<option value="manual">
{intl.formatMessage(messages.filterManual)}
</option>
<option value="blacktags">
{intl.formatMessage(messages.filterBlacktags)}
<option value="blacklistedTags">
{intl.formatMessage(messages.filterBlacklistedTags)}
</option>
</select>
</div>
Expand Down Expand Up @@ -428,9 +428,9 @@ const BlacklistedItem = ({ item, revalidateList }: BlacklistedItemProps) => {
</span>
</span>
</Link>
) : item.blacktags ? (
) : item.blacklistedTags ? (
<span className="ml-1">
<BlacktagsBadge data={item} />
<BlacklistedTagsBadge data={item} />
</span>
) : (
<span className="ml-1 truncate text-sm font-semibold">
Expand Down
6 changes: 3 additions & 3 deletions src/components/BlacklistBlock/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BlacktagsBadge from '@app/components/BlacktagsBadge';
import BlacklistedTagsBadge from '@app/components/BlacklistedTagsBadge';
import Badge from '@app/components/Common/Badge';
import Button from '@app/components/Common/Button';
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
Expand Down Expand Up @@ -98,12 +98,12 @@ const BlacklistBlock = ({
</Link>
</span>
</>
) : data.blacktags != null && data.blacktags != '' ? (
) : data.blacklistedTags != null && data.blacklistedTags != '' ? (
<>
<span className="w-40 truncate md:w-auto">
{intl.formatMessage(messages.blacklistedby)}:&nbsp;
</span>
<BlacktagsBadge data={data} />
<BlacklistedTagsBadge data={data} />
</>
) : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,31 @@
import Badge from '@app/components/Common/Badge';
import Tooltip from '@app/components/Common/Tooltip';
import defineMessages from '@app/utils/defineMessages';
import { TagIcon } from '@heroicons/react/20/solid';
import type { BlacklistItem } from '@server/interfaces/api/blacklistInterfaces';
import type { Keyword } from '@server/models/common';
import { useEffect, useState } from 'react';
import { useIntl } from 'react-intl';

interface BlacktagsBadgeProps {
const messages = defineMessages('components.Settings', {
blacklistedTagsText: 'Blacklisted Tags',
});

interface BlacklistedTagsBadgeProps {
data: BlacklistItem;
}

const BlacktagsBadge = ({ data }: BlacktagsBadgeProps) => {
const BlacklistedTagsBadge = ({ data }: BlacklistedTagsBadgeProps) => {
const [tagNamesBlacklistedFor, setTagNamesBlacklistedFor] =
useState<string>('Loading...');
const intl = useIntl();

useEffect(() => {
if (data.blacktags == null) {
if (data.blacklistedTags == null) {
return;
}

const keywordIds = data.blacktags.slice(1, -1).split(',');
const keywordIds = data.blacklistedTags.slice(1, -1).split(',');
Promise.all(
keywordIds.map(async (keywordId) => {
const res = await fetch(`/api/v1/keyword/${keywordId}`);
Expand All @@ -32,7 +39,7 @@ const BlacktagsBadge = ({ data }: BlacktagsBadgeProps) => {
).then((keywords) => {
setTagNamesBlacklistedFor(keywords.join(', '));
});
}, [data.blacktags]);
}, [data.blacklistedTags]);

return (
<Tooltip
Expand All @@ -44,10 +51,10 @@ const BlacktagsBadge = ({ data }: BlacktagsBadgeProps) => {
className="items-center border border-red-500 !text-red-400"
>
<TagIcon className="mr-1 h-4" />
Blacktags
{intl.formatMessage(messages.blacklistedTagsText)}
</Badge>
</Tooltip>
);
};

export default BlacktagsBadge;
export default BlacklistedTagsBadge;
Loading

0 comments on commit 971cadf

Please sign in to comment.