Fixed search inputs not working in Firefox/Safari. Added Stashes and Alerts to header menu. Indexing compilation tags as assigned tags in Manticore.

This commit is contained in:
2026-07-06 01:36:30 +02:00
parent 6f8d3b1ad2
commit ee1e347405
10 changed files with 143 additions and 20 deletions

View File

@@ -310,3 +310,23 @@
box-shadow: 0 0 3px var(--shadow-weak-10); box-shadow: 0 0 3px var(--shadow-weak-10);
} }
} }
.search-cancel {
width: 2rem;
height: 2rem;
padding: .5rem;
.icon {
width: 1rem;
height: 1rem;
fill: var(--glass);
}
&:hover {
cursor: pointer;
.icon {
fill: var(--error);
}
}
}

View File

@@ -5,12 +5,19 @@
<!-- onsearch not compatible with FF and Safari --> <!-- onsearch not compatible with FF and Safari -->
<input <input
v-model="q" v-model="q"
type="search" type="input"
placeholder="Search actors" placeholder="Search actors"
class="input search" class="input search"
@search="search" @keydown.enter="search"
> >
<Icon
v-if="q"
icon="cross2"
class="search-button"
@click="q = ''; search()"
/>
<Icon <Icon
icon="search" icon="search"
class="search-button" class="search-button"

View File

@@ -187,6 +187,26 @@
</a> </a>
</li> </li>
<li class="menu-item">
<a
:href="`/user/${user.username}/stashes`"
class="menu-button nolink stashes"
>
<Icon icon="folder-heart" />
Stashes
</a>
</li>
<li class="menu-item">
<a
:href="`/user/${user.username}/alerts`"
class="menu-button nolink alerts"
>
<Icon icon="alarm" />
Alerts
</a>
</li>
<li <li
v-close-popper v-close-popper
class="menu-item menu-button" class="menu-item menu-button"

View File

@@ -4,14 +4,28 @@
v-if="showFilters" v-if="showFilters"
:class="{ loading }" :class="{ loading }"
> >
<div class="filter"> <div class="filter search-container">
<!-- onsearch not compatible with FF and Safari -->
<input <input
v-model="filters.search" v-model="filters.search"
type="search" type="input"
placeholder="Search movies" placeholder="Search movies"
class="search input" class="search input"
@search="search" @keydown.enter="search"
> >
<Icon
v-if="filters.search"
icon="cross2"
class="search-button"
@click="filters.search = ''; search()"
/>
<Icon
icon="search"
class="search-button"
@click="search"
/>
</div> </div>
<YearsFilter <YearsFilter

View File

@@ -12,12 +12,19 @@
<!-- onsearch not compatible with FF and Safari --> <!-- onsearch not compatible with FF and Safari -->
<input <input
v-model="filters.search" v-model="filters.search"
type="search" type="input"
placeholder="Search scenes" placeholder="Search scenes"
class="search input" class="search input"
@search="search" @keydown.enter="search"
> >
<Icon
v-if="filters.search"
icon="cross2"
class="search-button"
@click="filters.search = ''; search()"
/>
<Icon <Icon
icon="search" icon="search"
class="search-button" class="search-button"

View File

@@ -1,13 +1,26 @@
<template> <template>
<Admin class="page"> <Admin class="page">
<div class="header"> <div class="header">
<input <form
v-model="actorQuery" class="search"
type="search" @submit.prevent="searchActors"
placeholder="Search actors"
class="input search"
@search="searchActors"
> >
<input
v-model="actorQuery"
type="input"
placeholder="Search actors"
class="input search-input"
>
<button
v-if="actorQuery?.length"
type="button"
class="search-cancel nobutton"
@click="actorQuery = ''; searchActors()"
>
<Icon icon="cross2" />
</button>
</form>
<div class="header-actions"> <div class="header-actions">
<button <button
@@ -208,10 +221,16 @@ onMounted(() => {
<style scoped> <style scoped>
.search { .search {
display: flex;
align-items: center;
max-width: 20rem; max-width: 20rem;
flex-grow: 1; flex-grow: 1;
} }
.search-input {
flex-grow: 1;
}
.header { .header {
display: flex; display: flex;
gap: 1rem; gap: 1rem;

View File

@@ -6,16 +6,23 @@
> >
<input <input
v-model="query" v-model="query"
type="search" type="input"
placeholder="Search channels" placeholder="Search channels"
class="search input" class="search input"
@search="search" @keydown.enter="search"
> >
<Icon <Icon
icon="search" icon="search"
@click="search" @click="search"
/> />
<Icon
v-if="query"
icon="cross2"
class="search-button"
@click="query = ''; search()"
/>
</form> </form>
<div <div

View File

@@ -35,19 +35,27 @@
class="search-container" class="search-container"
@submit.prevent="search" @submit.prevent="search"
> >
<!-- onsearch not compatible with FF and Safari -->
<input <input
ref="searchInput" ref="searchInput"
v-model="query" v-model="query"
type="search" type="input"
placeholder="Search tags" placeholder="Search tags"
class="search input" class="search input"
@search="search" @keydown.enter="search"
> >
<Icon <Icon
icon="search" icon="search"
@click="search" @click="search"
/> />
<Icon
v-if="query"
icon="cross2"
class="search-button"
@click="query = ''; search()"
/>
</form> </form>
<div <div

View File

@@ -717,6 +717,12 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) {
.whereIn('actor_id', sourceActorIds) .whereIn('actor_id', sourceActorIds)
.returning('stash_id'); .returning('stash_id');
/* TODO: add revision entries
console.log('SOURCES', targetActor, sourceActors);
throw new Error('ABORT');
*/
await trx.commit(); await trx.commit();
} catch (error) { } catch (error) {
await trx.rollback(); await trx.rollback();

View File

@@ -187,13 +187,28 @@ export async function syncManticoreScenes(sceneIds) {
const flatTags = scene.tags.filter((tag) => tag.f3 > 6).flatMap((tag) => [tag.f2].concat(tag.f4)).filter(Boolean); // only make top tags searchable to minimize cluttered results const flatTags = scene.tags.filter((tag) => tag.f3 > 6).flatMap((tag) => [tag.f2].concat(tag.f4)).filter(Boolean); // only make top tags searchable to minimize cluttered results
const filteredTitle = filterTitle(scene.title, [...flatActors, ...flatTags]); const filteredTitle = filterTitle(scene.title, [...flatActors, ...flatTags]);
const isCompilation = scene.tags.some((tag) => tag.f2 === 'compilation');
// use decimal packing with 5-decimal pad to allow for actor-specific tags, i.e. actor 135 tag 5 = 13500005 // use decimal packing with 5-decimal pad to allow for actor-specific tags, i.e. actor 135 tag 5 = 13500005
// all global tags are necessarily < 10,000, all tags for actor 135 are >= 13500000 and <= 13599999 // all global tags are necessarily < 10,000, all tags for actor 135 are >= 13500000 and <= 13599999
// f1 = tag ID, f5 = actor ID // f1 = tag ID, f5 = actor ID
const assignedTagIds = scene.tags.map((tag) => (tag.f5 === null ? tag.f1 : tag.f5 * 1_000_00 + tag.f1)); const assignedTagIds = scene.tags.map((tag) => {
if (tag.f5) {
// tag is assigned to actor, pack tag ID with actor ID
return tag.f5 * 1_000_00 + tag.f1;
}
/* if (isCompilation && tag.f2 !== 'compilation') {
if (sceneId === '187734') { // tag is part of a compilation, pack with arbitrary large number that will never be an actor ID (famous last words)
return 900_000_000 * 1_000_00 + tag.f1;
}
// plain tag ID
return tag.f1;
});
/* abort to inspect
if (sceneId === '554480') {
console.log(scene, assignedTagIds); console.log(scene, assignedTagIds);
throw new Error('ABORT'); throw new Error('ABORT');
} }