Files
bitvid/js/constants.js
T

323 lines
8.4 KiB
JavaScript

const DEFAULT_FLAGS = Object.freeze({
URL_FIRST_ENABLED: true, // try URL before magnet in the player
ACCEPT_LEGACY_V1: true, // accept v1 magnet-only notes
VIEW_FILTER_INCLUDE_LEGACY_VIDEO: false,
FEATURE_WATCH_HISTORY_V2: false,
FEATURE_PUBLISH_NIP71: false,
FEATURE_DESIGN_SYSTEM: true,
WSS_TRACKERS: Object.freeze([
"wss://tracker.openwebtorrent.com",
"wss://tracker.fastcast.nz",
"wss://tracker.webtorrent.dev",
"wss://tracker.sloppyta.co:443/announce",
]),
});
export const DESIGN_SYSTEM_EVENT_NAME = "bitvid:design-system-flag-change";
const globalScope = typeof globalThis === "object" && globalThis ? globalThis : undefined;
function dispatchDesignSystemFlagChange(enabled) {
if (
!globalScope ||
typeof globalScope.dispatchEvent !== "function" ||
(typeof globalScope.CustomEvent !== "function" &&
typeof globalScope.Event !== "function")
) {
return;
}
let event;
if (typeof globalScope.CustomEvent === "function") {
event = new globalScope.CustomEvent(DESIGN_SYSTEM_EVENT_NAME, {
detail: { enabled: enabled === true },
});
} else {
event = new globalScope.Event(DESIGN_SYSTEM_EVENT_NAME);
try {
Object.defineProperty(event, "detail", {
configurable: true,
enumerable: true,
writable: true,
value: { enabled: enabled === true },
});
} catch (error) {
// Older browsers may not allow redefining detail; ignore.
}
}
try {
globalScope.dispatchEvent(event);
} catch (error) {
if (typeof console !== "undefined" && console && console.warn) {
console.warn("[design-system] Failed to dispatch flag change event:", error);
}
}
}
const runtimeFlags = (() => {
if (globalScope && typeof globalScope.__BITVID_RUNTIME_FLAGS__ === "object") {
return globalScope.__BITVID_RUNTIME_FLAGS__;
}
const initial = {
URL_FIRST_ENABLED: DEFAULT_FLAGS.URL_FIRST_ENABLED,
ACCEPT_LEGACY_V1: DEFAULT_FLAGS.ACCEPT_LEGACY_V1,
VIEW_FILTER_INCLUDE_LEGACY_VIDEO:
DEFAULT_FLAGS.VIEW_FILTER_INCLUDE_LEGACY_VIDEO,
FEATURE_WATCH_HISTORY_V2: DEFAULT_FLAGS.FEATURE_WATCH_HISTORY_V2,
FEATURE_PUBLISH_NIP71: DEFAULT_FLAGS.FEATURE_PUBLISH_NIP71,
FEATURE_DESIGN_SYSTEM: DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM,
WSS_TRACKERS: [...DEFAULT_FLAGS.WSS_TRACKERS],
};
if (globalScope) {
globalScope.__BITVID_RUNTIME_FLAGS__ = initial;
}
return initial;
})();
function coerceBoolean(value, fallback) {
if (typeof value === "boolean") {
return value;
}
if (typeof value === "string") {
const normalized = value.trim().toLowerCase();
if (!normalized) {
return fallback;
}
if (["false", "0", "off", "no"].includes(normalized)) {
return false;
}
if (["true", "1", "on", "yes"].includes(normalized)) {
return true;
}
}
if (value == null) {
return fallback;
}
return Boolean(value);
}
function sanitizeTrackerList(candidate) {
const input = Array.isArray(candidate) ? candidate : DEFAULT_FLAGS.WSS_TRACKERS;
const seen = new Set();
const sanitized = [];
for (const tracker of input) {
if (typeof tracker !== "string") {
continue;
}
const trimmed = tracker.trim();
if (!trimmed) {
continue;
}
if (!/^wss:\/\//i.test(trimmed)) {
continue;
}
const normalized = trimmed.toLowerCase();
if (seen.has(normalized)) {
continue;
}
seen.add(normalized);
sanitized.push(trimmed);
}
if (!sanitized.length) {
return [...DEFAULT_FLAGS.WSS_TRACKERS];
}
return sanitized;
}
function freezeTrackers(list) {
return Object.freeze([...list]);
}
export let URL_FIRST_ENABLED = coerceBoolean(
runtimeFlags.URL_FIRST_ENABLED,
DEFAULT_FLAGS.URL_FIRST_ENABLED
);
export let ACCEPT_LEGACY_V1 = coerceBoolean(
runtimeFlags.ACCEPT_LEGACY_V1,
DEFAULT_FLAGS.ACCEPT_LEGACY_V1
);
export let VIEW_FILTER_INCLUDE_LEGACY_VIDEO = coerceBoolean(
runtimeFlags.VIEW_FILTER_INCLUDE_LEGACY_VIDEO,
DEFAULT_FLAGS.VIEW_FILTER_INCLUDE_LEGACY_VIDEO
);
export let FEATURE_WATCH_HISTORY_V2 = coerceBoolean(
runtimeFlags.FEATURE_WATCH_HISTORY_V2,
DEFAULT_FLAGS.FEATURE_WATCH_HISTORY_V2
);
export let FEATURE_PUBLISH_NIP71 = coerceBoolean(
runtimeFlags.FEATURE_PUBLISH_NIP71,
DEFAULT_FLAGS.FEATURE_PUBLISH_NIP71
);
export let FEATURE_DESIGN_SYSTEM = coerceBoolean(
runtimeFlags.FEATURE_DESIGN_SYSTEM,
DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM
);
export let WSS_TRACKERS = freezeTrackers(
sanitizeTrackerList(runtimeFlags.WSS_TRACKERS)
);
Object.defineProperty(runtimeFlags, "URL_FIRST_ENABLED", {
configurable: true,
enumerable: true,
get() {
return URL_FIRST_ENABLED;
},
set(next) {
URL_FIRST_ENABLED = coerceBoolean(next, DEFAULT_FLAGS.URL_FIRST_ENABLED);
},
});
Object.defineProperty(runtimeFlags, "ACCEPT_LEGACY_V1", {
configurable: true,
enumerable: true,
get() {
return ACCEPT_LEGACY_V1;
},
set(next) {
ACCEPT_LEGACY_V1 = coerceBoolean(next, DEFAULT_FLAGS.ACCEPT_LEGACY_V1);
},
});
Object.defineProperty(runtimeFlags, "VIEW_FILTER_INCLUDE_LEGACY_VIDEO", {
configurable: true,
enumerable: true,
get() {
return VIEW_FILTER_INCLUDE_LEGACY_VIDEO;
},
set(next) {
VIEW_FILTER_INCLUDE_LEGACY_VIDEO = coerceBoolean(
next,
DEFAULT_FLAGS.VIEW_FILTER_INCLUDE_LEGACY_VIDEO
);
},
});
Object.defineProperty(runtimeFlags, "FEATURE_WATCH_HISTORY_V2", {
configurable: true,
enumerable: true,
get() {
return FEATURE_WATCH_HISTORY_V2;
},
set(next) {
FEATURE_WATCH_HISTORY_V2 = coerceBoolean(
next,
DEFAULT_FLAGS.FEATURE_WATCH_HISTORY_V2
);
},
});
Object.defineProperty(runtimeFlags, "FEATURE_PUBLISH_NIP71", {
configurable: true,
enumerable: true,
get() {
return FEATURE_PUBLISH_NIP71;
},
set(next) {
FEATURE_PUBLISH_NIP71 = coerceBoolean(
next,
DEFAULT_FLAGS.FEATURE_PUBLISH_NIP71
);
},
});
Object.defineProperty(runtimeFlags, "FEATURE_DESIGN_SYSTEM", {
configurable: true,
enumerable: true,
get() {
return FEATURE_DESIGN_SYSTEM;
},
set(next) {
const previous = FEATURE_DESIGN_SYSTEM === true;
FEATURE_DESIGN_SYSTEM = coerceBoolean(
next,
DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM
);
const current = FEATURE_DESIGN_SYSTEM === true;
if (previous !== current) {
dispatchDesignSystemFlagChange(current);
}
},
});
Object.defineProperty(runtimeFlags, "WSS_TRACKERS", {
configurable: true,
enumerable: true,
get() {
return [...WSS_TRACKERS];
},
set(next) {
WSS_TRACKERS = freezeTrackers(sanitizeTrackerList(next));
},
});
// Ensure the runtime object reflects the sanitized defaults immediately.
runtimeFlags.URL_FIRST_ENABLED = URL_FIRST_ENABLED;
runtimeFlags.ACCEPT_LEGACY_V1 = ACCEPT_LEGACY_V1;
runtimeFlags.VIEW_FILTER_INCLUDE_LEGACY_VIDEO = VIEW_FILTER_INCLUDE_LEGACY_VIDEO;
runtimeFlags.FEATURE_WATCH_HISTORY_V2 = FEATURE_WATCH_HISTORY_V2;
runtimeFlags.FEATURE_PUBLISH_NIP71 = FEATURE_PUBLISH_NIP71;
runtimeFlags.FEATURE_DESIGN_SYSTEM = FEATURE_DESIGN_SYSTEM;
runtimeFlags.WSS_TRACKERS = WSS_TRACKERS;
export function setUrlFirstEnabled(next) {
runtimeFlags.URL_FIRST_ENABLED = next;
return URL_FIRST_ENABLED;
}
export function setAcceptLegacyV1(next) {
runtimeFlags.ACCEPT_LEGACY_V1 = next;
return ACCEPT_LEGACY_V1;
}
export function setViewFilterIncludeLegacyVideo(next) {
runtimeFlags.VIEW_FILTER_INCLUDE_LEGACY_VIDEO = next;
return VIEW_FILTER_INCLUDE_LEGACY_VIDEO;
}
export function getWatchHistoryV2Enabled() {
return FEATURE_WATCH_HISTORY_V2 === true;
}
export function getFeatureDesignSystemEnabled() {
return FEATURE_DESIGN_SYSTEM === true;
}
export function setWssTrackers(next) {
runtimeFlags.WSS_TRACKERS = next;
return WSS_TRACKERS;
}
export function resetRuntimeFlags() {
setUrlFirstEnabled(DEFAULT_FLAGS.URL_FIRST_ENABLED);
setAcceptLegacyV1(DEFAULT_FLAGS.ACCEPT_LEGACY_V1);
setViewFilterIncludeLegacyVideo(
DEFAULT_FLAGS.VIEW_FILTER_INCLUDE_LEGACY_VIDEO
);
setWatchHistoryV2Enabled(DEFAULT_FLAGS.FEATURE_WATCH_HISTORY_V2);
setFeatureDesignSystemEnabled(DEFAULT_FLAGS.FEATURE_DESIGN_SYSTEM);
setWssTrackers(DEFAULT_FLAGS.WSS_TRACKERS);
}
export const RUNTIME_FLAGS = runtimeFlags;
export function setWatchHistoryV2Enabled(next) {
runtimeFlags.FEATURE_WATCH_HISTORY_V2 = next;
return FEATURE_WATCH_HISTORY_V2;
}
export function setFeatureDesignSystemEnabled(next) {
runtimeFlags.FEATURE_DESIGN_SYSTEM = next;
return FEATURE_DESIGN_SYSTEM;
}