mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-08 04:27:15 +03:00
Move segment times from encoded array to normal js object
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
136
src/config.ts
136
src/config.ts
@@ -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) {
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user