feat: allow excluding addons from deduplication

This commit is contained in:
Viren070
2025-11-23 21:51:53 +00:00
parent 2648256c6c
commit 44be5657cb
3 changed files with 50 additions and 2 deletions
+1
View File
@@ -161,6 +161,7 @@ const DeduplicatorMode = z.enum([
const DeduplicatorOptions = z.object({
enabled: z.boolean().optional(),
excludeAddons: z.array(z.string().min(1)).optional(),
multiGroupBehaviour: z
.enum(['keep_all', 'aggressive', 'conservative'])
.optional(),
+24 -2
View File
@@ -5,6 +5,7 @@ import {
DSU,
getSimpleTextHash,
} from '../utils/index.js';
import StreamUtils from './utils.js';
const logger = createLogger('deduplicator');
@@ -27,6 +28,7 @@ class StreamDeduplicator {
deduplicator = {
enabled: true,
multiGroupBehaviour: deduplicator.multiGroupBehaviour || 'aggressive',
excludeAddons: deduplicator.excludeAddons || [],
keys: deduplicationKeys,
cached: deduplicator.cached || 'per_addon',
uncached: deduplicator.uncached || 'per_addon',
@@ -42,6 +44,18 @@ class StreamDeduplicator {
const dsu = new DSU<string>();
const keyToStreamIds = new Map<string, string[]>();
const excludedStreamIds = new Set<string>();
for (const stream of streams) {
const isExcluded =
stream.addon?.instanceId &&
deduplicator.excludeAddons?.includes(stream.addon.preset.id);
if (isExcluded) {
excludedStreamIds.add(stream.id);
}
}
// Process ALL streams (including excluded ones) for deduplication grouping
for (const stream of streams) {
// Create a unique key based on the selected deduplication methods
dsu.makeSet(stream.id);
@@ -113,6 +127,12 @@ class StreamDeduplicator {
}
const processedStreams = new Set<ParsedStream>();
for (const excludedStreamId of excludedStreamIds) {
const stream = idToStreamMap.get(excludedStreamId);
if (stream) {
processedStreams.add(stream);
}
}
for (const group of finalDuplicateGroupsMap.values()) {
// Group streams by type
@@ -349,9 +369,11 @@ class StreamDeduplicator {
}
}
let deduplicatedStreams = Array.from(processedStreams);
let deduplicatedStreams = StreamUtils.mergeStreams(
Array.from(processedStreams)
);
logger.info(
`Filtered out ${streams.length - deduplicatedStreams.length} duplicate streams to ${deduplicatedStreams.length} streams in ${getTimeTakenSincePoint(start)}`
`Filtered out ${streams.length - deduplicatedStreams.length} duplicate streams to ${deduplicatedStreams.length}${Array.from(excludedStreamIds.values()).length > 0 ? ' (' + Array.from(excludedStreamIds.values()).length + ' streams excluded from deduplication) ' : ''} streams in ${getTimeTakenSincePoint(start)}`
);
return deduplicatedStreams;
}
@@ -2616,6 +2616,7 @@ function Content() {
}}
/>
</SettingsCard>
{mode === 'pro' && (
<>
<SettingsCard
@@ -2760,6 +2761,30 @@ function Content() {
}))}
/>
<Combobox
help="Addons selected here will always have their results kept during deduplication."
label="Addon Exclusions"
value={userData.deduplicator?.excludeAddons ?? []}
onValueChange={(value) => {
setUserData((prev) => ({
...prev,
deduplicator: {
...prev.deduplicator,
excludeAddons: value,
},
}));
}}
options={userData.presets.map((preset) => ({
label: preset.options.name || preset.type,
value: preset.instanceId,
textValue: preset.options.name,
}))}
emptyMessage="You haven't installed any addons..."
placeholder="Select addons..."
multiple
disabled={userData.deduplicator?.enabled === false}
/>
<Select
label="Multi-Group Behaviour"
help={`Configure how duplicates across multiple types are handled. e.g. if a given duplicate set has both cached and uncached streams, what should be done.