From 6565544d4d1402f3e480fbc06f98121041b3d3e0 Mon Sep 17 00:00:00 2001 From: Gykes Date: Wed, 14 Aug 2024 19:30:55 -0700 Subject: [PATCH 1/4] File Size Filtering Adding in support for filesize filtering for scenes. --- graphql/schema/types/filters.graphql | 2 ++ pkg/models/scene.go | 2 ++ pkg/sqlite/scene_filter.go | 1 + 3 files changed, 5 insertions(+) diff --git a/graphql/schema/types/filters.graphql b/graphql/schema/types/filters.graphql index d1b16976905..cb4cb312789 100644 --- a/graphql/schema/types/filters.graphql +++ b/graphql/schema/types/filters.graphql @@ -300,6 +300,8 @@ input SceneFilterType { created_at: TimestampCriterionInput "Filter by last update time" updated_at: TimestampCriterionInput + "Filter by file size" + file_size: IntCriterionInput "Filter by related galleries that meet this criteria" galleries_filter: GalleryFilterType diff --git a/pkg/models/scene.go b/pkg/models/scene.go index 814c4a41d62..d4ff218c57a 100644 --- a/pkg/models/scene.go +++ b/pkg/models/scene.go @@ -47,6 +47,8 @@ type SceneFilterType struct { VideoCodec *StringCriterionInput `json:"video_codec"` // Filter by audio codec AudioCodec *StringCriterionInput `json:"audio_codec"` + // Filter by File Size + FileSize *IntCriterionInput `json:"file_size"` // Filter by duration (in seconds) Duration *IntCriterionInput `json:"duration"` // Filter to only include scenes which have markers. `true` or `false` diff --git a/pkg/sqlite/scene_filter.go b/pkg/sqlite/scene_filter.go index 3f2233395fa..4a53a0e95af 100644 --- a/pkg/sqlite/scene_filter.go +++ b/pkg/sqlite/scene_filter.go @@ -96,6 +96,7 @@ func (qb *sceneFilterHandler) criterionHandler() criterionHandler { qb.oCountCriterionHandler(sceneFilter.OCounter), boolCriterionHandler(sceneFilter.Organized, "scenes.organized", nil), + intCriterionHandler(sceneFilter.FileSize, "video_files.FileSize", qb.addVideoFilesTable), floatIntCriterionHandler(sceneFilter.Duration, "video_files.duration", qb.addVideoFilesTable), resolutionCriterionHandler(sceneFilter.Resolution, "video_files.height", "video_files.width", qb.addVideoFilesTable), orientationCriterionHandler(sceneFilter.Orientation, "video_files.height", "video_files.width", qb.addVideoFilesTable), From dc784d4b7d07b7e3c5ac1e667da2e9ebe536ac7b Mon Sep 17 00:00:00 2001 From: Gykes Date: Sat, 17 Aug 2024 13:09:43 -0700 Subject: [PATCH 2/4] Tests for PatchComponent Updating 1 page for Patch Component to make sure i'm not dumb. --- .../Settings/StashConfiguration.tsx | 358 +++++++++--------- 1 file changed, 182 insertions(+), 176 deletions(-) diff --git a/ui/v2.5/src/components/Settings/StashConfiguration.tsx b/ui/v2.5/src/components/Settings/StashConfiguration.tsx index 9680f2b1842..177f164ba06 100644 --- a/ui/v2.5/src/components/Settings/StashConfiguration.tsx +++ b/ui/v2.5/src/components/Settings/StashConfiguration.tsx @@ -7,6 +7,7 @@ import * as GQL from "src/core/generated-graphql"; import { FolderSelectDialog } from "../Shared/FolderSelect/FolderSelectDialog"; import { BooleanSetting } from "./Inputs"; import { SettingSection } from "./SettingSection"; +import { PatchComponent } from "src/patch"; interface IStashProps { index: number; @@ -16,193 +17,198 @@ interface IStashProps { onDelete: () => void; } -const Stash: React.FC = ({ - index, - stash, - onSave, - onEdit, - onDelete, -}) => { - // eslint-disable-next-line - const handleInput = (key: string, value: any) => { - const newObj = { - ...stash, - [key]: value, +export const Stash: React.FC = PatchComponent( + "Stash", + ({ + index, + stash, + onSave, + onEdit, + onDelete, + }) => { + const handleInput = (key: string, value: any) => { + const newObj = { + ...stash, + [key]: value, + }; + onSave(newObj); }; - onSave(newObj); - }; - - const classAdd = index % 2 === 1 ? "bg-dark" : ""; - - return ( - - - {stash.path} - - - {/* NOTE - language is opposite to meaning: - internally exclude flags, displayed as include */} -
-
- -
- handleInput("excludeVideo", !v)} - /> -
- - - -
-
- -
- handleInput("excludeImage", !v)} - /> -
- - - - - - - - onEdit()}> - - - onDelete()}> - - - - - -
- ); -}; - -interface IStashConfigurationProps { - stashes: GQL.StashConfig[]; - setStashes: (v: GQL.StashConfig[]) => void; -} -const StashConfiguration: React.FC = ({ - stashes, - setStashes, -}) => { - const [isCreating, setIsCreating] = useState(false); - const [editingIndex, setEditingIndex] = useState(); - - function onEdit(index: number) { - setEditingIndex(index); - } + const classAdd = index % 2 === 1 ? "bg-dark" : ""; - function onDelete(index: number) { - setStashes(stashes.filter((v, i) => i !== index)); - } - - function onNew() { - setIsCreating(true); - } - - const handleSave = (index: number, stash: GQL.StashConfig) => - setStashes(stashes.map((s, i) => (i === index ? stash : s))); - - return ( - <> - {isCreating ? ( - { - if (v) - setStashes([ - ...stashes, - { - path: v, - excludeVideo: false, - excludeImage: false, - }, - ]); - setIsCreating(false); - }} - /> - ) : undefined} - - {editingIndex !== undefined ? ( - { - if (v) - setStashes( - stashes.map((vv, index) => { - if (index === editingIndex) { - return { - ...vv, - path: v, - }; - } - return vv; - }) - ); - setEditingIndex(undefined); - }} - /> - ) : undefined} - -
- {stashes.length > 0 && ( - -
- -
-
+ return ( + + + {stash.path} + + +
+
-
+ handleInput("excludeVideo", !v)} + /> +
+ + + +
+
- - )} - {stashes.map((stash, index) => ( - handleSave(index, s)} - onEdit={() => onEdit(index)} - onDelete={() => onDelete(index)} - key={stash.path} + handleInput("excludeImage", !v)} + /> +
+ + + + + + + + onEdit()}> + + + onDelete()}> + + + + + +
+ ); + } +); + +interface IStashConfigurationProps { + stashes: GQL.StashConfig[]; + setStashes: (v: GQL.StashConfig[]) => void; +} + +export const StashConfiguration: React.FC = PatchComponent( + "StashConfiguration", + ({ + stashes, + setStashes, + }) => { + const [isCreating, setIsCreating] = useState(false); + const [editingIndex, setEditingIndex] = useState(); + + function onEdit(index: number) { + setEditingIndex(index); + } + + function onDelete(index: number) { + setStashes(stashes.filter((v, i) => i !== index)); + } + + function onNew() { + setIsCreating(true); + } + + const handleSave = (index: number, stash: GQL.StashConfig) => + setStashes(stashes.map((s, i) => (i === index ? stash : s))); + + return ( + <> + {isCreating ? ( + { + if (v) + setStashes([ + ...stashes, + { + path: v, + excludeVideo: false, + excludeImage: false, + }, + ]); + setIsCreating(false); + }} + /> + ) : undefined} + + {editingIndex !== undefined ? ( + { + if (v) + setStashes( + stashes.map((vv, index) => { + if (index === editingIndex) { + return { + ...vv, + path: v, + }; + } + return vv; + }) + ); + setEditingIndex(undefined); + }} /> - ))} - -
- - ); -}; + ) : undefined} + +
+ {stashes.length > 0 && ( + +
+ +
+
+ +
+
+ +
+
+ )} + {stashes.map((stash, index) => ( + handleSave(index, s)} + onEdit={() => onEdit(index)} + onDelete={() => onDelete(index)} + key={stash.path} + /> + ))} + +
+ + ); + } +); interface IStashSetting { value: GQL.StashConfigInput[]; onChange: (v: GQL.StashConfigInput[]) => void; } -export const StashSetting: React.FC = ({ value, onChange }) => { - return ( - - onChange(v)} /> - - ); -}; - -export default StashConfiguration; +export const StashSetting: React.FC = PatchComponent( + "StashSetting", + ({ value, onChange }) => { + return ( + + onChange(v)} /> + + ); + } +); +export default StashConfiguration; \ No newline at end of file From 9676254255d97429f077bd155fba99154d50a401 Mon Sep 17 00:00:00 2001 From: Gykes Date: Sat, 17 Aug 2024 13:16:19 -0700 Subject: [PATCH 3/4] Revert "Tests for PatchComponent" This reverts commit dc784d4b7d07b7e3c5ac1e667da2e9ebe536ac7b. Gonna change it around to look better --- .../Settings/StashConfiguration.tsx | 358 +++++++++--------- 1 file changed, 176 insertions(+), 182 deletions(-) diff --git a/ui/v2.5/src/components/Settings/StashConfiguration.tsx b/ui/v2.5/src/components/Settings/StashConfiguration.tsx index 177f164ba06..9680f2b1842 100644 --- a/ui/v2.5/src/components/Settings/StashConfiguration.tsx +++ b/ui/v2.5/src/components/Settings/StashConfiguration.tsx @@ -7,7 +7,6 @@ import * as GQL from "src/core/generated-graphql"; import { FolderSelectDialog } from "../Shared/FolderSelect/FolderSelectDialog"; import { BooleanSetting } from "./Inputs"; import { SettingSection } from "./SettingSection"; -import { PatchComponent } from "src/patch"; interface IStashProps { index: number; @@ -17,198 +16,193 @@ interface IStashProps { onDelete: () => void; } -export const Stash: React.FC = PatchComponent( - "Stash", - ({ - index, - stash, - onSave, - onEdit, - onDelete, - }) => { - const handleInput = (key: string, value: any) => { - const newObj = { - ...stash, - [key]: value, - }; - onSave(newObj); +const Stash: React.FC = ({ + index, + stash, + onSave, + onEdit, + onDelete, +}) => { + // eslint-disable-next-line + const handleInput = (key: string, value: any) => { + const newObj = { + ...stash, + [key]: value, }; - - const classAdd = index % 2 === 1 ? "bg-dark" : ""; - - return ( - - - {stash.path} - - -
-
- -
- handleInput("excludeVideo", !v)} - /> -
- - - -
-
- -
- handleInput("excludeImage", !v)} - /> -
- - - - - - - - onEdit()}> - - - onDelete()}> - - - - - -
- ); - } -); + onSave(newObj); + }; + + const classAdd = index % 2 === 1 ? "bg-dark" : ""; + + return ( + + + {stash.path} + + + {/* NOTE - language is opposite to meaning: + internally exclude flags, displayed as include */} +
+
+ +
+ handleInput("excludeVideo", !v)} + /> +
+ + + +
+
+ +
+ handleInput("excludeImage", !v)} + /> +
+ + + + + + + + onEdit()}> + + + onDelete()}> + + + + + +
+ ); +}; interface IStashConfigurationProps { stashes: GQL.StashConfig[]; setStashes: (v: GQL.StashConfig[]) => void; } -export const StashConfiguration: React.FC = PatchComponent( - "StashConfiguration", - ({ - stashes, - setStashes, - }) => { - const [isCreating, setIsCreating] = useState(false); - const [editingIndex, setEditingIndex] = useState(); - - function onEdit(index: number) { - setEditingIndex(index); - } - - function onDelete(index: number) { - setStashes(stashes.filter((v, i) => i !== index)); - } - - function onNew() { - setIsCreating(true); - } - - const handleSave = (index: number, stash: GQL.StashConfig) => - setStashes(stashes.map((s, i) => (i === index ? stash : s))); - - return ( - <> - {isCreating ? ( - { - if (v) - setStashes([ - ...stashes, - { - path: v, - excludeVideo: false, - excludeImage: false, - }, - ]); - setIsCreating(false); - }} - /> - ) : undefined} - - {editingIndex !== undefined ? ( - { - if (v) - setStashes( - stashes.map((vv, index) => { - if (index === editingIndex) { - return { - ...vv, - path: v, - }; - } - return vv; - }) - ); - setEditingIndex(undefined); - }} - /> - ) : undefined} - -
- {stashes.length > 0 && ( - -
- -
-
- -
-
- -
-
- )} - {stashes.map((stash, index) => ( - handleSave(index, s)} - onEdit={() => onEdit(index)} - onDelete={() => onDelete(index)} - key={stash.path} - /> - ))} - -
- - ); +const StashConfiguration: React.FC = ({ + stashes, + setStashes, +}) => { + const [isCreating, setIsCreating] = useState(false); + const [editingIndex, setEditingIndex] = useState(); + + function onEdit(index: number) { + setEditingIndex(index); + } + + function onDelete(index: number) { + setStashes(stashes.filter((v, i) => i !== index)); } -); + + function onNew() { + setIsCreating(true); + } + + const handleSave = (index: number, stash: GQL.StashConfig) => + setStashes(stashes.map((s, i) => (i === index ? stash : s))); + + return ( + <> + {isCreating ? ( + { + if (v) + setStashes([ + ...stashes, + { + path: v, + excludeVideo: false, + excludeImage: false, + }, + ]); + setIsCreating(false); + }} + /> + ) : undefined} + + {editingIndex !== undefined ? ( + { + if (v) + setStashes( + stashes.map((vv, index) => { + if (index === editingIndex) { + return { + ...vv, + path: v, + }; + } + return vv; + }) + ); + setEditingIndex(undefined); + }} + /> + ) : undefined} + +
+ {stashes.length > 0 && ( + +
+ +
+
+ +
+
+ +
+
+ )} + {stashes.map((stash, index) => ( + handleSave(index, s)} + onEdit={() => onEdit(index)} + onDelete={() => onDelete(index)} + key={stash.path} + /> + ))} + +
+ + ); +}; interface IStashSetting { value: GQL.StashConfigInput[]; onChange: (v: GQL.StashConfigInput[]) => void; } -export const StashSetting: React.FC = PatchComponent( - "StashSetting", - ({ value, onChange }) => { - return ( - - onChange(v)} /> - - ); - } -); -export default StashConfiguration; \ No newline at end of file +export const StashSetting: React.FC = ({ value, onChange }) => { + return ( + + onChange(v)} /> + + ); +}; + +export default StashConfiguration; From 0e2266327a429305fe40d75ff6646d8b6949c064 Mon Sep 17 00:00:00 2001 From: Gykes Date: Thu, 29 Aug 2024 18:17:34 -0700 Subject: [PATCH 4/4] Adding in File Post Hooks This seems too simple but I think this is it? fixes https://github.com/stashapp/stash/issues/3001 --- pkg/plugin/examples/js/js.yml | 3 +++ pkg/plugin/hook/hooks.go | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/pkg/plugin/examples/js/js.yml b/pkg/plugin/examples/js/js.yml index 25f0d56e345..4a1d96d291a 100644 --- a/pkg/plugin/examples/js/js.yml +++ b/pkg/plugin/examples/js/js.yml @@ -52,6 +52,9 @@ hooks: - Tag.Create.Post - Tag.Update.Post - Tag.Destroy.Post + - File.Destroy.Post + - File.Update.Post + - File.Create.Post defaultArgs: mode: hook diff --git a/pkg/plugin/hook/hooks.go b/pkg/plugin/hook/hooks.go index a8235b1834d..428e99cf57f 100644 --- a/pkg/plugin/hook/hooks.go +++ b/pkg/plugin/hook/hooks.go @@ -48,6 +48,10 @@ const ( TagUpdatePost TriggerEnum = "Tag.Update.Post" TagMergePost TriggerEnum = "Tag.Merge.Post" TagDestroyPost TriggerEnum = "Tag.Destroy.Post" + + FileDestroyPost TriggerEnum = "File.Destroy.Post" + FileUpdatePost TriggerEnum = "File.Update.Post" + FileCreatePost TriggerEnum = "File.Create.Post" ) var AllHookTriggerEnum = []TriggerEnum{ @@ -87,6 +91,10 @@ var AllHookTriggerEnum = []TriggerEnum{ TagUpdatePost, TagMergePost, TagDestroyPost, + + FileDestroyPost, + FileUpdatePost, + FileCreatePost, } func (e TriggerEnum) IsValid() bool { @@ -124,6 +132,10 @@ func (e TriggerEnum) IsValid() bool { StudioUpdatePost, StudioDestroyPost, + FileDestroyPost, + FileUpdatePost, + FileCreatePost, + TagCreatePost, TagUpdatePost, TagDestroyPost: