Upgraded dependencies, bumped to Node 24.
This commit is contained in:
+61
-48
@@ -1,29 +1,30 @@
|
||||
import process from 'node:process';
|
||||
import config from 'config';
|
||||
import convert from 'convert';
|
||||
import { differenceInYears } from 'date-fns';
|
||||
import { unit } from 'mathjs';
|
||||
import { MerkleJson } from 'merkle-json';
|
||||
import moment from 'moment';
|
||||
import { nanoid } from 'nanoid';
|
||||
import omit from 'object.omit';
|
||||
import convert from 'convert';
|
||||
import unprint from 'unprint';
|
||||
|
||||
import initLogger from './logger.js';
|
||||
import { knexOwner as knex, knexManticore } from './knex.js';
|
||||
import redis from './redis.js';
|
||||
import { utilsApi } from './manticore.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { fetchCountriesByAlpha2 } from './countries.js';
|
||||
import { curateEntity } from './entities.js';
|
||||
import { curateMedia } from './media.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
import { interpolateProfiles, platformsByHostname } from '../common/actors.mjs';
|
||||
import { resolvePlace } from '../common/geo.mjs';
|
||||
import escape from '../utils/escape-manticore.js';
|
||||
import slugify from '../utils/slugify.js';
|
||||
import { curateRevision } from './revisions.js';
|
||||
import { interpolateProfiles, platformsByHostname } from '../common/actors.mjs'; // eslint-disable-line import/namespace
|
||||
import { resolvePlace } from '../common/geo.mjs'; // eslint-disable-line import/namespace
|
||||
import { syncScenes, syncActors, syncStashes } from './sync.js';
|
||||
import verifyAbility from '../utils/verify-ability.js';
|
||||
import { fetchCountriesByAlpha2 } from './countries.js';
|
||||
import { curateEntity } from './entities.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { knexOwner as knex, knexManticore } from './knex.js';
|
||||
import initLogger from './logger.js';
|
||||
import { querySql } from './manticore.js';
|
||||
import { curateMedia } from './media.js';
|
||||
import redis from './redis.js';
|
||||
import { curateRevision } from './revisions.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
import { syncActors, syncScenes, syncStashes } from './sync.js';
|
||||
|
||||
const logger = initLogger();
|
||||
const mj = new MerkleJson();
|
||||
@@ -79,10 +80,10 @@ export function curateActor(actor, context = {}) {
|
||||
})) || [], // used for profile pages
|
||||
alias: actor.alias
|
||||
? {
|
||||
id: actor.alias.id,
|
||||
slug: actor.alias.slug,
|
||||
name: actor.alias.name,
|
||||
}
|
||||
id: actor.alias.id,
|
||||
slug: actor.alias.slug,
|
||||
name: actor.alias.name,
|
||||
}
|
||||
: null,
|
||||
gender: actor.gender,
|
||||
age: actor.age,
|
||||
@@ -213,20 +214,22 @@ export function sortActorsByGender(actors, context = {}) {
|
||||
|
||||
const titleSlug = slugify(context.title);
|
||||
|
||||
const titleActors = titleSlug ? genderActors.sort((actorA, actorB) => {
|
||||
const actorASlug = actorA.slug.split('-')[0];
|
||||
const actorBSlug = actorB.slug.split('-')[0];
|
||||
const titleActors = titleSlug
|
||||
? genderActors.sort((actorA, actorB) => {
|
||||
const actorASlug = actorA.slug.split('-')[0];
|
||||
const actorBSlug = actorB.slug.split('-')[0];
|
||||
|
||||
if (titleSlug.includes(actorASlug) && !titleSlug.includes(actorBSlug)) {
|
||||
return -1;
|
||||
}
|
||||
if (titleSlug.includes(actorASlug) && !titleSlug.includes(actorBSlug)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (titleSlug.includes(actorBSlug) && !titleSlug.includes(actorASlug)) {
|
||||
return 1;
|
||||
}
|
||||
if (titleSlug.includes(actorBSlug) && !titleSlug.includes(actorASlug)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}) : alphaActors;
|
||||
return 0;
|
||||
})
|
||||
: alphaActors;
|
||||
|
||||
return titleActors;
|
||||
}
|
||||
@@ -303,14 +306,14 @@ export async function fetchActorsById(actorIds, options = {}, reqUser) {
|
||||
.whereIn('actor_id', actorIds),
|
||||
reqUser
|
||||
? knex('stashes_actors')
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_actors.actor_id', actorIds)
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_actors.actor_id', actorIds)
|
||||
: [],
|
||||
reqUser
|
||||
? knex('alerts_users_actors')
|
||||
.where('user_id', reqUser.id)
|
||||
.whereIn('actor_id', actorIds)
|
||||
.where('user_id', reqUser.id)
|
||||
.whereIn('actor_id', actorIds)
|
||||
: [],
|
||||
].slice(0, options.shallow ? 1 : -1));
|
||||
|
||||
@@ -395,20 +398,20 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
builder
|
||||
.innerJoin('actors', 'actors.id', 'actors_stashed.actor_id')
|
||||
.where('stash_id', filters.stashId);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.select(knex.raw('*, weight() as _score'));
|
||||
}
|
||||
|
||||
if (filters.query) {
|
||||
if (filters.query.charAt(0) === '#') {
|
||||
builder.where('id', Number(escape(filters.query.slice(1))));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.whereRaw(`match('@(name,aliases) :query:${filters.query.charAt(0) === '=' ? '' : '*'}', actors)`, { query: escape(filters.query) });
|
||||
}
|
||||
}
|
||||
|
||||
console.log('FILTERS', filters);
|
||||
|
||||
if (!filters.includeAliased) {
|
||||
builder.where('alias_for', 0);
|
||||
}
|
||||
@@ -426,7 +429,8 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
|
||||
if (filters.gender === 'other') {
|
||||
builder.whereNull('gender');
|
||||
} else if (filters.gender) {
|
||||
}
|
||||
else if (filters.gender) {
|
||||
builder.where('gender', filters.gender);
|
||||
}
|
||||
|
||||
@@ -483,33 +487,39 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
{ column: 'actors.slug', order: options.order[1] },
|
||||
{ column: 'actors.entity_id', order: 'asc' },
|
||||
]);
|
||||
} else if (options.order?.[0] === 'likes') {
|
||||
}
|
||||
else if (options.order?.[0] === 'likes') {
|
||||
builder.orderBy([
|
||||
{ column: 'actors.stashed', order: options.order[1] },
|
||||
{ column: 'actors.slug', order: 'asc' },
|
||||
]);
|
||||
} else if (options.order?.[0] === 'scenes') {
|
||||
}
|
||||
else if (options.order?.[0] === 'scenes') {
|
||||
builder.orderBy([
|
||||
{ column: 'actors.scenes', order: options.order[1] },
|
||||
{ column: 'actors.slug', order: 'asc' },
|
||||
]);
|
||||
} else if (options.order?.[0] === 'results') {
|
||||
}
|
||||
else if (options.order?.[0] === 'results') {
|
||||
builder.orderBy([
|
||||
{ column: '_score', order: options.order[1] },
|
||||
{ column: 'actors.stashed', order: 'desc' },
|
||||
{ column: 'actors.slug', order: 'asc' },
|
||||
]);
|
||||
} else if (options.order?.[0] === 'stashed' && filters.stashId) {
|
||||
}
|
||||
else if (options.order?.[0] === 'stashed' && filters.stashId) {
|
||||
builder.orderBy([
|
||||
{ column: 'stashed_at', order: options.order[1] },
|
||||
{ column: 'actors.slug', order: 'asc' },
|
||||
]);
|
||||
} else if (options.order) {
|
||||
}
|
||||
else if (options.order) {
|
||||
builder.orderBy([
|
||||
{ column: `actors.${options.order[0]}`, order: options.order[1] },
|
||||
{ column: 'actors.slug', order: 'asc' },
|
||||
]);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.orderBy('actors.slug', 'asc');
|
||||
builder.orderBy([
|
||||
{ column: 'actors.slug', order: 'asc' },
|
||||
@@ -535,11 +545,13 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
console.log(curatedSqlQuery);
|
||||
}
|
||||
|
||||
const results = await utilsApi.sql(curatedSqlQuery);
|
||||
const results = await querySql(curatedSqlQuery);
|
||||
|
||||
const countries = results
|
||||
.find((result) => (result.columns[0].country || result.columns[0]['actors.country']) && result.columns[1]['count(*)'])
|
||||
?.data.map((row) => ({ key: row.country || row['actors.country'], doc_count: row['count(*)'] })).filter((country) => !!country.key)
|
||||
?.data
|
||||
.map((row) => ({ key: row.country || row['actors.country'], doc_count: row['count(*)'] }))
|
||||
.filter((country) => !!country.key)
|
||||
|| [];
|
||||
|
||||
const total = Number(results.at(-1).data.find((entry) => entry.Variable_name === 'total_found').Value);
|
||||
@@ -742,7 +754,8 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) {
|
||||
*/
|
||||
|
||||
await trx.commit();
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
await trx.rollback();
|
||||
|
||||
throw error;
|
||||
|
||||
+4
-2
@@ -13,7 +13,8 @@ function getWatchUrl(scene) {
|
||||
if (scene.network) {
|
||||
return new URL(scene.network.url).href;
|
||||
}
|
||||
} catch (_error) {
|
||||
}
|
||||
catch (_error) {
|
||||
// invalid URL
|
||||
}
|
||||
|
||||
@@ -88,7 +89,8 @@ export function getAffiliateSceneUrl(scene) {
|
||||
function getEntityUrl(entity) {
|
||||
try {
|
||||
return new URL(entity.url || entity.parent?.url).href;
|
||||
} catch (_error) {
|
||||
}
|
||||
catch (_error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
import escapeRegexp from 'escape-string-regexp';
|
||||
|
||||
import promiseProps from '../utils/promise-props.js';
|
||||
import { getIdsBySlug } from './cache.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import { fetchScenesById } from './scenes.js';
|
||||
import { getIdsBySlug } from './cache.js';
|
||||
import promiseProps from '../utils/promise-props.js';
|
||||
import { HttpError } from './errors.js';
|
||||
|
||||
function curateAlert(alert, context = {}) {
|
||||
return {
|
||||
@@ -263,7 +263,7 @@ function curateNotification(notification, scenes) {
|
||||
matchedTags: scene.tags.filter((tag) => notification.alert_tags.includes(tag.id)),
|
||||
matchedEntity: [scene.channel, scene.network].find((entity) => notification.alert_entities.includes(entity?.id)) || null,
|
||||
matchedExpressions: notification.alert_matches
|
||||
.filter((match) => new RegExp(match.expression, 'ui').test(scene[match.property]))
|
||||
.filter((match) => new RegExp(match.expression, 'iu').test(scene[match.property]))
|
||||
.map((match) => ({
|
||||
id: match.id,
|
||||
property: match.property,
|
||||
|
||||
+9
-5
@@ -1,4 +1,4 @@
|
||||
import { parse } from '@brillout/json-serializer/parse'; /* eslint-disable-line import/extensions */
|
||||
import { parse } from '@brillout/json-serializer/parse';
|
||||
import events from '#/src/events.js';
|
||||
|
||||
const postHeaders = {
|
||||
@@ -69,7 +69,8 @@ export async function get(path, query = {}, options = {}) {
|
||||
|
||||
showFeedback(false, options, body.statusMessage);
|
||||
throw new Error(body.statusMessage);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
showFeedback(false, options, error.message);
|
||||
throw error;
|
||||
}
|
||||
@@ -97,7 +98,8 @@ export async function post(path, data, options = {}) {
|
||||
|
||||
showFeedback(false, options, body.statusMessage);
|
||||
throw new Error(body.statusMessage);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
showFeedback(false, options, error.message);
|
||||
throw error;
|
||||
}
|
||||
@@ -125,7 +127,8 @@ export async function patch(path, data, options = {}) {
|
||||
|
||||
showFeedback(false, options, body.statusMessage);
|
||||
throw new Error(body.statusMessage);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
showFeedback(false, options, error.message);
|
||||
throw error;
|
||||
}
|
||||
@@ -153,7 +156,8 @@ export async function del(path, options = {}) {
|
||||
|
||||
showFeedback(false, options, body.statusMessage);
|
||||
throw new Error(body.statusMessage);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
showFeedback(false, options, error.message);
|
||||
throw error;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import initServer from './web/server.js';
|
||||
import { initCaches } from './cache.js';
|
||||
import { initSyncCron } from './sync.js';
|
||||
import initServer from './web/server.js';
|
||||
|
||||
async function init() {
|
||||
await initCaches();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import process from 'node:process';
|
||||
import yargs from 'yargs';
|
||||
|
||||
const { argv } = yargs(process.argv.slice(2))
|
||||
|
||||
+10
-9
@@ -1,18 +1,18 @@
|
||||
import config from 'config';
|
||||
import util from 'util';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs/promises';
|
||||
import { createAvatar } from '@dicebear/core';
|
||||
import crypto from 'node:crypto';
|
||||
import fs from 'node:fs/promises';
|
||||
import util from 'node:util';
|
||||
import { shapes } from '@dicebear/collection';
|
||||
import { createAvatar } from '@dicebear/core';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import config from 'config';
|
||||
import { verify } from 'hcaptcha';
|
||||
|
||||
import slugify from '../utils/slugify.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import initLogger, { initAccessLogger } from './logger.js';
|
||||
import redis from './redis.js';
|
||||
import { curateUser, fetchUser } from './users.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import slugify from '../utils/slugify.js';
|
||||
import initLogger, { initAccessLogger } from './logger.js';
|
||||
|
||||
const logger = initLogger();
|
||||
const accessLogger = initAccessLogger();
|
||||
@@ -67,7 +67,8 @@ export async function login(credentials, userIp) {
|
||||
|
||||
try {
|
||||
await fs.access(`media/avatars/${user.id}_${user.username}.png`);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
await generateAvatar(user);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
import redis from './redis.js';
|
||||
|
||||
import { cacheTagIds } from './tags.js';
|
||||
import { cacheEntityIds } from './entities.js';
|
||||
import { cacheCampaigns } from './campaigns.js';
|
||||
|
||||
import { cacheEntityIds } from './entities.js';
|
||||
import redis from './redis.js';
|
||||
import { cacheTagIds } from './tags.js';
|
||||
|
||||
export async function getIdsBySlug(slugs, domain, toMap) {
|
||||
if (!slugs) {
|
||||
return [];
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
import crypto from 'crypto';
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import { curateEntity } from './entities.js';
|
||||
import redis from './redis.js';
|
||||
import initLogger from './logger.js';
|
||||
import { getAffiliateEntityUrl } from './affiliates.js';
|
||||
import { curateEntity } from './entities.js';
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import initLogger from './logger.js';
|
||||
import redis from './redis.js';
|
||||
|
||||
const logger = initLogger();
|
||||
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
import config from 'config';
|
||||
|
||||
import {
|
||||
TextCensor,
|
||||
RegExpMatcher,
|
||||
DataSet,
|
||||
englishDataset,
|
||||
englishRecommendedTransformers,
|
||||
DataSet,
|
||||
pattern,
|
||||
RegExpMatcher,
|
||||
TextCensor,
|
||||
// asteriskCensorStrategy,
|
||||
} from 'obscenity';
|
||||
|
||||
|
||||
+24
-20
@@ -1,9 +1,9 @@
|
||||
import knex from './knex.js';
|
||||
import redis from './redis.js';
|
||||
import initLogger from './logger.js';
|
||||
import entityPrefixes from './entities-prefixes.js';
|
||||
import { getAffiliateEntityUrl } from './affiliates.js';
|
||||
import { censor } from './censor.js';
|
||||
import entityPrefixes from './entities-prefixes.js';
|
||||
import knex from './knex.js';
|
||||
import initLogger from './logger.js';
|
||||
import redis from './redis.js';
|
||||
|
||||
const logger = initLogger();
|
||||
|
||||
@@ -33,12 +33,14 @@ export function curateEntity(entity, context = {}) {
|
||||
parent: entity,
|
||||
restriction: context.restriction,
|
||||
})) || [],
|
||||
affiliate: entity.affiliate ? {
|
||||
id: entity.affiliate.id,
|
||||
entityId: entity.affiliate.entity_id,
|
||||
url: entity.affiliate.url,
|
||||
parameters: entity.affiliate.parameters || {},
|
||||
} : null,
|
||||
affiliate: entity.affiliate
|
||||
? {
|
||||
id: entity.affiliate.id,
|
||||
entityId: entity.affiliate.entity_id,
|
||||
url: entity.affiliate.url,
|
||||
parameters: entity.affiliate.parameters || {},
|
||||
}
|
||||
: null,
|
||||
...context?.append?.[entity.id],
|
||||
alerts: {
|
||||
only: context?.alerts?.filter((alert) => alert.is_only).flatMap((alert) => alert.alert_ids) || [],
|
||||
@@ -123,22 +125,24 @@ export async function fetchEntitiesById(entityIds, options = {}, reqUser, contex
|
||||
}
|
||||
})
|
||||
.groupBy('entities.id', 'parents.id', 'affiliates.id', 'affiliates.entity_id', 'network_affiliates.id', 'network_affiliates.entity_id'),
|
||||
options.includeChildren ? knex('entities')
|
||||
.whereIn('entities.parent_id', entityIds)
|
||||
.whereNot('type', 'info')
|
||||
.orderBy([
|
||||
{ column: knex.raw('array_position(array[\'network\', \'channel\']::varchar[], type)'), order: 'asc' },
|
||||
{ column: 'independent', order: 'desc' },
|
||||
{ column: 'slug', order: 'asc' },
|
||||
]) : [],
|
||||
options.includeChildren
|
||||
? knex('entities')
|
||||
.whereIn('entities.parent_id', entityIds)
|
||||
.whereNot('type', 'info')
|
||||
.orderBy([
|
||||
{ column: knex.raw('array_position(array[\'network\', \'channel\']::varchar[], type)'), order: 'asc' },
|
||||
{ column: 'independent', order: 'desc' },
|
||||
{ column: 'slug', order: 'asc' },
|
||||
])
|
||||
: [],
|
||||
knex('entities_tags')
|
||||
.select('entity_id', 'tags.*')
|
||||
.leftJoin('tags', 'tags.id', 'tag_id')
|
||||
.whereIn('entity_id', entityIds),
|
||||
reqUser
|
||||
? knex('alerts_users_entities')
|
||||
.where('user_id', reqUser.id)
|
||||
.whereIn('entity_id', entityIds)
|
||||
.where('user_id', reqUser.id)
|
||||
.whereIn('entity_id', entityIds)
|
||||
: [],
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import process from 'node:process';
|
||||
import config from 'config';
|
||||
import knex from 'knex';
|
||||
|
||||
|
||||
+8
-5
@@ -1,13 +1,13 @@
|
||||
import util from 'util';
|
||||
import path from 'path';
|
||||
import path from 'node:path';
|
||||
import util from 'node:util';
|
||||
import stackParser from 'error-stack-parser';
|
||||
import * as winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
import stackParser from 'error-stack-parser';
|
||||
|
||||
// import args from './args';
|
||||
|
||||
export default function initLogger(customLabel) {
|
||||
const filepath = stackParser.parse(new Error())[1]?.fileName;
|
||||
const filepath = stackParser.parse(new Error('stack'))[1]?.fileName;
|
||||
const contextLabel = customLabel || path.basename(filepath, '.js');
|
||||
|
||||
return winston.createLogger({
|
||||
@@ -18,7 +18,10 @@ export default function initLogger(customLabel) {
|
||||
: { ...info, message: typeof info.message === 'string' ? info.message : util.inspect(info.message) }))(),
|
||||
winston.format.colorize(),
|
||||
winston.format.printf(({
|
||||
level, timestamp, label, message,
|
||||
level,
|
||||
timestamp,
|
||||
label,
|
||||
message,
|
||||
}) => `${timestamp} ${level} [${label || contextLabel}] ${message}`),
|
||||
),
|
||||
transports: [
|
||||
|
||||
@@ -8,3 +8,11 @@ mantiClient.basePath = `http://${config.database.manticore.host}:${config.databa
|
||||
export const searchApi = new manticore.SearchApi(mantiClient);
|
||||
export const indexApi = new manticore.IndexApi(mantiClient);
|
||||
export const utilsApi = new manticore.UtilsApi();
|
||||
|
||||
// manticoresearch v10's utilsApi.sql() wraps the response in a `SqlResponse` oneOf model instead of
|
||||
// returning the parsed array/object directly; unwrap it to keep the previous plain data shape.
|
||||
export async function querySql(query) {
|
||||
const response = await utilsApi.sql(query);
|
||||
|
||||
return response.getActualInstance();
|
||||
}
|
||||
|
||||
+4
-4
@@ -34,10 +34,10 @@ export function curateMedia(media, context = {}) {
|
||||
isRestricted: context.isRestricted,
|
||||
biometrics: media.biometrics
|
||||
? {
|
||||
...media.biometrics.biometrics,
|
||||
width: media.biometrics.width,
|
||||
height: media.biometrics.height,
|
||||
}
|
||||
...media.biometrics.biometrics,
|
||||
width: media.biometrics.width,
|
||||
height: media.biometrics.height,
|
||||
}
|
||||
: null,
|
||||
createdAt: media.created_at,
|
||||
};
|
||||
|
||||
+60
-44
@@ -1,16 +1,17 @@
|
||||
import process from 'node:process';
|
||||
import config from 'config';
|
||||
|
||||
import { knexQuery as knex, knexOwner, knexManticore } from './knex.js';
|
||||
import { utilsApi } from './manticore.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { fetchActorsById, curateActor, sortActorsByGender } from './actors.js';
|
||||
import { curateMedia } from './media.js';
|
||||
import { fetchTagsById } from './tags.js';
|
||||
import { fetchEntitiesById } from './entities.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
import { censor } from './censor.js';
|
||||
import escape from '../utils/escape-manticore.js';
|
||||
import promiseProps from '../utils/promise-props.js';
|
||||
import { curateActor, fetchActorsById, sortActorsByGender } from './actors.js';
|
||||
import { censor } from './censor.js';
|
||||
import { fetchEntitiesById } from './entities.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { knexQuery as knex, knexManticore, knexOwner } from './knex.js';
|
||||
import { querySql } from './manticore.js';
|
||||
import { curateMedia } from './media.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
import { fetchTagsById } from './tags.js';
|
||||
|
||||
function curateMovie(rawMovie, assets, context = {}) {
|
||||
if (!rawMovie) {
|
||||
@@ -36,13 +37,15 @@ function curateMovie(rawMovie, assets, context = {}) {
|
||||
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: censor(assets.channel.network_name, context.restriction),
|
||||
type: assets.channel.network_type,
|
||||
hasLogo: assets.channel.has_logo,
|
||||
} : null,
|
||||
network: assets.channel.network_id
|
||||
? {
|
||||
id: assets.channel.network_id,
|
||||
slug: assets.channel.network_slug,
|
||||
name: censor(assets.channel.network_name, context.restriction),
|
||||
type: assets.channel.network_type,
|
||||
hasLogo: assets.channel.has_logo,
|
||||
}
|
||||
: null,
|
||||
actors: sortActorsByGender(assets.actors.map((actor) => curateActor(actor, { sceneDate: rawMovie.effective_date }))),
|
||||
directors: assets.directors.map((director) => ({
|
||||
id: director.id,
|
||||
@@ -130,20 +133,22 @@ export async function fetchMoviesById(movieIds, reqUser, context = {}) {
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.orderBy('media.index')
|
||||
.groupBy('media.id', 'movies_covers.movie_id', 'sfw_media.id'),
|
||||
photos: context.restriction ? [] : knex.transaction(async (trx) => {
|
||||
if (reqUser) {
|
||||
await trx.select(knex.raw('set_config(\'user.id\', :userId, true)', { userId: reqUser.id }));
|
||||
}
|
||||
photos: context.restriction
|
||||
? []
|
||||
: knex.transaction(async (trx) => {
|
||||
if (reqUser) {
|
||||
await trx.select(knex.raw('set_config(\'user.id\', :userId, true)', { userId: reqUser.id }));
|
||||
}
|
||||
|
||||
return trx('movies_scenes')
|
||||
.select('media.*', 'movies_scenes.movie_id', knex.raw('row_to_json(sfw_media) as sfw_media'))
|
||||
.whereIn('movies_scenes.movie_id', movieIds)
|
||||
.whereNotNull('media.id')
|
||||
.leftJoin('releases_photos', 'releases_photos.release_id', 'movies_scenes.scene_id')
|
||||
.leftJoin('media', 'media.id', 'releases_photos.media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.groupBy('media.id', 'movies_scenes.movie_id', 'sfw_media.id');
|
||||
}),
|
||||
return trx('movies_scenes')
|
||||
.select('media.*', 'movies_scenes.movie_id', knex.raw('row_to_json(sfw_media) as sfw_media'))
|
||||
.whereIn('movies_scenes.movie_id', movieIds)
|
||||
.whereNotNull('media.id')
|
||||
.leftJoin('releases_photos', 'releases_photos.release_id', 'movies_scenes.scene_id')
|
||||
.leftJoin('media', 'media.id', 'releases_photos.media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.groupBy('media.id', 'movies_scenes.movie_id', 'sfw_media.id');
|
||||
}),
|
||||
caps: knex.transaction(async (trx) => {
|
||||
if (reqUser) {
|
||||
await trx.select(knex.raw('set_config(\'user.id\', :userId, true)', { userId: reqUser.id }));
|
||||
@@ -163,9 +168,9 @@ export async function fetchMoviesById(movieIds, reqUser, context = {}) {
|
||||
.leftJoin('media', 'media.id', 'movies_trailers.media_id'),
|
||||
stashes: reqUser
|
||||
? knexOwner('stashes_movies')
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_movies.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_movies.movie_id', movieIds)
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_movies.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_movies.movie_id', movieIds)
|
||||
: [],
|
||||
});
|
||||
|
||||
@@ -267,7 +272,8 @@ async function queryManticoreSql(filters, options) {
|
||||
builder
|
||||
.innerJoin('movies', 'movies.id', 'movies_stashed.movie_id')
|
||||
.where('stash_id', filters.stashId);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.select(knex.raw(`
|
||||
*,
|
||||
year(movies.effective_date) as effective_year,
|
||||
@@ -311,32 +317,38 @@ async function queryManticoreSql(filters, options) {
|
||||
builder
|
||||
.where('effective_date', '<=', Math.round(Date.now() / 1000))
|
||||
.orderBy('movies.effective_date', 'desc'); // can't seem to use alias if it matches column-name? behavior not fully understand, but this works
|
||||
} else if (filters.scope === 'upcoming') {
|
||||
}
|
||||
else if (filters.scope === 'upcoming') {
|
||||
builder
|
||||
.where('effective_date', '>', Math.round(Date.now() / 1000))
|
||||
.orderBy('movies.effective_date', 'asc');
|
||||
} else if (filters.scope === 'new') {
|
||||
}
|
||||
else if (filters.scope === 'new') {
|
||||
builder.orderBy([
|
||||
{ column: 'movies.created_at', order: 'desc' },
|
||||
{ column: 'movies.effective_date', order: 'asc' },
|
||||
]);
|
||||
} else if (filters.scope === 'likes') {
|
||||
}
|
||||
else if (filters.scope === 'likes') {
|
||||
builder.orderBy([
|
||||
{ column: 'movies.stashed', order: 'desc' },
|
||||
{ column: 'movies.effective_date', order: 'desc' },
|
||||
]);
|
||||
} else if (filters.scope === 'results') {
|
||||
}
|
||||
else if (filters.scope === 'results') {
|
||||
builder.orderBy([
|
||||
{ column: '_score', order: 'desc' },
|
||||
{ column: 'movies.stashed', order: 'desc' },
|
||||
{ column: 'movies.effective_date', order: 'desc' },
|
||||
]);
|
||||
} else if (filters.scope === 'stashed' && filters.stashId) {
|
||||
}
|
||||
else if (filters.scope === 'stashed' && filters.stashId) {
|
||||
builder.orderBy([
|
||||
{ column: 'stashed_at', order: 'desc' },
|
||||
{ column: 'movies.effective_date', order: 'desc' },
|
||||
]);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.orderBy('movies.effective_date', 'desc');
|
||||
}
|
||||
})
|
||||
@@ -361,27 +373,31 @@ async function queryManticoreSql(filters, options) {
|
||||
console.log(curatedSqlQuery);
|
||||
}
|
||||
|
||||
const results = await utilsApi.sql(curatedSqlQuery);
|
||||
const results = await querySql(curatedSqlQuery);
|
||||
|
||||
// console.log(results[0]);
|
||||
const years = results
|
||||
.find((result) => (result.columns[0].years || result.columns[0]['movies.years']) && result.columns[1]['count(*)'])
|
||||
?.data.map((row) => ({ key: row.years || row['movies.years'], doc_count: row['count(*)'] }))
|
||||
?.data
|
||||
.map((row) => ({ key: row.years || row['movies.years'], doc_count: row['count(*)'] }))
|
||||
|| [];
|
||||
|
||||
const actorIds = results
|
||||
.find((result) => (result.columns[0].actor_ids || result.columns[0]['movies.actor_ids']) && result.columns[1]['count(*)'])
|
||||
?.data.map((row) => ({ key: row.actor_ids || row['movies.actor_ids'], doc_count: row['count(*)'] }))
|
||||
?.data
|
||||
.map((row) => ({ key: row.actor_ids || row['movies.actor_ids'], doc_count: row['count(*)'] }))
|
||||
|| [];
|
||||
|
||||
const tagIds = results
|
||||
.find((result) => (result.columns[0].tag_ids || result.columns[0]['movies.tag_ids']) && result.columns[1]['count(*)'])
|
||||
?.data.map((row) => ({ key: row.tag_ids || row['movies.tag_ids'], doc_count: row['count(*)'] }))
|
||||
?.data
|
||||
.map((row) => ({ key: row.tag_ids || row['movies.tag_ids'], doc_count: row['count(*)'] }))
|
||||
|| [];
|
||||
|
||||
const channelIds = results
|
||||
.find((result) => (result.columns[0].channel_id || result.columns[0]['movies.channel_id']) && result.columns[1]['count(*)'])
|
||||
?.data.map((row) => ({ key: row.channel_id || row['movies.channel_id'], doc_count: row['count(*)'] }))
|
||||
?.data
|
||||
.map((row) => ({ key: row.channel_id || row['movies.channel_id'], doc_count: row['count(*)'] }))
|
||||
|| [];
|
||||
|
||||
const total = Number(results.at(-1).data.find((entry) => entry.Variable_name === 'total_found')?.Value) || 0;
|
||||
|
||||
+6
-4
@@ -16,10 +16,12 @@ export default function navigate(path, query, options = {}) {
|
||||
|
||||
if (options.redirect) {
|
||||
window.location.href = url;
|
||||
} else if (options.replace) {
|
||||
history.replaceState({}, '', url); // eslint-disable-line no-restricted-globals
|
||||
} else {
|
||||
history.pushState({}, '', url); // eslint-disable-line no-restricted-globals
|
||||
}
|
||||
else if (options.replace) {
|
||||
history.replaceState({}, '', url);
|
||||
}
|
||||
else {
|
||||
history.pushState({}, '', url);
|
||||
}
|
||||
|
||||
events.emit('route', url);
|
||||
|
||||
+8
-6
@@ -11,12 +11,14 @@ export function curateRevision(revision) {
|
||||
id: revision.user_id,
|
||||
username: revision.username,
|
||||
},
|
||||
review: typeof revision.approved === 'boolean' ? {
|
||||
isApproved: revision.approved,
|
||||
userId: revision.reviewed_by,
|
||||
username: revision.reviewer_username,
|
||||
reviewedAt: revision.reviewed_at,
|
||||
} : null,
|
||||
review: typeof revision.approved === 'boolean'
|
||||
? {
|
||||
isApproved: revision.approved,
|
||||
userId: revision.reviewed_by,
|
||||
username: revision.reviewer_username,
|
||||
reviewedAt: revision.reviewed_at,
|
||||
}
|
||||
: null,
|
||||
appliedAt: revision.applied_at,
|
||||
failed: revision.failed,
|
||||
createdAt: revision.created_at,
|
||||
|
||||
+152
-120
@@ -1,23 +1,24 @@
|
||||
import process from 'node:process';
|
||||
import config from 'config';
|
||||
import { MerkleJson } from 'merkle-json';
|
||||
|
||||
import argv from './argv.js';
|
||||
import { knexQuery as knex, knexOwner, knexManticore } from './knex.js';
|
||||
import { utilsApi } from './manticore.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { fetchActorsById, curateActor, sortActorsByGender } from './actors.js';
|
||||
import { fetchTagsById } from './tags.js';
|
||||
import { fetchMoviesById } from './movies.js';
|
||||
import { fetchEntitiesById } from './entities.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
import { curateMedia } from './media.js';
|
||||
import escape from '../utils/escape-manticore.js';
|
||||
import promiseProps from '../utils/promise-props.js';
|
||||
import initLogger from './logger.js';
|
||||
import { curateRevision } from './revisions.js';
|
||||
import { curateActor, fetchActorsById, sortActorsByGender } from './actors.js';
|
||||
import { getAffiliateSceneUrl } from './affiliates.js';
|
||||
import argv from './argv.js';
|
||||
import { censor } from './censor.js';
|
||||
import { fetchEntitiesById } from './entities.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { knexQuery as knex, knexManticore, knexOwner } from './knex.js';
|
||||
import initLogger from './logger.js';
|
||||
import { querySql } from './manticore.js';
|
||||
import { curateMedia } from './media.js';
|
||||
import { fetchMoviesById } from './movies.js';
|
||||
import { curateRevision } from './revisions.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
import { syncScenes } from './sync.js';
|
||||
import { fetchTagsById } from './tags.js';
|
||||
|
||||
const logger = initLogger();
|
||||
const mj = new MerkleJson();
|
||||
@@ -50,27 +51,33 @@ function curateScene(rawScene, assets, reqUser, context) {
|
||||
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: censor(assets.channel.network_name, context.restriction),
|
||||
url: assets.network_url,
|
||||
type: assets.channel.network_type,
|
||||
hasLogo: assets.channel.network_has_logo,
|
||||
} : null,
|
||||
studio: assets.studio ? {
|
||||
id: assets.studio.id,
|
||||
slug: assets.studio.slug,
|
||||
name: assets.studio.name,
|
||||
type: assets.studio.type,
|
||||
hasLogo: assets.studio.has_logo,
|
||||
} : null,
|
||||
affiliate: assets.channel.affiliate ? {
|
||||
id: assets.channel.affiliate.id,
|
||||
url: assets.channel.affiliate.url,
|
||||
parameters: assets.channel.affiliate.parameters || {},
|
||||
entityId: assets.channel.affiliate.entity_id,
|
||||
} : null,
|
||||
network: assets.channel.network_id
|
||||
? {
|
||||
id: assets.channel.network_id,
|
||||
slug: assets.channel.network_slug,
|
||||
name: censor(assets.channel.network_name, context.restriction),
|
||||
url: assets.network_url,
|
||||
type: assets.channel.network_type,
|
||||
hasLogo: assets.channel.network_has_logo,
|
||||
}
|
||||
: null,
|
||||
studio: assets.studio
|
||||
? {
|
||||
id: assets.studio.id,
|
||||
slug: assets.studio.slug,
|
||||
name: assets.studio.name,
|
||||
type: assets.studio.type,
|
||||
hasLogo: assets.studio.has_logo,
|
||||
}
|
||||
: null,
|
||||
affiliate: assets.channel.affiliate
|
||||
? {
|
||||
id: assets.channel.affiliate.id,
|
||||
url: assets.channel.affiliate.url,
|
||||
parameters: assets.channel.affiliate.parameters || {},
|
||||
entityId: assets.channel.affiliate.entity_id,
|
||||
}
|
||||
: null,
|
||||
actors: sortActorsByGender(assets.actors.map((actor) => curateActor(actor, {
|
||||
sceneDate: rawScene.effective_date,
|
||||
stashes: assets.actorStashes.filter((actorStash) => actorStash.actor_id === actor.id),
|
||||
@@ -246,84 +253,98 @@ export async function fetchScenesById(sceneIds, { reqUser, ...context } = {}) {
|
||||
.whereIn('chapters.release_id', sceneIds)
|
||||
.groupBy('chapters.id', 'posters.id')
|
||||
.orderBy('time', 'asc'),
|
||||
movies: context.includePartOf ? knex('movies_scenes')
|
||||
.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)
|
||||
.groupBy('movies.id', 'movies_scenes.scene_id') : [],
|
||||
series: context.includePartOf ? knex('series_scenes')
|
||||
.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)
|
||||
.groupBy('series.id', 'series_scenes.scene_id', 'media.*') : [],
|
||||
movies: context.includePartOf
|
||||
? knex('movies_scenes')
|
||||
.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)
|
||||
.groupBy('movies.id', 'movies_scenes.scene_id')
|
||||
: [],
|
||||
series: context.includePartOf
|
||||
? knex('series_scenes')
|
||||
.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)
|
||||
.groupBy('series.id', 'series_scenes.scene_id', 'media.*')
|
||||
: [],
|
||||
posters: knex('releases_posters')
|
||||
.select('media.*', 'releases_posters.release_id', knex.raw('row_to_json(sfw_media) as sfw_media'))
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('media', 'media.id', 'releases_posters.media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.groupBy('media.id', 'releases_posters.release_id', 'sfw_media.id'),
|
||||
photos: context.includeAssets && !context.restriction ? knex.transaction(async (trx) => {
|
||||
if (reqUser) {
|
||||
await trx.select(knex.raw('set_config(\'user.id\', :userId, true)', { userId: reqUser.id }));
|
||||
}
|
||||
photos: context.includeAssets && !context.restriction
|
||||
? knex.transaction(async (trx) => {
|
||||
if (reqUser) {
|
||||
await trx.select(knex.raw('set_config(\'user.id\', :userId, true)', { userId: reqUser.id }));
|
||||
}
|
||||
|
||||
return trx('releases_photos')
|
||||
.select('media.*', 'releases_photos.release_id', knex.raw('row_to_json(sfw_media) as sfw_media'))
|
||||
.leftJoin('media', 'media.id', 'releases_photos.media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.orderBy('index')
|
||||
.groupBy('media.id', 'releases_photos.release_id', 'sfw_media.id');
|
||||
}) : [],
|
||||
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_photos')
|
||||
.select('media.*', 'releases_photos.release_id', knex.raw('row_to_json(sfw_media) as sfw_media'))
|
||||
.leftJoin('media', 'media.id', 'releases_photos.media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.orderBy('index')
|
||||
.groupBy('media.id', 'releases_photos.release_id', 'sfw_media.id');
|
||||
})
|
||||
: [],
|
||||
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')
|
||||
.select('media.*', 'releases_caps.release_id', knex.raw('row_to_json(sfw_media) as sfw_media'))
|
||||
.leftJoin('media', 'media.id', 'releases_caps.media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.orderBy('index')
|
||||
.groupBy('media.id', 'releases_caps.release_id', 'sfw_media.id');
|
||||
}) : [],
|
||||
trailers: 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')
|
||||
.select('media.*', 'releases_caps.release_id', knex.raw('row_to_json(sfw_media) as sfw_media'))
|
||||
.leftJoin('media', 'media.id', 'releases_caps.media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'media.sfw_media_id')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.orderBy('index')
|
||||
.groupBy('media.id', 'releases_caps.release_id', 'sfw_media.id');
|
||||
})
|
||||
: [],
|
||||
trailers: 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_trailers')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('media', 'media.id', 'releases_trailers.media_id');
|
||||
}) : [],
|
||||
teasers: 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_trailers')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('media', 'media.id', 'releases_trailers.media_id');
|
||||
})
|
||||
: [],
|
||||
teasers: 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_teasers')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('media', 'media.id', 'releases_teasers.media_id');
|
||||
}) : [],
|
||||
fingerprints: 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_teasers')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('media', 'media.id', 'releases_teasers.media_id');
|
||||
})
|
||||
: [],
|
||||
fingerprints: 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_fingerprints')
|
||||
.select('scene_id', 'hash', 'type', 'duration', 'source', 'source_submissions', knex.raw('min(coalesce(source_created_at, created_at)) as created_at'))
|
||||
.whereIn('scene_id', sceneIds)
|
||||
.orderBy([
|
||||
{ column: 'source_submissions', order: 'desc' },
|
||||
{ column: knex.raw('min(coalesce(source_created_at, created_at))'), order: 'desc' },
|
||||
])
|
||||
.groupBy(['scene_id', 'hash', 'type', 'duration', 'source', 'source_submissions']);
|
||||
}) : [],
|
||||
return trx('releases_fingerprints')
|
||||
.select('scene_id', 'hash', 'type', 'duration', 'source', 'source_submissions', knex.raw('min(coalesce(source_created_at, created_at)) as created_at'))
|
||||
.whereIn('scene_id', sceneIds)
|
||||
.orderBy([
|
||||
{ column: 'source_submissions', order: 'desc' },
|
||||
{ column: knex.raw('min(coalesce(source_created_at, created_at))'), order: 'desc' },
|
||||
])
|
||||
.groupBy(['scene_id', 'hash', 'type', 'duration', 'source', 'source_submissions']);
|
||||
})
|
||||
: [],
|
||||
lastBatch: knex('batches')
|
||||
.select('id')
|
||||
.where('showcased', true)
|
||||
@@ -331,17 +352,17 @@ export async function fetchScenesById(sceneIds, { reqUser, ...context } = {}) {
|
||||
.first(),
|
||||
stashes: reqUser
|
||||
? knexOwner('stashes_scenes')
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_scenes.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_scenes.scene_id', sceneIds)
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_scenes.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_scenes.scene_id', sceneIds)
|
||||
: [],
|
||||
});
|
||||
|
||||
const actorStashes = reqUser && context.actorStashes
|
||||
? await knexOwner('stashes_actors')
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_actors.actor_id', actors.map((actor) => actor.id))
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_actors.actor_id', actors.map((actor) => actor.id))
|
||||
: [];
|
||||
|
||||
return sceneIds.map((sceneId) => {
|
||||
@@ -415,7 +436,8 @@ function curateOptions(options) {
|
||||
function curateFacet(results, field) {
|
||||
return results
|
||||
.find((result) => result.columns[0][field] && (result.columns[1]['count(distinct id)'] || result.columns[1]['count(*)']))
|
||||
?.data.map((row) => ({ key: row[field], doc_count: row['count(distinct id)'] || row['count(*)'] }))
|
||||
?.data
|
||||
.map((row) => ({ key: row[field], doc_count: row['count(distinct id)'] || row['count(*)'] }))
|
||||
.filter((row) => !!row.key)
|
||||
|| [];
|
||||
}
|
||||
@@ -482,7 +504,8 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
builder
|
||||
.innerJoin('scenes', 'scenes.id', 'scenes_stashed.scene_id')
|
||||
.where('stash_id', filters.stashId);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.select(knex.raw(`
|
||||
*,
|
||||
year(scenes.effective_date) as effective_year,
|
||||
@@ -508,7 +531,8 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
whereBuilder.orWhere('any(assigned_tag_ids)', actorId * 1_000_00 + tagId);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.where('any(tag_ids)', tagId);
|
||||
}
|
||||
});
|
||||
@@ -561,34 +585,41 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
builder
|
||||
.where('effective_date', '<=', Math.round(Date.now() / 1000))
|
||||
.orderBy('scenes.effective_date', 'desc'); // can't seem to use alias if it matches column-name? behavior not fully understand, but this works
|
||||
} else if (filters.scope === 'upcoming') {
|
||||
}
|
||||
else if (filters.scope === 'upcoming') {
|
||||
builder
|
||||
.where('effective_date', '>', Math.round(Date.now() / 1000))
|
||||
.orderBy('scenes.effective_date', 'asc');
|
||||
} else if (filters.scope === 'new') {
|
||||
}
|
||||
else if (filters.scope === 'new') {
|
||||
builder.orderBy([
|
||||
{ column: 'scenes.created_at', order: 'desc' },
|
||||
{ column: 'scenes.effective_date', order: 'asc' },
|
||||
]);
|
||||
} else if (filters.scope === 'likes') {
|
||||
}
|
||||
else if (filters.scope === 'likes') {
|
||||
builder.orderBy([
|
||||
{ column: 'scenes.stashed', order: 'desc' },
|
||||
{ column: 'scenes.effective_date', order: 'desc' },
|
||||
]);
|
||||
} else if (filters.scope === 'results') {
|
||||
}
|
||||
else if (filters.scope === 'results') {
|
||||
builder.orderBy([
|
||||
{ column: '_score', order: 'desc' },
|
||||
{ column: 'scenes.stashed', order: 'desc' },
|
||||
{ column: 'scenes.effective_date', order: 'desc' },
|
||||
]);
|
||||
} else if (filters.scope === 'stashed' && filters.stashId) {
|
||||
}
|
||||
else if (filters.scope === 'stashed' && filters.stashId) {
|
||||
builder.orderBy([
|
||||
{ column: 'stashed_at', order: 'desc' },
|
||||
{ column: 'scenes.effective_date', order: 'desc' },
|
||||
]);
|
||||
} else if (filters.scope === 'oldest') {
|
||||
}
|
||||
else if (filters.scope === 'oldest') {
|
||||
builder.orderBy('scenes.effective_date', 'asc');
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.orderBy('scenes.effective_date', 'desc');
|
||||
}
|
||||
})
|
||||
@@ -608,14 +639,14 @@ async function queryManticoreSql(filters, options, _reqUser) {
|
||||
const curatedSqlQuery = filters.stashId
|
||||
? sqlQuery
|
||||
: sqlQuery
|
||||
.replace(/scenes\./g, '')
|
||||
.replace(/scenes_\./g, 'scenes.');
|
||||
.replace(/scenes\./g, '')
|
||||
.replace(/scenes_\./g, 'scenes.');
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && argv.debug) {
|
||||
console.log(curatedSqlQuery);
|
||||
}
|
||||
|
||||
const results = await utilsApi.sql(curatedSqlQuery);
|
||||
const results = await querySql(curatedSqlQuery);
|
||||
|
||||
const years = curateFacet(results, 'years_facet');
|
||||
const actorIds = curateFacet(results, 'actors_facet');
|
||||
@@ -952,7 +983,8 @@ export async function reviewSceneRevision(revisionId, isApproved, { feedback },
|
||||
if (isApproved) {
|
||||
try {
|
||||
await applySceneRevision([revisionId], reqUser);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
await knexOwner('scenes_revisions')
|
||||
.where('id', revisionId)
|
||||
.update({
|
||||
|
||||
+14
-12
@@ -1,8 +1,8 @@
|
||||
import { knexQuery as knex, knexOwner } from './knex.js';
|
||||
import promiseProps from '../utils/promise-props.js';
|
||||
import { curateActor, sortActorsByGender } from './actors.js';
|
||||
import { knexQuery as knex, knexOwner } from './knex.js';
|
||||
import { curateMedia } from './media.js';
|
||||
import { curateStash } from './stashes.js';
|
||||
import promiseProps from '../utils/promise-props.js';
|
||||
|
||||
function curateSerie(rawSerie, assets) {
|
||||
if (!rawSerie) {
|
||||
@@ -27,13 +27,15 @@ function curateSerie(rawSerie, assets) {
|
||||
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,
|
||||
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,
|
||||
actors: sortActorsByGender(assets.actors.map((actor) => curateActor(actor, { sceneDate: rawSerie.effective_date }))),
|
||||
directors: assets.directors.map((director) => ({
|
||||
id: director.id,
|
||||
@@ -116,9 +118,9 @@ export async function fetchSeriesById(serieIds, reqUser) {
|
||||
.leftJoin('media', 'media.id', 'releases_photos.media_id'),
|
||||
stashes: reqUser
|
||||
? knexOwner('stashes_series')
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_series.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_series.serie_id', serieIds)
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_series.stash_id')
|
||||
.where('stashes.user_id', reqUser.id)
|
||||
.whereIn('stashes_series.serie_id', serieIds)
|
||||
: [],
|
||||
});
|
||||
|
||||
|
||||
+38
-27
@@ -1,11 +1,11 @@
|
||||
import config from 'config';
|
||||
import { CronJob } from 'cron';
|
||||
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import { indexApi } from './manticore.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import slugify from './utils/slugify.js';
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import initLogger from './logger.js';
|
||||
import { indexApi } from './manticore.js';
|
||||
import slugify from './utils/slugify.js';
|
||||
|
||||
const logger = initLogger();
|
||||
|
||||
@@ -29,12 +29,14 @@ export function curateStash(stash, assets = {}) {
|
||||
stashedScenes: stash.stashed_scenes ?? null,
|
||||
stashedMovies: stash.stashed_movies ?? null,
|
||||
stashedActors: stash.stashed_actors ?? null,
|
||||
user: assets.user ? {
|
||||
id: assets.user.id,
|
||||
username: assets.user.username,
|
||||
avatar: `/media/avatars/${assets.user.id}_${assets.user.username}.png`,
|
||||
createdAt: assets.user.created_at,
|
||||
} : null,
|
||||
user: assets.user
|
||||
? {
|
||||
id: assets.user.id,
|
||||
username: assets.user.username,
|
||||
avatar: `/media/avatars/${assets.user.id}_${assets.user.username}.png`,
|
||||
createdAt: assets.user.created_at,
|
||||
}
|
||||
: null,
|
||||
comment: stash.comment,
|
||||
meta: stash.meta,
|
||||
};
|
||||
@@ -81,7 +83,8 @@ export async function fetchStashById(stashIdOrSlug, sessionUser) {
|
||||
.where((builder) => {
|
||||
if (typeof stashIdOrSlug === 'number') {
|
||||
builder.where('id', stashIdOrSlug);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder
|
||||
.where('slug', stashIdOrSlug)
|
||||
.where('user_id', sessionUser.id);
|
||||
@@ -99,7 +102,8 @@ export async function fetchStashByUsernameAndSlug(usernameOrId, stashSlug, sessi
|
||||
.where((builder) => {
|
||||
if (typeof usernameOrId === 'number') {
|
||||
builder.where('id', usernameOrId);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.where('username', usernameOrId);
|
||||
}
|
||||
})
|
||||
@@ -125,9 +129,9 @@ export async function fetchUserStashes(usernameOrId, reqUser) {
|
||||
const userId = typeof usernameOrId === 'number'
|
||||
? usernameOrId
|
||||
: await knex('users')
|
||||
.where('username', usernameOrId)
|
||||
.first()
|
||||
.then((user) => user?.id);
|
||||
.where('username', usernameOrId)
|
||||
.first()
|
||||
.then((user) => user?.id);
|
||||
|
||||
if (!userId) {
|
||||
throw new HttpError(`Could not find user '${usernameOrId}'`);
|
||||
@@ -214,7 +218,8 @@ export async function createStash(newStash, sessionUser) {
|
||||
const curatedStash = curateStash(stash, { user: sessionUser });
|
||||
|
||||
return curatedStash;
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
if (error.routine === '_bt_check_unique') {
|
||||
throw new HttpError('Stash name should be unique', 409);
|
||||
}
|
||||
@@ -245,7 +250,8 @@ export async function updateStash(stashIdOrSlug, updatedStash, sessionUser) {
|
||||
.where((builder) => {
|
||||
if (typeof stashIdOrSlug === 'number') {
|
||||
builder.where('id', stashIdOrSlug);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
builder.where('slug', stashIdOrSlug);
|
||||
}
|
||||
})
|
||||
@@ -258,7 +264,8 @@ export async function updateStash(stashIdOrSlug, updatedStash, sessionUser) {
|
||||
}
|
||||
|
||||
return curateStash(stash);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
if (error.routine === '_bt_check_unique') {
|
||||
throw new HttpError('Stash name should be unique', 409);
|
||||
}
|
||||
@@ -322,7 +329,7 @@ export async function stashActor(actorId, stashId, sessionUser) {
|
||||
.returning('*');
|
||||
|
||||
await indexApi.replace({
|
||||
index: 'actors_stashed',
|
||||
table: 'actors_stashed',
|
||||
id: stashed.id,
|
||||
doc: {
|
||||
actor_id: actorId,
|
||||
@@ -338,7 +345,8 @@ export async function stashActor(actorId, stashId, sessionUser) {
|
||||
|
||||
// return fetchDomainStashes('actor', actorId, sessionUser);
|
||||
return curateStashed(stashed);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
if (error.routine === '_bt_check_unique') {
|
||||
throw new HttpError(`Actor ${actorId} is already stashed in '${stash.name}'`, 409);
|
||||
}
|
||||
@@ -375,7 +383,7 @@ export async function unstashActor(actorId, stashId, sessionUser) {
|
||||
|
||||
try {
|
||||
await indexApi.callDelete({
|
||||
index: 'actors_stashed',
|
||||
table: 'actors_stashed',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
@@ -386,7 +394,8 @@ export async function unstashActor(actorId, stashId, sessionUser) {
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
@@ -422,7 +431,7 @@ export async function stashScene(sceneId, stashId, sessionUser) {
|
||||
.returning('*');
|
||||
|
||||
await indexApi.replace({
|
||||
index: 'scenes_stashed',
|
||||
table: 'scenes_stashed',
|
||||
id: stashed.id,
|
||||
doc: {
|
||||
// ...doc.replace.doc,
|
||||
@@ -439,7 +448,8 @@ export async function stashScene(sceneId, stashId, sessionUser) {
|
||||
|
||||
// return fetchDomainStashes('scene', sceneId, sessionUser);
|
||||
return curateStashed(stashed);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
if (error.routine === '_bt_check_unique') {
|
||||
throw new HttpError(`Scene ${sceneId} is already stashed in '${stash.name}'`, 409);
|
||||
}
|
||||
@@ -475,7 +485,7 @@ export async function unstashScene(sceneId, stashId, sessionUser) {
|
||||
.returning('*');
|
||||
|
||||
await indexApi.callDelete({
|
||||
index: 'scenes_stashed',
|
||||
table: 'scenes_stashed',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
@@ -519,7 +529,7 @@ export async function stashMovie(movieId, stashId, sessionUser) {
|
||||
.returning('*');
|
||||
|
||||
await indexApi.replace({
|
||||
index: 'movies_stashed',
|
||||
table: 'movies_stashed',
|
||||
id: stashed.id,
|
||||
doc: {
|
||||
movie_id: movieId,
|
||||
@@ -535,7 +545,8 @@ export async function stashMovie(movieId, stashId, sessionUser) {
|
||||
|
||||
// return fetchDomainStashes('movie', movieId, sessionUser);
|
||||
return curateStashed(stashed);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
if (error.routine === '_bt_check_unique') {
|
||||
throw new HttpError(`Movie ${movieId} is already stashed in '${stash.name}'`, 409);
|
||||
}
|
||||
@@ -571,7 +582,7 @@ export async function unstashMovie(movieId, stashId, sessionUser) {
|
||||
.delete();
|
||||
|
||||
await indexApi.callDelete({
|
||||
index: 'movies_stashed',
|
||||
table: 'movies_stashed',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
|
||||
+18
-17
@@ -1,12 +1,13 @@
|
||||
import process from 'node:process';
|
||||
import config from 'config';
|
||||
import { format } from 'date-fns';
|
||||
import { CronJob } from 'cron';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import initLogger from './logger.js';
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import { searchApi, indexApi } from './manticore.js';
|
||||
import chunk from '../utils/chunk.js';
|
||||
import filterTitle from '../utils/filter-title.js';
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
import initLogger from './logger.js';
|
||||
import { indexApi, searchApi } from './manticore.js';
|
||||
|
||||
const logger = initLogger();
|
||||
|
||||
@@ -31,7 +32,7 @@ export async function syncStashes(domain = 'scene', ids) {
|
||||
|
||||
const stashDocs = stashChunk.map((stash) => ({
|
||||
replace: {
|
||||
index: `${domain}s_stashed`,
|
||||
table: `${domain}s_stashed`,
|
||||
id: stash.stashed_id,
|
||||
doc: {
|
||||
[`${domain}_id`]: stash[`${domain}_id`],
|
||||
@@ -60,7 +61,7 @@ export async function syncStashes(domain = 'scene', ids) {
|
||||
await chain;
|
||||
|
||||
const searchResponse = await searchApi.search({
|
||||
index: `${domain}s_stashed`,
|
||||
table: `${domain}s_stashed`,
|
||||
query: {
|
||||
in: {
|
||||
[`${domain}_id`]: itemIdChunk,
|
||||
@@ -72,7 +73,7 @@ export async function syncStashes(domain = 'scene', ids) {
|
||||
const docs = searchResponse?.hits?.hits ?? [];
|
||||
|
||||
const orphanedIds = docs
|
||||
.map((hit) => hit._id)
|
||||
.map((hit) => hit.id)
|
||||
.filter((manticoreId) => !validStashedIds.has(manticoreId));
|
||||
|
||||
if (orphanedIds.length === 0) {
|
||||
@@ -81,7 +82,7 @@ export async function syncStashes(domain = 'scene', ids) {
|
||||
|
||||
const deleteDocs = orphanedIds.map((orphanId) => ({
|
||||
delete: {
|
||||
index: `${domain}s_stashed`,
|
||||
table: `${domain}s_stashed`,
|
||||
id: orphanId,
|
||||
},
|
||||
}));
|
||||
@@ -93,7 +94,7 @@ export async function syncStashes(domain = 'scene', ids) {
|
||||
}
|
||||
|
||||
export async function syncManticoreScenes(sceneIds) {
|
||||
logger.info(`Updating Manticore search documents for ${sceneIds ? sceneIds.length : 'all' } scenes`);
|
||||
logger.info(`Updating Manticore search documents for ${sceneIds ? sceneIds.length : 'all'} scenes`);
|
||||
|
||||
const scenes = await knex.raw(`
|
||||
SELECT
|
||||
@@ -177,7 +178,7 @@ export async function syncManticoreScenes(sceneIds) {
|
||||
if (!scene) {
|
||||
return {
|
||||
delete: {
|
||||
index: 'scenes',
|
||||
table: 'scenes',
|
||||
id: sceneId,
|
||||
},
|
||||
};
|
||||
@@ -216,7 +217,7 @@ export async function syncManticoreScenes(sceneIds) {
|
||||
|
||||
return {
|
||||
replace: {
|
||||
index: 'scenes',
|
||||
table: 'scenes',
|
||||
id: scene.id,
|
||||
doc: {
|
||||
title: scene.title || undefined,
|
||||
@@ -279,7 +280,7 @@ export async function syncScenes(releaseIds) {
|
||||
}
|
||||
|
||||
export async function syncManticoreMovies(movieIds) {
|
||||
logger.info(`Updating Manticore search documents for ${movieIds ? movieIds.length : 'all' } movies`);
|
||||
logger.info(`Updating Manticore search documents for ${movieIds ? movieIds.length : 'all'} movies`);
|
||||
|
||||
const movies = await knex.raw(`
|
||||
SELECT
|
||||
@@ -343,7 +344,7 @@ export async function syncManticoreMovies(movieIds) {
|
||||
if (!movie) {
|
||||
return {
|
||||
delete: {
|
||||
index: 'movies',
|
||||
table: 'movies',
|
||||
id: movieId,
|
||||
},
|
||||
};
|
||||
@@ -362,7 +363,7 @@ export async function syncManticoreMovies(movieIds) {
|
||||
|
||||
return {
|
||||
replace: {
|
||||
index: 'movies',
|
||||
table: 'movies',
|
||||
id: movie.id,
|
||||
doc: {
|
||||
title: movie.title || undefined,
|
||||
@@ -406,7 +407,7 @@ export async function syncMovies(releaseIds) {
|
||||
}
|
||||
|
||||
export async function syncManticoreActors(actorIds) {
|
||||
logger.info(`Updating Manticore search documents for ${actorIds ? actorIds.length : 'all' } actors`);
|
||||
logger.info(`Updating Manticore search documents for ${actorIds ? actorIds.length : 'all'} actors`);
|
||||
|
||||
// manually select date of birth, otherwise it is retrieved in local timezone but interpreted as UTC...
|
||||
const actors = await knex.raw(`
|
||||
@@ -430,7 +431,7 @@ export async function syncManticoreActors(actorIds) {
|
||||
if (!actor) {
|
||||
return {
|
||||
delete: {
|
||||
index: 'actors',
|
||||
table: 'actors',
|
||||
id: actorId,
|
||||
},
|
||||
};
|
||||
@@ -438,7 +439,7 @@ export async function syncManticoreActors(actorIds) {
|
||||
|
||||
return {
|
||||
replace: {
|
||||
index: 'actors',
|
||||
table: 'actors',
|
||||
id: actor.id,
|
||||
doc: {
|
||||
entity_id: actor.entity_id || undefined,
|
||||
|
||||
+24
-21
@@ -1,10 +1,10 @@
|
||||
import knex from './knex.js';
|
||||
import redis from './redis.js';
|
||||
import initLogger from './logger.js';
|
||||
import { censor } from './censor.js';
|
||||
|
||||
import knex from './knex.js';
|
||||
import initLogger from './logger.js';
|
||||
import { curateMedia } from './media.js';
|
||||
|
||||
import redis from './redis.js';
|
||||
|
||||
const logger = initLogger();
|
||||
|
||||
function curateTag(tag, context = {}) {
|
||||
@@ -52,7 +52,8 @@ export async function fetchTags(options = {}, context = {}) {
|
||||
order: 'asc',
|
||||
},
|
||||
]);
|
||||
} else if (!options.includeAliases) {
|
||||
}
|
||||
else if (!options.includeAliases) {
|
||||
builder.whereNull('tags.alias_for');
|
||||
}
|
||||
}),
|
||||
@@ -97,24 +98,26 @@ export async function fetchTagsById(tagIds, options = {}, reqUser, context = {})
|
||||
.whereIn('tags.id', tagIds.filter((tagId) => typeof tagId === 'number'))
|
||||
.orWhereIn('tags.slug', tagIds.filter((tagId) => typeof tagId === 'string'))
|
||||
.groupBy('media.id', 'tags_posters.tag_id', 'sfw_media.id', 'entities.id', 'parents.id'),
|
||||
context.restriction ? [] : knex('tags_photos')
|
||||
.select('tags_photos.tag_id', 'media.*', knex.raw('row_to_json(entities) as entity'), knex.raw('row_to_json(parents) as entity_parent'))
|
||||
.leftJoin('tags', 'tags.id', 'tags_photos.tag_id')
|
||||
.leftJoin('media', 'media.id', 'tags_photos.media_id')
|
||||
.leftJoin('entities', 'entities.id', 'media.entity_id')
|
||||
.leftJoin('entities as parents', 'parents.id', 'entities.parent_id')
|
||||
.whereIn('tags.id', tagIds.filter((tagId) => typeof tagId === 'number'))
|
||||
.orWhereIn('tags.slug', tagIds.filter((tagId) => typeof tagId === 'string')),
|
||||
context.restriction
|
||||
? []
|
||||
: knex('tags_photos')
|
||||
.select('tags_photos.tag_id', 'media.*', knex.raw('row_to_json(entities) as entity'), knex.raw('row_to_json(parents) as entity_parent'))
|
||||
.leftJoin('tags', 'tags.id', 'tags_photos.tag_id')
|
||||
.leftJoin('media', 'media.id', 'tags_photos.media_id')
|
||||
.leftJoin('entities', 'entities.id', 'media.entity_id')
|
||||
.leftJoin('entities as parents', 'parents.id', 'entities.parent_id')
|
||||
.whereIn('tags.id', tagIds.filter((tagId) => typeof tagId === 'number'))
|
||||
.orWhereIn('tags.slug', tagIds.filter((tagId) => typeof tagId === 'string')),
|
||||
reqUser
|
||||
? knex('alerts_users_tags')
|
||||
.select('alerts_users_tags.*')
|
||||
.leftJoin('tags', 'tags.id', 'alerts_users_tags.tag_id')
|
||||
.where('user_id', reqUser.id)
|
||||
.where((whereBuilder) => {
|
||||
whereBuilder
|
||||
.whereIn('tags.id', tagIds.filter((tagId) => typeof tagId === 'number'))
|
||||
.orWhereIn('tags.slug', tagIds.filter((tagId) => typeof tagId === 'string'));
|
||||
})
|
||||
.select('alerts_users_tags.*')
|
||||
.leftJoin('tags', 'tags.id', 'alerts_users_tags.tag_id')
|
||||
.where('user_id', reqUser.id)
|
||||
.where((whereBuilder) => {
|
||||
whereBuilder
|
||||
.whereIn('tags.id', tagIds.filter((tagId) => typeof tagId === 'number'))
|
||||
.orWhereIn('tags.slug', tagIds.filter((tagId) => typeof tagId === 'string'));
|
||||
})
|
||||
: [],
|
||||
]);
|
||||
|
||||
|
||||
+3
-2
@@ -1,9 +1,9 @@
|
||||
import config from 'config';
|
||||
import { parse } from 'yaml';
|
||||
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
// import { curateStash } from './stashes.js';
|
||||
import { HttpError } from './errors.js';
|
||||
import { knexOwner as knex } from './knex.js';
|
||||
|
||||
function curateTemplate(template) {
|
||||
return {
|
||||
@@ -90,7 +90,8 @@ export async function createTemplate(template, reqUser) {
|
||||
|
||||
try {
|
||||
parse(template.template);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
throw new HttpError(`Invalid YAML: ${error.message}`, 400);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
function parseBoolFromString(string) {
|
||||
if (string === 'true') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (string === 'false') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
function parseValue(value) {
|
||||
if (typeof value === 'string') {
|
||||
return parseBoolFromString(value);
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(parseValue);
|
||||
}
|
||||
|
||||
if (value && typeof value === 'object') {
|
||||
return parseObject(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseObject(obj) {
|
||||
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, parseValue(value)]));
|
||||
}
|
||||
|
||||
// Express 5's req.query is a getter that re-parses the URL on every access, so it can no longer
|
||||
// be reassigned like `req.query = ...` (that's a silent no-op); it must be shadowed with its own
|
||||
// property on the request instance instead. See https://github.com/expressjs/express/issues/6633
|
||||
export default function queryBoolean() {
|
||||
return (req, _res, next) => {
|
||||
Object.defineProperty(req, 'query', {
|
||||
value: parseObject(req.query),
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
}
|
||||
@@ -39,7 +39,7 @@ const accentMap = {
|
||||
ỹ: 'y',
|
||||
};
|
||||
|
||||
const plainCharRegex = /[a-zA-Z0-9]/;
|
||||
const plainCharRegex = /[a-z0-9]/i;
|
||||
const defaultPunctuationRegex = /[.,?!:;&'‘’"“”…()[\]{}<>/*—]/;
|
||||
const defaultSymbolRegex = /[@$€£#%^+=\\~]/;
|
||||
|
||||
@@ -111,7 +111,8 @@ export default function slugify(strings, delimiter = '-', {
|
||||
}
|
||||
|
||||
return '';
|
||||
}).join('');
|
||||
})
|
||||
.join('');
|
||||
|
||||
const components = normalized.trim().split(/\s+/).filter(Boolean);
|
||||
|
||||
|
||||
+4
-4
@@ -1,13 +1,13 @@
|
||||
import Router from 'express-promise-router';
|
||||
import { Router } from 'express';
|
||||
import omit from 'object.omit';
|
||||
|
||||
import {
|
||||
createActor,
|
||||
createActorRevision,
|
||||
fetchActorRevisions,
|
||||
fetchActors,
|
||||
fetchActorsById,
|
||||
createActor,
|
||||
mergeActors,
|
||||
fetchActorRevisions,
|
||||
createActorRevision,
|
||||
reviewActorRevision,
|
||||
} from '../actors.js';
|
||||
|
||||
|
||||
+4
-4
@@ -1,12 +1,12 @@
|
||||
import Router from 'express-promise-router';
|
||||
import { Router } from 'express';
|
||||
|
||||
import {
|
||||
fetchAlerts,
|
||||
createAlert,
|
||||
removeAlert,
|
||||
fetchAlerts,
|
||||
fetchNotifications,
|
||||
updateNotifications,
|
||||
removeAlert,
|
||||
updateNotification,
|
||||
updateNotifications,
|
||||
} from '../alerts.js';
|
||||
|
||||
// actors and actorIds, stashes and stashIds are aliases for consistency
|
||||
|
||||
+5
-7
@@ -1,15 +1,14 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
|
||||
import { stringify } from '@brillout/json-serializer/stringify';
|
||||
import IPCIDR from 'ip-cidr';
|
||||
import argv from '../argv.js';
|
||||
|
||||
import {
|
||||
login,
|
||||
signup,
|
||||
fetchUserKeys,
|
||||
createKey,
|
||||
removeUserKey,
|
||||
fetchUserKeys,
|
||||
flushUserKeys,
|
||||
login,
|
||||
removeUserKey,
|
||||
signup,
|
||||
} from '../auth.js';
|
||||
|
||||
import { fetchUser } from '../users.js';
|
||||
@@ -111,4 +110,3 @@ export async function flushUserKeysApi(req, res) {
|
||||
|
||||
res.status(204).send();
|
||||
}
|
||||
/* eslint-enable no-param-reassign */
|
||||
|
||||
+4
-4
@@ -4,26 +4,26 @@ export default function consentHandler(req, res, next) {
|
||||
if (Object.hasOwn(req.query, 'lgbt')) {
|
||||
const lgbtFilters = Array.from(new Set([...(req.tagFilter || []).filter((tag) => !['gay', 'bisexual', 'transsexual'].includes(tag)), 'extreme-insertion']));
|
||||
|
||||
req.tagFilter = lgbtFilters; // eslint-disable-line no-param-reassign
|
||||
req.tagFilter = lgbtFilters;
|
||||
res.cookie('tags', JSON.stringify(lgbtFilters));
|
||||
}
|
||||
|
||||
if (Object.hasOwn(req.query, 'straight')) {
|
||||
const straightFilters = Array.from(new Set([...(req.tagFilter || []), 'gay', 'bisexual', 'transsexual', 'extreme-insertion']));
|
||||
|
||||
req.tagFilter = straightFilters; // eslint-disable-line no-param-reassign
|
||||
req.tagFilter = straightFilters;
|
||||
res.cookie('tags', JSON.stringify(straightFilters));
|
||||
}
|
||||
|
||||
if (Object.hasOwn(req.query, 'consent')) {
|
||||
req.session.hasConsent = true; // eslint-disable-line no-param-reassign
|
||||
req.session.hasConsent = true;
|
||||
res.redirect(redirect || req.path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!req.path.includes('/consent') && !req.session?.hasConsent) {
|
||||
res.redirect(`/consent?redirect=${req.originalUrl === '/' ? '' : encodeURIComponent(req.originalUrl) }`);
|
||||
res.redirect(`/consent?redirect=${req.originalUrl === '/' ? '' : encodeURIComponent(req.originalUrl)}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,12 +1,12 @@
|
||||
import { parseResolveInfo } from 'graphql-parse-resolve-info';
|
||||
|
||||
import { getIdsBySlug } from '../cache.js';
|
||||
|
||||
import {
|
||||
fetchEntities,
|
||||
fetchEntitiesById,
|
||||
} from '../entities.js';
|
||||
|
||||
import { getIdsBySlug } from '../cache.js';
|
||||
|
||||
export async function fetchEntitiesApi(req, res) {
|
||||
const entities = await fetchEntities(req.query);
|
||||
|
||||
|
||||
+38
-38
@@ -2,8 +2,8 @@ import config from 'config';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
import {
|
||||
graphql,
|
||||
buildSchema,
|
||||
graphql,
|
||||
GraphQLScalarType,
|
||||
} from 'graphql';
|
||||
|
||||
@@ -12,56 +12,56 @@ import {
|
||||
JSONResolver,
|
||||
} from 'graphql-scalars';
|
||||
|
||||
import {
|
||||
scenesSchema,
|
||||
fetchScenesGraphql,
|
||||
fetchScenesByIdGraphql,
|
||||
} from './scenes.js';
|
||||
|
||||
import {
|
||||
moviesSchema,
|
||||
fetchMoviesGraphql,
|
||||
fetchMoviesByIdGraphql,
|
||||
} from './movies.js';
|
||||
|
||||
import {
|
||||
entitiesSchema,
|
||||
fetchEntitiesGraphql,
|
||||
fetchEntitiesByIdGraphql,
|
||||
} from './entities.js';
|
||||
import { verifyKey } from '../auth.js';
|
||||
|
||||
import {
|
||||
actorsSchema,
|
||||
fetchActorsGraphql,
|
||||
fetchActorsByIdGraphql,
|
||||
fetchActorsGraphql,
|
||||
} from './actors.js';
|
||||
|
||||
import {
|
||||
stashesSchema,
|
||||
fetchUserStashesGraphql,
|
||||
fetchStashGraphql,
|
||||
createStashGraphql,
|
||||
updateStashGraphql,
|
||||
removeStashGraphql,
|
||||
stashSceneGraphql,
|
||||
unstashSceneGraphql,
|
||||
stashActorGraphql,
|
||||
unstashActorGraphql,
|
||||
stashMovieGraphql,
|
||||
unstashMovieGraphql,
|
||||
} from './stashes.js';
|
||||
|
||||
import {
|
||||
alertsSchema,
|
||||
fetchAlertsGraphql,
|
||||
createAlertGraphql,
|
||||
removeAlertGraphql,
|
||||
fetchAlertsGraphql,
|
||||
fetchNotificationsGraphql,
|
||||
removeAlertGraphql,
|
||||
updateNotificationGraphql,
|
||||
updateNotificationsGraphql,
|
||||
} from './alerts.js';
|
||||
|
||||
import { verifyKey } from '../auth.js';
|
||||
import {
|
||||
entitiesSchema,
|
||||
fetchEntitiesByIdGraphql,
|
||||
fetchEntitiesGraphql,
|
||||
} from './entities.js';
|
||||
|
||||
import {
|
||||
fetchMoviesByIdGraphql,
|
||||
fetchMoviesGraphql,
|
||||
moviesSchema,
|
||||
} from './movies.js';
|
||||
|
||||
import {
|
||||
fetchScenesByIdGraphql,
|
||||
fetchScenesGraphql,
|
||||
scenesSchema,
|
||||
} from './scenes.js';
|
||||
|
||||
import {
|
||||
createStashGraphql,
|
||||
fetchStashGraphql,
|
||||
fetchUserStashesGraphql,
|
||||
removeStashGraphql,
|
||||
stashActorGraphql,
|
||||
stashesSchema,
|
||||
stashMovieGraphql,
|
||||
stashSceneGraphql,
|
||||
unstashActorGraphql,
|
||||
unstashMovieGraphql,
|
||||
unstashSceneGraphql,
|
||||
updateStashGraphql,
|
||||
} from './stashes.js';
|
||||
|
||||
const schema = buildSchema(`
|
||||
type Query {
|
||||
@@ -114,7 +114,7 @@ export async function graphqlApi(req, res) {
|
||||
|
||||
await verifyKey(req.headers['api-user'], req.headers['api-key'], req);
|
||||
|
||||
req.user = { // eslint-disable-line no-param-reassign
|
||||
req.user = {
|
||||
id: Number(req.headers['api-user']),
|
||||
};
|
||||
|
||||
|
||||
+18
-14
@@ -1,17 +1,19 @@
|
||||
import config from 'config';
|
||||
import { renderPage } from 'vike/server'; // eslint-disable-line import/extensions
|
||||
import { renderPage } from 'vike/server';
|
||||
|
||||
import { socials } from '../../common/actors.mjs';
|
||||
import { fetchUnseenNotificationsCount } from '../alerts.js';
|
||||
import { fetchUserStashes } from '../stashes.js';
|
||||
import { fetchUserTemplates } from '../users.js';
|
||||
import { fetchUnseenNotificationsCount } from '../alerts.js';
|
||||
import { socials } from '../../common/actors.mjs'; // eslint-disable-line import/namespace
|
||||
|
||||
export default async function mainHandler(req, res, next) {
|
||||
const [stashes, templates, unseenNotifications] = req.user ? await Promise.all([
|
||||
fetchUserStashes(req.user.id, req.user),
|
||||
fetchUserTemplates(req.user),
|
||||
fetchUnseenNotificationsCount(req.user),
|
||||
]) : [];
|
||||
const [stashes, templates, unseenNotifications] = req.user
|
||||
? await Promise.all([
|
||||
fetchUserStashes(req.user.id, req.user),
|
||||
fetchUserTemplates(req.user),
|
||||
fetchUnseenNotificationsCount(req.user),
|
||||
])
|
||||
: [];
|
||||
|
||||
const pageContextInit = {
|
||||
urlOriginal: req.originalUrl,
|
||||
@@ -27,12 +29,14 @@ export default async function mainHandler(req, res, next) {
|
||||
abilities: req.user.abilities,
|
||||
avatar: req.user.avatar,
|
||||
},
|
||||
assets: req.user ? {
|
||||
stashes,
|
||||
primaryStash: stashes.find((stash) => stash.isPrimary),
|
||||
templates,
|
||||
unseenNotifications,
|
||||
} : null,
|
||||
assets: req.user
|
||||
? {
|
||||
stashes,
|
||||
primaryStash: stashes.find((stash) => stash.isPrimary),
|
||||
templates,
|
||||
unseenNotifications,
|
||||
}
|
||||
: null,
|
||||
env: {
|
||||
theme: req.cookies.theme || req.headers['sec-ch-prefers-color-scheme'] || 'light',
|
||||
scenesView: req.cookies.scenesView || 'list',
|
||||
|
||||
+6
-6
@@ -1,12 +1,12 @@
|
||||
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
|
||||
import { stringify } from '@brillout/json-serializer/stringify';
|
||||
|
||||
import { fetchMovies, fetchMoviesById } from '../movies.js';
|
||||
import { fetchStashByUsernameAndSlug } from '../stashes.js';
|
||||
import { parseActorIdentifier } from '../query.js';
|
||||
import { getIdsBySlug } from '../cache.js';
|
||||
import slugify from '../../utils/slugify.js';
|
||||
import promiseProps from '../../utils/promise-props.js';
|
||||
import slugify from '../../utils/slugify.js';
|
||||
import { getIdsBySlug } from '../cache.js';
|
||||
import { HttpError } from '../errors.js';
|
||||
import { fetchMovies, fetchMoviesById } from '../movies.js';
|
||||
import { parseActorIdentifier } from '../query.js';
|
||||
import { fetchStashByUsernameAndSlug } from '../stashes.js';
|
||||
|
||||
export async function curateMoviesQuery(query) {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import config from 'config';
|
||||
import path from 'path';
|
||||
import path from 'node:path';
|
||||
import { Reader } from '@maxmind/geoip2-node';
|
||||
import config from 'config';
|
||||
|
||||
import initLogger from '../logger.js';
|
||||
|
||||
@@ -69,7 +69,8 @@ export default async function initRestrictionHandler() {
|
||||
|
||||
req.restriction = restriction;
|
||||
req.country = country;
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
logger.error(`Failed Maxmind IP lookup for ${req.ip}: ${error.message}`);
|
||||
|
||||
req.session.restrictionIp = req.userIp;
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag/50052194#50052194
|
||||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = `${__dirname}/..`;
|
||||
|
||||
+11
-11
@@ -1,22 +1,22 @@
|
||||
import Router from 'express-promise-router';
|
||||
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
|
||||
import { stringify } from '@brillout/json-serializer/stringify';
|
||||
import { Router } from 'express';
|
||||
|
||||
import promiseProps from '../../utils/promise-props.js';
|
||||
|
||||
import slugify from '../../utils/slugify.js';
|
||||
|
||||
import { getIdsBySlug } from '../cache.js';
|
||||
import { HttpError } from '../errors.js';
|
||||
import { parseActorIdentifier } from '../query.js';
|
||||
import {
|
||||
createSceneRevision,
|
||||
fetchSceneRevisions,
|
||||
fetchScenes,
|
||||
fetchScenesById,
|
||||
fetchSceneRevisions,
|
||||
createSceneRevision,
|
||||
reviewSceneRevision,
|
||||
} from '../scenes.js';
|
||||
|
||||
import { fetchStashByUsernameAndSlug } from '../stashes.js';
|
||||
|
||||
import { parseActorIdentifier } from '../query.js';
|
||||
import { getIdsBySlug } from '../cache.js';
|
||||
import slugify from '../../utils/slugify.js';
|
||||
import { HttpError } from '../errors.js';
|
||||
import promiseProps from '../../utils/promise-props.js';
|
||||
|
||||
export async function curateScenesQuery(query) {
|
||||
const splitYears = query.years?.split(',') || [];
|
||||
const splitTags = query.tags?.split(',') || [];
|
||||
|
||||
+45
-45
@@ -1,50 +1,50 @@
|
||||
import config from 'config';
|
||||
import path from 'path';
|
||||
import express from 'express';
|
||||
import boolParser from 'express-query-boolean';
|
||||
import Router from 'express-promise-router';
|
||||
import session from 'express-session';
|
||||
import RedisStore from 'connect-redis';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import compression from 'compression';
|
||||
import cookie from 'cookie';
|
||||
|
||||
import redis from '../redis.js';
|
||||
|
||||
import errorHandler from './error.js';
|
||||
import consentHandler from './consent.js';
|
||||
import initRestrictionHandler from './restrictions.js';
|
||||
|
||||
import { scenesRouter } from './scenes.js';
|
||||
import { actorsRouter } from './actors.js';
|
||||
import { syncRouter } from './sync.js';
|
||||
|
||||
import { fetchMoviesApi } from './movies.js';
|
||||
import { fetchEntitiesApi } from './entities.js';
|
||||
import { fetchTagsApi } from './tags.js';
|
||||
import config from 'config';
|
||||
import { RedisStore } from 'connect-redis';
|
||||
import { parseCookie } from 'cookie';
|
||||
import express, { Router } from 'express';
|
||||
import session from 'express-session';
|
||||
|
||||
import { verifyKey } from '../auth.js';
|
||||
import initLogger from '../logger.js';
|
||||
|
||||
import redis from '../redis.js';
|
||||
import queryBoolean from '../utils/query-boolean.js';
|
||||
import { actorsRouter } from './actors.js';
|
||||
|
||||
import { router as alertsRouter } from './alerts.js';
|
||||
import {
|
||||
createKeyApi,
|
||||
fetchUserKeysApi,
|
||||
flushUserKeysApi,
|
||||
loginApi,
|
||||
logoutApi,
|
||||
removeUserKeyApi,
|
||||
setUserApi,
|
||||
signupApi,
|
||||
} from './auth.js';
|
||||
import consentHandler from './consent.js';
|
||||
|
||||
import { fetchEntitiesApi } from './entities.js';
|
||||
import errorHandler from './error.js';
|
||||
import { graphqlApi } from './graphql.js';
|
||||
|
||||
import mainHandler from './main.js';
|
||||
import { fetchMoviesApi } from './movies.js';
|
||||
|
||||
import {
|
||||
setUserApi,
|
||||
loginApi,
|
||||
logoutApi,
|
||||
signupApi,
|
||||
fetchUserKeysApi,
|
||||
createKeyApi,
|
||||
removeUserKeyApi,
|
||||
flushUserKeysApi,
|
||||
} from './auth.js';
|
||||
import initRestrictionHandler from './restrictions.js';
|
||||
|
||||
import { scenesRouter } from './scenes.js';
|
||||
|
||||
import { router as userRouter } from './users.js';
|
||||
import { router as stashesRouter } from './stashes.js';
|
||||
import { router as alertsRouter } from './alerts.js';
|
||||
|
||||
import { syncRouter } from './sync.js';
|
||||
import { initCachesApi } from './system.js';
|
||||
|
||||
import initLogger from '../logger.js';
|
||||
import { fetchTagsApi } from './tags.js';
|
||||
|
||||
import { router as userRouter } from './users.js';
|
||||
|
||||
const logger = initLogger();
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
@@ -57,8 +57,11 @@ export default async function initServer() {
|
||||
app.use(compression());
|
||||
app.disable('x-powered-by');
|
||||
app.set('view engine', 'ejs');
|
||||
// Express 5 defaults to the 'simple' query parser (Node's querystring) instead of 'extended'
|
||||
// (qs), which drops support for the bracket/nested query syntax the app relies on.
|
||||
app.set('query parser', 'extended');
|
||||
|
||||
router.use(boolParser());
|
||||
router.use(queryBoolean());
|
||||
|
||||
router.use('/', express.static('public'));
|
||||
router.use('/', express.static('static'));
|
||||
@@ -66,12 +69,10 @@ export default async function initServer() {
|
||||
|
||||
router.use((req, _res, next) => {
|
||||
if (req.headers.cookie) {
|
||||
const cookies = cookie.parse(req.headers.cookie);
|
||||
const cookies = parseCookie(req.headers.cookie);
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
req.cookies = cookies;
|
||||
req.tagFilter = cookies.tags ? JSON.parse(cookies.tags) : [];
|
||||
/* eslint-enable no-param-reassign */
|
||||
}
|
||||
|
||||
next();
|
||||
@@ -99,7 +100,8 @@ export default async function initServer() {
|
||||
// (In dev, Vite's middleware serves our static assets.)
|
||||
const sirv = (await import('sirv')).default;
|
||||
router.use(sirv('dist/client'));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// We instantiate Vite's development server and integrate its middleware to our server.
|
||||
// ⚠️ We instantiate it only in development. (It isn't needed in production and it
|
||||
// would unnecessarily bloat our production server.)
|
||||
@@ -121,7 +123,7 @@ export default async function initServer() {
|
||||
res.sendFile(path.join(import.meta.dirname, '../../assets/consent.html'));
|
||||
});
|
||||
|
||||
router.use('/api/*', async (req, _res, next) => {
|
||||
router.use('/api/{*splat}', async (req, _res, next) => {
|
||||
if (req.headers['api-user']) {
|
||||
req.user = await verifyKey(req.headers['api-user'], req.headers['api-key'], req);
|
||||
}
|
||||
@@ -167,16 +169,14 @@ export default async function initServer() {
|
||||
router.use(consentHandler);
|
||||
|
||||
router.use((_req, res, next) => {
|
||||
/* eslint-disable no-param-reassign */
|
||||
res.set('Accept-CH', 'Sec-CH-Prefers-Color-Scheme');
|
||||
res.set('Vary', 'Sec-CH-Prefers-Color-Scheme');
|
||||
res.set('Critical-CH', 'Sec-CH-Prefers-Color-Scheme');
|
||||
/* eslint-enable no-param-reassign */
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
router.get('*', mainHandler);
|
||||
router.get('/{*splat}', mainHandler);
|
||||
|
||||
router.use(errorHandler);
|
||||
app.use(router);
|
||||
|
||||
+5
-5
@@ -1,17 +1,17 @@
|
||||
import Router from 'express-promise-router';
|
||||
import { Router } from 'express';
|
||||
|
||||
import {
|
||||
fetchUserStashes,
|
||||
createStash,
|
||||
fetchStashByUsernameAndSlug,
|
||||
fetchUserStashes,
|
||||
removeStash,
|
||||
stashActor,
|
||||
stashScene,
|
||||
stashMovie,
|
||||
stashScene,
|
||||
unstashActor,
|
||||
unstashScene,
|
||||
unstashMovie,
|
||||
unstashScene,
|
||||
updateStash,
|
||||
fetchStashByUsernameAndSlug,
|
||||
} from '../stashes.js';
|
||||
|
||||
export const stashesSchema = `
|
||||
|
||||
+9
-9
@@ -1,15 +1,15 @@
|
||||
import Router from 'express-promise-router';
|
||||
|
||||
import {
|
||||
syncScenes,
|
||||
syncMovies,
|
||||
syncActors,
|
||||
syncStashes,
|
||||
syncQueue,
|
||||
} from '../sync.js';
|
||||
import { Router } from 'express';
|
||||
|
||||
import verifyAbility from '../../utils/verify-ability.js';
|
||||
|
||||
import {
|
||||
syncActors,
|
||||
syncMovies,
|
||||
syncQueue,
|
||||
syncScenes,
|
||||
syncStashes,
|
||||
} from '../sync.js';
|
||||
|
||||
export const syncRouter = Router();
|
||||
|
||||
async function syncScenesApi(req, res) {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { HttpError } from '../errors.js';
|
||||
import { initCaches } from '../cache.js';
|
||||
import { HttpError } from '../errors.js';
|
||||
|
||||
export async function initCachesApi(req, res) {
|
||||
if (req.user?.role !== 'admin') {
|
||||
|
||||
+4
-4
@@ -1,12 +1,12 @@
|
||||
import Router from 'express-promise-router';
|
||||
import { stringify } from '@brillout/json-serializer/stringify'; /* eslint-disable-line import/extensions */
|
||||
import { stringify } from '@brillout/json-serializer/stringify';
|
||||
import { Router } from 'express';
|
||||
|
||||
import {
|
||||
createBan,
|
||||
createTemplate,
|
||||
fetchUser,
|
||||
fetchUserTemplates,
|
||||
createTemplate,
|
||||
removeTemplate,
|
||||
createBan,
|
||||
} from '../users.js';
|
||||
|
||||
async function fetchUserApi(req, res) {
|
||||
|
||||
Reference in New Issue
Block a user