// function extract(itemsSelector, fieldSelectors, url, from, to, interval) // function extract(itemsSelector, fieldSelectors, url, pages) function extract(itemsSelector, fieldSelectors, url, ...args) { let urls = []; if (url) { if (args[0] instanceof Array) { urls = args[0].map(p => url.replace("${page}", p)); } else if (args.length >= 3) { let from = args.shift(); let to = args.shift(); let interval = args.shift(); for (let i = from; i <= to; i += interval) { urls.push(url.replace("${page}", i)); } } } let data = []; return new Promise((resolve, reject) => { chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { let pms; let tab = tabs[0]; if (urls.length) { pms = urls.reduce((p, url) => p.then( results => { data.push(...results); return redirectTab(tab, url).then( () => extractData(tab, itemsSelector, fieldSelectors) ); }, () => p ), Promise.resolve([])); } else { pms = extractData(tab, itemsSelector, fieldSelectors); } pms.then( results => { data.push(...results); data.unshift(fieldSelectors); saveFileAsk(data); resolve("save done.") }, err => reject(err) ); }); }); } function redirectTab(tab, url) { let curUrl = ""; return queryUrl(tab) .then(u => { if (url !== u) { curUrl = u; let req = { from: "doExtractGotoUrl", url: url } chrome.tabs.sendMessage(tab.id, req); } }) .then(() => queryUrl(tab, curUrl)) .then(() => reportIn(tab)); } function extractData(tab, itemsSelector, fieldSelectors) { let req = { from: "doExtractRequest", itemsSelector: itemsSelector, fieldSelectors: fieldSelectors } let failMsg = "extractTabData failed after 10 second."; let cond = r => !!r; return sendMessageAndDetect(tab, req, cond, failMsg); } function reportIn(tab) { let req = { from: "doExtractReportIn" } let failMsg = "reportIn failed after 10 second."; let cond = r => r == req.from; return sendMessageAndDetect(tab, req, cond, failMsg); } function queryUrl(tab, urlExcluded) { let req = { from: "doExtractQueryUrl" } let failMsg = "queryUrl failed after 10 second."; let cond = url => url && (!urlExcluded || (urlExcluded && urlExcluded != url)); return sendMessageAndDetect(tab, req, cond, failMsg); } /** * Repeatedly sending a message to target tab until the response is detected good. * The response is returned with the Promise. * @param {chrome.tab} tab the table where to send the message * @param {object} req the request data. * @param {function} cond success condition function, r:any=>boolean * @param {string} failMsg message when failed after time out * @param {number} failedTimeOut fail time out * @param {number} detectInterval interval for detecting */ function sendMessageAndDetect(tab, req, cond, failMsg, failedTimeOut, detectInterval) { failedTimeOut = failedTimeOut || 10000; detectInterval = detectInterval || 500; return new Promise((resolve, reject) => { let timeOut; let rejectTimeout = setTimeout(() => { reject(failMsg); clearTimeout(timeOut); }, failedTimeOut); loop(); function loop() { chrome.tabs.sendMessage(tab.id, req, r => { if (cond(r)) { resolve(r); clearTimeout(rejectTimeout); } else { timeOut = setTimeout(() => { loop(); }, detectInterval); } }); } }); }