Showing curated campaigns on tags page.
This commit is contained in:
parent
64bf3b65ac
commit
f9b7a8731e
|
@ -72,5 +72,6 @@ const bannerSrc = (() => {
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -34,16 +34,19 @@ export async function onBeforeRender(pageContext) {
|
||||||
{
|
{
|
||||||
entityIds: [entity.id, entity.parent?.id].filter(Boolean),
|
entityIds: [entity.id, entity.parent?.id].filter(Boolean),
|
||||||
minRatio: 1.5,
|
minRatio: 1.5,
|
||||||
|
allowRandomFallback: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
entityIds: [entity.id, entity.parent?.id].filter(Boolean),
|
entityIds: [entity.id, entity.parent?.id].filter(Boolean),
|
||||||
minRatio: 0.75,
|
minRatio: 0.75,
|
||||||
maxRatio: 1.25,
|
maxRatio: 1.25,
|
||||||
|
allowRandomFallback: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
entityIds: [entity.id, entity.parent?.id].filter(Boolean),
|
entityIds: [entity.id, entity.parent?.id].filter(Boolean),
|
||||||
parentEntityId: entity.parent?.id,
|
parentEntityId: entity.parent?.id,
|
||||||
minRatio: 1.5,
|
minRatio: 1.5,
|
||||||
|
allowRandomFallback: false,
|
||||||
},
|
},
|
||||||
], { tagFilter: pageContext.tagFilter });
|
], { tagFilter: pageContext.tagFilter });
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,15 @@ import markdownItClass from '@toycode/markdown-it-class';
|
||||||
import { fetchTagsById } from '#/src/tags.js';
|
import { fetchTagsById } from '#/src/tags.js';
|
||||||
import { fetchScenes } from '#/src/scenes.js';
|
import { fetchScenes } from '#/src/scenes.js';
|
||||||
import { curateScenesQuery } from '#/src/web/scenes.js';
|
import { curateScenesQuery } from '#/src/web/scenes.js';
|
||||||
|
import { getRandomCampaigns, getCampaignIndex } from '#/src/campaigns.js';
|
||||||
|
|
||||||
const md = markdownIt().use(markdownItClass, { a: 'link' });
|
const md = markdownIt().use(markdownItClass, { a: 'link' });
|
||||||
|
|
||||||
export async function onBeforeRender(pageContext) {
|
export async function onBeforeRender(pageContext) {
|
||||||
const [[tag], tagScenes] = await Promise.all([
|
const tagSlug = pageContext.routeParams.tagSlug;
|
||||||
fetchTagsById([pageContext.routeParams.tagSlug]),
|
|
||||||
|
const [[tag], tagScenes, campaigns] = await Promise.all([
|
||||||
|
fetchTagsById([tagSlug]),
|
||||||
fetchScenes(await curateScenesQuery({
|
fetchScenes(await curateScenesQuery({
|
||||||
...pageContext.urlQuery,
|
...pageContext.urlQuery,
|
||||||
scope: pageContext.routeParams.scope || 'latest',
|
scope: pageContext.routeParams.scope || 'latest',
|
||||||
|
@ -20,6 +23,11 @@ export async function onBeforeRender(pageContext) {
|
||||||
limit: Number(pageContext.urlParsed.search.limit) || 30,
|
limit: Number(pageContext.urlParsed.search.limit) || 30,
|
||||||
aggregate: true,
|
aggregate: true,
|
||||||
}, pageContext.user),
|
}, pageContext.user),
|
||||||
|
getRandomCampaigns([
|
||||||
|
{ tagSlugs: [tagSlug], minRatio: 1.5 },
|
||||||
|
{ tagSlugs: [tagSlug], minRatio: 0.75, maxRatio: 1.25 },
|
||||||
|
{ tagSlugs: [tagSlug], minRatio: 1.5 },
|
||||||
|
], { tagFilter: pageContext.tagFilter }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -33,6 +41,9 @@ export async function onBeforeRender(pageContext) {
|
||||||
|
|
||||||
const description = tag.description && md.renderInline(tag.description);
|
const description = tag.description && md.renderInline(tag.description);
|
||||||
|
|
||||||
|
const campaignIndex = getCampaignIndex(scenes.length);
|
||||||
|
const [metaCampaign, sceneCampaign, paginationCampaign] = campaigns;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pageContext: {
|
pageContext: {
|
||||||
title: tag.name,
|
title: tag.name,
|
||||||
|
@ -46,6 +57,12 @@ export async function onBeforeRender(pageContext) {
|
||||||
total,
|
total,
|
||||||
limit,
|
limit,
|
||||||
},
|
},
|
||||||
|
campaigns: {
|
||||||
|
index: campaignIndex,
|
||||||
|
meta: metaCampaign,
|
||||||
|
scenes: scenes.length > 5 && sceneCampaign,
|
||||||
|
pagination: paginationCampaign,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { fetchScenes } from '#/src/scenes.js';
|
import { fetchScenes } from '#/src/scenes.js';
|
||||||
import { curateScenesQuery } from '#/src/web/scenes.js';
|
import { curateScenesQuery } from '#/src/web/scenes.js';
|
||||||
import { getRandomCampaigns } from '#/src/campaigns.js';
|
import { getRandomCampaigns, getCampaignIndex } from '#/src/campaigns.js';
|
||||||
|
|
||||||
export async function onBeforeRender(pageContext) {
|
export async function onBeforeRender(pageContext) {
|
||||||
const withQuery = Object.hasOwn(pageContext.urlParsed.search, 'q');
|
const withQuery = Object.hasOwn(pageContext.urlParsed.search, 'q');
|
||||||
|
@ -35,7 +35,7 @@ export async function onBeforeRender(pageContext) {
|
||||||
total,
|
total,
|
||||||
} = sceneResults;
|
} = sceneResults;
|
||||||
|
|
||||||
const campaignIndex = Math.floor((Math.random() * (0.5 - 0.2) + 0.2) * scenes.length);
|
const campaignIndex = getCampaignIndex(scenes.length);
|
||||||
const [scopeCampaign, sceneCampaign, paginationCampaign] = campaigns;
|
const [scopeCampaign, sceneCampaign, paginationCampaign] = campaigns;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -33,6 +33,26 @@ function curateCampaign(campaign) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectRandomCampaign(primaryCampaigns, entityCampaigns, preferredCampaigns, allCampaigns, options) {
|
||||||
|
if (primaryCampaigns.length > 0) {
|
||||||
|
return primaryCampaigns[crypto.randomInt(primaryCampaigns.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityCampaigns.length > 0) {
|
||||||
|
return entityCampaigns[crypto.randomInt(entityCampaigns.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preferredCampaigns.length > 0) {
|
||||||
|
return preferredCampaigns[crypto.randomInt(preferredCampaigns.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allCampaigns.length > 0 && options.allowRandomFallback !== false) {
|
||||||
|
return allCampaigns[crypto.randomInt(allCampaigns.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getRandomCampaign(options = {}, context = {}) {
|
export async function getRandomCampaign(options = {}, context = {}) {
|
||||||
const campaigns = options.campaigns
|
const campaigns = options.campaigns
|
||||||
|| await redis.hGetAll('traxxx:campaigns').then((rawCampaigns) => Object.values(rawCampaigns).map((rawCampaign) => JSON.parse(rawCampaign)));
|
|| await redis.hGetAll('traxxx:campaigns').then((rawCampaigns) => Object.values(rawCampaigns).map((rawCampaign) => JSON.parse(rawCampaign)));
|
||||||
|
@ -50,40 +70,40 @@ export async function getRandomCampaign(options = {}, context = {}) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.tagFilter && campaign.banner && campaign.banner.tags.some((tag) => context.tagFilter.includes(tag))) {
|
if (context.tagFilter && campaign.banner && campaign.banner.tags.some((tag) => context.tagFilter.includes(tag) && !options.tagSlugs?.includes(tag))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag page overrides tag filter
|
||||||
|
if (options.tagSlugs && campaign.banner && !campaign.banner.tags.some((tag) => options.tagSlugs.includes(tag))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (validCampaigns.length > 0) {
|
// console.log(validCampaigns);
|
||||||
const campaignsByEntityId = validCampaigns.reduce((acc, campaign) => {
|
|
||||||
const entityId = campaign.entity.parent?.id || campaign.entity.id;
|
|
||||||
|
|
||||||
if (!acc[entityId]) {
|
const campaignsByEntityId = validCampaigns.reduce((acc, campaign) => {
|
||||||
acc[entityId] = [];
|
const entityId = campaign.entity.parent?.id || campaign.entity.id;
|
||||||
}
|
|
||||||
|
|
||||||
acc[entityId].push(campaign);
|
if (!acc[entityId]) {
|
||||||
|
acc[entityId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
return acc;
|
acc[entityId].push(campaign);
|
||||||
}, {});
|
|
||||||
|
|
||||||
// randomize entities first to ensure fair exposure for entities with fewer banners
|
return acc;
|
||||||
const entityIds = Object.keys(campaignsByEntityId);
|
}, {});
|
||||||
const randomEntityCampaigns = campaignsByEntityId[entityIds[crypto.randomInt(entityIds.length)]];
|
|
||||||
|
|
||||||
const primaryCampaigns = randomEntityCampaigns.filter((campaign) => campaign.entity.id === options.entityIds?.[0]);
|
// randomize entities first to ensure fair exposure for entities with fewer banners
|
||||||
|
const entityIds = Object.keys(campaignsByEntityId);
|
||||||
|
const randomEntityCampaigns = entityIds.length > 0 ? campaignsByEntityId[entityIds[crypto.randomInt(entityIds.length)]] : [];
|
||||||
|
const primaryCampaigns = randomEntityCampaigns.filter((campaign) => campaign.entity.id === options.entityIds?.[0]);
|
||||||
|
|
||||||
const randomCampaign = (primaryCampaigns.length > 0 ? primaryCampaigns[crypto.randomInt(primaryCampaigns.length)] : null)
|
const randomCampaign = selectRandomCampaign(primaryCampaigns, randomEntityCampaigns, validCampaigns, campaigns, options);
|
||||||
|| (randomEntityCampaigns.length > 0 ? randomEntityCampaigns[crypto.randomInt(randomEntityCampaigns.length)] : null)
|
|
||||||
|| validCampaigns[crypto.randomInt(validCampaigns.length)];
|
|
||||||
|
|
||||||
return randomCampaign;
|
return randomCampaign;
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRandomCampaigns(allOptions = [], context = {}) {
|
export async function getRandomCampaigns(allOptions = [], context = {}) {
|
||||||
|
@ -96,6 +116,10 @@ export async function getRandomCampaigns(allOptions = [], context = {}) {
|
||||||
}, context)));
|
}, context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCampaignIndex(scenesCount) {
|
||||||
|
return Math.floor((Math.random() * (0.5 - 0.2) + 0.2) * scenesCount); // avoid start and end of scenes list
|
||||||
|
}
|
||||||
|
|
||||||
export async function cacheCampaigns() {
|
export async function cacheCampaigns() {
|
||||||
const campaigns = await knex('campaigns')
|
const campaigns = await knex('campaigns')
|
||||||
.select('campaigns.*')
|
.select('campaigns.*')
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
export default function consentHandler(req, res, next) {
|
export default function consentHandler(req, res, next) {
|
||||||
const redirect = req.headers.referer && new URL(req.headers.referer).searchParams.get('redirect');
|
const redirect = req.headers.referer && new URL(req.headers.referer).searchParams.get('redirect');
|
||||||
|
|
||||||
|
if (req.path.includes('/api')) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Object.hasOwn(req.query, 'lgbt')) {
|
if (Object.hasOwn(req.query, 'lgbt')) {
|
||||||
const lgbtFilters = (req.tagFilter || []).filter((tag) => !['gay', 'bisexual', 'transsexual'].includes(tag));
|
const lgbtFilters = (req.tagFilter || []).filter((tag) => !['gay', 'bisexual', 'transsexual'].includes(tag));
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ export async function curateScenesQuery(query) {
|
||||||
notEntityIds: await getIdsBySlug(splitEntities.filter((entity) => entity.charAt(0) === '!').map((entity) => entity.slice(1)), 'entities'),
|
notEntityIds: await getIdsBySlug(splitEntities.filter((entity) => entity.charAt(0) === '!').map((entity) => entity.slice(1)), 'entities'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('QUERY', query);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scope: query.scope || 'latest',
|
scope: query.scope || 'latest',
|
||||||
query: query.q,
|
query: query.q,
|
||||||
|
@ -41,6 +43,8 @@ export async function curateScenesQuery(query) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchScenesApi(req, res) {
|
export async function fetchScenesApi(req, res) {
|
||||||
|
console.log('REQUEST', req.query);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
scenes,
|
scenes,
|
||||||
aggActors,
|
aggActors,
|
||||||
|
@ -56,6 +60,8 @@ export async function fetchScenesApi(req, res) {
|
||||||
limit: Number(req.query.limit) || 30,
|
limit: Number(req.query.limit) || 30,
|
||||||
}, req.user);
|
}, req.user);
|
||||||
|
|
||||||
|
console.log('OUTPUT', scenes.length);
|
||||||
|
|
||||||
res.send(stringify({
|
res.send(stringify({
|
||||||
scenes,
|
scenes,
|
||||||
aggActors,
|
aggActors,
|
||||||
|
|
Loading…
Reference in New Issue