feat(api): decouple media requests from media info

This commit is contained in:
sct
2020-09-21 00:01:38 +09:00
parent 4aa74319e0
commit 8577db1be1
21 changed files with 409 additions and 264 deletions

87
server/entity/Media.ts Normal file
View File

@@ -0,0 +1,87 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
Index,
OneToMany,
CreateDateColumn,
UpdateDateColumn,
getRepository,
In,
} from 'typeorm';
import { MediaRequest } from './MediaRequest';
import { MediaStatus, MediaType } from '../constants/media';
@Entity()
class Media {
public static async getRelatedMedia(
tmdbIds: number | number[]
): Promise<Media[]> {
const mediaRepository = getRepository(Media);
try {
let finalIds: number[];
if (!Array.isArray(tmdbIds)) {
finalIds = [tmdbIds];
} else {
finalIds = tmdbIds;
}
const media = await mediaRepository.find({
tmdbId: In(finalIds),
});
return media;
} catch (e) {
console.error(e.messaage);
return [];
}
}
public static async getMedia(id: number): Promise<Media | undefined> {
const mediaRepository = getRepository(Media);
try {
const media = await mediaRepository.findOneOrFail({
where: { tmdbId: id },
});
return media;
} catch (e) {
console.error(e.messaage);
return undefined;
}
}
@PrimaryGeneratedColumn()
public id: number;
@Column({ type: 'varchar' })
public mediaType: MediaType;
@Column({ unique: true })
@Index()
public tmdbId: number;
@Column({ unique: true, nullable: true })
@Index()
public tvdbId: number;
@Column({ type: 'int', default: MediaStatus.UNKNOWN })
public status: MediaStatus;
@OneToMany(() => MediaRequest, (request) => request.media)
public requests: MediaRequest;
@CreateDateColumn()
public createdAt: Date;
@UpdateDateColumn()
public updatedAt: Date;
constructor(init?: Partial<Media>) {
Object.assign(this, init);
}
}
export default Media;

View File

@@ -5,144 +5,53 @@ import {
Column,
CreateDateColumn,
UpdateDateColumn,
getRepository,
In,
Index,
TableInheritance,
AfterUpdate,
AfterInsert,
getRepository,
} from 'typeorm';
import { User } from './User';
import RadarrAPI from '../api/radarr';
import { getSettings } from '../lib/settings';
import TheMovieDb from '../api/themoviedb';
export enum MediaRequestStatus {
PENDING = 1,
APPROVED,
DECLINED,
AVAILABLE,
}
import Media from './Media';
import { MediaStatus, MediaRequestStatus, MediaType } from '../constants/media';
@Entity()
@TableInheritance({ column: { type: 'varchar', name: 'type' } })
export class MediaRequest {
public static async getRelatedRequests(
mediaIds: number | number[]
): Promise<MediaRequest[]> {
const requestRepository = getRepository(MediaRequest);
try {
let finalIds: number[];
if (!Array.isArray(mediaIds)) {
finalIds = [mediaIds];
} else {
finalIds = mediaIds;
}
const requests = await requestRepository.find({
mediaId: In(finalIds),
});
return requests;
} catch (e) {
console.error(e.messaage);
return [];
}
}
public static async getRequest(
id: number
): Promise<MediaRequest | undefined> {
const requestRepository = getRepository(MediaRequest);
try {
const request = await requestRepository.findOneOrFail({
where: { mediaId: id },
});
return request;
} catch (e) {
console.error(e.messaage);
return undefined;
}
}
@PrimaryGeneratedColumn()
public id: number;
@Column({ unique: true })
@Index()
public mediaId: number;
@Column({ unique: true, nullable: true })
@Index()
public tvdbId: number;
@Column({ nullable: true })
public seasons?: string;
@Column()
public mediaType: 'movie' | 'tv';
@Column({ type: 'integer' })
public status: MediaRequestStatus;
@ManyToOne(() => Media, (media) => media.requests, { eager: true })
public media: Media;
@ManyToOne(() => User, (user) => user.requests, { eager: true })
public requestedBy: User;
@ManyToOne(() => User, { nullable: true })
public modifiedBy?: User;
@CreateDateColumn()
public createdAt: Date;
@UpdateDateColumn()
public updatedAt: Date;
@Column()
public type: MediaType;
constructor(init?: Partial<MediaRequest>) {
Object.assign(this, init);
}
@AfterUpdate()
@AfterInsert()
private async sendToRadarr() {
if (
this.mediaType === 'movie' &&
this.status === MediaRequestStatus.APPROVED
) {
try {
const settings = getSettings();
if (settings.radarr.length === 0 && !settings.radarr[0]) {
console.log(
'[MediaRequest] Skipped radarr request as there is no radarr configured'
);
return;
}
const tmdb = new TheMovieDb();
const radarrSettings = settings.radarr[0];
const radarr = new RadarrAPI({
apiKey: radarrSettings.apiKey,
url: `${radarrSettings.useSsl ? 'https' : 'http'}://${
radarrSettings.hostname
}:${radarrSettings.port}/api`,
});
const movie = await tmdb.getMovie({ movieId: this.mediaId });
await radarr.addMovie({
profileId: radarrSettings.activeProfileId,
qualityProfileId: radarrSettings.activeProfileId,
rootFolderPath: radarrSettings.activeDirectory,
title: movie.title,
tmdbId: movie.id,
year: Number(movie.release_date.slice(0, 4)),
monitored: true,
searchNow: true,
});
console.log('[MediaRequest] Sent request to Radarr');
} catch (e) {
throw new Error(
`[MediaRequest] Request failed to send to radarr: ${e.message}`
);
}
private async updateParentStatus() {
const mediaRepository = getRepository(Media);
if (this.status === MediaRequestStatus.APPROVED) {
this.media.status = MediaStatus.PROCESSING;
mediaRepository.save(this.media);
}
}
}

View File

@@ -0,0 +1,57 @@
import { MediaRequest } from './MediaRequest';
import { ChildEntity, AfterUpdate, AfterInsert } from 'typeorm';
import TheMovieDb from '../api/themoviedb';
import RadarrAPI from '../api/radarr';
import { getSettings } from '../lib/settings';
import { MediaType, MediaRequestStatus } from '../constants/media';
@ChildEntity(MediaType.MOVIE)
class MovieRequest extends MediaRequest {
constructor(init?: Partial<MovieRequest>) {
super(init);
}
@AfterUpdate()
@AfterInsert()
private async sendToRadarr() {
if (this.status === MediaRequestStatus.APPROVED) {
try {
const settings = getSettings();
if (settings.radarr.length === 0 && !settings.radarr[0]) {
console.log(
'[MediaRequest] Skipped radarr request as there is no radarr configured'
);
return;
}
const tmdb = new TheMovieDb();
const radarrSettings = settings.radarr[0];
const radarr = new RadarrAPI({
apiKey: radarrSettings.apiKey,
url: `${radarrSettings.useSsl ? 'https' : 'http'}://${
radarrSettings.hostname
}:${radarrSettings.port}/api`,
});
const movie = await tmdb.getMovie({ movieId: this.media.tmdbId });
await radarr.addMovie({
profileId: radarrSettings.activeProfileId,
qualityProfileId: radarrSettings.activeProfileId,
rootFolderPath: radarrSettings.activeDirectory,
title: movie.title,
tmdbId: movie.id,
year: Number(movie.release_date.slice(0, 4)),
monitored: true,
searchNow: true,
});
console.log('[MediaRequest] Sent request to Radarr');
} catch (e) {
throw new Error(
`[MediaRequest] Request failed to send to radarr: ${e.message}`
);
}
}
}
}
export default MovieRequest;

View File

@@ -0,0 +1,37 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
} from 'typeorm';
import TvRequest from './TvRequest';
import { MediaRequestStatus } from '../constants/media';
@Entity()
class SeasonRequest {
@PrimaryGeneratedColumn()
public id: number;
@Column()
public seasonNumber: number;
@Column({ type: 'int', default: MediaRequestStatus.PENDING })
public status: MediaRequestStatus;
@ManyToOne(() => TvRequest, (request) => request.seasons)
public request: TvRequest;
@CreateDateColumn()
public createdAt: Date;
@UpdateDateColumn()
public updatedAt: Date;
constructor(init?: Partial<SeasonRequest>) {
Object.assign(this, init);
}
}
export default SeasonRequest;

View File

@@ -0,0 +1,16 @@
import { MediaRequest } from './MediaRequest';
import { ChildEntity, OneToMany } from 'typeorm';
import SeasonRequest from './SeasonRequest';
import { MediaType } from '../constants/media';
@ChildEntity(MediaType.TV)
class TvRequest extends MediaRequest {
@OneToMany(() => SeasonRequest, (season) => season.request)
public seasons: SeasonRequest[];
constructor(init?: Partial<TvRequest>) {
super(init);
}
}
export default TvRequest;