stashapp / stash

An organizer for your porn, written in Go. Documentation: https://docs.stashapp.cc
https://stashapp.cc/
GNU Affero General Public License v3.0
9.38k stars 803 forks source link

[Feature] Separating tags for higher-level objects #1253

Open QxxxGit opened 3 years ago

QxxxGit commented 3 years ago

Is your feature request related to a problem? Please describe. Some tags aren't always related to every object. For example, you might have a tag for an action like blowjob. This isn't useful for performers and can clutter up the list for selecting tags.

Though, some people might want to associate blowjob with performers as well as media (images, scenes, galleries, etc.)

Describe the solution you'd like I'd like to see a solution to allow the separation of tags. My initial thoughts are to have a field in the tag table that describes if the tag is for performers or media.

However, it was mentioned in the discord that some people want to separate the media category even further to specify a tag for galleries, scenes, or images individually. I haven't given this one much thought so maybe someone else can comment to clarify.

On a specific tag page, when clicking on edit, I suggest:

AdultSun commented 3 years ago

Hi, I was the one from Discord who brought up concerns about lumping all media types together for this proposal.

I've been playing around with the tags in my Stash instance lately and have already created tags that are exclusive to Images and Galleries. For me, I've been playing with tags for general categories (Hardcore, Softcore, Portraits), states of dress (Clothed, Topless, Nude), and pose (Standing, Sitting, Kneeling). Those last two groups have also been used for Markers, but their utility for Scenes and Performers is slim to none. If Studios or Movies ever saw tags added to them, I can think of a few exclusive tags for them as well.

All this is to say that I feel each form of media is different enough that it would be worth preserving the ability to assign tags as exclusive to each of them, rather than keeping it strictly Performer/Media/Both, assuming there aren't any unforeseen complications with this implementation.

CosimoVestri commented 3 years ago

Perhaps I can refine the problem a bit.

@QxxxGit refers to "higher-level objects." Looking at the database structure, there is no concept of higher- or lower-level objects.

There is a single tags table listing all of the tags. There are tables for scenes, scene_markers, performers, galleries, images. (I'll refer to these as item tables) A many-to-many relationship between tags and item tables is implemented in the form of junction tables mapping tags to items in the item tables (specifically: galleries_tags, images_tags, performers_tags, scene_marker_tags, scenes_tags). This is an efficient, normalized approach. It does not, however, allow for the requested feature to be implemented.

So @QxxxGit proposes separating tags for each category. So a particular tag is valid only for particular categories. They also bring out the problem that can arise by having completely separate categories. It. doesn't work for all use cases. Some would want the same tag available for different types of items.

So we can't create separate tag tables for each type of object. Specifically adding a field in the tag table that describes the valid object type also doesn't really provide a good solution to the problem.

I've been racking my brain on how to come up with a solution that works for a SQL relational database. Pretty much everything that I can think of is fairly bad when it comes to efficiency and query time.

One possible option that allows for multiple use cases is that for each tag we can specify all of the user-defined categories the tag is valid for. In each tag, I suppose this could be accomplished by using a single field as a bitmap, or creating a bunch of boolean fields for each of the valid object types. Intuitively, this would be fairly simple to implement; however, my questions are would this be efficient and would it scale well?

I'm also interested in this feature, but I can't figure out how I'd implement it.

stg-annon commented 3 years ago

Specifically adding a field in the tag table that describes the valid object type also doesn't really provide a good solution to the problem.

I think this could as the problem seems to be with cluttering the interface and this could just enable proper filters for a tag, where on the DB side every tag still has a many-to-many relationship with all the tables it currently does it just allows the interface to filter out irrelevant tags when assigning them to a specific object type, this could either come in a very crude form of a single field that would hold all valid object types or None as a default value making the tag universal as it is now.

It would seem like the following would be acceptable but perhaps I'm wrong

SELECT * FROM tags WHERE type LIKE %<type_identifier>%

would this not allow filtering by type of tag?

CosimoVestri commented 3 years ago

SELECT * FROM tags WHERE type LIKE %<type_identifier>%

would this not allow filtering by type of tag?

It certainly would. There would be a performance penalty that could be nontrivial, though.

Avoiding leading wildcards in LIKE clauses is generally a good idea.

stg-annon commented 3 years ago

for a bitmap are you suggesting something like the following?

object_type_bitmap_idx: object_type bitmap_idx
scenes 0
scene_markers 1
performers 2
galleries 3
images 4

filter tags by scene tags:

SELECT id, SUBSTRING(types, 0, 1) as "isSceneTag"
FROM tags
WHERE isSceneTag= 1

where tags types column might look like this

types
10000
00110
11100
00000
10101

If performance is the major concern would another junction table of tag_id=> object_type_id not be preferable

E,X.

CREATE TABLE "tag_types" (
    "tag_id"    INTEGER,
    "object_type_id"    INTEGER,
    PRIMARY KEY("tag_id","object_type_id")
)

where tag types can just be found via lookup in this table, where this would only require the addition of two new tables (object_types, tag_types) and should scale

CosimoVestri commented 3 years ago

If performance is the major concern would another junction table of tag_id=> object_type_id not be preferable

In comparison to a bitmap, not sure. But with another junction table, that would result in additional queries, wouldn't it?

I mean on the one hand, we're just talking about a private collection. How large can it be? Do we even need to worry about performance? On the other hand, best practices, scalability, extensibility, and maintainability are things to always strive for.

Edit: bitmaps don't do wonders for extensibility and maintainability.