mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 20:07:05 +03:00
Added Sort Performers by Last O At / Last Played At / Play Count and Added Filter Performers by Play Count. Changes to display O Count rather than O-Counter for better consistency. Grammar fixes for 'Interactive Speed' and 'pHash'. (#4649)
* Sort Performers by Last O / View Added 2 New Sorts 'Last O At' and 'Last Played At' for Performers * Filter Performers by Play Count Was not sure whether to label this 'views' as the code does, or 'plays' but chose the latter as it gives parity across the scenes and performers filters. * Sort Performers by Play Count Reutilised the prior selectPerformerLastOAtSQL code that was used to filter by play count to additionally provide useful sorting options. * Replaced O-Counter with O Count To better match other sort and filter options like Gallery Count, Image Count, Play Count, Scene Count, Tag Count, File Count, Performer Count and Play Count, we should really use O Count rather than O-Counter for increased legibility and coherence. * Title Case on 'Interactive speed' and correct capitalization for 'phash' Every other filter/sort option is using Title Case other than 'Interactive speed' which stands out as incorrect. Also, fixing the correct mid-word capitalization on phash to pHash. * Formatting Formatted source code and Ran all tests
This commit is contained in:
@@ -143,6 +143,8 @@ input PerformerFilterType {
|
|||||||
image_count: IntCriterionInput
|
image_count: IntCriterionInput
|
||||||
"Filter by gallery count"
|
"Filter by gallery count"
|
||||||
gallery_count: IntCriterionInput
|
gallery_count: IntCriterionInput
|
||||||
|
"Filter by play count"
|
||||||
|
play_count: IntCriterionInput
|
||||||
"Filter by o count"
|
"Filter by o count"
|
||||||
o_counter: IntCriterionInput
|
o_counter: IntCriterionInput
|
||||||
"Filter by StashID"
|
"Filter by StashID"
|
||||||
|
|||||||
@@ -160,6 +160,8 @@ type PerformerFilterType struct {
|
|||||||
ImageCount *IntCriterionInput `json:"image_count"`
|
ImageCount *IntCriterionInput `json:"image_count"`
|
||||||
// Filter by gallery count
|
// Filter by gallery count
|
||||||
GalleryCount *IntCriterionInput `json:"gallery_count"`
|
GalleryCount *IntCriterionInput `json:"gallery_count"`
|
||||||
|
// Filter by play count
|
||||||
|
PlayCount *IntCriterionInput `json:"play_count"`
|
||||||
// Filter by O count
|
// Filter by O count
|
||||||
OCounter *IntCriterionInput `json:"o_counter"`
|
OCounter *IntCriterionInput `json:"o_counter"`
|
||||||
// Filter by StashID
|
// Filter by StashID
|
||||||
|
|||||||
@@ -670,6 +670,7 @@ func (qb *PerformerStore) makeFilter(ctx context.Context, filter *models.Perform
|
|||||||
query.handleCriterion(ctx, performerSceneCountCriterionHandler(qb, filter.SceneCount))
|
query.handleCriterion(ctx, performerSceneCountCriterionHandler(qb, filter.SceneCount))
|
||||||
query.handleCriterion(ctx, performerImageCountCriterionHandler(qb, filter.ImageCount))
|
query.handleCriterion(ctx, performerImageCountCriterionHandler(qb, filter.ImageCount))
|
||||||
query.handleCriterion(ctx, performerGalleryCountCriterionHandler(qb, filter.GalleryCount))
|
query.handleCriterion(ctx, performerGalleryCountCriterionHandler(qb, filter.GalleryCount))
|
||||||
|
query.handleCriterion(ctx, performerPlayCounterCriterionHandler(qb, filter.PlayCount))
|
||||||
query.handleCriterion(ctx, performerOCounterCriterionHandler(qb, filter.OCounter))
|
query.handleCriterion(ctx, performerOCounterCriterionHandler(qb, filter.OCounter))
|
||||||
query.handleCriterion(ctx, dateCriterionHandler(filter.Birthdate, tableName+".birthdate"))
|
query.handleCriterion(ctx, dateCriterionHandler(filter.Birthdate, tableName+".birthdate"))
|
||||||
query.handleCriterion(ctx, dateCriterionHandler(filter.DeathDate, tableName+".death_date"))
|
query.handleCriterion(ctx, dateCriterionHandler(filter.DeathDate, tableName+".death_date"))
|
||||||
@@ -874,6 +875,63 @@ var selectPerformerOCountSQL = utils.StrFormat(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// used for sorting and filtering play count on performer view count
|
||||||
|
var selectPerformerPlayCountSQL = utils.StrFormat(
|
||||||
|
"SELECT COUNT(DISTINCT {view_date}) FROM ("+
|
||||||
|
"SELECT {view_date} FROM {performers_scenes} s "+
|
||||||
|
"LEFT JOIN {scenes} ON {scenes}.id = s.{scene_id} "+
|
||||||
|
"LEFT JOIN {scenes_view_dates} ON {scenes_view_dates}.{scene_id} = {scenes}.id "+
|
||||||
|
"WHERE s.{performer_id} = {performers}.id"+
|
||||||
|
")",
|
||||||
|
map[string]interface{}{
|
||||||
|
"performer_id": performerIDColumn,
|
||||||
|
"performers": performerTable,
|
||||||
|
"performers_scenes": performersScenesTable,
|
||||||
|
"scenes": sceneTable,
|
||||||
|
"scene_id": sceneIDColumn,
|
||||||
|
"scenes_view_dates": scenesViewDatesTable,
|
||||||
|
"view_date": sceneViewDateColumn,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// used for sorting on performer last o_date
|
||||||
|
var selectPerformerLastOAtSQL = utils.StrFormat(
|
||||||
|
"SELECT MAX(o_date) FROM ("+
|
||||||
|
"SELECT {o_date} FROM {performers_scenes} s "+
|
||||||
|
"LEFT JOIN {scenes} ON {scenes}.id = s.{scene_id} "+
|
||||||
|
"LEFT JOIN {scenes_o_dates} ON {scenes_o_dates}.{scene_id} = {scenes}.id "+
|
||||||
|
"WHERE s.{performer_id} = {performers}.id"+
|
||||||
|
")",
|
||||||
|
map[string]interface{}{
|
||||||
|
"performer_id": performerIDColumn,
|
||||||
|
"performers": performerTable,
|
||||||
|
"performers_scenes": performersScenesTable,
|
||||||
|
"scenes": sceneTable,
|
||||||
|
"scene_id": sceneIDColumn,
|
||||||
|
"scenes_o_dates": scenesODatesTable,
|
||||||
|
"o_date": sceneODateColumn,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// used for sorting on performer last view_date
|
||||||
|
var selectPerformerLastPlayedAtSQL = utils.StrFormat(
|
||||||
|
"SELECT MAX(view_date) FROM ("+
|
||||||
|
"SELECT {view_date} FROM {performers_scenes} s "+
|
||||||
|
"LEFT JOIN {scenes} ON {scenes}.id = s.{scene_id} "+
|
||||||
|
"LEFT JOIN {scenes_view_dates} ON {scenes_view_dates}.{scene_id} = {scenes}.id "+
|
||||||
|
"WHERE s.{performer_id} = {performers}.id"+
|
||||||
|
")",
|
||||||
|
map[string]interface{}{
|
||||||
|
"performer_id": performerIDColumn,
|
||||||
|
"performers": performerTable,
|
||||||
|
"performers_scenes": performersScenesTable,
|
||||||
|
"scenes": sceneTable,
|
||||||
|
"scene_id": sceneIDColumn,
|
||||||
|
"scenes_view_dates": scenesViewDatesTable,
|
||||||
|
"view_date": sceneViewDateColumn,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
func performerOCounterCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
func performerOCounterCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||||
return func(ctx context.Context, f *filterBuilder) {
|
return func(ctx context.Context, f *filterBuilder) {
|
||||||
if count == nil {
|
if count == nil {
|
||||||
@@ -887,6 +945,19 @@ func performerOCounterCriterionHandler(qb *PerformerStore, count *models.IntCrit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func performerPlayCounterCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||||
|
return func(ctx context.Context, f *filterBuilder) {
|
||||||
|
if count == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs := "(" + selectPerformerPlayCountSQL + ")"
|
||||||
|
clause, args := getIntCriterionWhereClause(lhs, *count)
|
||||||
|
|
||||||
|
f.addWhere(clause, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func performerStudiosCriterionHandler(qb *PerformerStore, studios *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
func performerStudiosCriterionHandler(qb *PerformerStore, studios *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||||
return func(ctx context.Context, f *filterBuilder) {
|
return func(ctx context.Context, f *filterBuilder) {
|
||||||
if studios != nil {
|
if studios != nil {
|
||||||
@@ -1027,6 +1098,21 @@ func (qb *PerformerStore) sortByOCounter(direction string) string {
|
|||||||
return " ORDER BY (" + selectPerformerOCountSQL + ") " + direction
|
return " ORDER BY (" + selectPerformerOCountSQL + ") " + direction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) sortByPlayCount(direction string) string {
|
||||||
|
// need to sum the o_counter from scenes and images
|
||||||
|
return " ORDER BY (" + selectPerformerPlayCountSQL + ") " + direction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) sortByLastOAt(direction string) string {
|
||||||
|
// need to get the o_dates from scenes
|
||||||
|
return " ORDER BY (" + selectPerformerLastOAtSQL + ") " + direction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) sortByLastPlayedAt(direction string) string {
|
||||||
|
// need to get the view_dates from scenes
|
||||||
|
return " ORDER BY (" + selectPerformerLastPlayedAtSQL + ") " + direction
|
||||||
|
}
|
||||||
|
|
||||||
func (qb *PerformerStore) getPerformerSort(findFilter *models.FindFilterType) string {
|
func (qb *PerformerStore) getPerformerSort(findFilter *models.FindFilterType) string {
|
||||||
var sort string
|
var sort string
|
||||||
var direction string
|
var direction string
|
||||||
@@ -1048,8 +1134,14 @@ func (qb *PerformerStore) getPerformerSort(findFilter *models.FindFilterType) st
|
|||||||
sortQuery += getCountSort(performerTable, performersImagesTable, performerIDColumn, direction)
|
sortQuery += getCountSort(performerTable, performersImagesTable, performerIDColumn, direction)
|
||||||
case "galleries_count":
|
case "galleries_count":
|
||||||
sortQuery += getCountSort(performerTable, performersGalleriesTable, performerIDColumn, direction)
|
sortQuery += getCountSort(performerTable, performersGalleriesTable, performerIDColumn, direction)
|
||||||
|
case "play_count":
|
||||||
|
sortQuery += qb.sortByPlayCount(direction)
|
||||||
case "o_counter":
|
case "o_counter":
|
||||||
sortQuery += qb.sortByOCounter(direction)
|
sortQuery += qb.sortByOCounter(direction)
|
||||||
|
case "last_played_at":
|
||||||
|
sortQuery += qb.sortByLastPlayedAt(direction)
|
||||||
|
case "last_o_at":
|
||||||
|
sortQuery += qb.sortByLastOAt(direction)
|
||||||
default:
|
default:
|
||||||
sortQuery += getSort(sort, direction, "performers")
|
sortQuery += getSort(sort, direction, "performers")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ export const PerformerListTable: React.FC<IPerformerListTableProps> = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "o_counter",
|
value: "o_counter",
|
||||||
label: intl.formatMessage({ id: "o_counter" }),
|
label: intl.formatMessage({ id: "o_count" }),
|
||||||
defaultShow: true,
|
defaultShow: true,
|
||||||
render: OCounterCell,
|
render: OCounterCell,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ export const SceneListTable: React.FC<ISceneListTableProps> = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "o_counter",
|
value: "o_counter",
|
||||||
label: intl.formatMessage({ id: "o_counter" }),
|
label: intl.formatMessage({ id: "o_count" }),
|
||||||
render: (s) => <>{s.o_counter}</>,
|
render: (s) => <>{s.o_counter}</>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
onChange={(value) => setRating(value)}
|
onChange={(value) => setRating(value)}
|
||||||
/>
|
/>
|
||||||
<ScrapeDialogRow
|
<ScrapeDialogRow
|
||||||
title={intl.formatMessage({ id: "o_counter" })}
|
title={intl.formatMessage({ id: "o_count" })}
|
||||||
result={oCounter}
|
result={oCounter}
|
||||||
renderOriginalField={() => (
|
renderOriginalField={() => (
|
||||||
<FormControl
|
<FormControl
|
||||||
|
|||||||
@@ -971,7 +971,7 @@
|
|||||||
"select_youngest": "Select the youngest file in the duplicate group",
|
"select_youngest": "Select the youngest file in the duplicate group",
|
||||||
"title": "Duplicate Scenes"
|
"title": "Duplicate Scenes"
|
||||||
},
|
},
|
||||||
"duplicated_phash": "Duplicated (phash)",
|
"duplicated_phash": "Duplicated (pHash)",
|
||||||
"duration": "Duration",
|
"duration": "Duration",
|
||||||
"effect_filters": {
|
"effect_filters": {
|
||||||
"aspect": "Aspect",
|
"aspect": "Aspect",
|
||||||
@@ -1066,7 +1066,7 @@
|
|||||||
"index_of_total": "{index} of {total}",
|
"index_of_total": "{index} of {total}",
|
||||||
"instagram": "Instagram",
|
"instagram": "Instagram",
|
||||||
"interactive": "Interactive",
|
"interactive": "Interactive",
|
||||||
"interactive_speed": "Interactive speed",
|
"interactive_speed": "Interactive Speed",
|
||||||
"isMissing": "Is Missing",
|
"isMissing": "Is Missing",
|
||||||
"last_o_at": "Last O At",
|
"last_o_at": "Last O At",
|
||||||
"last_played_at": "Last Played At",
|
"last_played_at": "Last Played At",
|
||||||
@@ -1082,7 +1082,7 @@
|
|||||||
"checksum": "Checksum",
|
"checksum": "Checksum",
|
||||||
"downloaded_from": "Downloaded From",
|
"downloaded_from": "Downloaded From",
|
||||||
"hash": "Hash",
|
"hash": "Hash",
|
||||||
"interactive_speed": "Interactive speed",
|
"interactive_speed": "Interactive Speed",
|
||||||
"o_count": "O Count",
|
"o_count": "O Count",
|
||||||
"performer_card": {
|
"performer_card": {
|
||||||
"age": "{age} {years_old}",
|
"age": "{age} {years_old}",
|
||||||
@@ -1102,6 +1102,7 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"new": "New",
|
"new": "New",
|
||||||
"none": "None",
|
"none": "None",
|
||||||
|
"o_count": "O Count",
|
||||||
"o_counter": "O-Counter",
|
"o_counter": "O-Counter",
|
||||||
"o_history": "O History",
|
"o_history": "O History",
|
||||||
"odate_recorded_no": "No O Date Recorded",
|
"odate_recorded_no": "No O Date Recorded",
|
||||||
@@ -1155,7 +1156,7 @@
|
|||||||
"penis": "Penis",
|
"penis": "Penis",
|
||||||
"penis_length": "Penis Length",
|
"penis_length": "Penis Length",
|
||||||
"penis_length_cm": "Penis Length (cm)",
|
"penis_length_cm": "Penis Length (cm)",
|
||||||
"perceptual_similarity": "Perceptual Similarity (phash)",
|
"perceptual_similarity": "Perceptual Similarity (pHash)",
|
||||||
"performer": "Performer",
|
"performer": "Performer",
|
||||||
"performer_age": "Performer Age",
|
"performer_age": "Performer Age",
|
||||||
"performer_count": "Performer Count",
|
"performer_count": "Performer Count",
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ import { GalleriesCriterionOption } from "./criteria/galleries";
|
|||||||
|
|
||||||
const defaultSortBy = "path";
|
const defaultSortBy = "path";
|
||||||
|
|
||||||
const sortByOptions = [
|
const sortByOptions = ["filesize", "file_count", "date", ...MediaSortByOptions]
|
||||||
"o_counter",
|
.map(ListFilterOptions.createSortBy)
|
||||||
"filesize",
|
.concat([
|
||||||
"file_count",
|
{
|
||||||
"date",
|
messageID: "o_count",
|
||||||
...MediaSortByOptions,
|
value: "o_counter",
|
||||||
].map(ListFilterOptions.createSortBy);
|
},
|
||||||
|
]);
|
||||||
const displayModeOptions = [DisplayMode.Grid, DisplayMode.Wall];
|
const displayModeOptions = [DisplayMode.Grid, DisplayMode.Wall];
|
||||||
const criterionOptions = [
|
const criterionOptions = [
|
||||||
createStringCriterionOption("title"),
|
createStringCriterionOption("title"),
|
||||||
@@ -42,7 +42,7 @@ const criterionOptions = [
|
|||||||
PathCriterionOption,
|
PathCriterionOption,
|
||||||
GalleriesCriterionOption,
|
GalleriesCriterionOption,
|
||||||
OrganizedCriterionOption,
|
OrganizedCriterionOption,
|
||||||
createMandatoryNumberCriterionOption("o_counter"),
|
createMandatoryNumberCriterionOption("o_counter", "o_count"),
|
||||||
ResolutionCriterionOption,
|
ResolutionCriterionOption,
|
||||||
OrientationCriterionOption,
|
OrientationCriterionOption,
|
||||||
ImageIsMissingCriterionOption,
|
ImageIsMissingCriterionOption,
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ const sortByOptions = [
|
|||||||
"random",
|
"random",
|
||||||
"rating",
|
"rating",
|
||||||
"penis_length",
|
"penis_length",
|
||||||
|
"play_count",
|
||||||
|
"last_played_at",
|
||||||
|
"last_o_at",
|
||||||
]
|
]
|
||||||
.map(ListFilterOptions.createSortBy)
|
.map(ListFilterOptions.createSortBy)
|
||||||
.concat([
|
.concat([
|
||||||
@@ -43,7 +46,7 @@ const sortByOptions = [
|
|||||||
value: "galleries_count",
|
value: "galleries_count",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
messageID: "o_counter",
|
messageID: "o_count",
|
||||||
value: "o_counter",
|
value: "o_counter",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -91,7 +94,8 @@ const criterionOptions = [
|
|||||||
createMandatoryNumberCriterionOption("scene_count"),
|
createMandatoryNumberCriterionOption("scene_count"),
|
||||||
createMandatoryNumberCriterionOption("image_count"),
|
createMandatoryNumberCriterionOption("image_count"),
|
||||||
createMandatoryNumberCriterionOption("gallery_count"),
|
createMandatoryNumberCriterionOption("gallery_count"),
|
||||||
createMandatoryNumberCriterionOption("o_counter"),
|
createMandatoryNumberCriterionOption("play_count"),
|
||||||
|
createMandatoryNumberCriterionOption("o_counter", "o_count"),
|
||||||
createBooleanCriterionOption("ignore_auto_tag"),
|
createBooleanCriterionOption("ignore_auto_tag"),
|
||||||
CountryCriterionOption,
|
CountryCriterionOption,
|
||||||
createNumberCriterionOption("height_cm", "height"),
|
createNumberCriterionOption("height_cm", "height"),
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import { OrientationCriterionOption } from "./criteria/orientation";
|
|||||||
const defaultSortBy = "date";
|
const defaultSortBy = "date";
|
||||||
const sortByOptions = [
|
const sortByOptions = [
|
||||||
"organized",
|
"organized",
|
||||||
"o_counter",
|
|
||||||
"date",
|
"date",
|
||||||
"file_count",
|
"file_count",
|
||||||
"filesize",
|
"filesize",
|
||||||
@@ -52,8 +51,14 @@ const sortByOptions = [
|
|||||||
"interactive_speed",
|
"interactive_speed",
|
||||||
"perceptual_similarity",
|
"perceptual_similarity",
|
||||||
...MediaSortByOptions,
|
...MediaSortByOptions,
|
||||||
].map(ListFilterOptions.createSortBy);
|
]
|
||||||
|
.map(ListFilterOptions.createSortBy)
|
||||||
|
.concat([
|
||||||
|
{
|
||||||
|
messageID: "o_count",
|
||||||
|
value: "o_counter",
|
||||||
|
},
|
||||||
|
]);
|
||||||
const displayModeOptions = [
|
const displayModeOptions = [
|
||||||
DisplayMode.Grid,
|
DisplayMode.Grid,
|
||||||
DisplayMode.List,
|
DisplayMode.List,
|
||||||
@@ -73,7 +78,7 @@ const criterionOptions = [
|
|||||||
DuplicatedCriterionOption,
|
DuplicatedCriterionOption,
|
||||||
OrganizedCriterionOption,
|
OrganizedCriterionOption,
|
||||||
RatingCriterionOption,
|
RatingCriterionOption,
|
||||||
createMandatoryNumberCriterionOption("o_counter"),
|
createMandatoryNumberCriterionOption("o_counter", "o_count"),
|
||||||
ResolutionCriterionOption,
|
ResolutionCriterionOption,
|
||||||
OrientationCriterionOption,
|
OrientationCriterionOption,
|
||||||
createMandatoryNumberCriterionOption("framerate"),
|
createMandatoryNumberCriterionOption("framerate"),
|
||||||
|
|||||||
Reference in New Issue
Block a user