Added selectable tag function for actors. Implemented experimental filtering by tag.

This commit is contained in:
ThePendulum 2020-06-30 04:33:47 +02:00
parent 3fba2d8a77
commit b803afa973
7 changed files with 135 additions and 55 deletions

View File

@ -301,6 +301,7 @@
:fetch-releases="fetchActor" :fetch-releases="fetchActor"
:items-total="totalCount" :items-total="totalCount"
:items-per-page="limit" :items-per-page="limit"
:available-tags="actor.tags"
/> />
<Releases :releases="releases" /> <Releases :releases="releases" />

View File

@ -24,6 +24,7 @@
<Filters <Filters
class="filters-block" class="filters-block"
:filter="filter" :filter="filter"
:available-tags="availableTags"
@set-filter="setFilter" @set-filter="setFilter"
/> />
@ -97,6 +98,10 @@ export default {
type: Number, type: Number,
default: 10, default: 10,
}, },
availableTags: {
type: Array,
default: () => [],
},
}, },
computed: { computed: {
...mapState({ ...mapState({

View File

@ -17,12 +17,12 @@
<div slot="popover"> <div slot="popover">
<ul class="tags nolist"> <ul class="tags nolist">
<li <li
v-for="tag in tags" v-for="tag in availableTags"
:key="`tag-${tag}`" :key="`tag-${tag.id}`"
class="tag" class="tag"
:class="{ selected: selectedTags.includes(tag) }" :class="{ selected: selectedTags.includes(tag.slug) }"
> >
<router-link :to="{ query: { ...getNewRange(tag) } }"> <router-link :to="{ query: { ...getNewRange(tag.slug) } }">
<Icon <Icon
icon="checkmark" icon="checkmark"
class="include" class="include"
@ -30,9 +30,9 @@
</router-link> </router-link>
<router-link <router-link
:to="{ query: { ...(selectedTags.length === 1 && selectedTags.includes(tag) ? null : { tags: tag }) } }" :to="{ query: { ...(selectedTags.length === 1 && selectedTags.includes(tag.slug) ? null : { tags: tag.slug }) } }"
class="name" class="name"
>{{ tag }}</router-link> >{{ tag.name }}</router-link>
</li> </li>
</ul> </ul>
</div> </div>
@ -40,19 +40,6 @@
</template> </template>
<script> <script>
const tags = [
'airtight',
'anal',
'blowjob',
'double-penetration',
'facial',
'gangbang',
'lesbian',
'mff',
'mfm',
'orgy',
];
function getNewRange(tag) { function getNewRange(tag) {
if (this.selectedTags.includes(tag)) { if (this.selectedTags.includes(tag)) {
if (this.selectedTags.length > 1) { if (this.selectedTags.length > 1) {
@ -79,11 +66,10 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
availableTags: {
type: Array,
default: () => [],
}, },
data() {
return {
tags,
};
}, },
computed: { computed: {
selectedTags, selectedTags,
@ -141,6 +127,7 @@ export default {
} }
.name { .name {
min-width: 8rem;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-grow: 1; flex-grow: 1;

View File

@ -1,3 +1,4 @@
import config from 'config';
import { graphql, get } from '../api'; import { graphql, get } from '../api';
import { import {
releaseFields, releaseFields,
@ -8,7 +9,7 @@ import {
import { curateActor, curateRelease } from '../curate'; import { curateActor, curateRelease } from '../curate';
import getDateRange from '../get-date-range'; import getDateRange from '../get-date-range';
function initActorActions(store, _router) { function initActorActions(store, router) {
async function fetchActorById({ _commit }, { async function fetchActorById({ _commit }, {
actorId, actorId,
limit = 10, limit = 10,
@ -16,6 +17,7 @@ function initActorActions(store, _router) {
range = 'latest', range = 'latest',
}) { }) {
const { before, after, orderBy } = getDateRange(range); const { before, after, orderBy } = getDateRange(range);
const includeTags = router.currentRoute.query.tags ? router.currentRoute.query.tags.split(',') : [];
const { actor, connection: { releases, totalCount } } = await graphql(` const { actor, connection: { releases, totalCount } } = await graphql(`
query Actor( query Actor(
@ -25,7 +27,9 @@ function initActorActions(store, _router) {
$after:Date = "1900-01-01", $after:Date = "1900-01-01",
$before:Date = "2100-01-01", $before:Date = "2100-01-01",
$orderBy:[ReleasesActorsOrderBy!] $orderBy:[ReleasesActorsOrderBy!]
$exclude: [String!] $selectableTags: [String],
$excludeTags: [String!]
${includeTags.length > 0 ? '$includeTags: [String!]' : ''}
) { ) {
actor(id: $actorId) { actor(id: $actorId) {
id id
@ -139,18 +143,24 @@ function initActorActions(store, _router) {
name name
slug slug
} }
tags(selectableTags: $selectableTags) {
id
name
slug
priority
}
releasesConnection: releasesActorsConnection( releasesConnection: releasesActorsConnection(
filter: { filter: {
release: { release: {
date: { date: {
lessThan: $before, lessThan: $before,
greaterThan: $after, greaterThan: $after,
}, }
releasesTagsConnection: { releasesTagsConnection: {
none: { none: {
tag: { tag: {
slug: { slug: {
in: $exclude in: $excludeTags
} }
} }
} }
@ -191,10 +201,10 @@ function initActorActions(store, _router) {
first: $limit first: $limit
offset: $offset offset: $offset
orderBy: $orderBy orderBy: $orderBy
filter: { condition: {
actorId: { actorId: $actorId
equalTo: $actorId
} }
filter: {
or: [ or: [
{ {
release: { release: {
@ -205,6 +215,17 @@ function initActorActions(store, _router) {
} }
}, },
] ]
${includeTags.length > 0 ? `release: {
releasesTagsConnection: {
some: {
tag: {
slug: {
in: $includeTags
}
}
}
}
}` : ''}
} }
) { ) {
releases: nodes { releases: nodes {
@ -221,8 +242,10 @@ function initActorActions(store, _router) {
offset: Math.max(0, (pageNumber - 1)) * limit, offset: Math.max(0, (pageNumber - 1)) * limit,
after, after,
before, before,
selectableTags: config.selectableTags,
orderBy: orderBy === 'DATE_DESC' ? 'RELEASE_BY_RELEASE_ID__DATE_DESC' : 'RELEASE_BY_RELEASE_ID__DATE_ASC', orderBy: orderBy === 'DATE_DESC' ? 'RELEASE_BY_RELEASE_ID__DATE_DESC' : 'RELEASE_BY_RELEASE_ID__DATE_ASC',
exclude: store.state.ui.filter, excludeTags: store.state.ui.filter,
includeTags,
}); });
return { return {

View File

@ -2,9 +2,25 @@ export default {
api: { api: {
url: `${window.location.origin}/api`, url: `${window.location.origin}/api`,
}, },
filename: { selectableTags: [
pattern: '{site.name} - {title} ({actors.$n.name}, {date} {shootId})', 'airtight',
separator: ', ', 'anal',
date: 'DD-MM-YYYY', 'blowjob',
}, 'creampie',
'deepthroat',
'double-anal',
'double-penetration',
'double-vaginal',
'facefucking',
'facial',
'fisting',
'gaping',
'gangbang',
'lesbian',
'mff',
'mfm',
'orgy',
'pov',
'squirting',
],
}; };

View File

@ -5,3 +5,11 @@ LEFT JOIN tags ON tags.id = releases_tags.tag_id
WHERE actors.slug = 'vina-sky' WHERE actors.slug = 'vina-sky'
GROUP BY tags.id GROUP BY tags.id
ORDER BY tags.name; ORDER BY tags.name;
SELECT tags.*
FROM releases_actors
LEFT JOIN releases_tags ON releases_tags.release_id = releases_actors.release_id
LEFT JOIN tags ON tags.id = releases_tags.tag_id
WHERE releases_actors.actor_id = actor.id
GROUP BY tags.id
ORDER BY tags.name;

View File

@ -147,12 +147,15 @@ exports.up = knex => Promise.resolve()
table.text('type') table.text('type')
.primary(); .primary();
})) }))
.then(() => knex('entities_types').insert([ .then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex('entities_types').insert([
{ type: 'network' }, { type: 'network' },
{ type: 'channel' }, { type: 'channel' },
{ type: 'studio' }, { type: 'studio' },
{ type: 'info' }, { type: 'info' },
])) ]);
})
.then(() => knex.schema.createTable('entities', (table) => { .then(() => knex.schema.createTable('entities', (table) => {
table.increments('id', 12); table.increments('id', 12);
@ -756,6 +759,7 @@ exports.up = knex => Promise.resolve()
.references('id') .references('id')
.inTable('releases'); .inTable('releases');
})) }))
// SEARCH
.then(() => { // eslint-disable-line arrow-body-style .then(() => { // eslint-disable-line arrow-body-style
// allow vim fold // allow vim fold
return knex.raw(` return knex.raw(`
@ -771,15 +775,25 @@ exports.up = knex => Promise.resolve()
ALTER TABLE releases_search ALTER TABLE releases_search
ADD COLUMN document tsvector; ADD COLUMN document tsvector;
ALTER TEXT SEARCH CONFIGURATION traxxx
ALTER MAPPING FOR word, numword, hword, numhword, hword_part, hword_numpart, asciiword, asciihword, hword_asciipart WITH traxxx_dict, simple, english_stem;
`);
})
// INDEXES
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
CREATE UNIQUE INDEX unique_actor_slugs_network ON actors (slug, entity_id); CREATE UNIQUE INDEX unique_actor_slugs_network ON actors (slug, entity_id);
CREATE UNIQUE INDEX unique_actor_slugs ON actors (slug, (entity_id IS NULL)); CREATE UNIQUE INDEX unique_actor_slugs ON actors (slug, (entity_id IS NULL));
ALTER TEXT SEARCH CONFIGURATION traxxx
ALTER MAPPING FOR word, numword, hword, numhword, hword_part, hword_numpart, asciiword, asciihword, hword_asciipart WITH traxxx_dict, simple, english_stem;
CREATE UNIQUE INDEX releases_search_unique ON releases_search (release_id); CREATE UNIQUE INDEX releases_search_unique ON releases_search (release_id);
CREATE INDEX releases_search_index ON releases_search USING GIN (document); CREATE INDEX releases_search_index ON releases_search USING GIN (document);
`);
})
// FUNCTIONS
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
CREATE FUNCTION search_releases(query text) RETURNS SETOF releases AS $$ CREATE FUNCTION search_releases(query text) RETURNS SETOF releases AS $$
SELECT * FROM releases WHERE releases.id IN ( SELECT * FROM releases WHERE releases.id IN (
SELECT release_id FROM releases_search AS search SELECT release_id FROM releases_search AS search
@ -802,10 +816,33 @@ exports.up = knex => Promise.resolve()
AND name ILIKE ('%' || search || '%') AND name ILIKE ('%' || search || '%')
$$ LANGUAGE SQL STABLE; $$ LANGUAGE SQL STABLE;
CREATE FUNCTION actors_tags(actor actors, selectable_tags text[]) RETURNS SETOF tags AS $$
SELECT tags.*
FROM releases_actors
LEFT JOIN
releases_tags ON releases_tags.release_id = releases_actors.release_id
LEFT JOIN
tags ON tags.id = releases_tags.tag_id
WHERE
releases_actors.actor_id = actor.id
AND
CASE WHEN array_length(selectable_tags, 1) IS NOT NULL
THEN tags.slug = ANY(selectable_tags)
ELSE true
END
GROUP BY tags.id
ORDER BY tags.name;
$$ LANGUAGE SQL STABLE;
CREATE FUNCTION releases_is_new(release releases) RETURNS boolean AS $$ CREATE FUNCTION releases_is_new(release releases) RETURNS boolean AS $$
SELECT EXISTS(SELECT true WHERE (SELECT id FROM batches ORDER BY created_at DESC LIMIT 1) = release.created_batch_id); SELECT EXISTS(SELECT true WHERE (SELECT id FROM batches ORDER BY created_at DESC LIMIT 1) = release.created_batch_id);
$$ LANGUAGE sql STABLE; $$ LANGUAGE sql STABLE;
`);
})
// VIEWS AND COMMENTS
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
CREATE VIEW movie_actors AS CREATE VIEW movie_actors AS
SELECT releases_movies.movie_id, releases_actors.actor_id FROM releases_movies SELECT releases_movies.movie_id, releases_actors.actor_id FROM releases_movies
LEFT JOIN releases ON releases.id = releases_movies.scene_id LEFT JOIN releases ON releases.id = releases_movies.scene_id
@ -881,6 +918,9 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
DROP FUNCTION IF EXISTS search_actors; DROP FUNCTION IF EXISTS search_actors;
DROP FUNCTION IF EXISTS get_random_sfw_media_id; DROP FUNCTION IF EXISTS get_random_sfw_media_id;
DROP FUNCTION IF EXISTS releases_is_new;
DROP FUNCTION IF EXISTS actors_tags;
DROP TEXT SEARCH CONFIGURATION IF EXISTS traxxx; DROP TEXT SEARCH CONFIGURATION IF EXISTS traxxx;
DROP TEXT SEARCH DICTIONARY IF EXISTS traxxx_dict; DROP TEXT SEARCH DICTIONARY IF EXISTS traxxx_dict;
`); `);