Skip to content

Instantly share code, notes, and snippets.

@kkeybbs
Last active February 5, 2024 07:47
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save kkeybbs/d817fad016b401485ab8c4c8fcffe568 to your computer and use it in GitHub Desktop.
Save kkeybbs/d817fad016b401485ab8c4c8fcffe568 to your computer and use it in GitHub Desktop.
Backup chrome flags to json and restore the backup on another machine.
// 2022-04-03, tested with Chrome 99.0.4844.84 on MacBook Pro m1
/*
Open chrome://flags/
F12 open developer console, swtich to tab "Console"
Paste below codes
- input backup() to download flags backup file
- input restore() to select one backup to restore
*/
function saveFile(filename, data) {
return new Promise(resolve => {
const blob = new Blob([data], { type: 'octet/stream' });
const url = window.URL.createObjectURL(blob);
const dom = document.createElement('a');
setTimeout(() => {
dom.href = url;
dom.download = filename;
dom.dispatchEvent(new MouseEvent('click'));
window.URL.revokeObjectURL(url);
resolve();
});
});
}
function selectFile(ext) {
return new Promise((resolve, reject) => {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = (e) => {
if (e.target.files.length == 0) {
reject("canceled");
return;
}
const file = e.target.files[0];
resolve(file);
};
input.dispatchEvent(new MouseEvent('click'));
});
}
function readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onabort = reader.onerror = e => reject(e);
reader.onload = e => resolve(e.target.result);
reader.readAsBinaryString(file);
});
}
async function getFlags() {
const module = await import('chrome://resources/js/cr.m.js');
const config = await module.sendWithPromise('requestExperimentalFeatures');
return config;
}
function parseFlags(config) {
const flags = {};
config.supportedFeatures.forEach(flag => {
const k = flag.internal_name;
flags[k] = flag;
if (flag.options) {
const options = flag.options.filter(option => option.selected);
flag.selected = options.length == 0 ? flag.options[0] : options[0];
flag.value = flag.selected.internal_name;
} else {
flag.value = flag.enabled.toString();
}
});
return flags;
}
async function backup() {
const config = await getFlags();
await saveFile("backup.chrome-flags.json", JSON.stringify(config));
}
async function restore() {
const file = await selectFile('.json');
const data = await readFile(file);
const flags = parseFlags(JSON.parse(data));
const current = parseFlags(await getFlags());
const keys = Array.from(new Set(Object.keys(flags).concat(Object.keys(current))));
const same = keys.filter(k => current[k].value == flags[k].value);
const diff = keys.filter(k => same.indexOf(k) == -1);
const tasks = [];
const table = diff.map(k => {
const a = current[k];
const b = flags[k];
const noOptions = ["trie", "false"].indexOf(a.value) != -1;
tasks.push(noOptions ? [k, b.value] : [b.value, "true"]);
return noOptions ? {
name: flags[k].name,
current: a.value,
update: b.value,
url: `chrome://flags/#${current[k].internal_name}`,
} : {
name: flags[k].name,
current: a.selected.description,
update: b.selected.description,
url: `chrome://flags/#${current[k].internal_name}`,
};
});
console.table(table);
console.log(`%c skip ${same.length} same items`, 'background: #FF0; color: #202124');
console.log(`%c restore ${diff.length} diff items:`, 'background: #FF0; color: #202124');
for (const task of tasks) {
chrome.send("enableExperimentalFeature", task);
}
}
// backup();
// restore();
@mikeman8224
Copy link

Forgive the novice here. How do I load/use this? Do I load it like an extension in developer mode?

@mvasim007
Copy link

Backup works but
Restore error @chrome version 67

VM109:55 Uncaught TypeError: Cannot read property 'length' of undefined
at parse_data (:55:48)
at HTMLButtonElement.restore (:107:24)
parse_data @ VM109:55
restore @ VM109:107

@vadash
Copy link

vadash commented May 1, 2019

Everything still works @ ms edge chrome canary 76. Thanks for script !

@dennyamarojr
Copy link

dennyamarojr commented Jul 26, 2020

Hi, I try these script but it seems that in latest versions of chromium appear an error when I try to restore

Here's a Image, the browser used was Brave Browser Version 1.11.101 Chromium: 84.0.4147.89 (Official Build) (64-bit)

image

@Rannison
Copy link

This doesn't seem to be working as-is at this time of writing, I suspect due to recent security-driven changes. Particularly, if I'm understanding correctly based on what search results I was able to find (apologies if I'm off base here, I'm a layman), the issue appears to be due to content security policies affecting innerHTML (e.g., see this SE post).

Based upon the answers iI did make an attempt to modify the code in-line directly from the console, but as I expected due to my complete lack of knowledge/experience, I'm getting a syntactical error:

Uncaught SyntaxError: Invalid or unexpected token

@shpj123
Copy link

shpj123 commented Sep 29, 2022

thx! This works on Edge 105, though the line
const keys = Array.from(new Set(Object.keys(flags).concat(Object.keys(current))));
needs to be changed to
const keys = Object.keys(current);
to avoid undefined key problem in the line
const same = keys.filter((k) => current[k].value == flags[k].value);

the same problem also occurs when current has more keys than flags

@MANICX100
Copy link

MANICX100 commented Nov 15, 2022

thx! This works on Edge 105, though the line const keys = Array.from(new Set(Object.keys(flags).concat(Object.keys(current)))); needs to be changed to const keys = Object.keys(current); to avoid undefined key problem in the line const same = keys.filter((k) => current[k].value == flags[k].value);

the same problem also occurs when current has more keys than flags

No longer works for me on Edge 108 Beta on Windows Insider build
backup does not prompt to save
restore says
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'value')
Was working a few months back on earlier versions with @shpj123 fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment