mirror of
https://github.com/chrisbenincasa/tunarr.git
synced 2026-04-18 09:03:35 -04:00
fix: apply tag values to denormalized parent/grandparent search index fields
This commit is contained in:
@@ -76,4 +76,5 @@ Fields available for search:
|
||||
| `release_date` | `date` | Program's original release date | `1990-12-05` (`YYYY-MM-DD` or `YYYYMMDD`) |
|
||||
| `show_title` | `string` | Title of the show a program belongs to (only applicable to episodes) | 30 Rock |
|
||||
| `show_genre` | `string` | Genre of the show a program belongs to (only applicable to episodes) | comedy |
|
||||
| `show_tag` | `string` | Tag on the show the program belongs to (only applicable to episodes) | - |
|
||||
| `show_tags` | `string` | Tag on the show the program belongs to (only applicable to episodes) | - |
|
||||
| `show_studio` | `string` | Studio on the show the program belongs to | - |
|
||||
@@ -10,11 +10,16 @@ import {
|
||||
reject,
|
||||
uniq,
|
||||
} from 'lodash-es';
|
||||
import { match, P } from 'ts-pattern';
|
||||
import { v4 } from 'uuid';
|
||||
import { ExternalCollectionRepo } from '../../db/ExternalCollectionRepo.ts';
|
||||
import { IProgramDB } from '../../db/interfaces/IProgramDB.ts';
|
||||
import { MediaSourceDB } from '../../db/mediaSourceDB.ts';
|
||||
import type { MediaSourceWithRelations } from '../../db/schema/derivedTypes.ts';
|
||||
import type {
|
||||
MediaSourceWithRelations,
|
||||
ProgramGroupingOrmWithRelations,
|
||||
ProgramWithRelationsOrm,
|
||||
} from '../../db/schema/derivedTypes.ts';
|
||||
import { ExternalCollection } from '../../db/schema/ExternalCollection.ts';
|
||||
import { MediaSourceOrm } from '../../db/schema/MediaSource.ts';
|
||||
import { MediaSourceLibraryOrm } from '../../db/schema/MediaSourceLibrary.ts';
|
||||
@@ -275,30 +280,99 @@ export class PlexCollectionScanner extends ExternalCollectionScanner<PlexApiClie
|
||||
|
||||
for (const newKeyChunk of chunk([...newKeys], 100)) {
|
||||
let searchDocs: ProgramSearchDocument[];
|
||||
const childSearchDocs: ProgramSearchDocument[] = [];
|
||||
if (isGroupingCollectionType) {
|
||||
const groupings = await this.getProgramGroupingsAndSearchDocuments(
|
||||
context,
|
||||
newKeyChunk,
|
||||
);
|
||||
searchDocs = groupings.searchDocs;
|
||||
await this.tagRepo.tagProgramGroupings(tag.uuid, groupings.daos);
|
||||
await this.tagRepo.tagProgramGroupings(
|
||||
tag.uuid,
|
||||
groupings.daos.map((dao) => dao.uuid),
|
||||
);
|
||||
// For groupings, we also need to expand the hierarchy so we can update nested
|
||||
// documents in the search index.
|
||||
const allDescendentIds = uniq(
|
||||
(
|
||||
await Promise.all(
|
||||
groupings.daos.map(({ type, uuid }) => {
|
||||
return Promise.all([
|
||||
this.programDB
|
||||
.getChildren(uuid, type)
|
||||
.then((_) =>
|
||||
_.results.map(
|
||||
(
|
||||
p:
|
||||
| ProgramGroupingOrmWithRelations
|
||||
| ProgramWithRelationsOrm,
|
||||
) => p.uuid,
|
||||
),
|
||||
),
|
||||
this.programDB
|
||||
.getProgramGroupingDescendants(uuid, type)
|
||||
.then((_) => _.map((p) => p.uuid)),
|
||||
]).then((_) => uniq(_.flat()));
|
||||
}),
|
||||
)
|
||||
).flat(),
|
||||
);
|
||||
childSearchDocs.push(
|
||||
...(await this.searchService.getPrograms(allDescendentIds)),
|
||||
);
|
||||
} else {
|
||||
const programs = await this.getProgramsAndSearchDocuments(
|
||||
context,
|
||||
newKeyChunk,
|
||||
);
|
||||
searchDocs = programs.searchDocs;
|
||||
await this.tagRepo.tagPrograms(tag.uuid, programs.daos);
|
||||
await this.tagRepo.tagPrograms(
|
||||
tag.uuid,
|
||||
programs.daos.map((dao) => dao.uuid),
|
||||
);
|
||||
}
|
||||
|
||||
const updates = searchDocs.map((doc) => {
|
||||
const updates: ProgramIndexPartialUpdate[] = searchDocs.map((doc) => {
|
||||
return {
|
||||
id: doc.id,
|
||||
tags: uniq(doc.tags.concat(collection.title)),
|
||||
} satisfies ProgramIndexPartialUpdate;
|
||||
};
|
||||
});
|
||||
|
||||
await this.searchService.updatePrograms(updates);
|
||||
// Update any children we have too.
|
||||
const childUpdates: ProgramIndexPartialUpdate[] = seq.collect(
|
||||
childSearchDocs,
|
||||
(doc) => {
|
||||
return match(doc)
|
||||
.with(
|
||||
{ type: P.union('episode', 'track'), grandparent: P.nonNullable },
|
||||
(doc) => {
|
||||
return {
|
||||
id: doc.id,
|
||||
grandparent: {
|
||||
...doc.grandparent,
|
||||
tags: uniq(doc.grandparent.tags.concat(collection.title)),
|
||||
},
|
||||
} satisfies ProgramIndexPartialUpdate;
|
||||
},
|
||||
)
|
||||
.with(
|
||||
{ type: P.union('album', 'season'), parent: P.nonNullable },
|
||||
(doc) => {
|
||||
return {
|
||||
id: doc.id,
|
||||
parent: {
|
||||
...doc.parent,
|
||||
tags: uniq(doc.parent.tags.concat(collection.title)),
|
||||
},
|
||||
} satisfies ProgramIndexPartialUpdate;
|
||||
},
|
||||
)
|
||||
.otherwise(() => null);
|
||||
},
|
||||
);
|
||||
|
||||
await this.searchService.updatePrograms(updates.concat(childUpdates));
|
||||
}
|
||||
|
||||
// Removed keys
|
||||
@@ -402,7 +476,10 @@ export class PlexCollectionScanner extends ExternalCollectionScanner<PlexApiClie
|
||||
}
|
||||
|
||||
return {
|
||||
daos: daoIds,
|
||||
daos: programs.map((group) => ({
|
||||
uuid: group.uuid,
|
||||
type: group.type,
|
||||
})),
|
||||
searchDocs: docs,
|
||||
};
|
||||
}
|
||||
@@ -447,7 +524,10 @@ export class PlexCollectionScanner extends ExternalCollectionScanner<PlexApiClie
|
||||
}
|
||||
|
||||
return {
|
||||
daos: daoIds,
|
||||
daos: groups.map((group) => ({
|
||||
uuid: group.uuid,
|
||||
type: group.type,
|
||||
})),
|
||||
searchDocs: docs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,7 +57,8 @@ const StringFields = [
|
||||
'type',
|
||||
'show_title',
|
||||
'show_genre',
|
||||
'show_tag',
|
||||
'show_tags',
|
||||
'show_studio',
|
||||
'audio_language',
|
||||
'subtitle_language',
|
||||
] as const;
|
||||
@@ -327,6 +328,7 @@ export const virtualFieldToIndexField: Record<string, string> = {
|
||||
show_genre: 'grandparent.genres',
|
||||
show_title: 'grandparent.title',
|
||||
show_tags: 'grandparent.tags',
|
||||
show_studio: 'grandparent.studio',
|
||||
grandparent_genre: 'grandparent.genres',
|
||||
video_bit_depth: 'videoBitDepth',
|
||||
video_codec: 'videoCodec',
|
||||
|
||||
Reference in New Issue
Block a user