diff --git a/server/entity/MediaRequest.ts b/server/entity/MediaRequest.ts index 6b2c7b56..ac4cfc7c 100644 --- a/server/entity/MediaRequest.ts +++ b/server/entity/MediaRequest.ts @@ -13,6 +13,7 @@ import { MediaType, } from '@server/constants/media'; import { getRepository } from '@server/datasource'; +import OverrideRule from '@server/entity/OverrideRule'; import type { MediaRequestBody } from '@server/interfaces/api/requestInterfaces'; import notificationManager, { Notification } from '@server/lib/notifications'; import { Permission } from '@server/lib/permissions'; @@ -713,48 +714,6 @@ export class MediaRequest { return; } - let rootFolder = radarrSettings.activeDirectory; - let qualityProfile = radarrSettings.activeProfileId; - let tags = radarrSettings.tags ? [...radarrSettings.tags] : []; - - if ( - this.rootFolder && - this.rootFolder !== '' && - this.rootFolder !== radarrSettings.activeDirectory - ) { - rootFolder = this.rootFolder; - logger.info(`Request has an override root folder: ${rootFolder}`, { - label: 'Media Request', - requestId: this.id, - mediaId: this.media.id, - }); - } - - if ( - this.profileId && - this.profileId !== radarrSettings.activeProfileId - ) { - qualityProfile = this.profileId; - logger.info( - `Request has an override quality profile ID: ${qualityProfile}`, - { - label: 'Media Request', - requestId: this.id, - mediaId: this.media.id, - } - ); - } - - if (this.tags && !isEqual(this.tags, radarrSettings.tags)) { - tags = this.tags; - logger.info(`Request has override tags`, { - label: 'Media Request', - requestId: this.id, - mediaId: this.media.id, - tagIds: tags, - }); - } - const tmdb = new TheMovieDb(); const radarr = new RadarrAPI({ apiKey: radarrSettings.apiKey, @@ -775,6 +734,137 @@ export class MediaRequest { return; } + let rootFolder = radarrSettings.activeDirectory; + let qualityProfile = radarrSettings.activeProfileId; + let tags = radarrSettings.tags ? [...radarrSettings.tags] : []; + + const overrideRuleRepository = getRepository(OverrideRule); + const overrideRules = await overrideRuleRepository.find({ + where: { radarrServiceId: radarrSettings.id }, + }); + const appliedOverrideRules = overrideRules.filter((rule) => { + if ( + rule.genre && + !rule.genre + .split(',') + .some((genreId) => + movie.genres.map((genre) => genre.id).includes(Number(genreId)) + ) + ) { + return false; + } + if ( + rule.language && + !rule.language + .split('|') + .some((languageId) => languageId === movie.original_language) + ) { + return false; + } + if ( + rule.keywords && + !rule.keywords + .split(',') + .some((keywordId) => + movie.keywords.keywords + .map((keyword) => keyword.id) + .includes(Number(keywordId)) + ) + ) { + return false; + } + return true; + }); + + if ( + this.rootFolder && + this.rootFolder !== '' && + this.rootFolder !== radarrSettings.activeDirectory + ) { + rootFolder = this.rootFolder; + logger.info( + `Request has a manually overriden root folder: ${rootFolder}`, + { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + } + ); + } else { + const overrideRootFolder = appliedOverrideRules.find( + (rule) => rule.rootFolder + )?.rootFolder; + if (overrideRootFolder) { + rootFolder = overrideRootFolder; + logger.info( + `Request has an override root folder from override rules: ${rootFolder}`, + { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + } + ); + } + } + + if ( + this.profileId && + this.profileId !== radarrSettings.activeProfileId + ) { + qualityProfile = this.profileId; + logger.info( + `Request has a manually overriden quality profile ID: ${qualityProfile}`, + { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + } + ); + } else { + const overrideProfileId = appliedOverrideRules.find( + (rule) => rule.profileId + )?.profileId; + if (overrideProfileId) { + qualityProfile = overrideProfileId; + logger.info( + `Request has an override quality profile ID from override rules: ${qualityProfile}`, + { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + } + ); + } + } + + if (this.tags && !isEqual(this.tags, radarrSettings.tags)) { + tags = this.tags; + logger.info(`Request has manually overriden tags`, { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + tagIds: tags, + }); + } else { + const overrideTags = appliedOverrideRules.find( + (rule) => rule.tags + )?.tags; + if (overrideTags) { + tags = [ + ...new Set([ + ...tags, + ...overrideTags.split(',').map((tag) => Number(tag)), + ]), + ]; + logger.info(`Request has override tags from override rules`, { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + tagIds: tags, + }); + } + } + if (radarrSettings.tagRequests) { let userTag = (await radarr.getTags()).find((v) => v.label.startsWith(this.requestedBy.id + ' - ') @@ -1019,29 +1109,100 @@ export class MediaRequest { ? [...sonarrSettings.tags] : []; + const overrideRuleRepository = getRepository(OverrideRule); + const overrideRules = await overrideRuleRepository.find({ + where: { radarrServiceId: sonarrSettings.id }, + }); + const appliedOverrideRules = overrideRules.filter((rule) => { + if ( + rule.genre && + !rule.genre + .split(',') + .some((genreId) => + series.genres.map((genre) => genre.id).includes(Number(genreId)) + ) + ) { + return false; + } + if ( + rule.language && + !rule.language + .split('|') + .some((languageId) => languageId === series.original_language) + ) { + return false; + } + if ( + rule.keywords && + !rule.keywords + .split(',') + .some((keywordId) => + series.keywords.results + .map((keyword) => keyword.id) + .includes(Number(keywordId)) + ) + ) { + return false; + } + return true; + }); + if ( this.rootFolder && this.rootFolder !== '' && this.rootFolder !== rootFolder ) { rootFolder = this.rootFolder; - logger.info(`Request has an override root folder: ${rootFolder}`, { - label: 'Media Request', - requestId: this.id, - mediaId: this.media.id, - }); - } - - if (this.profileId && this.profileId !== qualityProfile) { - qualityProfile = this.profileId; logger.info( - `Request has an override quality profile ID: ${qualityProfile}`, + `Request has a manually overriden root folder: ${rootFolder}`, { label: 'Media Request', requestId: this.id, mediaId: this.media.id, } ); + } else { + const overrideRootFolder = appliedOverrideRules.find( + (rule) => rule.rootFolder + )?.rootFolder; + if (overrideRootFolder) { + rootFolder = overrideRootFolder; + logger.info( + `Request has an override root folder from override rules: ${rootFolder}`, + { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + } + ); + } + } + + if (this.profileId && this.profileId !== qualityProfile) { + qualityProfile = this.profileId; + logger.info( + `Request has a manually overriden quality profile ID: ${qualityProfile}`, + { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + } + ); + } else { + const overrideProfileId = appliedOverrideRules.find( + (rule) => rule.profileId + )?.profileId; + if (overrideProfileId) { + qualityProfile = overrideProfileId; + logger.info( + `Request has an override quality profile ID from override rules: ${qualityProfile}`, + { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + } + ); + } } if ( @@ -1061,12 +1222,30 @@ export class MediaRequest { if (this.tags && !isEqual(this.tags, tags)) { tags = this.tags; - logger.info(`Request has override tags`, { + logger.info(`Request has manually overriden tags`, { label: 'Media Request', requestId: this.id, mediaId: this.media.id, tagIds: tags, }); + } else { + const overrideTags = appliedOverrideRules.find( + (rule) => rule.tags + )?.tags; + if (overrideTags) { + tags = [ + ...new Set([ + ...tags, + ...overrideTags.split(',').map((tag) => Number(tag)), + ]), + ]; + logger.info(`Request has override tags from override rules`, { + label: 'Media Request', + requestId: this.id, + mediaId: this.media.id, + tagIds: tags, + }); + } } if (sonarrSettings.tagRequests) { diff --git a/server/entity/OverrideRule.ts b/server/entity/OverrideRule.ts index 91d28768..ab576891 100644 --- a/server/entity/OverrideRule.ts +++ b/server/entity/OverrideRule.ts @@ -2,12 +2,9 @@ import { Column, CreateDateColumn, Entity, - JoinTable, - ManyToMany, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; -import { User } from './User'; @Entity() class OverrideRule { @@ -29,18 +26,14 @@ class OverrideRule { @Column({ nullable: true }) public keywords?: string; - @ManyToMany(() => User) - @JoinTable() - public users: User[]; - @Column({ type: 'int', nullable: true }) public profileId?: number; @Column({ nullable: true }) public rootFolder?: string; - @Column({ type: 'simple-array', nullable: true }) - public tags?: number[]; + @Column({ nullable: true }) + public tags?: string; @CreateDateColumn() public createdAt: Date; diff --git a/server/routes/overrideRule.ts b/server/routes/overrideRule.ts index 661e3c1c..3fdf06c6 100644 --- a/server/routes/overrideRule.ts +++ b/server/routes/overrideRule.ts @@ -32,7 +32,7 @@ overrideRuleRoutes.post< keywords?: string; profileId?: number; rootFolder?: string; - tags?: number[]; + tags?: string; radarrServiceId?: number; sonarrServiceId?: number; } @@ -68,7 +68,7 @@ overrideRuleRoutes.put< keywords?: string; profileId?: number; rootFolder?: string; - tags?: number[]; + tags?: string; radarrServiceId?: number; sonarrServiceId?: number; } diff --git a/src/components/Settings/OverrideRule/OverrideRuleModal.tsx b/src/components/Settings/OverrideRule/OverrideRuleModal.tsx index 3aa1e668..e436a846 100644 --- a/src/components/Settings/OverrideRule/OverrideRuleModal.tsx +++ b/src/components/Settings/OverrideRule/OverrideRuleModal.tsx @@ -200,7 +200,6 @@ const OverrideRuleModal = ({ { setFieldValue('language', value); }} @@ -315,7 +314,8 @@ const OverrideRuleModal = ({ classNamePrefix="react-select" value={ (values?.tags - ?.map((tagId) => { + ?.split(',') + .map((tagId) => { const foundTag = testResponse.tags.find( (tag) => tag.id === Number(tagId) ); @@ -336,7 +336,7 @@ const OverrideRuleModal = ({ onChange={(value) => { setFieldValue( 'tags', - value.map((option) => option.value) + value.map((option) => option.value).join(',') ); }} noOptionsMessage={() => diff --git a/src/components/Settings/OverrideRule/OverrideRuleTile.tsx b/src/components/Settings/OverrideRule/OverrideRuleTile.tsx index 91a3763e..7c6f0e86 100644 --- a/src/components/Settings/OverrideRule/OverrideRuleTile.tsx +++ b/src/components/Settings/OverrideRule/OverrideRuleTile.tsx @@ -39,6 +39,7 @@ interface OverrideRuleTileProps { testResponse: DVRTestResponse; radarr?: RadarrSettings | null; sonarr?: SonarrSettings | null; + revalidate: () => void; } const OverrideRuleTile = ({ @@ -47,6 +48,7 @@ const OverrideRuleTile = ({ testResponse, radarr, sonarr, + revalidate, }: OverrideRuleTileProps) => { const intl = useIntl(); const [keywords, setKeywords] = useState(null); @@ -172,7 +174,7 @@ const OverrideRuleTile = ({ {intl.formatMessage(messages.tags)}
- {rule.tags.map((tag) => ( + {rule.tags.split(',').map((tag) => ( { testResponse.tags?.find((t) => t.id === Number(tag)) @@ -205,6 +207,7 @@ const OverrideRuleTile = ({ method: 'DELETE', }); if (!res.ok) throw new Error(); + revalidate(); }} className="focus:ring-blue relative inline-flex w-0 flex-1 items-center justify-center rounded-br-lg border border-transparent py-4 text-sm font-medium leading-5 text-gray-200 transition duration-150 ease-in-out hover:text-white focus:z-10 focus:border-gray-500 focus:outline-none" > diff --git a/src/components/Settings/RadarrModal/index.tsx b/src/components/Settings/RadarrModal/index.tsx index e190ff06..a843797e 100644 --- a/src/components/Settings/RadarrModal/index.tsx +++ b/src/components/Settings/RadarrModal/index.tsx @@ -780,6 +780,7 @@ const RadarrModal = ({ setOverrideRuleModal={setOverrideRuleModal} testResponse={testResponse} radarr={radarr} + revalidate={revalidate} /> )}
  • diff --git a/src/components/Settings/SettingsServices.tsx b/src/components/Settings/SettingsServices.tsx index 54c69cff..39b2edf2 100644 --- a/src/components/Settings/SettingsServices.tsx +++ b/src/components/Settings/SettingsServices.tsx @@ -289,7 +289,6 @@ const SettingsServices = () => { { - console.log(overrideRuleModal); if (!overrideRuleModal.open) setEditSonarrModal({ open: false, sonarr: null }); }} diff --git a/src/components/Settings/SonarrModal/index.tsx b/src/components/Settings/SonarrModal/index.tsx index a763824d..c5ef6441 100644 --- a/src/components/Settings/SonarrModal/index.tsx +++ b/src/components/Settings/SonarrModal/index.tsx @@ -1084,6 +1084,7 @@ const SonarrModal = ({ setOverrideRuleModal={setOverrideRuleModal} testResponse={testResponse} sonarr={sonarr} + revalidate={revalidate} /> )}