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-06-07 03:20:13 +00:00
import { curateMedia } from './media.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
2024-06-22 20:51:57 +00:00
function getWatchUrl ( scene ) {
if ( scene . url ) {
return scene . url ;
}
if ( scene . channel && ( scene . channel . isIndependent || scene . channel . type === 'network' ) ) {
return scene . channel . url ;
}
if ( scene . network ) {
return scene . network . url ;
}
return null ;
}
function getAffiliateUrl ( scene ) {
const watchUrl = getWatchUrl ( scene ) ;
if ( ! watchUrl ) {
return null ;
}
if ( ! scene . affiliate ? . parameters ) {
return scene . url ;
}
const newParams = new URLSearchParams ( {
... Object . fromEntries ( new URL ( watchUrl ) . searchParams ) ,
... Object . fromEntries ( new URLSearchParams ( scene . affiliate . parameters ) ) ,
} ) ;
return ` ${ watchUrl } ? ${ newParams . toString ( ) } ` ;
}
2023-12-30 05:29:53 +00:00
function curateScene ( rawScene , assets ) {
if ( ! rawScene ) {
return null ;
}
2024-06-22 20:51:57 +00:00
const curatedScene = {
2023-12-30 05:29:53 +00:00
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-06-22 20:51:57 +00:00
affiliate : assets . channel . affiliate ? {
id : assets . channel . affiliate . id ,
url : assets . channel . affiliate . url ,
parameters : assets . channel . affiliate . parameters ,
} : 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 ,
} ) ) ,
2024-06-04 03:19:36 +00:00
qualities : rawScene . qualities ? . sort ( ( qualityA , qualityB ) => qualityB - qualityA ) || [ ] ,
2024-05-31 01:48:17 +00:00
movies : assets . movies . map ( ( movie ) => ( {
id : movie . id ,
slug : movie . slug ,
title : movie . title ,
covers : movie . movie _covers ? . map ( ( cover ) => curateMedia ( cover ) ) . toSorted ( ( coverA , coverB ) => coverA . index - coverB . index ) || [ ] ,
} ) ) ,
2024-06-01 22:30:56 +00:00
series : assets . series . map ( ( serie ) => ( {
id : serie . id ,
slug : serie . slug ,
title : serie . title ,
poster : curateMedia ( serie . serie _poster ) ,
} ) ) ,
2023-12-30 05:29:53 +00:00
poster : curateMedia ( assets . poster ) ,
2024-03-24 03:22:37 +00:00
trailer : curateMedia ( assets . trailer ) ,
teaser : curateMedia ( assets . teaser ) ,
2024-06-12 15:09:53 +00:00
photos : assets . photos ? . map ( ( photo ) => curateMedia ( photo ) ) || [ ] ,
caps : assets . caps ? . map ( ( cap ) => curateMedia ( cap ) ) || [ ] ,
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-06-22 20:51:57 +00:00
curatedScene . watchUrl = getAffiliateUrl ( curatedScene ) ;
return curatedScene ;
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 ,
2024-05-31 01:48:17 +00:00
movies ,
2024-06-01 22:30:56 +00:00
series ,
2024-03-21 04:16:19 +00:00
posters ,
photos ,
2024-06-12 15:09:53 +00:00
caps ,
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' )
2024-06-22 20:51:57 +00:00
. select (
'channels.*' ,
'networks.id as network_id' ,
'networks.slug as network_slug' ,
'networks.name as network_name' ,
'networks.type as network_type' ,
knex . raw ( 'row_to_json(affiliates) as affiliate' ) ,
)
2023-12-30 05:29:53 +00:00
. whereIn ( 'releases.id' , sceneIds )
. leftJoin ( 'entities as channels' , 'channels.id' , 'releases.entity_id' )
. leftJoin ( 'entities as networks' , 'networks.id' , 'channels.parent_id' )
2024-06-22 20:51:57 +00:00
. leftJoin ( 'affiliates' , knex . raw ( 'affiliates.entity_id in (channels.id, networks.id)' ) )
. groupBy ( 'channels.id' , 'networks.id' , 'affiliates.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.*' ,
2024-04-02 01:01:15 +00:00
'countries.name as birth_country_name' ,
'countries.alias as birth_country_alias' ,
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' )
2024-04-02 01:01:15 +00:00
. leftJoin ( 'countries' , 'countries.alpha2' , 'actors.birth_country_alpha2' )
2024-03-03 01:33:35 +00:00
. 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-06-12 15:09:53 +00:00
movies : context . includePartOf ? knex ( 'movies_scenes' )
2024-05-31 01:48:17 +00:00
. select ( 'movies_scenes.scene_id' , 'movies.*' , knex . raw ( 'json_agg(media) as movie_covers' ) )
. leftJoin ( 'movies' , 'movies.id' , 'movies_scenes.movie_id' )
. leftJoin ( 'movies_covers' , 'movies_covers.movie_id' , 'movies.id' )
. leftJoin ( 'media' , 'media.id' , 'movies_covers.media_id' )
. whereIn ( 'scene_id' , sceneIds )
2024-06-12 15:09:53 +00:00
. groupBy ( 'movies.id' , 'movies_scenes.scene_id' ) : [ ] ,
series : context . includePartOf ? knex ( 'series_scenes' )
2024-06-01 22:30:56 +00:00
. select ( 'series_scenes.scene_id' , 'series.*' , knex . raw ( 'row_to_json(media) as serie_poster' ) )
. leftJoin ( 'series' , 'series.id' , 'series_scenes.serie_id' )
. leftJoin ( 'series_posters' , 'series_posters.serie_id' , 'series.id' )
. leftJoin ( 'media' , 'media.id' , 'series_posters.media_id' )
. whereIn ( 'scene_id' , sceneIds )
2024-06-12 15:09:53 +00:00
. groupBy ( 'series.id' , 'series_scenes.scene_id' , 'media.*' ) : [ ] ,
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-06-12 15:09:53 +00:00
photos : context . includeAssets ? knex . transaction ( async ( trx ) => {
2024-03-24 03:22:37 +00:00
if ( reqUser ) {
await trx . select ( knex . raw ( 'set_config(\'user.id\', :userId, true)' , { userId : reqUser . id } ) ) ;
}
return trx ( 'releases_photos' )
2024-06-04 01:00:23 +00:00
. leftJoin ( 'media' , 'media.id' , 'releases_photos.media_id' )
2024-03-24 03:22:37 +00:00
. whereIn ( 'release_id' , sceneIds )
2024-06-04 01:00:23 +00:00
. orderBy ( 'index' ) ;
2024-06-12 15:09:53 +00:00
} ) : [ ] ,
caps : context . includeAssets ? knex . transaction ( async ( trx ) => {
if ( reqUser ) {
await trx . select ( knex . raw ( 'set_config(\'user.id\', :userId, true)' , { userId : reqUser . id } ) ) ;
}
return trx ( 'releases_caps' )
. leftJoin ( 'media' , 'media.id' , 'releases_caps.media_id' )
. whereIn ( 'release_id' , sceneIds )
. orderBy ( 'index' ) ;
} ) : [ ] ,
trailers : context . includeAssets ? knex . transaction ( async ( trx ) => {
2024-03-24 03:22:37 +00:00
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' ) ;
2024-06-12 15:09:53 +00:00
} ) : [ ] ,
teasers : context . includeAssets ? knex . transaction ( async ( trx ) => {
2024-03-24 03:22:37 +00:00
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-06-12 15:09:53 +00:00
} ) : [ ] ,
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 ) ;
2024-05-31 01:48:17 +00:00
const sceneMovies = movies . filter ( ( movie ) => movie . scene _id === sceneId ) ;
2024-06-01 22:30:56 +00:00
const sceneSeries = series . filter ( ( serie ) => serie . scene _id === sceneId ) ;
2023-12-30 05:29:53 +00:00
const scenePoster = posters . find ( ( poster ) => poster . release _id === sceneId ) ;
const scenePhotos = photos . filter ( ( photo ) => photo . release _id === sceneId ) ;
2024-06-12 15:09:53 +00:00
const sceneCaps = caps . filter ( ( cap ) => cap . 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 ,
2024-05-31 01:48:17 +00:00
movies : sceneMovies ,
2024-06-01 22:30:56 +00:00
series : sceneSeries ,
2023-12-30 05:29:53 +00:00
poster : scenePoster ,
photos : scenePhotos ,
2024-06-12 15:09:53 +00:00
caps : sceneCaps ,
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-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 ) ;
} ) ;
2024-04-02 03:55:53 +00:00
if ( filters . notTagIds ) {
builder . whereNotIn ( 'tag_ids' , filters . notTagIds ) ;
}
2024-03-17 16:41:31 +00:00
filters . actorIds ? . forEach ( ( actorId ) => {
builder . where ( 'any(actor_ids)' , actorId ) ;
} ) ;
2024-03-14 23:08:24 +00:00
2024-04-02 03:55:53 +00:00
if ( filters . notActorIds ) {
builder . whereNotIn ( 'actor_ids' , filters . notActorIds ) ;
}
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-04-02 03:55:53 +00:00
if ( filters . notEntityIds ) {
builder . whereNotIn ( 'entity_ids' , filters . notEntityIds ) ;
}
2024-03-25 01:08:09 +00:00
if ( filters . movieId ) {
builder . whereRaw ( 'any(movie_ids) = ?' , filters . movieId ) ;
}
2024-06-01 22:30:56 +00:00
if ( filters . serieId ) {
builder . whereRaw ( 'any(serie_ids) = ?' , filters . serieId ) ;
}
2024-03-17 02:55:26 +00:00
if ( typeof filters . isShowcased === 'boolean' ) {
2024-04-03 01:31:35 +00:00
builder . where ( 'scenes.is_showcased' , filters . isShowcased ) ;
2024-03-17 02:55:26 +00:00
}
2024-06-04 03:19:36 +00:00
if ( filters . isShowcased ) {
builder . where ( 'scenes.date' , '>' , 0 ) ;
}
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-06-02 03:22:08 +00:00
{ column : 'scenes.stashed' , 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
] ) ;
2024-05-31 03:05:33 +00:00
} else if ( filters . scope === 'oldest' ) {
builder . orderBy ( 'scenes.effective_date' , 'asc' ) ;
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 ) ;
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
} ;
}