2024-02-29 00:40:11 +00:00
import config from 'config' ;
2024-03-14 23:08:24 +00:00
import util from 'util' ; /* eslint-disable-line no-unused-vars */
2024-02-29 00:40:11 +00:00
2024-03-24 03:22:37 +00:00
import { knexQuery as knex , knexOwner , knexManticore } from './knex.js' ;
2024-03-21 01:54:05 +00:00
import { utilsApi } from './manticore.js' ;
2023-12-30 05:29:53 +00:00
import { HttpError } from './errors.js' ;
2024-01-07 05:13:40 +00:00
import { fetchActorsById , curateActor , sortActorsByGender } from './actors.js' ;
2024-01-08 01:21:57 +00:00
import { fetchTagsById } from './tags.js' ;
2024-01-09 01:26:32 +00:00
import { fetchEntitiesById } from './entities.js' ;
2024-03-03 01:33:35 +00:00
import { curateStash } from './stashes.js' ;
2024-03-31 23:50:24 +00:00
import escape from '../utils/escape-manticore.js' ;
2024-03-21 04:16:19 +00:00
import promiseProps from '../utils/promise-props.js' ;
2023-12-30 05:29:53 +00:00
function curateMedia ( media ) {
if ( ! media ) {
return null ;
}
return {
id : media . id ,
path : media . path ,
thumbnail : media . thumbnail ,
lazy : media . lazy ,
2024-03-24 03:22:37 +00:00
hash : media . hash ,
2023-12-30 05:29:53 +00:00
isS3 : media . is _s3 ,
width : media . width ,
height : media . height ,
} ;
}
function curateScene ( rawScene , assets ) {
if ( ! rawScene ) {
return null ;
}
return {
id : rawScene . id ,
title : rawScene . title ,
slug : rawScene . slug ,
url : rawScene . url ,
date : rawScene . date ,
createdAt : rawScene . created _at ,
effectiveDate : rawScene . effective _date ,
description : rawScene . description ,
duration : rawScene . duration ,
2024-03-24 03:22:37 +00:00
shootId : rawScene . shoot _id ,
2023-12-30 05:29:53 +00:00
channel : {
id : assets . channel . id ,
slug : assets . channel . slug ,
name : assets . channel . name ,
type : assets . channel . type ,
isIndependent : assets . channel . independent ,
hasLogo : assets . channel . has _logo ,
} ,
network : assets . channel . network _id ? {
id : assets . channel . network _id ,
slug : assets . channel . network _slug ,
name : assets . channel . network _name ,
type : assets . channel . network _type ,
hasLogo : assets . channel . has _logo ,
} : null ,
2024-03-21 01:54:05 +00:00
actors : sortActorsByGender ( assets . actors . map ( ( actor ) => curateActor ( actor , {
sceneDate : rawScene . effective _date ,
2024-03-27 15:18:55 +00:00
stashes : assets . actorStashes . filter ( ( actorStash ) => actorStash . actor _id === actor . id ) ,
2024-03-21 02:49:03 +00:00
} ) ) , { title : rawScene . title } ) ,
2023-12-30 05:29:53 +00:00
directors : assets . directors . map ( ( director ) => ( {
id : director . id ,
slug : director . slug ,
name : director . name ,
} ) ) ,
tags : assets . tags . map ( ( tag ) => ( {
id : tag . id ,
slug : tag . slug ,
name : tag . name ,
} ) ) ,
poster : curateMedia ( assets . poster ) ,
2024-03-24 03:22:37 +00:00
trailer : curateMedia ( assets . trailer ) ,
teaser : curateMedia ( assets . teaser ) ,
2023-12-30 05:29:53 +00:00
photos : assets . photos . map ( ( photo ) => curateMedia ( photo ) ) ,
2024-03-03 01:33:35 +00:00
stashes : assets . stashes ? . map ( ( stash ) => curateStash ( stash ) ) || [ ] ,
2023-12-30 05:29:53 +00:00
createdBatchId : rawScene . created _batch _id ,
updatedBatchId : rawScene . updated _batch _id ,
2024-03-21 04:16:19 +00:00
isNew : assets . lastBatchId === rawScene . created _batch _id ,
2023-12-30 05:29:53 +00:00
} ;
}
2024-03-21 01:54:05 +00:00
export async function fetchScenesById ( sceneIds , { reqUser , ... context } = { } ) {
2024-03-21 04:16:19 +00:00
const {
scenes ,
channels ,
actors ,
directors ,
tags ,
posters ,
photos ,
2024-03-24 03:22:37 +00:00
trailers ,
teasers ,
2024-03-21 04:16:19 +00:00
stashes ,
lastBatch : { id : lastBatchId } ,
} = await promiseProps ( {
scenes : knex ( 'releases' ) . whereIn ( 'releases.id' , sceneIds ) ,
channels : knex ( 'releases' )
2023-12-30 05:29:53 +00:00
. select ( 'channels.*' , 'networks.id as network_id' , 'networks.slug as network_slug' , 'networks.name as network_name' , 'networks.type as network_type' )
. whereIn ( 'releases.id' , sceneIds )
. leftJoin ( 'entities as channels' , 'channels.id' , 'releases.entity_id' )
. leftJoin ( 'entities as networks' , 'networks.id' , 'channels.parent_id' )
. groupBy ( 'channels.id' , 'networks.id' ) ,
2024-03-21 04:16:19 +00:00
actors : knex ( 'releases_actors' )
2023-12-30 05:29:53 +00:00
. select (
2024-02-27 00:20:15 +00:00
'actors.*' ,
2024-01-10 01:00:38 +00:00
'actors_meta.*' ,
2023-12-30 05:29:53 +00:00
'releases_actors.release_id' ,
)
2024-02-27 00:20:15 +00:00
. leftJoin ( 'actors' , 'actors.id' , 'releases_actors.actor_id' )
2024-03-03 01:33:35 +00:00
. leftJoin ( 'actors_meta' , 'actors_meta.actor_id' , 'actors.id' )
. whereIn ( 'release_id' , sceneIds ) ,
2024-03-21 04:16:19 +00:00
directors : knex ( 'releases_directors' )
2023-12-30 05:29:53 +00:00
. whereIn ( 'release_id' , sceneIds )
. leftJoin ( 'actors as directors' , 'directors.id' , 'releases_directors.director_id' ) ,
2024-03-21 04:16:19 +00:00
tags : knex ( 'releases_tags' )
2023-12-30 05:29:53 +00:00
. select ( 'id' , 'slug' , 'name' , 'release_id' )
2024-03-03 01:33:35 +00:00
. leftJoin ( 'tags' , 'tags.id' , 'releases_tags.tag_id' )
2023-12-30 05:29:53 +00:00
. whereNotNull ( 'tags.id' )
. whereIn ( 'release_id' , sceneIds )
2024-01-07 05:13:40 +00:00
. orderBy ( 'priority' , 'desc' ) ,
2024-03-21 04:16:19 +00:00
posters : knex ( 'releases_posters' )
2023-12-30 05:29:53 +00:00
. whereIn ( 'release_id' , sceneIds )
. leftJoin ( 'media' , 'media.id' , 'releases_posters.media_id' ) ,
2024-03-24 03:22:37 +00:00
photos : knex . transaction ( async ( trx ) => {
if ( reqUser ) {
await trx . select ( knex . raw ( 'set_config(\'user.id\', :userId, true)' , { userId : reqUser . id } ) ) ;
}
return trx ( 'releases_photos' )
. whereIn ( 'release_id' , sceneIds )
. leftJoin ( 'media' , 'media.id' , 'releases_photos.media_id' ) ;
} ) ,
trailers : knex . transaction ( async ( trx ) => {
if ( reqUser ) {
await trx . select ( knex . raw ( 'set_config(\'user.id\', :userId, true)' , { userId : reqUser . id } ) ) ;
}
return trx ( 'releases_trailers' )
. whereIn ( 'release_id' , sceneIds )
. leftJoin ( 'media' , 'media.id' , 'releases_trailers.media_id' ) ;
} ) ,
teasers : knex . transaction ( async ( trx ) => {
if ( reqUser ) {
await trx . select ( knex . raw ( 'set_config(\'user.id\', :userId, true)' , { userId : reqUser . id } ) ) ;
}
return trx ( 'releases_teasers' )
. whereIn ( 'release_id' , sceneIds )
. leftJoin ( 'media' , 'media.id' , 'releases_teasers.media_id' ) ;
} ) ,
2024-03-21 04:16:19 +00:00
lastBatch : knex ( 'batches' )
. select ( 'id' )
. where ( 'showcased' , true )
. orderBy ( 'created_at' , 'desc' )
. first ( ) ,
stashes : reqUser
2024-03-24 03:22:37 +00:00
? knexOwner ( 'stashes_scenes' )
2024-03-03 01:33:35 +00:00
. leftJoin ( 'stashes' , 'stashes.id' , 'stashes_scenes.stash_id' )
. where ( 'stashes.user_id' , reqUser . id )
. whereIn ( 'stashes_scenes.scene_id' , sceneIds )
: [ ] ,
2024-03-21 04:16:19 +00:00
} ) ;
2023-12-30 05:29:53 +00:00
2024-03-21 01:54:05 +00:00
const actorStashes = reqUser && context . actorStashes
2024-03-27 15:21:50 +00:00
? await knexOwner ( 'stashes_actors' )
2024-03-21 01:54:05 +00:00
. leftJoin ( 'stashes' , 'stashes.id' , 'stashes_actors.stash_id' )
. where ( 'stashes.user_id' , reqUser . id )
. whereIn ( 'stashes_actors.actor_id' , actors . map ( ( actor ) => actor . id ) )
: [ ] ;
2023-12-30 05:29:53 +00:00
return sceneIds . map ( ( sceneId ) => {
const scene = scenes . find ( ( sceneEntry ) => sceneEntry . id === sceneId ) ;
if ( ! scene ) {
return null ;
}
const sceneChannel = channels . find ( ( entity ) => entity . id === scene . entity _id ) ;
const sceneActors = actors . filter ( ( actor ) => actor . release _id === sceneId ) ;
const sceneDirectors = directors . filter ( ( director ) => director . release _id === sceneId ) ;
const sceneTags = tags . filter ( ( tag ) => tag . release _id === sceneId ) ;
const scenePoster = posters . find ( ( poster ) => poster . release _id === sceneId ) ;
const scenePhotos = photos . filter ( ( photo ) => photo . release _id === sceneId ) ;
2024-03-24 03:22:37 +00:00
const sceneTrailers = trailers . find ( ( trailer ) => trailer . release _id === sceneId ) ;
const sceneTeasers = teasers . find ( ( teaser ) => teaser . release _id === sceneId ) ;
2024-03-03 01:33:35 +00:00
const sceneStashes = stashes . filter ( ( stash ) => stash . scene _id === sceneId ) ;
2024-03-21 01:54:05 +00:00
const sceneActorStashes = sceneActors . map ( ( actor ) => actorStashes . find ( ( stash ) => stash . actor _id === actor . id ) ) . filter ( Boolean ) ;
2023-12-30 05:29:53 +00:00
return curateScene ( scene , {
channel : sceneChannel ,
actors : sceneActors ,
directors : sceneDirectors ,
tags : sceneTags ,
poster : scenePoster ,
photos : scenePhotos ,
2024-03-24 03:22:37 +00:00
trailer : sceneTrailers ,
teaser : sceneTeasers ,
2024-03-03 01:33:35 +00:00
stashes : sceneStashes ,
2024-03-21 01:54:05 +00:00
actorStashes : sceneActorStashes ,
2024-03-21 04:16:19 +00:00
lastBatchId ,
2023-12-30 05:29:53 +00:00
} ) ;
} ) . filter ( Boolean ) ;
}
2024-03-14 23:08:24 +00:00
const sqlImplied = [ 'scenes_stashed' ] ;
2024-01-07 05:13:40 +00:00
function curateOptions ( options ) {
if ( options ? . limit > 100 ) {
throw new HttpError ( 'Limit must be <= 100' , 400 ) ;
}
2023-12-30 05:29:53 +00:00
return {
2024-01-07 05:13:40 +00:00
limit : options ? . limit || 30 ,
page : Number ( options ? . page ) || 1 ,
aggregate : options . aggregate ? ? true ,
2024-01-08 01:21:57 +00:00
aggregateActors : ( options . aggregate ? ? true ) && ( options . aggregateActors ? ? true ) ,
aggregateTags : ( options . aggregate ? ? true ) && ( options . aggregateTags ? ? true ) ,
2024-01-09 01:26:32 +00:00
aggregateChannels : ( options . aggregate ? ? true ) && ( options . aggregateChannels ? ? true ) ,
2024-03-14 23:08:24 +00:00
index : options . index || 'scenes' ,
useSql : options . useSql || ( typeof options . useSql === 'undefined' && sqlImplied . includes ( options . index ) ) || false ,
2023-12-30 05:29:53 +00:00
} ;
}
2024-03-21 01:54:05 +00:00
/ *
2024-03-14 23:08:24 +00:00
function buildQuery ( filters = { } , options ) {
2024-01-07 05:13:40 +00:00
const query = {
bool : {
must : [ ] ,
} ,
} ;
2023-12-30 05:29:53 +00:00
2024-01-07 05:13:40 +00:00
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' } ] ;
}
2024-01-25 02:07:26 +00:00
if ( filters . scope === 'likes' ) {
sort = [ { stashed : 'desc' } , { effective _date : 'desc' } ] ;
}
2024-02-22 04:08:06 +00:00
if ( filters . scope === 'results' ) {
sort = [ { _score : 'desc' } , { effective _date : 'desc' } ] ;
}
if ( filters . query ) {
2024-03-14 23:08:24 +00:00
query . bool . must . push ( { match : { '!title' : filters . query } } ) ; // title_filtered is matched instead of title
2024-02-22 04:08:06 +00:00
}
2024-01-10 01:00:38 +00:00
if ( filters . tagIds ) {
filters . tagIds . forEach ( ( tagId ) => {
query . bool . must . push ( { equals : { 'any(tag_ids)' : tagId } } ) ;
2024-01-07 05:13:40 +00:00
} ) ;
}
2024-01-10 01:00:38 +00:00
if ( filters . entityId ) {
query . bool . must . push ( {
bool : {
should : [
{ equals : { channel _id : filters . entityId } } ,
{ equals : { network _id : filters . entityId } } ,
] ,
} ,
} ) ;
}
if ( filters . actorIds ) {
filters . actorIds . forEach ( ( actorId ) => {
query . bool . must . push ( { equals : { 'any(actor_ids)' : actorId } } ) ;
2024-01-08 01:21:57 +00:00
} ) ;
}
2024-03-14 23:08:24 +00:00
if ( filters . stashId && options . index === 'scenes_stashed' ) {
query . bool . must . push ( { equals : { stash _id : filters . stashId } } ) ;
}
2024-01-07 05:13:40 +00:00
return { query , sort } ;
2023-12-30 05:29:53 +00:00
}
2024-01-09 01:26:32 +00:00
function buildAggregates ( options ) {
const aggregates = { } ;
if ( options . aggregateActors ) {
aggregates . actorIds = {
terms : {
field : 'actor_ids' ,
2024-02-29 00:40:11 +00:00
size : config . database . manticore . maxAggregateSize ,
2024-01-09 01:26:32 +00:00
} ,
2024-02-29 00:40:11 +00:00
sort : [ { 'count(*)' : { order : 'desc' } } ] ,
2024-01-09 01:26:32 +00:00
} ;
}
if ( options . aggregateTags ) {
aggregates . tagIds = {
terms : {
field : 'tag_ids' ,
2024-02-29 00:40:11 +00:00
size : config . database . manticore . maxAggregateSize ,
2024-01-09 01:26:32 +00:00
} ,
2024-03-14 23:08:24 +00:00
sort : [ { 'count(*)' : { order : 'desc' } } ] ,
2024-01-09 01:26:32 +00:00
} ;
}
if ( options . aggregateChannels ) {
aggregates . channelIds = {
terms : {
field : 'channel_id' ,
2024-02-29 00:40:11 +00:00
size : config . database . manticore . maxAggregateSize ,
2024-01-09 01:26:32 +00:00
} ,
2024-03-14 23:08:24 +00:00
sort : [ { 'count(*)' : { order : 'desc' } } ] ,
2024-01-09 01:26:32 +00:00
} ;
}
return aggregates ;
}
2024-03-14 23:08:24 +00:00
async function queryManticoreJson ( filters , options , _reqUser ) {
const { query , sort } = buildQuery ( filters , options ) ;
2024-02-29 00:40:11 +00:00
2023-12-30 05:29:53 +00:00
const result = await searchApi . search ( {
2024-03-14 23:08:24 +00:00
index : options . index ,
2024-01-07 05:13:40 +00:00
query ,
limit : options . limit ,
offset : ( options . page - 1 ) * options . limit ,
sort ,
2024-01-09 01:26:32 +00:00
aggs : buildAggregates ( options ) ,
2024-02-22 04:08:06 +00:00
options : {
2024-02-29 00:40:11 +00:00
max _matches : config . database . manticore . maxMatches ,
max _query _time : config . database . manticore . maxQueryTime ,
2024-02-22 04:08:06 +00:00
field _weights : {
title _filtered : 7 ,
actors : 10 ,
tags : 9 ,
meta : 6 ,
channel _name : 2 ,
channel _slug : 3 ,
network _name : 1 ,
network _slug : 1 ,
} ,
} ,
2023-12-30 05:29:53 +00:00
} ) ;
2024-03-14 23:08:24 +00:00
const scenes = result . hits . hits . map ( ( hit ) => ( {
id : hit . _id ,
... hit . _source ,
_score : hit . _score ,
} ) ) ;
return {
scenes ,
total : result . hits . total ,
aggregations : result . aggregations && Object . fromEntries ( Object . entries ( result . aggregations ) . map ( ( [ key , { buckets } ] ) => [ key , buckets ] ) ) ,
} ;
}
2024-03-21 01:54:05 +00:00
* /
2024-03-14 23:08:24 +00:00
async function queryManticoreSql ( filters , options , _reqUser ) {
2024-03-17 02:03:36 +00:00
const aggSize = config . database . manticore . maxAggregateSize ;
2024-03-14 23:08:24 +00:00
const sqlQuery = knexManticore . raw ( `
: query :
2024-03-21 01:54:05 +00:00
OPTION
field _weights = (
title _filtered = 7 ,
actors = 10 ,
tags = 9 ,
meta = 6 ,
channel _name = 2 ,
channel _slug = 3 ,
network _name = 1 ,
network _slug = 1
) ,
max _matches = : maxMatches : ,
max _query _time = : maxQueryTime :
2024-03-14 23:08:24 +00:00
: actorsFacet :
: tagsFacet :
2024-03-17 21:15:11 +00:00
: channelsFacet : ;
show meta ;
2024-03-14 23:08:24 +00:00
` , {
2024-03-17 02:03:36 +00:00
query : knexManticore ( filters . stashId ? 'scenes_stashed' : 'scenes' )
2024-03-14 23:08:24 +00:00
. modify ( ( builder ) => {
if ( filters . stashId ) {
2024-03-17 02:03:36 +00:00
builder . select ( knex . raw ( `
scenes . id as id ,
scenes . title as title ,
scenes . actor _ids as actor _ids ,
2024-03-24 22:36:25 +00:00
scenes . entity _ids as entity _ids ,
2024-03-17 02:03:36 +00:00
scenes . tag _ids as tag _ids ,
scenes . channel _id as channel _id ,
scenes . network _id as network _id ,
scenes . effective _date as effective _date ,
2024-03-21 01:54:05 +00:00
scenes . stashed as stashed ,
2024-03-17 02:03:36 +00:00
scenes . created _at ,
created _at as stashed _at ,
weight ( ) as _score
` ));
2024-03-14 23:08:24 +00:00
builder
2024-03-17 02:03:36 +00:00
. innerJoin ( 'scenes' , 'scenes.id' , 'scenes_stashed.scene_id' )
. where ( 'stash_id' , filters . stashId ) ;
} else {
builder . select ( knex . raw ( '*, weight() as _score' ) ) ;
2024-03-14 23:08:24 +00:00
}
if ( filters . query ) {
2024-03-31 23:50:24 +00:00
builder . whereRaw ( 'match(\'@!title :query:\', scenes)' , { query : escape ( filters . query ) } ) ;
2024-03-14 23:08:24 +00:00
}
2024-03-17 16:41:31 +00:00
filters . tagIds ? . forEach ( ( tagId ) => {
builder . where ( 'any(tag_ids)' , tagId ) ;
} ) ;
filters . actorIds ? . forEach ( ( actorId ) => {
builder . where ( 'any(actor_ids)' , actorId ) ;
} ) ;
2024-03-14 23:08:24 +00:00
if ( filters . entityId ) {
2024-03-24 22:36:25 +00:00
builder . whereRaw ( 'any(entity_ids) = ?' , filters . entityId ) ;
2024-03-25 01:08:09 +00:00
/* manticore does not currently support OR if both left and right table are queried https:/ / github . com / manticoresoftware / manticoresearch / issues / 1978 # issuecomment - 2010470068
2024-03-14 23:08:24 +00:00
builder . where ( ( whereBuilder ) => {
whereBuilder
2024-03-19 19:50:50 +00:00
. where ( 'scenes.channel_id' , filters . entityId )
. orWhere ( 'scenes.network_id' , filters . entityId ) ;
2024-03-14 23:08:24 +00:00
} ) ;
2024-03-24 22:36:25 +00:00
* /
2024-03-14 23:08:24 +00:00
}
2024-03-25 01:08:09 +00:00
if ( filters . movieId ) {
builder . whereRaw ( 'any(movie_ids) = ?' , filters . movieId ) ;
}
2024-03-17 02:55:26 +00:00
if ( typeof filters . isShowcased === 'boolean' ) {
builder . where ( 'is_showcased' , filters . isShowcased ) ;
}
2024-03-14 23:08:24 +00:00
if ( ! filters . scope || filters . scope === 'latest' ) {
builder
. where ( 'effective_date' , '<=' , Math . round ( Date . now ( ) / 1000 ) )
2024-03-17 02:03:36 +00:00
. orderBy ( 'scenes.effective_date' , 'desc' ) ; // can't seem to use alias if it matches column-name? behavior not fully understand, but this works
2024-03-14 23:08:24 +00:00
} else if ( filters . scope === 'upcoming' ) {
builder
. where ( 'effective_date' , '>' , Math . round ( Date . now ( ) / 1000 ) )
2024-03-17 02:03:36 +00:00
. orderBy ( 'scenes.effective_date' , 'asc' ) ;
2024-03-14 23:08:24 +00:00
} else if ( filters . scope === 'new' ) {
builder . orderBy ( [
2024-03-17 02:03:36 +00:00
{ column : 'scenes.created_at' , order : 'desc' } ,
{ column : 'scenes.effective_date' , order : 'asc' } ,
2024-03-14 23:08:24 +00:00
] ) ;
} else if ( filters . scope === 'likes' ) {
builder . orderBy ( [
2024-03-17 02:03:36 +00:00
{ column : 'scenes.stashed' , order : 'desc' } ,
{ column : 'scenes.effective_date' , order : 'desc' } ,
2024-03-14 23:08:24 +00:00
] ) ;
} else if ( filters . scope === 'results' ) {
builder . orderBy ( [
2024-03-24 22:36:25 +00:00
{ column : '_score' , order : 'desc' } ,
2024-03-17 02:03:36 +00:00
{ column : 'scenes.effective_date' , order : 'desc' } ,
] ) ;
} else if ( filters . scope === 'stashed' && filters . stashId ) {
builder . orderBy ( [
{ column : 'stashed_at' , order : 'desc' } ,
{ column : 'scenes.effective_date' , order : 'desc' } ,
2024-03-14 23:08:24 +00:00
] ) ;
} else {
2024-03-17 02:03:36 +00:00
builder . orderBy ( 'scenes.effective_date' , 'desc' ) ;
2024-03-14 23:08:24 +00:00
}
} )
. limit ( options . limit )
2024-03-31 23:50:24 +00:00
. offset ( ( options . page - 1 ) * options . limit ) ,
2024-03-14 23:08:24 +00:00
// option threads=1 fixes actors, but drastically slows down performance, wait for fix
2024-03-17 02:03:36 +00:00
actorsFacet : options . aggregateActors ? knex . raw ( 'facet scenes.actor_ids order by count(*) desc limit ?' , [ aggSize ] ) : null ,
tagsFacet : options . aggregateTags ? knex . raw ( 'facet scenes.tag_ids order by count(*) desc limit ?' , [ aggSize ] ) : null ,
channelsFacet : options . aggregateChannels ? knex . raw ( 'facet scenes.channel_id order by count(*) desc limit ?' , [ aggSize ] ) : null ,
2024-03-14 23:08:24 +00:00
maxMatches : config . database . manticore . maxMatches ,
maxQueryTime : config . database . manticore . maxQueryTime ,
} ) . toString ( ) ;
2024-03-17 16:41:31 +00:00
// manticore does not seem to accept table.column syntax if 'table' is primary (yet?), crude work-around
2024-03-17 02:03:36 +00:00
const curatedSqlQuery = filters . stashId
? sqlQuery
: sqlQuery . replace ( /scenes\./g , '' ) ;
2024-03-17 16:41:31 +00:00
if ( process . env . NODE _ENV === 'development' ) {
console . log ( curatedSqlQuery ) ;
}
2024-03-17 02:03:36 +00:00
const results = await utilsApi . sql ( curatedSqlQuery ) ;
2024-03-14 23:08:24 +00:00
2024-03-21 01:54:05 +00:00
// console.log(results[0]);
2024-03-14 23:08:24 +00:00
const actorIds = results
2024-03-17 02:03:36 +00:00
. find ( ( result ) => ( result . columns [ 0 ] . actor _ids || result . columns [ 0 ] [ 'scenes.actor_ids' ] ) && result . columns [ 1 ] [ 'count(*)' ] )
? . data . map ( ( row ) => ( { key : row . actor _ids || row [ 'scenes.actor_ids' ] , doc _count : row [ 'count(*)' ] } ) )
2024-03-14 23:08:24 +00:00
|| [ ] ;
const tagIds = results
2024-03-17 02:03:36 +00:00
. find ( ( result ) => ( result . columns [ 0 ] . tag _ids || result . columns [ 0 ] [ 'scenes.tag_ids' ] ) && result . columns [ 1 ] [ 'count(*)' ] )
? . data . map ( ( row ) => ( { key : row . tag _ids || row [ 'scenes.tag_ids' ] , doc _count : row [ 'count(*)' ] } ) )
2024-03-14 23:08:24 +00:00
|| [ ] ;
const channelIds = results
2024-03-17 02:03:36 +00:00
. find ( ( result ) => ( result . columns [ 0 ] . channel _id || result . columns [ 0 ] [ 'scenes.channel_id' ] ) && result . columns [ 1 ] [ 'count(*)' ] )
? . data . map ( ( row ) => ( { key : row . channel _id || row [ 'scenes.channel_id' ] , doc _count : row [ 'count(*)' ] } ) )
2024-03-14 23:08:24 +00:00
|| [ ] ;
2024-03-24 22:36:25 +00:00
const total = Number ( results . at ( - 1 ) . data . find ( ( entry ) => entry . Variable _name === 'total_found' ) ? . Value ) || 0 ;
2024-03-17 21:15:11 +00:00
2024-03-14 23:08:24 +00:00
return {
scenes : results [ 0 ] . data ,
2024-03-17 21:15:11 +00:00
total ,
2024-03-14 23:08:24 +00:00
aggregations : {
actorIds ,
tagIds ,
channelIds ,
} ,
} ;
}
2024-02-29 00:40:11 +00:00
2024-03-21 01:54:05 +00:00
function countAggregations ( buckets ) {
if ( ! buckets ) {
return null ;
}
return Object . fromEntries ( buckets . map ( ( bucket ) => [ bucket . key , { count : bucket . doc _count } ] ) ) ;
}
2024-03-14 23:08:24 +00:00
export async function fetchScenes ( filters , rawOptions , reqUser ) {
const options = curateOptions ( rawOptions ) ;
console . log ( 'filters' , filters ) ;
console . log ( 'options' , options ) ;
/ *
const result = config . database . manticore . forceSql || filters . stashId
? await queryManticoreSql ( filters , options , reqUser )
: await queryManticoreJson ( filters , options , reqUser ) ;
* /
console . time ( 'manticore sql' ) ;
const result = await queryManticoreSql ( filters , options , reqUser ) ;
console . timeEnd ( 'manticore sql' ) ;
const actorCounts = options . aggregateActors && countAggregations ( result . aggregations ? . actorIds ) ;
const tagCounts = options . aggregateTags && countAggregations ( result . aggregations ? . tagIds ) ;
const channelCounts = options . aggregateChannels && countAggregations ( result . aggregations ? . channelIds ) ;
2024-01-07 22:44:33 +00:00
2024-02-29 00:40:11 +00:00
console . time ( 'fetch aggregations' ) ;
2024-01-09 01:26:32 +00:00
const [ aggActors , aggTags , aggChannels ] = await Promise . all ( [
2024-03-27 22:54:23 +00:00
options . aggregateActors ? fetchActorsById ( result . aggregations . actorIds . map ( ( bucket ) => bucket . key ) , { order : [ 'slug' , 'asc' ] , append : actorCounts } ) : [ ] ,
options . aggregateTags ? fetchTagsById ( result . aggregations . tagIds . map ( ( bucket ) => bucket . key ) , { order : [ knex . raw ( 'lower(name)' ) , 'asc' ] , append : tagCounts } ) : [ ] ,
options . aggregateChannels ? fetchEntitiesById ( result . aggregations . channelIds . map ( ( bucket ) => bucket . key ) , { order : [ 'slug' , 'asc' ] , append : channelCounts } ) : [ ] ,
2024-01-07 05:13:40 +00:00
] ) ;
2024-02-29 00:40:11 +00:00
console . timeEnd ( 'fetch aggregations' ) ;
2024-03-14 23:08:24 +00:00
console . time ( 'fetch full' ) ;
const sceneIds = result . scenes . map ( ( scene ) => Number ( scene . id ) ) ;
2024-03-21 01:54:05 +00:00
const scenes = await fetchScenesById ( sceneIds , { reqUser } ) ;
2024-03-14 23:08:24 +00:00
console . timeEnd ( 'fetch full' ) ;
2023-12-30 05:29:53 +00:00
return {
scenes ,
2024-01-08 01:21:57 +00:00
aggActors ,
aggTags ,
2024-01-09 01:26:32 +00:00
aggChannels ,
2024-03-14 23:08:24 +00:00
total : result . total ,
2024-01-07 05:13:40 +00:00
limit : options . limit ,
2023-12-30 05:29:53 +00:00
} ;
}