Added basic actor page with scenes and co-star filtering.
This commit is contained in:
178
src/scenes.js
178
src/scenes.js
@@ -1,7 +1,7 @@
|
||||
import knex from './knex.js';
|
||||
import { searchApi } from './manticore.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { curateActor, sortActorsByGender } from './actors.js';
|
||||
import { fetchActorsById, curateActor, sortActorsByGender } from './actors.js';
|
||||
|
||||
function curateMedia(media) {
|
||||
if (!media) {
|
||||
@@ -67,16 +67,6 @@ function curateScene(rawScene, assets) {
|
||||
};
|
||||
}
|
||||
|
||||
function curateOptions(options) {
|
||||
if (options?.limit > 100) {
|
||||
throw new HttpError('Limit must be <= 100', 400);
|
||||
}
|
||||
|
||||
return {
|
||||
limit: options.limit || 30,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchScenesById(sceneIds) {
|
||||
const [scenes, channels, actors, directors, tags, posters, photos] = await Promise.all([
|
||||
knex('releases').whereIn('id', sceneIds),
|
||||
@@ -114,7 +104,8 @@ export async function fetchScenesById(sceneIds) {
|
||||
.select('id', 'slug', 'name', 'release_id')
|
||||
.whereNotNull('tags.id')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('tags', 'tags.id', 'releases_tags.tag_id'),
|
||||
.leftJoin('tags', 'tags.id', 'releases_tags.tag_id')
|
||||
.orderBy('priority', 'desc'),
|
||||
knex('releases_posters')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('media', 'media.id', 'releases_posters.media_id'),
|
||||
@@ -148,97 +139,116 @@ export async function fetchScenesById(sceneIds) {
|
||||
}).filter(Boolean);
|
||||
}
|
||||
|
||||
export async function fetchLatest(page, rawOptions) {
|
||||
const { limit } = curateOptions(rawOptions);
|
||||
function curateOptions(options) {
|
||||
if (options?.limit > 100) {
|
||||
throw new HttpError('Limit must be <= 100', 400);
|
||||
}
|
||||
|
||||
const result = await searchApi.search({
|
||||
index: 'scenes',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
range: {
|
||||
effective_date: {
|
||||
lte: Math.round(Date.now() / 1000),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
/*
|
||||
must_not: [
|
||||
{
|
||||
in: {
|
||||
'any(tag_ids)': [101, 180, 32],
|
||||
},
|
||||
},
|
||||
],
|
||||
*/
|
||||
return {
|
||||
limit: options?.limit || 30,
|
||||
page: Number(options?.page) || 1,
|
||||
aggregate: options.aggregate ?? true,
|
||||
};
|
||||
}
|
||||
|
||||
function buildQuery(filters = {}) {
|
||||
const query = {
|
||||
bool: {
|
||||
must: [],
|
||||
},
|
||||
};
|
||||
|
||||
let sort = [{ effective_date: 'desc' }];
|
||||
|
||||
if (!filters.scope || filters.scope === 'latest') {
|
||||
query.bool.must.push({
|
||||
range: {
|
||||
effective_date: {
|
||||
lte: Math.round(Date.now() / 1000),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (filters.scope === 'upcoming') {
|
||||
query.bool.must.push({
|
||||
range: {
|
||||
effective_date: {
|
||||
gt: Math.round(Date.now() / 1000),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
sort = [{ effective_date: 'asc' }];
|
||||
}
|
||||
|
||||
if (filters.scope === 'new') {
|
||||
sort = [{ created_at: 'desc' }, { effective_date: 'asc' }];
|
||||
}
|
||||
|
||||
if (filters.actorIds) {
|
||||
console.log('actor ids', filters.actorIds);
|
||||
|
||||
filters.actorIds.forEach((actorId) => {
|
||||
query.bool.must.push({
|
||||
equals: {
|
||||
'any(actor_ids)': actorId,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* tag filter
|
||||
must_not: [
|
||||
{
|
||||
in: {
|
||||
'any(tag_ids)': [101, 180, 32],
|
||||
},
|
||||
},
|
||||
limit,
|
||||
offset: (page - 1) * limit,
|
||||
sort: [{ effective_date: 'desc' }],
|
||||
});
|
||||
],
|
||||
*/
|
||||
|
||||
const sceneIds = result.hits.hits.map((hit) => Number(hit._id));
|
||||
const scenes = await fetchScenesById(sceneIds);
|
||||
console.log(query.bool.must);
|
||||
|
||||
return {
|
||||
scenes,
|
||||
total: result.hits.total,
|
||||
limit,
|
||||
};
|
||||
return { query, sort };
|
||||
}
|
||||
|
||||
export async function fetchUpcoming(page, rawOptions) {
|
||||
const { limit } = curateOptions(rawOptions);
|
||||
export async function fetchScenes(filters, rawOptions) {
|
||||
const options = curateOptions(rawOptions);
|
||||
const { query, sort } = buildQuery(filters);
|
||||
|
||||
console.log(filters);
|
||||
|
||||
const result = await searchApi.search({
|
||||
index: 'scenes',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
range: {
|
||||
effective_date: {
|
||||
gt: Math.round(Date.now() / 1000),
|
||||
},
|
||||
},
|
||||
query,
|
||||
limit: options.limit,
|
||||
offset: (options.page - 1) * options.limit,
|
||||
sort,
|
||||
...(options.aggregate && {
|
||||
aggs: {
|
||||
actorIds: {
|
||||
terms: {
|
||||
field: 'actor_ids',
|
||||
size: 5000,
|
||||
},
|
||||
],
|
||||
// sort: [{ doc_count: { order: 'asc' } }],
|
||||
},
|
||||
},
|
||||
},
|
||||
limit,
|
||||
offset: (page - 1) * limit,
|
||||
sort: [{ effective_date: 'asc' }],
|
||||
}),
|
||||
});
|
||||
|
||||
const [actors] = await Promise.all([
|
||||
options.aggregate ? fetchActorsById(result.aggregations.actorIds.buckets.map((bucket) => bucket.key), { order: ['name', 'asc'] }) : [],
|
||||
]);
|
||||
|
||||
const sceneIds = result.hits.hits.map((hit) => Number(hit._id));
|
||||
const scenes = await fetchScenesById(sceneIds);
|
||||
|
||||
return {
|
||||
scenes,
|
||||
actors,
|
||||
total: result.hits.total,
|
||||
limit,
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetchNew(page, rawOptions) {
|
||||
const { limit } = curateOptions(rawOptions);
|
||||
|
||||
const result = await searchApi.search({
|
||||
index: 'scenes',
|
||||
limit,
|
||||
offset: (page - 1) * limit,
|
||||
sort: [{ created_at: 'desc' }, { effective_date: 'asc' }],
|
||||
});
|
||||
|
||||
const sceneIds = result.hits.hits.map((hit) => Number(hit._id));
|
||||
const scenes = await fetchScenesById(sceneIds);
|
||||
|
||||
return {
|
||||
scenes,
|
||||
total: result.hits.total,
|
||||
limit,
|
||||
limit: options.limit,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user