This commit is contained in:
y-e-r 2025-12-04 19:09:34 +05:30 committed by GitHub
commit d81243503d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 123 additions and 0 deletions

View file

@ -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",

View file

@ -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",