feature: collecting item links

This commit is contained in:
johnathan 2025-04-12 18:19:29 +08:00
parent bdc3d0d512
commit 94fa61dfa1
5 changed files with 71 additions and 6 deletions

View File

@ -39,6 +39,7 @@
"chokidar": "^4.0.3",
"cross-env": "^7.0.3",
"crx": "^5.0.1",
"emittery": "^1.1.0",
"esno": "^4.8.0",
"fs-extra": "^11.2.0",
"husky": "^9.1.7",

9
pnpm-lock.yaml generated
View File

@ -41,6 +41,9 @@ importers:
crx:
specifier: ^5.0.1
version: 5.0.1
emittery:
specifier: ^1.1.0
version: 1.1.0
esno:
specifier: ^4.8.0
version: 4.8.0
@ -1381,6 +1384,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
emittery@1.1.0:
resolution: {integrity: sha512-rsX7ktqARv/6UQDgMaLfIqUWAEzzbCQiVh7V9rhDXp6c37yoJcks12NVD+XPkgl4AEavmNhVfrhGoqYwIsMYYA==}
engines: {node: '>=14.16'}
emoji-regex@10.4.0:
resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==}
@ -4869,6 +4876,8 @@ snapshots:
minimatch: 9.0.1
semver: 7.6.3
emittery@1.1.0: {}
emoji-regex@10.4.0: {}
emoji-regex@8.0.0: {}

View File

@ -1,4 +1,9 @@
import Emittery from 'emittery';
import { AmazonPageWorker, AmazonPageWorkerEvents } from './types';
class AmazonPageWorkerImpl implements AmazonPageWorker {
readonly channel = new Emittery<AmazonPageWorkerEvents>();
public async doSearch(keywords: string): Promise<string> {
const url = new URL('https://www.amazon.com/s');
url.searchParams.append('k', keywords);
@ -16,7 +21,7 @@ class AmazonPageWorkerImpl implements AmazonPageWorker {
return url.toString();
}
public async wanderSearchList(): Promise<void> {
private async wanderSearchSinglePage() {
const tab = await browser.tabs
.query({ active: true, currentWindow: true })
.then((tabs) => tabs[0]);
@ -31,6 +36,15 @@ class AmazonPageWorkerImpl implements AmazonPageWorker {
window.scrollBy(0, ~~(Math.random() * 500) + 500);
await new Promise((resolve) => setTimeout(resolve, 10));
}
const items = document.querySelectorAll<HTMLDivElement>(
'.a-section.a-spacing-small.puis-padding-left-small',
);
const links: string[] = [];
items.forEach((el) => {
const link =
el.querySelector<HTMLAnchorElement>('a.a-link-normal')?.href;
link && links.push(link);
});
const nextButton =
document.querySelector<HTMLLinkElement>('.s-pagination-next');
if (
@ -41,14 +55,25 @@ class AmazonPageWorkerImpl implements AmazonPageWorker {
setTimeout(resolve, 500 + ~~(500 * Math.random())),
);
nextButton.click();
} else {
return null;
}
return true;
return links;
} catch (e) {
return false;
return null;
}
},
});
console.log('results', results);
await new Promise((resolve) => setTimeout(resolve, 1000));
return results.pop()?.result as string[] | null;
}
public async wanderSearchList(): Promise<void> {
let links = await this.wanderSearchSinglePage();
while (links) {
this.channel.emit('item-links-collected', { links });
links = await this.wanderSearchSinglePage();
}
return new Promise((resolve) => setTimeout(resolve, 1000));
}
}

View File

@ -1,4 +1,21 @@
import type Emittery from 'emittery';
interface AmazonPageWorkerEvents {
/**
* Emitted when a new item is found on the Amazon page.
* @param link - The item link that was found.
*/
['item-links-collected']: { links: string[] };
}
interface AmazonPageWorker {
/**
* The channel for communication with the Amazon page worker.
* This is an instance of Emittery, which allows for event-based communication.
*/
readonly channel: Emittery<AmazonPageWorkerEvents>;
/**
* Search for a list of items on Amazon
* @param keywords - The keywords to search for on Amazon.

View File

@ -2,11 +2,19 @@
import { keywords } from '~/logic/storage';
import pageWorker from '~/logic/page-worker';
const links = ref<string[]>([]);
const worker = pageWorker.createAmazonPageWorker();
onMounted(() => {
worker.channel.on('item-links-collected', (ev) => {
links.value = links.value.concat(ev.links);
});
});
const onSearch = async () => {
if (keywords.value.trim() === '') {
return;
}
const worker = pageWorker.createAmazonPageWorker();
await worker.doSearch(keywords.value);
await worker.wanderSearchList();
};
@ -31,13 +39,18 @@ const onSearch = async () => {
</n-space>
<div style="height: 10px"></div>
<n-card class="result-content-container" title="结果框">
<n-empty description="还没有结果哦">
<n-empty v-if="links.length === 0" description="还没有结果哦">
<template #icon>
<n-icon :size="50">
<solar-cat-linear />
</n-icon>
</template>
</n-empty>
<n-list size="medium" v-else>
<n-list-item v-for="(link, index) in links" :key="index">
<n-tag :href="link" target="_blank">{{ link }}</n-tag>
</n-list-item>
</n-list>
</n-card>
</main>
</template>