mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 00:13:46 +01:00
Merge b8d11b5788 into 39fd8a6550
This commit is contained in:
commit
d81243503d
2 changed files with 123 additions and 0 deletions
|
|
@ -49,6 +49,7 @@ import { FileSize } from "../Shared/FileSize";
|
|||
const CLASSNAME = "duplicate-checker";
|
||||
|
||||
const defaultDurationDiff = "1";
|
||||
const defaultSelectedCodec = "hevc";
|
||||
|
||||
export const SceneDuplicateChecker: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
|
@ -60,6 +61,7 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||
const durationDiff = Number.parseFloat(
|
||||
query.get("durationDiff") ?? defaultDurationDiff
|
||||
);
|
||||
let SelectedCodec = query.get("SelectedCodec") ?? defaultSelectedCodec;
|
||||
|
||||
const [currentPageSize, setCurrentPageSize] = useState(pageSize);
|
||||
const [isMultiDelete, setIsMultiDelete] = useState(false);
|
||||
|
|
@ -195,6 +197,19 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const findSmallestScene = (group: GQL.SlimSceneDataFragment[]) => {
|
||||
// Get maximum file size of a scene
|
||||
const totalSize = (scene: GQL.SlimSceneDataFragment) => {
|
||||
return scene.files.reduce((prev: number, f) => Math.max(prev, f.size), 0);
|
||||
};
|
||||
// Find scene object with minimum total size
|
||||
return group.reduce((smallest, scene) => {
|
||||
const smallestSize = totalSize(smallest);
|
||||
const currentSize = totalSize(scene);
|
||||
return currentSize < smallestSize ? scene : smallest;
|
||||
});
|
||||
};
|
||||
|
||||
const findLargestResolutionScene = (group: GQL.SlimSceneDataFragment[]) => {
|
||||
// Get maximum resolution of a scene
|
||||
const sceneResolution = (scene: GQL.SlimSceneDataFragment) => {
|
||||
|
|
@ -277,6 +292,53 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||
setCheckedScenes(checkedArray);
|
||||
};
|
||||
|
||||
const onSelectSmallestClick = () => {
|
||||
setSelectedScenes([]);
|
||||
const checkedArray: Record<string, boolean> = {};
|
||||
|
||||
filteredScenes.forEach((group) => {
|
||||
if (chkSafeSelect && !checkSameCodec(group)) {
|
||||
return;
|
||||
}
|
||||
// Find smallest scene in group a
|
||||
const smallest = findSmallestScene(group);
|
||||
group.forEach((scene) => {
|
||||
if (scene !== smallest) {
|
||||
checkedArray[scene.id] = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
setCheckedScenes(checkedArray);
|
||||
};
|
||||
|
||||
const onSelectCodecClick = () => {
|
||||
setSelectedScenes([]);
|
||||
const checkedArray: Record<string, boolean> = {};
|
||||
|
||||
filteredScenes.forEach((group) => {
|
||||
if (chkSafeSelect && !checkSameCodec(group)) {
|
||||
return;
|
||||
}
|
||||
// select scenes where codec is not preferred
|
||||
let hasCodec = false;
|
||||
group.forEach((scene) => {
|
||||
if (scene.files[0]?.video_codec != SelectedCodec) {
|
||||
checkedArray[scene.id] = true;
|
||||
} else if (scene.files[0]?.video_codec == SelectedCodec) {
|
||||
hasCodec = true;
|
||||
}
|
||||
});
|
||||
if (!hasCodec) {
|
||||
// when no scenes with preferred codec are in the group select nothing
|
||||
group.forEach((scene) => {
|
||||
checkedArray[scene.id] = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
setCheckedScenes(checkedArray);
|
||||
};
|
||||
|
||||
const onSelectLargestResolutionClick = () => {
|
||||
setSelectedScenes([]);
|
||||
const checkedArray: Record<string, boolean> = {};
|
||||
|
|
@ -755,6 +817,47 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||
</Col>
|
||||
</Row>
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group>
|
||||
<Row noGutters>
|
||||
<Form.Label>
|
||||
<FormattedMessage id="dupe_check.select_all_but_specified_codec.title" />
|
||||
</Form.Label>
|
||||
<Col xs="auto">
|
||||
<Form.Control
|
||||
as="select"
|
||||
onChange={(e) =>
|
||||
setQuery({
|
||||
SelectedCodec:
|
||||
e.currentTarget.value === defaultSelectedCodec
|
||||
? undefined
|
||||
: e.currentTarget.value,
|
||||
page: undefined,
|
||||
})
|
||||
}
|
||||
defaultValue={SelectedCodec}
|
||||
className="input-control ml-4"
|
||||
>
|
||||
<option value={"av1"}>
|
||||
{intl.formatMessage({
|
||||
id: "dupe_check.select_all_but_specified_codec.av1",
|
||||
})}
|
||||
</option>
|
||||
<option value={"hevc"}>
|
||||
{intl.formatMessage({
|
||||
id: "dupe_check.select_all_but_specified_codec.hevc",
|
||||
})}
|
||||
</option>
|
||||
<option value={"h264"}>
|
||||
{intl.formatMessage({
|
||||
id: "dupe_check.select_all_but_specified_codec.h264",
|
||||
})}
|
||||
</option>
|
||||
</Form.Control>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group>
|
||||
<Row noGutters>
|
||||
<Col xs="12">
|
||||
|
|
@ -767,6 +870,12 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||
{intl.formatMessage({ id: "dupe_check.select_none" })}
|
||||
</Dropdown.Item>
|
||||
|
||||
<Dropdown.Item onClick={() => onSelectCodecClick()}>
|
||||
{intl.formatMessage({
|
||||
id: "dupe_check.select_all_but_specified_codec.label",
|
||||
})}
|
||||
</Dropdown.Item>
|
||||
|
||||
<Dropdown.Item
|
||||
onClick={() => onSelectLargestResolutionClick()}
|
||||
>
|
||||
|
|
@ -781,6 +890,12 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||
})}
|
||||
</Dropdown.Item>
|
||||
|
||||
<Dropdown.Item onClick={() => onSelectSmallestClick()}>
|
||||
{intl.formatMessage({
|
||||
id: "dupe_check.select_all_but_smallest_file",
|
||||
})}
|
||||
</Dropdown.Item>
|
||||
|
||||
<Dropdown.Item onClick={() => onSelectByAge(true)}>
|
||||
{intl.formatMessage({
|
||||
id: "dupe_check.select_oldest",
|
||||
|
|
|
|||
|
|
@ -1054,7 +1054,15 @@
|
|||
"medium": "Medium"
|
||||
},
|
||||
"search_accuracy_label": "Search Accuracy",
|
||||
"select_all_but_specified_codec": {
|
||||
"title": "Preferred video codec",
|
||||
"label": "Select every file in each group, except for the file with the preferred codec",
|
||||
"av1": "av1",
|
||||
"hevc": "hevc",
|
||||
"h264": "h264"
|
||||
},
|
||||
"select_all_but_largest_file": "Select every file in each duplicated group, except the largest file",
|
||||
"select_all_but_smallest_file": "Select every file in each duplicated group, except the smallest file",
|
||||
"select_all_but_largest_resolution": "Select every file in each duplicated group, except the file with highest resolution",
|
||||
"select_none": "Select None",
|
||||
"select_oldest": "Select the oldest file in the duplicate group",
|
||||
|
|
|
|||
Loading…
Reference in a new issue