Extractor.watch() improvements

- only watch current window
- stop watch on window close
- don't ask user to confirm when fails
This commit is contained in:
2020-01-15 18:28:28 +08:00
parent 7644a1363f
commit d82010686d
3 changed files with 65 additions and 22 deletions

View File

@ -1,5 +1,6 @@
import { Actions, Request } from "../common"; import { Actions, Request } from "../common";
import { sendMessage } from "./messaging"; import { sendMessage } from "./messaging";
import { logger } from "./common";
/** /**
* redirect tab to url. * redirect tab to url.
@ -41,7 +42,7 @@ export function redirectTab(tab: chrome.tabs.Tab, url: string) {
* @param {Array<string>} fieldSelectors fields selectors for selecting fields (data columns) under each item * @param {Array<string>} fieldSelectors fields selectors for selecting fields (data columns) under each item
* @returns {Promise<string[]>} a promise of extracted data * @returns {Promise<string[]>} a promise of extracted data
*/ */
export function extractTabData(tab, itemsSelector, fieldSelectors) { export function extractTabData(tab: chrome.tabs.Tab, itemsSelector: string, fieldSelectors: string[], askOnfail?: boolean) {
let req = { let req = {
action: Actions.EXTRACT, action: Actions.EXTRACT,
itemsSelector: itemsSelector, itemsSelector: itemsSelector,
@ -49,7 +50,13 @@ export function extractTabData(tab, itemsSelector, fieldSelectors) {
} }
let checker = (result, err, tryCount) => { let checker = (result, err, tryCount) => {
if (!result || !result.length) { if (!result || !result.length) {
if (tryCount % 20 == 0 && confirm('No data found in current page. \n\nContinue to next page?')) { if (
tryCount % 20 == 0 && (
!askOnfail ||
confirm('No data found in current page. \n\nContinue to next page?')
)
) {
logger.warn(`Failed after ${tryCount} tries: ${tab.url}`)
return []; return [];
} else { } else {
return undefined; return undefined;
@ -135,6 +142,25 @@ export async function findIncognitoWindow(): Promise<chrome.windows.Window> {
}); });
} }
export async function getCurrentWindow(): Promise<chrome.windows.Window> {
return new Promise((resolve, reject) => {
chrome.windows.getCurrent(
(windows: chrome.windows.Window) => {
return resolve(windows);
}
);
});
}
export async function getWindowByID(id: number) {
return new Promise<chrome.windows.Window>((resolve, reject) => {
chrome.windows.get(id, function (window) {
chrome.runtime.lastError;
resolve(window);
})
})
}
export async function CreateIncognitoWindow() { export async function CreateIncognitoWindow() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
chrome.windows.create( chrome.windows.create(

View File

@ -31,7 +31,7 @@ export function sendMessage<T>(
loop(); loop();
async function loop() { async function loop() {
logger.debug("Request for", req.action); logger.debug("Request for", Actions[req.action]);
let tabAvailable = await getTabByID(tab.id); let tabAvailable = await getTabByID(tab.id);
if (!tabAvailable) { if (!tabAvailable) {
reject("Task interrupted due to the target tab is closed."); reject("Task interrupted due to the target tab is closed.");

View File

@ -1,5 +1,5 @@
import { parseUrls } from "./tools"; import { parseUrls } from "./tools";
import { queryUrl, redirectTab, scrollToBottom, extractTabData } from "./actions"; import { queryUrl, redirectTab, scrollToBottom, extractTabData, findIncognitoWindow, getCurrentWindow, getWindowByID } from "./actions";
import { testArgs, signitures } from "./signiture"; import { testArgs, signitures } from "./signiture";
import { ExtractResult } from "./result"; import { ExtractResult } from "./result";
import { messageSubscribers, ActionSubscriber } from "./messaging"; import { messageSubscribers, ActionSubscriber } from "./messaging";
@ -14,6 +14,7 @@ export class Task {
private _fieldSelectors: string[]; private _fieldSelectors: string[];
private _urls: string[] = []; private _urls: string[] = [];
private _running = false; private _running = false;
private _listeners: ActionSubscriber[] = [];
constructor(options: any, ...arg: any); constructor(options: any, ...arg: any);
constructor(options: any, itemsSelector: string, fieldSelectors: string[]); constructor(options: any, itemsSelector: string, fieldSelectors: string[]);
@ -56,15 +57,46 @@ export class Task {
} }
stop() { stop() {
this._running = false; this._running = false;
messageSubscribers.removeListener(Actions.REPORT_NEW_PAGE, this.listener); let listener: ActionSubscriber;
while (listener = this._listeners.pop()) {
messageSubscribers.removeListener(Actions.REPORT_NEW_PAGE, listener);
}
} }
watch() { async watch() {
if (this._running) { if (this._running) {
logger.info("The task is running. Please wait..."); logger.info("The task is running. Please wait...");
return; return;
} }
this._running = true; this._running = true;
messageSubscribers.addListener(Actions.REPORT_NEW_PAGE, this.listener); let window = await findIncognitoWindow() || await getCurrentWindow();
if (!window) {
logger.info("No window to watch...");
return;
}
let listener: ActionSubscriber = async (request, sender, sendResponse) => {
let findWindow = await getWindowByID(window.id);
if (!findWindow) {
// stop watch on window close.
messageSubscribers.removeListener(Actions.REPORT_NEW_PAGE, listener);
return;
}
// only watch current window.
if (sender.tab.windowId != window.id) return;
let pm = this.makeOptionalTasks(sender.tab);
return pm.then(
() => extractTabData(sender.tab, this._itemsSelector, this._fieldSelectors, false)
).then(
results => {
if (results && results.length) {
this.saveResult(results, sender.tab.url);
}
}
).catch(
e => logger.error(e)
)
}
this._listeners.push(listener);
messageSubscribers.addListener(Actions.REPORT_NEW_PAGE, listener);
} }
async execute(tab: chrome.tabs.Tab, upstreamData?: ExtractResult): Promise<void> { async execute(tab: chrome.tabs.Tab, upstreamData?: ExtractResult): Promise<void> {
if (!tab) return Promise.reject("No tab to execute the task."); if (!tab) return Promise.reject("No tab to execute the task.");
@ -108,21 +140,6 @@ export class Task {
} }
); );
} }
private listener: ActionSubscriber = (request, sender, sendResponse) => {
sendResponse('recieved!');
let pm = this.makeOptionalTasks(sender.tab);
return pm.then(
() => extractTabData(sender.tab, this._itemsSelector, this._fieldSelectors)
).then(
results => {
if (results && results.length) {
this.saveResult(results, sender.tab.url);
}
}
).catch(
e => logger.error(e)
)
}
private makeOptionalTasks(tab: chrome.tabs.Tab): Promise<any> { private makeOptionalTasks(tab: chrome.tabs.Tab): Promise<any> {
let pm: Promise<any>; let pm: Promise<any>;
if (this._options["scrollToBottom"]) { if (this._options["scrollToBottom"]) {