Skip to content

Commit

Permalink
[Files Refactor] Filter and sort by file count (#2744)
Browse files Browse the repository at this point in the history
* Add filtering on file count
* Add sorting by file count
  • Loading branch information
WithoutPants authored Jul 14, 2022
1 parent 62a2224 commit bde922d
Show file tree
Hide file tree
Showing 17 changed files with 85 additions and 14 deletions.
6 changes: 6 additions & 0 deletions graphql/schema/types/filters.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ input SceneFilterType {
phash: StringCriterionInput
"""Filter by path"""
path: StringCriterionInput
"""Filter by file count"""
file_count: IntCriterionInput
"""Filter by rating"""
rating: IntCriterionInput
"""Filter by organized"""
Expand Down Expand Up @@ -239,6 +241,8 @@ input GalleryFilterType {
checksum: StringCriterionInput
"""Filter by path"""
path: StringCriterionInput
"""Filter by zip-file count"""
file_count: IntCriterionInput
"""Filter to only include galleries missing this property"""
is_missing: String
"""Filter to include/exclude galleries that were created from zip"""
Expand Down Expand Up @@ -327,6 +331,8 @@ input ImageFilterType {
checksum: StringCriterionInput
"""Filter by path"""
path: StringCriterionInput
"""Filter by file count"""
file_count: IntCriterionInput
"""Filter by rating"""
rating: IntCriterionInput
"""Filter by organized"""
Expand Down
2 changes: 2 additions & 0 deletions pkg/models/gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type GalleryFilterType struct {
Checksum *StringCriterionInput `json:"checksum"`
// Filter by path
Path *StringCriterionInput `json:"path"`
// Filter by zip file count
FileCount *IntCriterionInput `json:"file_count"`
// Filter to only include galleries missing this property
IsMissing *string `json:"is_missing"`
// Filter to include/exclude galleries that were created from zip
Expand Down
2 changes: 2 additions & 0 deletions pkg/models/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ type ImageFilterType struct {
Checksum *StringCriterionInput `json:"checksum"`
// Filter by path
Path *StringCriterionInput `json:"path"`
// Filter by file count
FileCount *IntCriterionInput `json:"file_count"`
// Filter by rating
Rating *IntCriterionInput `json:"rating"`
// Filter by organized
Expand Down
2 changes: 2 additions & 0 deletions pkg/models/scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ type SceneFilterType struct {
Phash *StringCriterionInput `json:"phash"`
// Filter by path
Path *StringCriterionInput `json:"path"`
// Filter by file count
FileCount *IntCriterionInput `json:"file_count"`
// Filter by rating
Rating *IntCriterionInput `json:"rating"`
// Filter by organized
Expand Down
13 changes: 13 additions & 0 deletions pkg/sqlite/gallery.go
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ func (qb *GalleryStore) makeFilter(ctx context.Context, galleryFilter *models.Ga
}))

query.handleCriterion(ctx, pathCriterionHandler(galleryFilter.Path, "galleries_query.parent_folder_path", "galleries_query.basename"))
query.handleCriterion(ctx, galleryFileCountCriterionHandler(qb, galleryFilter.FileCount))
query.handleCriterion(ctx, intCriterionHandler(galleryFilter.Rating, "galleries.rating"))
query.handleCriterion(ctx, stringCriterionHandler(galleryFilter.URL, "galleries.url"))
query.handleCriterion(ctx, boolCriterionHandler(galleryFilter.Organized, "galleries.organized"))
Expand Down Expand Up @@ -683,6 +684,16 @@ func (qb *GalleryStore) QueryCount(ctx context.Context, galleryFilter *models.Ga
return query.executeCount(ctx)
}

func galleryFileCountCriterionHandler(qb *GalleryStore, fileCount *models.IntCriterionInput) criterionHandlerFunc {
h := countCriterionHandlerBuilder{
primaryTable: galleryTable,
joinTable: galleriesFilesTable,
primaryFK: galleryIDColumn,
}

return h.handler(fileCount)
}

func galleryIsMissingCriterionHandler(qb *GalleryStore, isMissing *string) criterionHandlerFunc {
return func(ctx context.Context, f *filterBuilder) {
if isMissing != nil && *isMissing != "" {
Expand Down Expand Up @@ -897,6 +908,8 @@ func (qb *GalleryStore) getGallerySort(findFilter *models.FindFilterType) string
}

switch sort {
case "file_count":
return getCountSort(galleryTable, galleriesFilesTable, galleryIDColumn, direction)
case "images_count":
return getCountSort(galleryTable, galleriesImagesTable, galleryIDColumn, direction)
case "tag_count":
Expand Down
13 changes: 13 additions & 0 deletions pkg/sqlite/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@ func (qb *ImageStore) makeFilter(ctx context.Context, imageFilter *models.ImageF
query.handleCriterion(ctx, stringCriterionHandler(imageFilter.Title, "images.title"))

query.handleCriterion(ctx, pathCriterionHandler(imageFilter.Path, "images_query.parent_folder_path", "images_query.basename"))
query.handleCriterion(ctx, imageFileCountCriterionHandler(qb, imageFilter.FileCount))
query.handleCriterion(ctx, intCriterionHandler(imageFilter.Rating, "images.rating"))
query.handleCriterion(ctx, intCriterionHandler(imageFilter.OCounter, "images.o_counter"))
query.handleCriterion(ctx, boolCriterionHandler(imageFilter.Organized, "images.organized"))
Expand Down Expand Up @@ -689,6 +690,16 @@ func (qb *ImageStore) QueryCount(ctx context.Context, imageFilter *models.ImageF
return query.executeCount(ctx)
}

func imageFileCountCriterionHandler(qb *ImageStore, fileCount *models.IntCriterionInput) criterionHandlerFunc {
h := countCriterionHandlerBuilder{
primaryTable: imageTable,
joinTable: imagesFilesTable,
primaryFK: imageIDColumn,
}

return h.handler(fileCount)
}

func imageIsMissingCriterionHandler(qb *ImageStore, isMissing *string) criterionHandlerFunc {
return func(ctx context.Context, f *filterBuilder) {
if isMissing != nil && *isMissing != "" {
Expand Down Expand Up @@ -869,6 +880,8 @@ func (qb *ImageStore) getImageSort(findFilter *models.FindFilterType) string {
switch sort {
case "path":
return " ORDER BY images_query.parent_folder_path " + direction + ", images_query.basename " + direction
case "file_count":
return getCountSort(imageTable, imagesFilesTable, imageIDColumn, direction)
case "tag_count":
return getCountSort(imageTable, imagesTagsTable, imageIDColumn, direction)
case "performer_count":
Expand Down
13 changes: 13 additions & 0 deletions pkg/sqlite/scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,7 @@ func (qb *SceneStore) makeFilter(ctx context.Context, sceneFilter *models.SceneF
}

query.handleCriterion(ctx, pathCriterionHandler(sceneFilter.Path, "scenes_query.parent_folder_path", "scenes_query.basename"))
query.handleCriterion(ctx, sceneFileCountCriterionHandler(qb, sceneFilter.FileCount))
query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Title, "scenes.title"))
query.handleCriterion(ctx, stringCriterionHandler(sceneFilter.Details, "scenes.details"))
query.handleCriterion(ctx, criterionHandlerFunc(func(ctx context.Context, f *filterBuilder) {
Expand Down Expand Up @@ -916,6 +917,16 @@ func (qb *SceneStore) queryGroupedFields(ctx context.Context, options models.Sce
return ret, nil
}

func sceneFileCountCriterionHandler(qb *SceneStore, fileCount *models.IntCriterionInput) criterionHandlerFunc {
h := countCriterionHandlerBuilder{
primaryTable: sceneTable,
joinTable: scenesFilesTable,
primaryFK: sceneIDColumn,
}

return h.handler(fileCount)
}

func scenePhashDuplicatedCriterionHandler(duplicatedFilter *models.PHashDuplicationCriterionInput) criterionHandlerFunc {
return func(ctx context.Context, f *filterBuilder) {
// TODO: Wishlist item: Implement Distance matching
Expand Down Expand Up @@ -1204,6 +1215,8 @@ func (qb *SceneStore) setSceneSort(query *queryBuilder, findFilter *models.FindF
query.sortAndPagination += getCountSort(sceneTable, scenesTagsTable, sceneIDColumn, direction)
case "performer_count":
query.sortAndPagination += getCountSort(sceneTable, performersScenesTable, sceneIDColumn, direction)
case "file_count":
query.sortAndPagination += getCountSort(sceneTable, scenesFilesTable, sceneIDColumn, direction)
case "path":
// special handling for path
query.sortAndPagination += fmt.Sprintf(" ORDER BY scenes_query.parent_folder_path %s, scenes_query.basename %[1]s", direction)
Expand Down
7 changes: 4 additions & 3 deletions ui/v2.5/src/docs/en/Changelog/v0170.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ After migrating, please run a scan on your entire library to populate missing da
Please report all issues to the following Github issue: https://github.com/stashapp/stash/issues/2737

### 💥 Known issues
* import/export functionality is currently disabled. Needs further design.
* missing covers are not currently regenerated. Need to consider further, especially around scene cover redesign.
* deleting galleries is currently slow.
* Import/export functionality is currently disabled. Needs further design.
* Missing covers are not currently regenerated. Need to consider further, especially around scene cover redesign.
* Deleting galleries is currently slow.
* Don't include file extension as part of the title scan flag is not supported.
* Set name, date, details from embedded file metadata scan flag is not supported.

### ✨ New Features
* Added support for identical files. Identical files are assigned to the same scene/gallery/image and can be viewed in File Info. ([#2676](https://github.com/stashapp/stash/pull/2676))
* Added support for filtering and sorting by file count. ([#2744](https://github.com/stashapp/stash/pull/2744))
* Added release notes dialog. ([#2726](https://github.com/stashapp/stash/pull/2726))

### 🎨 Improvements
Expand Down
2 changes: 1 addition & 1 deletion ui/v2.5/src/docs/en/ReleaseNotes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface IReleaseNotes {

export const releaseNotes: IReleaseNotes[] = [
{
date: 20220707,
date: 20220715,
content: v0170,
},
];
7 changes: 4 additions & 3 deletions ui/v2.5/src/docs/en/ReleaseNotes/v0170.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ After migrating, please run a scan on your entire library to populate missing da
Please report all issues to the following Github issue: https://github.com/stashapp/stash/issues/2737

### 💥 Known issues
* import/export functionality is currently disabled. Needs further design.
* missing covers are not currently regenerated. Need to consider further, especially around scene cover redesign.
* deleting galleries is currently slow.
* Import/export functionality is currently disabled. Needs further design.
* Missing covers are not currently regenerated. Need to consider further, especially around scene cover redesign.
* Deleting galleries is currently slow.
* Don't include file extension as part of the title scan flag is not supported.
* Set name, date, details from embedded file metadata scan flag is not supported.

### Other changes:

* Added support for filtering and sorting by file count. ([#2744](https://github.com/stashapp/stash/pull/2744))
* Changelog has been moved from the stats page to a section in the Settings page.
4 changes: 3 additions & 1 deletion ui/v2.5/src/locales/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@
"false": "False",
"favourite": "Favourite",
"file": "file",
"file_count": "File Count",
"file_info": "File Info",
"file_mod_time": "File Modification Time",
"files": "files",
Expand Down Expand Up @@ -1024,5 +1025,6 @@
"videos": "Videos",
"view_all": "View All",
"weight": "Weight",
"years_old": "years old"
"years_old": "years old",
"zip_file_count": "Zip File Count"
}
7 changes: 5 additions & 2 deletions ui/v2.5/src/models/list-filter/criteria/criterion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,11 @@ export class MandatoryNumberCriterionOption extends CriterionOption {
}
}

export function createMandatoryNumberCriterionOption(value: CriterionType) {
return new MandatoryNumberCriterionOption(value, value, value);
export function createMandatoryNumberCriterionOption(
value: CriterionType,
messageID?: string
) {
return new MandatoryNumberCriterionOption(messageID ?? value, value, value);
}

export class DurationCriterion extends Criterion<INumberValue> {
Expand Down
1 change: 1 addition & 0 deletions ui/v2.5/src/models/list-filter/criteria/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export function makeCriteria(type: CriterionType = "none") {
case "performer_count":
case "performer_age":
case "tag_count":
case "file_count":
return new NumberCriterion(
new MandatoryNumberCriterionOption(type, type)
);
Expand Down
5 changes: 5 additions & 0 deletions ui/v2.5/src/models/list-filter/galleries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const sortByOptions = ["date", ...MediaSortByOptions]
messageID: "image_count",
value: "images_count",
},
{
messageID: "zip_file_count",
value: "file_count",
},
]);

const displayModeOptions = [
Expand Down Expand Up @@ -56,6 +60,7 @@ const criterionOptions = [
createStringCriterionOption("image_count"),
StudiosCriterionOption,
createStringCriterionOption("url"),
createMandatoryNumberCriterionOption("file_count", "zip_file_count"),
];

export const GalleryListFilterOptions = new ListFilterOptions(
Expand Down
10 changes: 7 additions & 3 deletions ui/v2.5/src/models/list-filter/images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ import { DisplayMode } from "./types";

const defaultSortBy = "path";

const sortByOptions = ["o_counter", "filesize", ...MediaSortByOptions].map(
ListFilterOptions.createSortBy
);
const sortByOptions = [
"o_counter",
"filesize",
"file_count",
...MediaSortByOptions,
].map(ListFilterOptions.createSortBy);

const displayModeOptions = [DisplayMode.Grid, DisplayMode.Wall];
const criterionOptions = [
Expand All @@ -41,6 +44,7 @@ const criterionOptions = [
createMandatoryNumberCriterionOption("performer_age"),
PerformerFavoriteCriterionOption,
StudiosCriterionOption,
createMandatoryNumberCriterionOption("file_count"),
];
export const ImageListFilterOptions = new ListFilterOptions(
defaultSortBy,
Expand Down
2 changes: 2 additions & 0 deletions ui/v2.5/src/models/list-filter/scenes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const sortByOptions = [
"organized",
"o_counter",
"date",
"file_count",
"filesize",
"duration",
"framerate",
Expand Down Expand Up @@ -81,6 +82,7 @@ const criterionOptions = [
InteractiveCriterionOption,
CaptionsCriterionOption,
createMandatoryNumberCriterionOption("interactive_speed"),
createMandatoryNumberCriterionOption("file_count"),
];

export const SceneListFilterOptions = new ListFilterOptions(
Expand Down
3 changes: 2 additions & 1 deletion ui/v2.5/src/models/list-filter/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,5 @@ export type CriterionType =
| "performer_favorite"
| "performer_age"
| "duplicated"
| "ignore_auto_tag";
| "ignore_auto_tag"
| "file_count";

0 comments on commit bde922d

Please sign in to comment.