mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-07 21:32:51 +00:00
Adjust moderation defaults and store per-profile settings
This commit is contained in:
1 parent
213ba3970f
commit
15b94cfff3
7 files changed
+240
-121
No files matched your search
+185
-74
@@ -11,6 +11,7 @@ import {
|
||||
removeUrlHealthFromStorage,
|
||||
writeUrlHealthToStorage,
|
||||
} from "../utils/storage.js";
|
||||
import createProfileSettingsStore from "./profileSettingsStore.js";
|
||||
|
||||
const PROFILE_CACHE_STORAGE_KEY = "bitvid:profileCache:v1";
|
||||
const PROFILE_CACHE_VERSION = 1;
|
||||
@@ -29,7 +30,7 @@ const HEX64_REGEX = /^[0-9a-f]{64}$/i;
|
||||
const MODERATION_OVERRIDE_STORAGE_KEY = "bitvid:moderationOverrides:v1";
|
||||
const MODERATION_OVERRIDE_STORAGE_VERSION = 1;
|
||||
const MODERATION_SETTINGS_STORAGE_KEY = "bitvid:moderationSettings:v1";
|
||||
const MODERATION_SETTINGS_STORAGE_VERSION = 1;
|
||||
const MODERATION_SETTINGS_STORAGE_VERSION = 2;
|
||||
|
||||
function computeDefaultModerationSettings() {
|
||||
let runtimeMuteHide = DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD;
|
||||
@@ -58,8 +59,8 @@ function computeDefaultModerationSettings() {
|
||||
}
|
||||
|
||||
return {
|
||||
blurThreshold: 3,
|
||||
autoplayBlockThreshold: 2,
|
||||
blurThreshold: 1,
|
||||
autoplayBlockThreshold: 1,
|
||||
trustedMuteHideThreshold: sanitizeModerationThreshold(
|
||||
runtimeMuteHide,
|
||||
DEFAULT_TRUSTED_MUTE_HIDE_THRESHOLD,
|
||||
@@ -71,12 +72,19 @@ function computeDefaultModerationSettings() {
|
||||
};
|
||||
}
|
||||
|
||||
const DEFAULT_MODERATION_SETTINGS = Object.freeze(computeDefaultModerationSettings());
|
||||
|
||||
function createDefaultModerationSettings() {
|
||||
return { ...computeDefaultModerationSettings() };
|
||||
}
|
||||
|
||||
const GLOBAL_MODERATION_PROFILE_KEY = "__global__";
|
||||
const moderationSettingsStore = createProfileSettingsStore({
|
||||
clone: (value) => ({ ...value }),
|
||||
});
|
||||
moderationSettingsStore.set(
|
||||
GLOBAL_MODERATION_PROFILE_KEY,
|
||||
createDefaultModerationSettings(),
|
||||
);
|
||||
|
||||
function sanitizeModerationThreshold(value, fallback) {
|
||||
if (value === null || value === undefined) {
|
||||
return fallback;
|
||||
@@ -111,7 +119,6 @@ const profileCache = new Map();
|
||||
const urlHealthCache = new Map();
|
||||
const urlHealthInFlight = new Map();
|
||||
const moderationOverrides = new Map();
|
||||
let moderationSettings = createDefaultModerationSettings();
|
||||
|
||||
function hasSavedProfilesChanged(previousProfiles, nextProfiles) {
|
||||
if (previousProfiles === nextProfiles) {
|
||||
@@ -228,6 +235,7 @@ export function setActiveProfilePubkey(pubkey, { persist = true } = {}) {
|
||||
}
|
||||
|
||||
activeProfilePubkey = nextValue;
|
||||
ensureModerationSettingsForKey(getActiveModerationStoreKey());
|
||||
if (persist) {
|
||||
persistSavedProfiles({ persistActive: true });
|
||||
}
|
||||
@@ -809,68 +817,152 @@ function haveModerationSettingsChanged(previous, next) {
|
||||
);
|
||||
}
|
||||
|
||||
function getModerationStoreKeyForPubkey(pubkey) {
|
||||
const normalized = normalizeHexPubkey(pubkey);
|
||||
return normalized || GLOBAL_MODERATION_PROFILE_KEY;
|
||||
}
|
||||
|
||||
function getActiveModerationStoreKey() {
|
||||
return getModerationStoreKeyForPubkey(activeProfilePubkey);
|
||||
}
|
||||
|
||||
function ensureModerationSettingsForKey(key) {
|
||||
const storeKey = key || GLOBAL_MODERATION_PROFILE_KEY;
|
||||
if (!moderationSettingsStore.has(storeKey)) {
|
||||
moderationSettingsStore.set(storeKey, createDefaultModerationSettings());
|
||||
}
|
||||
return moderationSettingsStore.get(storeKey);
|
||||
}
|
||||
|
||||
export function getDefaultModerationSettings() {
|
||||
return createDefaultModerationSettings();
|
||||
}
|
||||
|
||||
export function getModerationSettingsForPubkey(pubkey) {
|
||||
const key = getModerationStoreKeyForPubkey(pubkey);
|
||||
const settings = ensureModerationSettingsForKey(key);
|
||||
return { ...settings };
|
||||
}
|
||||
|
||||
export function getModerationSettings() {
|
||||
return { ...moderationSettings };
|
||||
return getModerationSettingsForPubkey(activeProfilePubkey);
|
||||
}
|
||||
|
||||
export function loadModerationSettingsFromStorage() {
|
||||
moderationSettingsStore.clear();
|
||||
moderationSettingsStore.set(
|
||||
GLOBAL_MODERATION_PROFILE_KEY,
|
||||
createDefaultModerationSettings(),
|
||||
);
|
||||
|
||||
if (typeof localStorage === "undefined") {
|
||||
moderationSettings = createDefaultModerationSettings();
|
||||
return getModerationSettings();
|
||||
}
|
||||
|
||||
const raw = localStorage.getItem(MODERATION_SETTINGS_STORAGE_KEY);
|
||||
if (!raw) {
|
||||
moderationSettings = createDefaultModerationSettings();
|
||||
return getModerationSettings();
|
||||
}
|
||||
|
||||
let shouldRewrite = false;
|
||||
|
||||
try {
|
||||
const payload = JSON.parse(raw);
|
||||
if (!payload || typeof payload !== "object") {
|
||||
moderationSettings = createDefaultModerationSettings();
|
||||
return getModerationSettings();
|
||||
shouldRewrite = true;
|
||||
} else if (payload.version === 1) {
|
||||
const defaults = createDefaultModerationSettings();
|
||||
const overrides =
|
||||
payload.overrides && typeof payload.overrides === "object"
|
||||
? payload.overrides
|
||||
: {};
|
||||
|
||||
const legacySettings = {
|
||||
blurThreshold: sanitizeModerationThreshold(
|
||||
overrides.blurThreshold,
|
||||
defaults.blurThreshold,
|
||||
),
|
||||
autoplayBlockThreshold: sanitizeModerationThreshold(
|
||||
overrides.autoplayBlockThreshold,
|
||||
defaults.autoplayBlockThreshold,
|
||||
),
|
||||
trustedMuteHideThreshold: sanitizeModerationThreshold(
|
||||
overrides.trustedMuteHideThreshold,
|
||||
defaults.trustedMuteHideThreshold,
|
||||
),
|
||||
trustedSpamHideThreshold: sanitizeModerationThreshold(
|
||||
overrides.trustedSpamHideThreshold,
|
||||
defaults.trustedSpamHideThreshold,
|
||||
),
|
||||
};
|
||||
|
||||
moderationSettingsStore.set(
|
||||
GLOBAL_MODERATION_PROFILE_KEY,
|
||||
legacySettings,
|
||||
);
|
||||
shouldRewrite = true;
|
||||
} else if (payload.version === MODERATION_SETTINGS_STORAGE_VERSION) {
|
||||
const defaults = createDefaultModerationSettings();
|
||||
const entries =
|
||||
payload.entries && typeof payload.entries === "object"
|
||||
? payload.entries
|
||||
: {};
|
||||
|
||||
for (const [key, entry] of Object.entries(entries)) {
|
||||
if (!entry || typeof entry !== "object") {
|
||||
shouldRewrite = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const overrides =
|
||||
entry.overrides && typeof entry.overrides === "object"
|
||||
? entry.overrides
|
||||
: {};
|
||||
|
||||
const storeKey =
|
||||
key === "default"
|
||||
? GLOBAL_MODERATION_PROFILE_KEY
|
||||
: getModerationStoreKeyForPubkey(key);
|
||||
|
||||
if (!storeKey) {
|
||||
shouldRewrite = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const settings = {
|
||||
blurThreshold: sanitizeModerationThreshold(
|
||||
overrides.blurThreshold,
|
||||
defaults.blurThreshold,
|
||||
),
|
||||
autoplayBlockThreshold: sanitizeModerationThreshold(
|
||||
overrides.autoplayBlockThreshold,
|
||||
defaults.autoplayBlockThreshold,
|
||||
),
|
||||
trustedMuteHideThreshold: sanitizeModerationThreshold(
|
||||
overrides.trustedMuteHideThreshold,
|
||||
defaults.trustedMuteHideThreshold,
|
||||
),
|
||||
trustedSpamHideThreshold: sanitizeModerationThreshold(
|
||||
overrides.trustedSpamHideThreshold,
|
||||
defaults.trustedSpamHideThreshold,
|
||||
),
|
||||
};
|
||||
|
||||
moderationSettingsStore.set(storeKey, settings);
|
||||
}
|
||||
} else {
|
||||
shouldRewrite = true;
|
||||
}
|
||||
|
||||
if (payload.version !== MODERATION_SETTINGS_STORAGE_VERSION) {
|
||||
moderationSettings = createDefaultModerationSettings();
|
||||
return getModerationSettings();
|
||||
}
|
||||
|
||||
const defaults = createDefaultModerationSettings();
|
||||
const overrides =
|
||||
payload.overrides && typeof payload.overrides === "object"
|
||||
? payload.overrides
|
||||
: {};
|
||||
|
||||
moderationSettings = {
|
||||
blurThreshold: sanitizeModerationThreshold(
|
||||
overrides.blurThreshold,
|
||||
defaults.blurThreshold,
|
||||
),
|
||||
autoplayBlockThreshold: sanitizeModerationThreshold(
|
||||
overrides.autoplayBlockThreshold,
|
||||
defaults.autoplayBlockThreshold,
|
||||
),
|
||||
trustedMuteHideThreshold: sanitizeModerationThreshold(
|
||||
overrides.trustedMuteHideThreshold,
|
||||
defaults.trustedMuteHideThreshold,
|
||||
),
|
||||
trustedSpamHideThreshold: sanitizeModerationThreshold(
|
||||
overrides.trustedSpamHideThreshold,
|
||||
defaults.trustedSpamHideThreshold,
|
||||
),
|
||||
};
|
||||
} catch (error) {
|
||||
moderationSettings = createDefaultModerationSettings();
|
||||
userLogger.warn(
|
||||
"[cache.loadModerationSettingsFromStorage] Failed to parse payload:",
|
||||
error,
|
||||
);
|
||||
shouldRewrite = true;
|
||||
}
|
||||
|
||||
if (shouldRewrite) {
|
||||
persistModerationSettingsToStorage();
|
||||
}
|
||||
|
||||
return getModerationSettings();
|
||||
@@ -882,31 +974,46 @@ function persistModerationSettingsToStorage() {
|
||||
}
|
||||
|
||||
const defaults = createDefaultModerationSettings();
|
||||
const overrides = {};
|
||||
const entries = {};
|
||||
|
||||
if (moderationSettings.blurThreshold !== defaults.blurThreshold) {
|
||||
overrides.blurThreshold = moderationSettings.blurThreshold;
|
||||
for (const [key, value] of moderationSettingsStore.entries()) {
|
||||
const settings =
|
||||
value && typeof value === "object"
|
||||
? value
|
||||
: createDefaultModerationSettings();
|
||||
|
||||
const overrides = {};
|
||||
|
||||
if (settings.blurThreshold !== defaults.blurThreshold) {
|
||||
overrides.blurThreshold = settings.blurThreshold;
|
||||
}
|
||||
|
||||
if (settings.autoplayBlockThreshold !== defaults.autoplayBlockThreshold) {
|
||||
overrides.autoplayBlockThreshold = settings.autoplayBlockThreshold;
|
||||
}
|
||||
|
||||
if (settings.trustedMuteHideThreshold !== defaults.trustedMuteHideThreshold) {
|
||||
overrides.trustedMuteHideThreshold = settings.trustedMuteHideThreshold;
|
||||
}
|
||||
|
||||
if (settings.trustedSpamHideThreshold !== defaults.trustedSpamHideThreshold) {
|
||||
overrides.trustedSpamHideThreshold = settings.trustedSpamHideThreshold;
|
||||
}
|
||||
|
||||
if (Object.keys(overrides).length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const storageKey =
|
||||
key === GLOBAL_MODERATION_PROFILE_KEY ? "default" : key;
|
||||
|
||||
entries[storageKey] = {
|
||||
overrides,
|
||||
savedAt: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
if (moderationSettings.autoplayBlockThreshold !== defaults.autoplayBlockThreshold) {
|
||||
overrides.autoplayBlockThreshold = moderationSettings.autoplayBlockThreshold;
|
||||
}
|
||||
|
||||
if (
|
||||
moderationSettings.trustedMuteHideThreshold !==
|
||||
defaults.trustedMuteHideThreshold
|
||||
) {
|
||||
overrides.trustedMuteHideThreshold = moderationSettings.trustedMuteHideThreshold;
|
||||
}
|
||||
|
||||
if (
|
||||
moderationSettings.trustedSpamHideThreshold !==
|
||||
defaults.trustedSpamHideThreshold
|
||||
) {
|
||||
overrides.trustedSpamHideThreshold = moderationSettings.trustedSpamHideThreshold;
|
||||
}
|
||||
|
||||
if (Object.keys(overrides).length === 0) {
|
||||
if (Object.keys(entries).length === 0) {
|
||||
try {
|
||||
localStorage.removeItem(MODERATION_SETTINGS_STORAGE_KEY);
|
||||
} catch (error) {
|
||||
@@ -920,7 +1027,7 @@ function persistModerationSettingsToStorage() {
|
||||
|
||||
const payload = {
|
||||
version: MODERATION_SETTINGS_STORAGE_VERSION,
|
||||
overrides,
|
||||
entries,
|
||||
savedAt: Date.now(),
|
||||
};
|
||||
|
||||
@@ -938,8 +1045,10 @@ function persistModerationSettingsToStorage() {
|
||||
}
|
||||
|
||||
export function setModerationSettings(partial = {}, { persist = true } = {}) {
|
||||
const key = getActiveModerationStoreKey();
|
||||
const defaults = createDefaultModerationSettings();
|
||||
const next = { ...moderationSettings };
|
||||
const current = ensureModerationSettingsForKey(key);
|
||||
const next = { ...current };
|
||||
let changed = false;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(partial, "blurThreshold")) {
|
||||
@@ -994,33 +1103,35 @@ export function setModerationSettings(partial = {}, { persist = true } = {}) {
|
||||
if (persist) {
|
||||
persistModerationSettingsToStorage();
|
||||
}
|
||||
return { ...moderationSettings };
|
||||
return ensureModerationSettingsForKey(key);
|
||||
}
|
||||
|
||||
moderationSettings = next;
|
||||
moderationSettingsStore.set(key, next);
|
||||
|
||||
if (persist) {
|
||||
persistModerationSettingsToStorage();
|
||||
}
|
||||
|
||||
return { ...moderationSettings };
|
||||
return ensureModerationSettingsForKey(key);
|
||||
}
|
||||
|
||||
export function resetModerationSettings({ persist = true } = {}) {
|
||||
const previous = moderationSettings;
|
||||
moderationSettings = createDefaultModerationSettings();
|
||||
const key = getActiveModerationStoreKey();
|
||||
const previous = ensureModerationSettingsForKey(key);
|
||||
const defaults = createDefaultModerationSettings();
|
||||
moderationSettingsStore.set(key, defaults);
|
||||
|
||||
const changed = haveModerationSettingsChanged(previous, moderationSettings);
|
||||
const changed = haveModerationSettingsChanged(previous, defaults);
|
||||
|
||||
if (persist) {
|
||||
persistModerationSettingsToStorage();
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
return { ...moderationSettings };
|
||||
return ensureModerationSettingsForKey(key);
|
||||
}
|
||||
|
||||
return { ...moderationSettings };
|
||||
return ensureModerationSettingsForKey(key);
|
||||
}
|
||||
|
||||
export function getModerationOverridesMap() {
|
||||
|
||||
Reference in new issue
Block a user