Skip to content

Instantly share code, notes, and snippets.

@syusui-s
Last active February 4, 2023 03:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syusui-s/d3810aa34f68d8476a9c0eb182a18b9d to your computer and use it in GitHub Desktop.
Save syusui-s/d3810aa34f68d8476a9c0eb182a18b9d to your computer and use it in GitHub Desktop.
Chrome Search Engine Extractor / Importer

Chrome(Chromium) Search Engine Extractor/Importer + Firefox Importer

How to use

  1. Press F12 (Open "Chrome Dev Tools")
  2. Select "Console Tab" in Dev Tools
  3. Paste a content of file which you want to execute
  4. Press enter to execute
  5. The result of execution will be saved to clipboard

If you want to save the result, open the text editor, paste it and save it.

  • Extractor: extract search engines as JSON
  • Importer: import search engines from an extracted JSON
  • Converter: convert an extracted JSON to other format

Files

Comparing Features

TBD add table

// Custom Search Engine https://addons.mozilla.org/ja/firefox/addon/custom-search-engine/
{
const convertGoogleSearchUrl = (queryUrl) => queryUrl
.replace('{google:baseURL}', 'https://www.google.co.jp/')
.replace(/{google:\w+}/g, '')
.replaceAll('{inputEncoding}', 'UTF-8')
.replace('%s', '{searchTerms}');
const json = prompt('Paste exported JSON');
const engines = JSON.parse(json);
const result = {
"file_version": "2.0",
"preferences": { "custom_engines": {} },
};
engines.forEach(({ name, keyword, queryUrl }) => {
result['preferences']['custom_engines'][keyword] = {
name,
url: convertGoogleSearchUrl(queryUrl),
category: '',
description: '',
};
});
copy(JSON.stringify(result, null, 2));
}
(() => {
const convertGoogleSearchUrl = (queryUrl) => queryUrl
.replace('{google:baseURL}', 'https://www.google.co.jp/')
.replace(/{google:\w+}/g, '')
.replaceAll('{inputEncoding}', 'UTF-8');
const json = prompt('Paste exported JSON');
const engines = JSON.parse(json);
const doc = new Document();
const root = doc.createElement('html');
doc.appendChild(root);
const body = doc.createElement('body');
root.appendChild(body);
const h1 = doc.createElement('h1');
h1.textContent = 'Search Engines';
body.appendChild(h1);
const dl = doc.createElement('dl');
body.appendChild(dl);
const p = doc.createElement('p');
dl.appendChild(p);
const h3 = doc.createElement('h3');
p.appendChild(h3);
h3.textContent = 'Search Engines';
engines.forEach(({ name, keyword, queryUrl, icon }) => {
const link = doc.createElement('a');
link.setAttribute('HREF', convertGoogleSearchUrl(queryUrl));
link.setAttribute('SHORTCUTURL', keyword);
link.setAttribute('ICON_URI', icon);
link.textContent = name;
const dt = doc.createElement('dt');
dt.appendChild(link);
dl.appendChild(dt);
});
copy(doc.documentElement.outerHTML);
})()
// Search Engines Helper
// https://addons.mozilla.org/ja/firefox/addon/search-engines-helper/
{
const convertGoogleSearchUrl = (queryUrl) => queryUrl
.replace('{google:baseURL}', 'https://www.google.co.jp/')
.replace(/{google:\w+}/g, '')
.replaceAll('{inputEncoding}', 'UTF-8');
const json = prompt('Paste exported JSON');
const engines = JSON.parse(json);
const result = {};
engines.forEach(({ name, keyword, queryUrl, icon}) => {
result[name] = {
'searchURL': convertGoogleSearchUrl(queryUrl),
'iconURL': icon,
'keyword': keyword,
};
});
copy(JSON.stringify(result, null, 4));
}
{
const json = prompt('Paste exported JSON');
const engines = JSON.parse(json);
copy(engines.map(e => `${e.keyword}\t${e.name}\t${e.queryUrl}`).join('\n'))
}
{
class Engine {
constructor(name, keyword, queryUrl, icon) {
Object.assign(this, { name, keyword, queryUrl, icon });
}
}
const querySelectorAllShadow = (doc, paths) =>
paths.reduce((docs, selector) =>
docs.reduce((init, doc) => {
const elems = doc && doc.querySelectorAll(selector);
elems.forEach(elem =>
init.push(
elem && 'shadowRoot' in elem ? elem.shadowRoot : elem
)
);
return init;
}, []),
[doc]);
const querySelectorShadow = (doc, paths) => querySelectorAllShadow(doc, paths).find(e => e != null);
const settingsSearchEnginesPage = querySelectorShadow(document, [
'body > settings-ui', '#main', 'settings-basic-page',
'#basicPage > settings-section[section="search"] > settings-search-page',
'#pages > settings-subpage > settings-search-engines-page'
]);
const parseSiteFavicon = (siteFavicon) => {
return siteFavicon.__data?.faviconUrl;
};
const toDataUri = () => {
};
const findEngines = (page, id = null) => {
const engineListQuery = `settings-search-engines-list${id || ':not([id])'}`;
const engines = querySelectorAllShadow(page, [engineListQuery, '#container > iron-list > settings-search-engine-entry']);
return engines;
};
const buildEngine = engineElem => {
if (engineElem == null)
return null;
const name = engineElem.querySelector('#name-column > div:nth-child(2)').textContent;
const keyword = engineElem.querySelector('#keyword-column > div').textContent;
const queryUrl = engineElem.querySelector('#url-column').textContent;
const icon = parseSiteFavicon(engineElem.querySelector('#name-column site-favicon'));
return new Engine(name, keyword, queryUrl, icon);
};
const otherEngines = findEngines(settingsSearchEnginesPage, '#otherEngines');
copy(JSON.stringify(otherEngines.map(buildEngine).sort(e => e.name)));
}
Bookmark(async () => {
class Engine {
constructor(name, keyword, queryUrl) {
Object.assign(this, { name, keyword, queryUrl });
}
}
const sleep = x => new Promise(res => setTimeout(res, x));
const querySelectorAllShadow = (doc, paths) =>
paths.reduce((docs, selector) =>
docs.reduce((init, doc) => {
const elems = doc && doc.querySelectorAll(selector);
elems.forEach(elem =>
init.push(
elem && 'shadowRoot' in elem ? elem.shadowRoot : elem
)
);
return init;
}, []),
[doc]);
const querySelectorShadow = (doc, paths) => querySelectorAllShadow(doc, paths).find(e => e != null);
const json = prompt('Paste a extracted search engines', '[{"name": "a", "keyword": "a", "queryUrl": "a"}]');
let rawEngines;
try {
rawEngines = JSON.parse(json);
} catch (e) {
if (e instanceof SyntaxError) {
alert('Could not parse input; Check a pasted text is correct.');
return;
}
throw e;
}
const engines = rawEngines.map(engine => {
const { name, keyword, queryUrl } = engine;
return new Engine(name, keyword, queryUrl);
});
for (const engine of engines) {
const settingsSearchEnginesPage = querySelectorShadow(document, [
'body > settings-ui', '#main', 'settings-basic-page',
'#basicPage > settings-section[section="search"] > settings-search-page',
'#pages > settings-subpage > settings-search-engines-page'
]);
const addSearchEngine = settingsSearchEnginesPage.querySelector('#addSearchEngine');
addSearchEngine.click();
await sleep(100);
const dialog = settingsSearchEnginesPage.querySelector('settings-search-engine-dialog').shadowRoot.querySelector('#dialog');
const nameInput = querySelectorShadow(dialog, ['#searchEngine']).querySelector('#input');
const keywordInput = querySelectorShadow(dialog, ['#keyword']).querySelector('#input');
const queryUrlInput = querySelectorShadow(dialog, ['#queryUrl']).querySelector('#input');
nameInput.focus();
nameInput.value = engine.name;
nameInput.dispatchEvent(new Event('input'));
keywordInput.focus();
keywordInput.value = engine.keyword;
keywordInput.dispatchEvent(new Event('input'));
queryUrlInput.focus();
queryUrlInput.value = engine.queryUrl;
queryUrlInput.dispatchEvent(new Event('input'));
dialog.querySelector('#actionButton').click();
await sleep(100);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment