-
-
Save kkeybbs/d817fad016b401485ab8c4c8fcffe568 to your computer and use it in GitHub Desktop.
// 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(); |
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
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
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 toconst keys = Object.keys(current);
to avoid undefined key problem in the lineconst 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
Everything still works @ ms edge chrome canary 76. Thanks for script !