Skip to content

Commit

Permalink
feat: blacklist items from Discover page
Browse files Browse the repository at this point in the history
fix #490
  • Loading branch information
JoaquinOlivero committed Jan 22, 2024
1 parent 7af193b commit 6aea2af
Show file tree
Hide file tree
Showing 10 changed files with 393 additions and 53 deletions.
28 changes: 28 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ tags:
description: Endpoints related to getting service (Radarr/Sonarr) details.
- name: watchlist
description: Collection of media to watch later
- name: blacklist
description: Blacklisted media from discovery page.
servers:
- url: '{server}/api/v1'
variables:
Expand All @@ -46,6 +48,16 @@ servers:

components:
schemas:
Blacklist:
type: object
properties:
tmdbId:
type: number
example: 1
title:
type: string
media:
$ref: '#/components/schemas/MediaInfo'
Watchlist:
type: object
properties:
Expand Down Expand Up @@ -4027,6 +4039,22 @@ paths:
restricted:
type: boolean
example: false
/blacklist:
post:
summary: Add media to blacklist
tags:
- blacklist
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Blacklist'
responses:
'201':
description: Item succesfully blacklisted
'412':
description: Item has already been blacklisted
/watchlist:
post:
summary: Add media to watchlist
Expand Down
53 changes: 53 additions & 0 deletions server/entity/Blacklist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { MediaType } from '@server/constants/media';
import { getRepository } from '@server/datasource';
import type { BlacklistItem } from '@server/interfaces/api/discoverInterfaces';
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
Unique,
} from 'typeorm';
import type { ZodNumber, ZodOptional, ZodString } from 'zod';

@Entity()
@Unique(['tmdbId'])
export class Blacklist implements BlacklistItem {
@PrimaryGeneratedColumn()
public id: number;

@Column({ type: 'varchar' })
public mediaType: MediaType;

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

@Column()
public tmdbId: number;

@CreateDateColumn()
public createdAt: Date;

constructor(init?: Partial<Blacklist>) {
Object.assign(this, init);
}

public static async addToBlacklist({
blacklistRequest,
}: {
blacklistRequest: {
mediaType: MediaType;
title?: ZodOptional<ZodString>['_output'];
tmdbId: ZodNumber['_output'];
};
}): Promise<void> {
const blacklistRepository = getRepository(this);

const blacklistItem = new this({
...blacklistRequest,
});

await blacklistRepository.save(blacklistItem);
return;
}
}
8 changes: 8 additions & 0 deletions server/interfaces/api/blacklistAdd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { MediaType } from '@server/constants/media';
import { z } from 'zod';

export const blacklistAdd = z.object({
tmdbId: z.coerce.number(),
mediaType: z.nativeEnum(MediaType),
title: z.coerce.string().optional(),
});
6 changes: 6 additions & 0 deletions server/interfaces/api/discoverInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ export interface WatchlistResponse {
totalResults: number;
results: WatchlistItem[];
}

export interface BlacklistItem {
tmdbId: number;
mediaType: 'movie' | 'tv';
title?: string;
}
15 changes: 15 additions & 0 deletions server/migration/1699901142442-AddBlacklist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { MigrationInterface, QueryRunner } from 'typeorm';

export class AddBlacklist1699901142442 implements MigrationInterface {
name = 'AddBlacklist1699901142442';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "blacklist" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "mediaType" varchar NOT NULL, "title" varchar, "tmdbId" integer NOT NULL, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), CONSTRAINT "UQ_6bbafa28411e6046421991ea21c" UNIQUE ("tmdbId"))`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "blacklist"`);
}
}
48 changes: 48 additions & 0 deletions server/routes/blacklist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Blacklist } from '@server/entity/Blacklist';
import { blacklistAdd } from '@server/interfaces/api/blacklistAdd';
import logger from '@server/logger';
import { Router } from 'express';
import { QueryFailedError } from 'typeorm';

const blacklistRoutes = Router();

blacklistRoutes.post('/', async (req, res, next) => {
try {
if (!req.user) {
return next({
status: 401,
message: 'You must be logged in to blacklist an item.',
});
}

const values = blacklistAdd.parse(req.body);

await Blacklist.addToBlacklist({
blacklistRequest: values,
});

return res.status(201).send();
} catch (error) {
if (!(error instanceof Error)) {
return;
}

if (error instanceof QueryFailedError) {
switch (error.driverError.errno) {
case 19:
return next({ status: 412, message: 'Item already blacklisted' });
default:
logger.warn('Something wrong with data blacklist', {
tmdbId: req.body.tmdbId,
mediaType: req.body.mediaType,
label: 'Blacklist',
});
return next({ status: 409, message: 'Something wrong' });
}
}

return next({ status: 500, message: error.message });
}
});

export default blacklistRoutes;
Loading

0 comments on commit 6aea2af

Please sign in to comment.