From 6877ee75ed70bff9b01810175cc91799abcbb2c1 Mon Sep 17 00:00:00 2001 From: DebaucheryLibrarian Date: Sat, 7 Mar 2026 02:09:04 +0100 Subject: [PATCH] Added toggle to select actor tags or all tags in filters. --- assets/img/icons/user-tags.svg | 27 ++++++++++++++++++++++ components/filters/tags.vue | 41 +++++++++++++++++++++++++++------- components/scenes/scenes.vue | 3 +++ src/scenes.js | 18 ++++++++++----- src/web/scenes.js | 2 ++ 5 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 assets/img/icons/user-tags.svg diff --git a/assets/img/icons/user-tags.svg b/assets/img/icons/user-tags.svg new file mode 100644 index 0000000..4a1c65e --- /dev/null +++ b/assets/img/icons/user-tags.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + diff --git a/components/filters/tags.vue b/components/filters/tags.vue index 19d8a38..4f41249 100644 --- a/components/filters/tags.vue +++ b/components/filters/tags.vue @@ -12,14 +12,30 @@ +
+ +
+ +
+ +
+
- +
[], }, + actorTags: { + type: Array, + default: () => [], + }, }); const emit = defineEmits(['update']); +const { pageProps } = inject('pageContext'); +const { tag: pageTag, actor: pageActor } = pageProps; + const search = ref(''); const searchRegexp = computed(() => new RegExp(search.value, 'i')); const order = ref('priority'); - -const { pageProps } = inject('pageContext'); -const { tag: pageTag } = pageProps; +const showActorTags = ref(true); const priorityTags = [ 'anal', @@ -148,8 +169,12 @@ const priorityTags = [ ]; const groupedTags = computed(() => { - const selected = props.tags.filter((tag) => props.filters.tags.includes(tag.slug)); - const filtered = props.tags.filter((tag) => !props.filters.tags.includes(tag.slug) + const tags = showActorTags.value && props.actorTags && (props.filters.actors.length > 0 || pageActor) + ? props.actorTags + : props.tags; + + const selected = tags.filter((tag) => props.filters.tags.includes(tag.slug)); + const filtered = tags.filter((tag) => !props.filters.tags.includes(tag.slug) && tag.id !== pageTag?.id && searchRegexp.value.test(tag.name)); diff --git a/components/scenes/scenes.vue b/components/scenes/scenes.vue index 643a0e9..bf1b341 100644 --- a/components/scenes/scenes.vue +++ b/components/scenes/scenes.vue @@ -34,6 +34,7 @@ @@ -263,6 +264,7 @@ const scenes = ref(pageProps.scenes); const aggYears = ref(pageProps.aggYears || []); const aggActors = ref(pageProps.aggActors || []); const aggTags = ref(pageProps.aggTags || []); +const aggActorTags = ref(pageProps.aggActorTags || []); const aggChannels = ref(pageProps.aggChannels || []); const currentPage = ref(Number(routeParams.page)); @@ -363,6 +365,7 @@ async function search(options = {}) { aggYears.value = res.aggYears; aggActors.value = res.aggActors; aggTags.value = res.aggTags; + aggActorTags.value = res.aggActorTags; aggChannels.value = res.aggChannels; total.value = res.total; diff --git a/src/scenes.js b/src/scenes.js index f3e5d1b..01856ed 100644 --- a/src/scenes.js +++ b/src/scenes.js @@ -424,6 +424,7 @@ async function queryManticoreSql(filters, options, _reqUser) { :yearsFacet: :actorsFacet: :tagsFacet: + :actorTagsFacet: :channelsFacet: :studiosFacet:; show meta; @@ -566,10 +567,9 @@ async function queryManticoreSql(filters, options, _reqUser) { yearsFacet: options.aggregateYears ? knex.raw('facet effective_year as years_facet order by effective_year desc limit ?', [aggSize]) : null, actorsFacet: options.aggregateActors ? knex.raw('facet scenes.actor_ids as actors_facet distinct id order by count(distinct id) desc limit ?', [aggSize]) : null, // don't facet tags associated to other actors, actor ID 0 means global - tagsFacet: options.aggregateTags // eslint-disable-line no-nested-ternary - ? (filters.stashId || !filters?.actorIds || filters.actorIds.length === 0 // we can't join the tags table as well as the stashes table - ? knex.raw('facet scenes.tag_ids as tags_facet order by count(distinct id) desc limit ?', [aggSize]) - : knex.raw(`facet IF(IN(scenes_tags.actor_id, ${[0, ...filters?.actorIds || []]}), scenes_tags.tag_id, 0) tags_facet distinct id order by count(distinct id) desc limit ?`, [aggSize])) + tagsFacet: options.aggregateTags ? knex.raw('facet scenes.tag_ids as tags_facet order by count(distinct id) desc limit ?', [aggSize]) : null, + actorTagsFacet: options.aggregateTags && !filters.stashId // eslint-disable-line no-nested-ternary + ? knex.raw(`facet IF(IN(scenes_tags.actor_id, ${[0, ...filters?.actorIds || []]}), scenes_tags.tag_id, 0) actor_tags_facet distinct id order by count(distinct id) desc limit ?`, [aggSize]) : null, channelsFacet: options.aggregateChannels ? knex.raw('facet scenes.channel_id as channels_facet distinct id order by count(distinct id) desc limit ?', [aggSize]) : null, studiosFacet: options.aggregateChannels ? knex.raw('facet scenes.studio_id as studios_facet distinct id order by count(distinct id) desc limit ?', [aggSize]) : null, @@ -607,6 +607,11 @@ async function queryManticoreSql(filters, options, _reqUser) { ?.data.map((row) => ({ key: row.tags_facet, doc_count: row['count(distinct id)'] || row['count(*)'] })) || []; + const actorTagIds = results + .find((result) => result.columns[0].actor_tags_facet && result.columns[1]['count(distinct id)']) + ?.data.map((row) => ({ key: row.actor_tags_facet, doc_count: row['count(distinct id)'] || row['count(*)'] })) + || []; + const channelIds = results .find((result) => result.columns[0].channels_facet && result.columns[1]['count(distinct id)']) ?.data.map((row) => ({ key: row.channels_facet || row['scenes.channel_id'], doc_count: row['count(distinct id)'] })) @@ -626,6 +631,7 @@ async function queryManticoreSql(filters, options, _reqUser) { years, actorIds, tagIds, + actorTagIds, channelIds, studioIds, }, @@ -663,9 +669,10 @@ export async function fetchScenes(filters, rawOptions, reqUser, context) { console.time('fetch aggregations'); - const [aggActors, aggTags, aggChannels] = await Promise.all([ + const [aggActors, aggTags, aggActorTags, aggChannels] = await Promise.all([ options.aggregateActors ? fetchActorsById(result.aggregations.actorIds.map((bucket) => bucket.key), { shallow: true, order: ['slug', 'asc'], append: actorCounts }, reqUser) : [], options.aggregateTags ? fetchTagsById(result.aggregations.tagIds.map((bucket) => bucket.key), { order: [knex.raw('lower(name)'), 'asc'], append: tagCounts }, reqUser, context) : [], + options.aggregateTags ? fetchTagsById(result.aggregations.actorTagIds.map((bucket) => bucket.key), { order: [knex.raw('lower(name)'), 'asc'], append: tagCounts }, reqUser, context) : [], options.aggregateChannels ? fetchEntitiesById(entityIds.map((bucket) => bucket.key), { order: ['slug', 'asc'], append: channelCounts }, reqUser, context) : [], ]); @@ -681,6 +688,7 @@ export async function fetchScenes(filters, rawOptions, reqUser, context) { aggYears, aggActors, aggTags, + aggActorTags, aggChannels, total: result.total, limit: options.limit, diff --git a/src/web/scenes.js b/src/web/scenes.js index 5c80e2c..e3fe2d3 100644 --- a/src/web/scenes.js +++ b/src/web/scenes.js @@ -59,6 +59,7 @@ async function fetchScenesApi(req, res) { aggYears, aggActors, aggTags, + aggActorTags, aggChannels, limit, total, @@ -77,6 +78,7 @@ async function fetchScenesApi(req, res) { aggYears, aggActors, aggTags, + aggActorTags, aggChannels, limit, total,