Move segment times from encoded array to normal js object

This commit is contained in:
Ajay
2022-02-06 15:10:46 -05:00
parent 32fa9c3398
commit 199ccb1b12
6 changed files with 46 additions and 144 deletions

View File

@@ -517,9 +517,10 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
source: SponsorSourceType.Local source: SponsorSourceType.Local
}; };
const segmentTimes = Config.config.segmentTimes.get(sponsorVideoID) || []; const segmentTimes = Config.config.unsubmittedSegments[sponsorVideoID] || [];
segmentTimes.push(sponsorTimesSubmitting); segmentTimes.push(sponsorTimesSubmitting);
Config.config.segmentTimes.set(sponsorVideoID, segmentTimes); Config.config.unsubmittedSegments[sponsorVideoID] = segmentTimes;
Config.forceUpdate("unsubmittedSegments");
this.props.contentContainer().sponsorTimesSubmitting.push(sponsorTimesSubmitting); this.props.contentContainer().sponsorTimesSubmitting.push(sponsorTimesSubmitting);
this.props.contentContainer().updatePreviewBar(); this.props.contentContainer().updatePreviewBar();

View File

@@ -509,7 +509,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
const inputActionType = this.actionTypeOptionRef?.current?.value as ActionType; const inputActionType = this.actionTypeOptionRef?.current?.value as ActionType;
sponsorTimesSubmitting[this.props.index].actionType = this.getNextActionType(category, inputActionType); sponsorTimesSubmitting[this.props.index].actionType = this.getNextActionType(category, inputActionType);
Config.config.segmentTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimesSubmitting); Config.config.unsubmittedSegments[this.props.contentContainer().sponsorVideoID] = sponsorTimesSubmitting;
Config.forceUpdate("unsubmittedSegments");
this.props.contentContainer().updatePreviewBar(); this.props.contentContainer().updatePreviewBar();
@@ -555,7 +556,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
sponsorTimes.splice(index, 1); sponsorTimes.splice(index, 1);
//save this //save this
Config.config.segmentTimes.set(this.props.contentContainer().sponsorVideoID, sponsorTimes); Config.config.unsubmittedSegments[this.props.contentContainer().sponsorVideoID] = sponsorTimes;
Config.forceUpdate("unsubmittedSegments");
this.props.contentContainer().updatePreviewBar(); this.props.contentContainer().updatePreviewBar();

View File

@@ -8,7 +8,7 @@ interface SBConfig {
isVip: boolean, isVip: boolean,
lastIsVipUpdate: number, lastIsVipUpdate: number,
/* Contains unsubmitted segments that the user has created. */ /* Contains unsubmitted segments that the user has created. */
segmentTimes: SBMap<string, SponsorTime[]>, unsubmittedSegments: Record<string, SponsorTime[]>,
defaultCategory: Category, defaultCategory: Category,
whitelistedChannels: string[], whitelistedChannels: string[],
forceChannelCheck: boolean, forceChannelCheck: boolean,
@@ -99,73 +99,7 @@ export interface SBObject {
defaults: SBConfig; defaults: SBConfig;
localConfig: SBConfig; localConfig: SBConfig;
config: SBConfig; config: SBConfig;
forceUpdate(prop: string): void;
// Functions
encodeStoredItem<T>(data: T): T | UnencodedSegmentTimes;
convertJSON(): void;
}
// Allows a SBMap to be conveted into json form
// Currently used for local storage
class SBMap<T, U> extends Map {
id: string;
constructor(id: string, entries?: [T, U][]) {
super();
this.id = id;
// Import all entries if they were given
if (entries !== undefined) {
for (const item of entries) {
super.set(item[0], item[1])
}
}
}
get(key): U {
return super.get(key);
}
rawSet(key, value) {
return super.set(key, value);
}
update() {
// Store updated SBMap locally
chrome.storage.sync.set({
[this.id]: encodeStoredItem(this)
});
}
set(key: T, value: U) {
const result = super.set(key, value);
this.update();
return result;
}
delete(key) {
const result = super.delete(key);
// Make sure there are no empty elements
for (const entry of this.entries()) {
if (entry[1].length === 0) {
super.delete(entry[0]);
}
}
this.update();
return result;
}
clear() {
const result = super.clear();
this.update();
return result;
}
} }
const Config: SBObject = { const Config: SBObject = {
@@ -177,7 +111,7 @@ const Config: SBObject = {
userID: null, userID: null,
isVip: false, isVip: false,
lastIsVipUpdate: 0, lastIsVipUpdate: 0,
segmentTimes: new SBMap("segmentTimes"), unsubmittedSegments: {},
defaultCategory: "chooseACategory" as Category, defaultCategory: "chooseACategory" as Category,
whitelistedChannels: [], whitelistedChannels: [],
forceChannelCheck: false, forceChannelCheck: false,
@@ -334,52 +268,15 @@ const Config: SBObject = {
}, },
localConfig: null, localConfig: null,
config: null, config: null,
forceUpdate
// Functions
encodeStoredItem,
convertJSON
}; };
// Function setup // Function setup
/**
* A SBMap cannot be stored in the chrome storage.
* This data will be encoded into an array instead
*
* @param data
*/
function encodeStoredItem<T>(data: T): T | UnencodedSegmentTimes {
// if data is SBMap convert to json for storing
if(!(data instanceof SBMap)) return data;
return Array.from(data.entries()).filter((element) => element[1].length > 0); // Remove empty entries
}
/**
* An SBMap cannot be stored in the chrome storage.
* This data will be decoded from the array it is stored in
*
* @param {*} data
*/
function decodeStoredItem<T>(id: string, data: T): T | SBMap<string, SponsorTime[]> {
if (!Config.defaults[id]) return data;
if (Config.defaults[id] instanceof SBMap) {
try {
if (!Array.isArray(data)) return data;
return new SBMap(id, data as UnencodedSegmentTimes);
} catch(e) {
console.error("Failed to parse SBMap: " + id);
}
}
// If all else fails, return the data
return data;
}
function configProxy(): SBConfig { function configProxy(): SBConfig {
chrome.storage.onChanged.addListener((changes: {[key: string]: chrome.storage.StorageChange}) => { chrome.storage.onChanged.addListener((changes: {[key: string]: chrome.storage.StorageChange}) => {
for (const key in changes) { for (const key in changes) {
Config.localConfig[key] = decodeStoredItem(key, changes[key].newValue); Config.localConfig[key] = changes[key].newValue;
} }
for (const callback of Config.configListeners) { for (const callback of Config.configListeners) {
@@ -392,7 +289,7 @@ function configProxy(): SBConfig {
Config.localConfig[prop] = value; Config.localConfig[prop] = value;
chrome.storage.sync.set({ chrome.storage.sync.set({
[prop]: encodeStoredItem(value) [prop]: value
}); });
return true; return true;
@@ -415,6 +312,12 @@ function configProxy(): SBConfig {
return new Proxy<SBConfig>({handler} as unknown as SBConfig, handler); return new Proxy<SBConfig>({handler} as unknown as SBConfig, handler);
} }
function forceUpdate(prop: string): void {
chrome.storage.sync.set({
[prop]: Config.localConfig[prop]
});
}
function fetchConfig(): Promise<void> { function fetchConfig(): Promise<void> {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.storage.sync.get(null, function(items) { chrome.storage.sync.get(null, function(items) {
@@ -425,6 +328,14 @@ function fetchConfig(): Promise<void> {
} }
function migrateOldFormats(config: SBConfig) { function migrateOldFormats(config: SBConfig) {
if (config["segmentTimes"]) {
for (const item of config["segmentTimes"]) {
config.unsubmittedSegments[item[0]] = item[1];
}
chrome.storage.sync.remove("segmentTimes");
}
if (!config["exclusive_accessCategoryAdded"] && !config.categorySelections.some((s) => s.name === "exclusive_access")) { if (!config["exclusive_accessCategoryAdded"] && !config.categorySelections.some((s) => s.name === "exclusive_access")) {
config["exclusive_accessCategoryAdded"] = true; config["exclusive_accessCategoryAdded"] = true;
@@ -512,19 +423,12 @@ function migrateOldFormats(config: SBConfig) {
async function setupConfig() { async function setupConfig() {
await fetchConfig(); await fetchConfig();
addDefaults(); addDefaults();
convertJSON();
const config = configProxy(); const config = configProxy();
migrateOldFormats(config); migrateOldFormats(config);
Config.config = config; Config.config = config;
} }
function convertJSON(): void {
Object.keys(Config.localConfig).forEach(key => {
Config.localConfig[key] = decodeStoredItem(key, Config.localConfig[key]);
});
}
// Add defaults // Add defaults
function addDefaults() { function addDefaults() {
for (const key in Config.defaults) { for (const key in Config.defaults) {

View File

@@ -1510,7 +1510,8 @@ function startOrEndTimingNewSegment() {
} }
// Save the newly created segment // Save the newly created segment
Config.config.segmentTimes.set(sponsorVideoID, sponsorTimesSubmitting); Config.config.unsubmittedSegments[sponsorVideoID] = sponsorTimesSubmitting;
Config.forceUpdate("unsubmittedSegments");
// Make sure they know if someone has already submitted something it while they were watching // Make sure they know if someone has already submitted something it while they were watching
sponsorsLookup(sponsorVideoID); sponsorsLookup(sponsorVideoID);
@@ -1532,7 +1533,8 @@ function isSegmentCreationInProgress(): boolean {
function cancelCreatingSegment() { function cancelCreatingSegment() {
if (isSegmentCreationInProgress()) { if (isSegmentCreationInProgress()) {
sponsorTimesSubmitting.splice(sponsorTimesSubmitting.length - 1, 1); sponsorTimesSubmitting.splice(sponsorTimesSubmitting.length - 1, 1);
Config.config.segmentTimes.set(sponsorVideoID, sponsorTimesSubmitting); Config.config.unsubmittedSegments[sponsorVideoID] = sponsorTimesSubmitting;
Config.forceUpdate("unsubmittedSegments");
if (sponsorTimesSubmitting.length <= 0) resetSponsorSubmissionNotice(); if (sponsorTimesSubmitting.length <= 0) resetSponsorSubmissionNotice();
} }
@@ -1542,7 +1544,7 @@ function cancelCreatingSegment() {
} }
function updateSponsorTimesSubmitting(getFromConfig = true) { function updateSponsorTimesSubmitting(getFromConfig = true) {
const segmentTimes = Config.config.segmentTimes.get(sponsorVideoID); const segmentTimes = Config.config.unsubmittedSegments[sponsorVideoID];
//see if this data should be saved in the sponsorTimesSubmitting variable //see if this data should be saved in the sponsorTimesSubmitting variable
if (getFromConfig && segmentTimes != undefined) { if (getFromConfig && segmentTimes != undefined) {
@@ -1671,7 +1673,7 @@ function closeInfoMenuAnd<T>(func: () => T): T {
function clearSponsorTimes() { function clearSponsorTimes() {
const currentVideoID = sponsorVideoID; const currentVideoID = sponsorVideoID;
const sponsorTimes = Config.config.segmentTimes.get(currentVideoID); const sponsorTimes = Config.config.unsubmittedSegments[currentVideoID];
if (sponsorTimes != undefined && sponsorTimes.length > 0) { if (sponsorTimes != undefined && sponsorTimes.length > 0) {
const confirmMessage = chrome.i18n.getMessage("clearThis") + getSegmentsMessage(sponsorTimes) const confirmMessage = chrome.i18n.getMessage("clearThis") + getSegmentsMessage(sponsorTimes)
@@ -1681,7 +1683,8 @@ function clearSponsorTimes() {
resetSponsorSubmissionNotice(); resetSponsorSubmissionNotice();
//clear the sponsor times //clear the sponsor times
Config.config.segmentTimes.delete(currentVideoID); delete Config.config.unsubmittedSegments[currentVideoID];
Config.forceUpdate("unsubmittedSegments");
//clear sponsor times submitting //clear sponsor times submitting
sponsorTimesSubmitting = []; sponsorTimesSubmitting = [];
@@ -1828,7 +1831,8 @@ async function sendSubmitMessage() {
} }
//update sponsorTimes //update sponsorTimes
Config.config.segmentTimes.set(sponsorVideoID, sponsorTimesSubmitting); Config.config.unsubmittedSegments[sponsorVideoID] = sponsorTimesSubmitting;
Config.forceUpdate("unsubmittedSegments");
// Check to see if any of the submissions are below the minimum duration set // Check to see if any of the submissions are below the minimum duration set
if (Config.config.minDuration > 0) { if (Config.config.minDuration > 0) {
@@ -1855,7 +1859,8 @@ async function sendSubmitMessage() {
stopAnimation(); stopAnimation();
// Remove segments from storage since they've already been submitted // Remove segments from storage since they've already been submitted
Config.config.segmentTimes.delete(sponsorVideoID); delete Config.config.unsubmittedSegments[sponsorVideoID];
Config.forceUpdate("unsubmittedSegments");
const newSegments = sponsorTimesSubmitting; const newSegments = sponsorTimesSubmitting;
try { try {
@@ -2079,6 +2084,7 @@ function checkForPreloadedSegment() {
} }
if (pushed) { if (pushed) {
Config.config.segmentTimes.set(sponsorVideoID, sponsorTimesSubmitting); Config.config.unsubmittedSegments[sponsorVideoID] = sponsorTimesSubmitting;
Config.forceUpdate("unsubmittedSegments");
} }
} }

View File

@@ -494,16 +494,10 @@ function activatePrivateTextChange(element: HTMLElement) {
} }
let result = Config.config[option]; let result = Config.config[option];
// See if anything extra must be done // See if anything extra must be done
switch (option) { switch (option) {
case "*": { case "*": {
const jsonData = JSON.parse(JSON.stringify(Config.localConfig)); result = JSON.stringify(Config.localConfig);
// Fix segmentTimes data as it is destroyed from the JSON stringify
jsonData.segmentTimes = Config.encodeStoredItem(Config.localConfig.segmentTimes);
result = JSON.stringify(jsonData);
break; break;
} }
} }
@@ -557,7 +551,6 @@ async function setTextOption(option: string, element: HTMLElement, value: string
for (const key in newConfig) { for (const key in newConfig) {
Config.config[key] = newConfig[key]; Config.config[key] = newConfig[key];
} }
Config.convertJSON();
if (newConfig.supportInvidious) { if (newConfig.supportInvidious) {
const checkbox = <HTMLInputElement> document.querySelector("#support-invidious > div > label > input"); const checkbox = <HTMLInputElement> document.querySelector("#support-invidious > div > label > input");
@@ -585,7 +578,6 @@ async function setTextOption(option: string, element: HTMLElement, value: string
function downloadConfig() { function downloadConfig() {
const file = document.createElement("a"); const file = document.createElement("a");
const jsonData = JSON.parse(JSON.stringify(Config.localConfig)); const jsonData = JSON.parse(JSON.stringify(Config.localConfig));
jsonData.segmentTimes = Config.encodeStoredItem(Config.localConfig.segmentTimes);
file.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(jsonData))); file.setAttribute("href", "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(jsonData)));
file.setAttribute("download", "SponsorBlockConfig.json"); file.setAttribute("download", "SponsorBlockConfig.json");
document.body.append(file); document.body.append(file);
@@ -642,9 +634,6 @@ function copyDebugOutputToClipboard() {
config: JSON.parse(JSON.stringify(Config.localConfig)) // Deep clone config object config: JSON.parse(JSON.stringify(Config.localConfig)) // Deep clone config object
}; };
// Fix segmentTimes data as it is destroyed from the JSON stringify
output.config.segmentTimes = Config.encodeStoredItem(Config.localConfig.segmentTimes);
// Sanitise sensitive user config values // Sanitise sensitive user config values
delete output.config.userID; delete output.config.userID;
output.config.serverAddress = (output.config.serverAddress === CompileConfig.serverAddress) output.config.serverAddress = (output.config.serverAddress === CompileConfig.serverAddress)

View File

@@ -262,7 +262,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
return; return;
} }
sponsorTimes = Config.config.segmentTimes.get(currentVideoID) ?? []; sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] ?? [];
updateSegmentEditingUI(); updateSegmentEditingUI();
messageHandler.sendMessage( messageHandler.sendMessage(
@@ -360,7 +360,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
// Only update the segments after a segment was created // Only update the segments after a segment was created
if (!creatingSegment) { if (!creatingSegment) {
sponsorTimes = Config.config.segmentTimes.get(currentVideoID) || []; sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] || [];
} }
// Update the UI // Update the UI