mirror of
https://github.com/opelly27/streetmerchant.git
synced 2026-05-20 04:07:36 +00:00
feat(docs): add mkdocs
This commit is contained in:
+2
-1
@@ -232,7 +232,8 @@ const notifications = {
|
||||
['tmobile', 'tmomail.net'],
|
||||
['verizon', 'vtext.com'],
|
||||
['virgin', 'vmobl.com'],
|
||||
['virgin-ca', 'vmobile.ca']
|
||||
['virgin-ca', 'vmobile.ca'],
|
||||
['visible', 'vtext.com']
|
||||
]),
|
||||
carrier: envOrArray(process.env.PHONE_CARRIER),
|
||||
number: envOrArray(process.env.PHONE_NUMBER)
|
||||
|
||||
+11
-4
@@ -20,7 +20,9 @@ const prettyJson = winston.format.printf((info) => {
|
||||
export const logger = winston.createLogger({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.metadata({fillExcept: ['level', 'message', 'timestamp']}),
|
||||
winston.format.metadata({
|
||||
fillExcept: ['level', 'message', 'timestamp']
|
||||
}),
|
||||
prettyJson
|
||||
),
|
||||
level: config.logLevel,
|
||||
@@ -129,7 +131,9 @@ export const Print = {
|
||||
'✖ ' +
|
||||
buildProductString(link, store, true) +
|
||||
' :: ' +
|
||||
chalk.yellow(`PRICE ${link.price ?? ''} EXCEEDS LIMIT ${maxPrice}`)
|
||||
chalk.yellow(
|
||||
`PRICE ${link.price ?? ''} EXCEEDS LIMIT ${maxPrice}`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -180,7 +184,8 @@ export const Print = {
|
||||
},
|
||||
productInStock(link: Link): string {
|
||||
let productString = `Product Page: ${link.url}`;
|
||||
if (link.cartUrl) productString += `\nAdd To Cart Link: ${link.cartUrl}`;
|
||||
if (link.cartUrl)
|
||||
productString += `\nAdd To Cart Link: ${link.cartUrl}`;
|
||||
|
||||
return productString;
|
||||
},
|
||||
@@ -204,7 +209,9 @@ function buildSetupString(
|
||||
color?: boolean
|
||||
): string {
|
||||
if (color) {
|
||||
return chalk.cyan(`[${store.name}]`) + chalk.grey(` [setup (${topic})]`);
|
||||
return (
|
||||
chalk.cyan(`[${store.name}]`) + chalk.grey(` [setup (${topic})]`)
|
||||
);
|
||||
}
|
||||
|
||||
return `[${store.name}] [setup (${topic})]`;
|
||||
|
||||
@@ -31,7 +31,7 @@ export function sendDiscordMessage(link: Link, store: Store) {
|
||||
'> provided by [streetmerchant](https://github.com/jef/streetmerchant) with :heart:'
|
||||
)
|
||||
.setThumbnail(
|
||||
'https://raw.githubusercontent.com/jef/streetmerchant/main/media/streetmerchant-square.png'
|
||||
'https://raw.githubusercontent.com/jef/streetmerchant/main/docs/assets/images/streetmerchant-square.png'
|
||||
)
|
||||
.setColor('#52b788')
|
||||
.setTimestamp();
|
||||
@@ -57,7 +57,9 @@ export function sendDiscordMessage(link: Link, store: Store) {
|
||||
});
|
||||
}
|
||||
|
||||
(await Promise.all(promises)).forEach(({client}) => client.destroy());
|
||||
(await Promise.all(promises)).forEach(({client}) =>
|
||||
client.destroy()
|
||||
);
|
||||
|
||||
logger.info('✔ discord message sent');
|
||||
} catch (error: unknown) {
|
||||
|
||||
@@ -45,13 +45,14 @@ const adjustLightsWithAPI = (hueBridge: Api) => {
|
||||
const arrayOfIDs = lightIds.split(',');
|
||||
arrayOfIDs.forEach((light) => {
|
||||
logger.debug('adjusting all hue lights');
|
||||
(hueBridge.lights.setLightState(light, lightState) as Promise<any>).catch(
|
||||
(error: Error) => {
|
||||
logger.error('Failed to adjust all lights.');
|
||||
logger.error(error);
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
(hueBridge.lights.setLightState(
|
||||
light,
|
||||
lightState
|
||||
) as Promise<any>).catch((error: Error) => {
|
||||
logger.error('Failed to adjust all lights.');
|
||||
logger.error(error);
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Adjust all light IDs
|
||||
@@ -102,15 +103,26 @@ export function adjustPhilipsHueLights() {
|
||||
} else if (hue.apiKey && hue.clientId && hue.clientSecret) {
|
||||
logger.info('↗ adjusting Philips Hue lights over cloud');
|
||||
(async () => {
|
||||
logger.debug('Attempting to connect to Philips Hue bridge over cloud');
|
||||
const remoteBootstrap = hueAPI.api.createRemote(clientId, clientSecret);
|
||||
logger.debug(
|
||||
'Attempting to connect to Philips Hue bridge over cloud'
|
||||
);
|
||||
const remoteBootstrap = hueAPI.api.createRemote(
|
||||
clientId,
|
||||
clientSecret
|
||||
);
|
||||
if (hue.accessToken && hue.refreshToken) {
|
||||
remoteBootstrap
|
||||
.connectWithTokens(accessToken, refreshToken, remoteApiUsername)
|
||||
.connectWithTokens(
|
||||
accessToken,
|
||||
refreshToken,
|
||||
remoteApiUsername
|
||||
)
|
||||
.then(
|
||||
(hueBridge) => {
|
||||
adjustLightsWithAPI(hueBridge);
|
||||
logger.info('✔ adjusted Philips Hue lights over cloud');
|
||||
logger.info(
|
||||
'✔ adjusted Philips Hue lights over cloud'
|
||||
);
|
||||
},
|
||||
(error: Error) => {
|
||||
logger.error(
|
||||
|
||||
@@ -4,7 +4,7 @@ import {WebClient} from '@slack/web-api';
|
||||
import {config} from '../config';
|
||||
|
||||
const slack = config.notifications.slack;
|
||||
const channel = slack.channel;
|
||||
const channel = slack.channel.replace('#', '');
|
||||
const token = slack.token;
|
||||
const web = new WebClient(token);
|
||||
|
||||
|
||||
+17
-11
@@ -20,19 +20,25 @@ export function playSound() {
|
||||
if (config.notifications.playSound && player.player !== null) {
|
||||
logger.debug('↗ playing sound');
|
||||
|
||||
fs.access(config.notifications.playSound, fs.constants.F_OK, (error) => {
|
||||
if (error) {
|
||||
logger.error(`✖ error opening sound file: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
player.play(config.notifications.playSound, (error: Error) => {
|
||||
fs.access(
|
||||
config.notifications.playSound,
|
||||
fs.constants.F_OK,
|
||||
(error) => {
|
||||
if (error) {
|
||||
logger.error("✖ couldn't play sound", error);
|
||||
logger.error(
|
||||
`✖ error opening sound file: ${error.message}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info('✔ played sound');
|
||||
});
|
||||
});
|
||||
player.play(config.notifications.playSound, (error: Error) => {
|
||||
if (error) {
|
||||
logger.error("✖ couldn't play sound", error);
|
||||
}
|
||||
|
||||
logger.info('✔ played sound');
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,9 @@ const chatClient: ChatClient = new ChatClient(
|
||||
{
|
||||
accessToken,
|
||||
expiryTimestamp:
|
||||
expiryDate === null ? null : expiryDate.getTime(),
|
||||
expiryDate === null
|
||||
? null
|
||||
: expiryDate.getTime(),
|
||||
refreshToken
|
||||
},
|
||||
null,
|
||||
@@ -90,7 +92,9 @@ export function sendTwitchMessage(link: Link, store: Store) {
|
||||
logger.debug('↗ sending twitch message');
|
||||
|
||||
messages.push(
|
||||
`${Print.inStock(link, store)}\n${link.cartUrl ? link.cartUrl : link.url}`
|
||||
`${Print.inStock(link, store)}\n${
|
||||
link.cartUrl ? link.cartUrl : link.url
|
||||
}`
|
||||
);
|
||||
|
||||
if (!alreadySaying) {
|
||||
|
||||
@@ -7,7 +7,9 @@ import {usingResponse} from '../util';
|
||||
|
||||
function addNewLinks(store: Store, links: Link[], series: Series) {
|
||||
if (links.length === 0) {
|
||||
logger.debug(Print.message('NO STORE LINKS FOUND', series, store, true));
|
||||
logger.debug(
|
||||
Print.message('NO STORE LINKS FOUND', series, store, true)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -20,7 +22,12 @@ function addNewLinks(store: Store, links: Link[], series: Series) {
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
Print.message(`FOUND ${newLinks.length} STORE LINKS`, series, store, true)
|
||||
Print.message(
|
||||
`FOUND ${newLinks.length} STORE LINKS`,
|
||||
series,
|
||||
store,
|
||||
true
|
||||
)
|
||||
);
|
||||
logger.debug(JSON.stringify(newLinks, null, 2));
|
||||
|
||||
@@ -39,7 +46,9 @@ export async function fetchLinks(store: Store, browser: Browser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.debug(Print.message('DETECTING STORE LINKS', series, store, true));
|
||||
logger.debug(
|
||||
Print.message('DETECTING STORE LINKS', series, store, true)
|
||||
);
|
||||
|
||||
if (!Array.isArray(url)) {
|
||||
url = [url];
|
||||
@@ -51,12 +60,17 @@ export async function fetchLinks(store: Store, browser: Browser) {
|
||||
const text = await response?.text();
|
||||
|
||||
if (!text) {
|
||||
logger.error(Print.message('NO RESPONSE', series, store, true));
|
||||
logger.error(
|
||||
Print.message('NO RESPONSE', series, store, true)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const docElement = cheerio.load(text).root();
|
||||
const links = store.linksBuilder!.builder(docElement, series);
|
||||
const links = store.linksBuilder!.builder(
|
||||
docElement,
|
||||
series
|
||||
);
|
||||
|
||||
addNewLinks(store, links, series);
|
||||
})
|
||||
|
||||
+4
-1
@@ -29,7 +29,10 @@ function filterModel(model: Link['model'], series: Link['series']): boolean {
|
||||
const sanitizedSeries = series.replace(/\s/g, '');
|
||||
for (const configModelEntry of config.store.showOnlyModels) {
|
||||
const sanitizedConfigModel = configModelEntry.name.replace(/\s/g, '');
|
||||
const sanitizedConfigSeries = configModelEntry.series.replace(/\s/g, '');
|
||||
const sanitizedConfigSeries = configModelEntry.series.replace(
|
||||
/\s/g,
|
||||
''
|
||||
);
|
||||
if (sanitizedConfigSeries) {
|
||||
if (
|
||||
sanitizedSeries === sanitizedConfigSeries &&
|
||||
|
||||
+19
-8
@@ -152,7 +152,8 @@ async function lookup(browser: Browser, store: Store) {
|
||||
|
||||
const proxy = nextProxy(store);
|
||||
|
||||
const useAdBlock = !config.browser.lowBandwidth && !store.disableAdBlocker;
|
||||
const useAdBlock =
|
||||
!config.browser.lowBandwidth && !store.disableAdBlocker;
|
||||
const customContext = config.browser.isIncognito;
|
||||
|
||||
const context = customContext
|
||||
@@ -212,9 +213,9 @@ async function lookup(browser: Browser, store: Store) {
|
||||
statusCode = await lookupCard(browser, store, page, link);
|
||||
} catch (error: unknown) {
|
||||
logger.error(
|
||||
`✖ [${store.name}] ${link.brand} ${link.series} ${link.model} - ${
|
||||
(error as Error).message
|
||||
}`
|
||||
`✖ [${store.name}] ${link.brand} ${link.series} ${
|
||||
link.model
|
||||
} - ${(error as Error).message}`
|
||||
);
|
||||
const client = await page.target().createCDPSession();
|
||||
await client.send('Network.clearBrowserCookies');
|
||||
@@ -266,7 +267,9 @@ async function lookupCard(
|
||||
|
||||
if (await lookupCardInStock(store, page, link)) {
|
||||
const givenUrl =
|
||||
link.cartUrl && config.store.autoAddToCart ? link.cartUrl : link.url;
|
||||
link.cartUrl && config.store.autoAddToCart
|
||||
? link.cartUrl
|
||||
: link.url;
|
||||
logger.info(`${Print.inStock(link, store, true)}\n${givenUrl}`);
|
||||
|
||||
if (config.browser.open) {
|
||||
@@ -313,7 +316,11 @@ async function lookupCardInStock(store: Store, page: Page, link: Link) {
|
||||
|
||||
if (store.labels.bannedSeller) {
|
||||
if (
|
||||
await pageIncludesLabels(page, store.labels.bannedSeller, baseOptions)
|
||||
await pageIncludesLabels(
|
||||
page,
|
||||
store.labels.bannedSeller,
|
||||
baseOptions
|
||||
)
|
||||
) {
|
||||
logger.warn(Print.bannedSeller(link, store, true));
|
||||
return false;
|
||||
@@ -367,7 +374,9 @@ async function lookupCardInStock(store: Store, page: Page, link: Link) {
|
||||
}
|
||||
|
||||
if (store.labels.outOfStock) {
|
||||
if (await pageIncludesLabels(page, store.labels.outOfStock, baseOptions)) {
|
||||
if (
|
||||
await pageIncludesLabels(page, store.labels.outOfStock, baseOptions)
|
||||
) {
|
||||
logger.info(Print.outOfStock(link, store, true));
|
||||
return false;
|
||||
}
|
||||
@@ -378,7 +387,9 @@ async function lookupCardInStock(store: Store, page: Page, link: Link) {
|
||||
|
||||
export async function tryLookupAndLoop(browser: Browser, store: Store) {
|
||||
if (!browser.isConnected()) {
|
||||
logger.debug(`[${store.name}] Ending this loop as browser is disposed...`);
|
||||
logger.debug(
|
||||
`[${store.name}] Ending this loop as browser is disposed...`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ export const AmazonNl: Store = {
|
||||
},
|
||||
{
|
||||
container: '#outOfStock',
|
||||
text: ['we weten niet of en wanneer dit item weer op voorraad is']
|
||||
text: [
|
||||
'we weten niet of en wanneer dit item weer op voorraad is'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -55,13 +55,15 @@ export const Asus: Store = {
|
||||
],
|
||||
name: 'asus',
|
||||
realTimeInventoryLookup: async (itemNumber: string) => {
|
||||
const request_url = 'https://store.asus.com/us/category/get_real_time_data';
|
||||
const request_url =
|
||||
'https://store.asus.com/us/category/get_real_time_data';
|
||||
const response = await fetch(request_url, {
|
||||
body: 'sm_seq_list%5B%5D=' + itemNumber,
|
||||
headers: {
|
||||
'accept-language': 'en-US,en;q=0.9',
|
||||
'cache-control': 'no-cache',
|
||||
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
||||
'content-type':
|
||||
'application/x-www-form-urlencoded; charset=UTF-8'
|
||||
},
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
@@ -3,7 +3,8 @@ import {Store} from './store';
|
||||
export const BestBuy: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '[data-sticky-media-gallery] .fulfillment-add-to-cart-button',
|
||||
container:
|
||||
'[data-sticky-media-gallery] .fulfillment-add-to-cart-button',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
|
||||
@@ -59,7 +59,8 @@ export const Computeruniverse: Store = {
|
||||
brand: 'evga',
|
||||
model: 'xc3 black',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/evga-geforce-rtx3070-xc3-black'
|
||||
url:
|
||||
'https://www.computeruniverse.net/de/evga-geforce-rtx3070-xc3-black'
|
||||
},
|
||||
{
|
||||
brand: 'gainward',
|
||||
@@ -142,7 +143,8 @@ export const Computeruniverse: Store = {
|
||||
brand: 'pny',
|
||||
model: 'dual fan',
|
||||
series: '3070',
|
||||
url: 'https://www.computeruniverse.net/de/pny-geforce-rtx3070-m-dual-8-gb'
|
||||
url:
|
||||
'https://www.computeruniverse.net/de/pny-geforce-rtx3070-m-dual-8-gb'
|
||||
},
|
||||
{
|
||||
brand: 'pny',
|
||||
|
||||
@@ -8,7 +8,8 @@ export const Currys: Store = {
|
||||
text: ['add to basket']
|
||||
},
|
||||
maxPrice: {
|
||||
container: '#product-actions span[class*="ProductPriceBlock__Price"]',
|
||||
container:
|
||||
'#product-actions span[class*="ProductPriceBlock__Price"]',
|
||||
euroFormat: false // Note: Currys uses non-euroFromat as price seperator
|
||||
},
|
||||
outOfStock: {
|
||||
|
||||
@@ -28,7 +28,8 @@ export const Ebuyer: Store = {
|
||||
brand: 'sony',
|
||||
model: 'ps5 console',
|
||||
series: 'sonyps5c',
|
||||
url: 'https://www.ebuyer.com/1125329-sony-playstation-5-console-cfi-1015a'
|
||||
url:
|
||||
'https://www.ebuyer.com/1125329-sony-playstation-5-console-cfi-1015a'
|
||||
},
|
||||
{
|
||||
brand: 'sony',
|
||||
|
||||
@@ -12,7 +12,8 @@ export const Elcorteingles: Store = {
|
||||
// },
|
||||
inStock: [
|
||||
{
|
||||
container: '.product_detail-purchase.mb-2.c12 .js-add-cart-text',
|
||||
container:
|
||||
'.product_detail-purchase.mb-2.c12 .js-add-cart-text',
|
||||
text: ['a la cesta']
|
||||
}
|
||||
],
|
||||
|
||||
@@ -10,7 +10,8 @@ export const Expert: Store = {
|
||||
}
|
||||
],
|
||||
maxPrice: {
|
||||
container: '.widget-Container-subContent .widget-ArticlePrice-price',
|
||||
container:
|
||||
'.widget-Container-subContent .widget-ArticlePrice-price',
|
||||
euroFormat: false
|
||||
},
|
||||
outOfStock: [
|
||||
@@ -30,7 +31,8 @@ export const Expert: Store = {
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.expert.de/shop/11364114744-ps4-pro-1tb-jet-black.html'
|
||||
url:
|
||||
'https://www.expert.de/shop/11364114744-ps4-pro-1tb-jet-black.html'
|
||||
},
|
||||
{
|
||||
brand: 'sony',
|
||||
|
||||
@@ -33,7 +33,8 @@ export const Game: Store = {
|
||||
brand: 'sony',
|
||||
model: 'ps5 digital',
|
||||
series: 'sonyps5de',
|
||||
url: 'https://www.game.co.uk/en/playstation-5-digital-edition-2826341'
|
||||
url:
|
||||
'https://www.game.co.uk/en/playstation-5-digital-edition-2826341'
|
||||
}
|
||||
],
|
||||
name: 'game'
|
||||
|
||||
@@ -38,7 +38,10 @@ export async function processBackoffDelay(
|
||||
if (!isBackoff) {
|
||||
if (backoff.count > 0) {
|
||||
backoff.count--;
|
||||
backoff.time = Math.max(backoff.time / 2, config.browser.minBackoff);
|
||||
backoff.time = Math.max(
|
||||
backoff.time / 2,
|
||||
config.browser.minBackoff
|
||||
);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
@@ -23,7 +23,9 @@ export function getProductLinksBuilder(options: LinksBuilderOptions) {
|
||||
const links: Link[] = [];
|
||||
for (let i = 0; i < productElements.length; i++) {
|
||||
const productElement = productElements.eq(i);
|
||||
const titleElement = productElement.find(options.titleSelector).first();
|
||||
const titleElement = productElement
|
||||
.find(options.titleSelector)
|
||||
.first();
|
||||
|
||||
const title = options.titleAttribute
|
||||
? titleElement.attr()?.[options.titleAttribute]
|
||||
|
||||
@@ -62,7 +62,9 @@ export class NvidiaCart {
|
||||
|
||||
public async addToCard(productId: number, name: string): Promise<string> {
|
||||
let cartUrl: string | undefined;
|
||||
logger.info(`🚀🚀🚀 [nvidia] ${name}, starting auto add to cart 🚀🚀🚀`);
|
||||
logger.info(
|
||||
`🚀🚀🚀 [nvidia] ${name}, starting auto add to cart 🚀🚀🚀`
|
||||
);
|
||||
try {
|
||||
logger.info(`🚀🚀🚀 [nvidia] ${name}, adding to cart 🚀🚀🚀`);
|
||||
let lastError: Error | string | undefined;
|
||||
@@ -70,7 +72,9 @@ export class NvidiaCart {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
for (let i = 0; i < config.nvidia.addToCardAttempts; i++) {
|
||||
try {
|
||||
cartUrl = await this.addToCartAndGetLocationRedirect(productId);
|
||||
cartUrl = await this.addToCartAndGetLocationRedirect(
|
||||
productId
|
||||
);
|
||||
|
||||
break;
|
||||
} catch (error: unknown) {
|
||||
@@ -92,7 +96,9 @@ export class NvidiaCart {
|
||||
throw lastError;
|
||||
}
|
||||
|
||||
logger.info(`🚀🚀🚀 [nvidia] ${name}, opening checkout page 🚀🚀🚀`);
|
||||
logger.info(
|
||||
`🚀🚀🚀 [nvidia] ${name}, opening checkout page 🚀🚀🚀`
|
||||
);
|
||||
logger.info(cartUrl);
|
||||
|
||||
await open(cartUrl);
|
||||
@@ -129,7 +135,9 @@ export class NvidiaCart {
|
||||
this.browser,
|
||||
this.sessionUrl,
|
||||
async (response) => {
|
||||
return response?.json() as NvidiaSessionTokenJSON | undefined;
|
||||
return response?.json() as
|
||||
| NvidiaSessionTokenJSON
|
||||
| undefined;
|
||||
}
|
||||
);
|
||||
if (
|
||||
@@ -154,7 +162,8 @@ export class NvidiaCart {
|
||||
protected async addToCartAndGetLocationRedirect(
|
||||
productId: number
|
||||
): Promise<string> {
|
||||
const url = 'https://api-prod.nvidia.com/direct-sales-shop/DR/add-to-cart';
|
||||
const url =
|
||||
'https://api-prod.nvidia.com/direct-sales-shop/DR/add-to-cart';
|
||||
const sessionToken = await this.getSessionToken();
|
||||
|
||||
logger.info(`ℹ [nvidia] session_token=${sessionToken}`);
|
||||
|
||||
@@ -67,7 +67,10 @@ export function generateLinks(): Link[] {
|
||||
links.push({
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
openCartAction: generateOpenCartAction(fe2060SuperId, 'TEST CARD debug'),
|
||||
openCartAction: generateOpenCartAction(
|
||||
fe2060SuperId,
|
||||
'TEST CARD debug'
|
||||
),
|
||||
series: 'test:series',
|
||||
url: nvidiaStockUrl(fe2060SuperId, drLocale, currency)
|
||||
});
|
||||
|
||||
@@ -208,7 +208,9 @@ function printConfig() {
|
||||
}
|
||||
|
||||
if (config.store.showOnlyBrands.length > 0) {
|
||||
logger.info(`ℹ selected brands: ${config.store.showOnlyBrands.join(', ')}`);
|
||||
logger.info(
|
||||
`ℹ selected brands: ${config.store.showOnlyBrands.join(', ')}`
|
||||
);
|
||||
}
|
||||
|
||||
if (config.store.showOnlyModels.length > 0) {
|
||||
@@ -224,7 +226,9 @@ function printConfig() {
|
||||
}
|
||||
|
||||
if (config.store.showOnlySeries.length > 0) {
|
||||
logger.info(`ℹ selected series: ${config.store.showOnlySeries.join(', ')}`);
|
||||
logger.info(
|
||||
`ℹ selected series: ${config.store.showOnlySeries.join(', ')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ export const NeweggCa: Store = {
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
container: 'div#app div.product-price > ul > li.price-current > strong',
|
||||
container:
|
||||
'div#app div.product-price > ul > li.price-current > strong',
|
||||
euroFormat: false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -271,7 +271,8 @@ export const Notebooksbilliger: Store = {
|
||||
brand: 'amd',
|
||||
model: '5800x',
|
||||
series: 'ryzen5800',
|
||||
url: 'https://www.notebooksbilliger.de/amd+ryzen+ryzen+7+5800x+cpu+684018'
|
||||
url:
|
||||
'https://www.notebooksbilliger.de/amd+ryzen+ryzen+7+5800x+cpu+684018'
|
||||
},
|
||||
{
|
||||
brand: 'amd',
|
||||
|
||||
@@ -28,7 +28,8 @@ export const Nvidia: Store = {
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.nvidia.com/en-us/geforce/graphics-cards/rtx-2060-super/'
|
||||
url:
|
||||
'https://www.nvidia.com/en-us/geforce/graphics-cards/rtx-2060-super/'
|
||||
},
|
||||
{
|
||||
brand: 'nvidia',
|
||||
|
||||
@@ -15,7 +15,9 @@ export const Otto: Store = {
|
||||
},
|
||||
outOfStock: {
|
||||
container: 'div.p_message.p_message--hint > strong',
|
||||
text: ['Deinen gewünschten Artikel können wir leider nicht mehr liefern']
|
||||
text: [
|
||||
'Deinen gewünschten Artikel können wir leider nicht mehr liefern'
|
||||
]
|
||||
}
|
||||
},
|
||||
links: [
|
||||
|
||||
@@ -41,7 +41,8 @@ export const PCComponentes: Store = {
|
||||
brand: 'asus',
|
||||
model: 'tuf',
|
||||
series: '3080',
|
||||
url: 'https://www.pccomponentes.com/asus-tuf-geforce-rtx-3080-10gb-gddr6x'
|
||||
url:
|
||||
'https://www.pccomponentes.com/asus-tuf-geforce-rtx-3080-10gb-gddr6x'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
@@ -246,7 +247,8 @@ export const PCComponentes: Store = {
|
||||
brand: 'asus',
|
||||
model: 'dual',
|
||||
series: '3070',
|
||||
url: 'https://www.pccomponentes.com/asus-geforce-rtx-3070-dual-8gb-gddr6'
|
||||
url:
|
||||
'https://www.pccomponentes.com/asus-geforce-rtx-3070-dual-8gb-gddr6'
|
||||
},
|
||||
{
|
||||
brand: 'asus',
|
||||
|
||||
@@ -32,13 +32,17 @@ export const Very: Store = {
|
||||
const links: Link[] = [];
|
||||
for (let i = 0; i < productElements.length; i++) {
|
||||
const productElement = productElements.eq(i);
|
||||
const titleElement = productElement.find('.productTitle').first();
|
||||
const titleElement = productElement
|
||||
.find('.productTitle')
|
||||
.first();
|
||||
const title = titleElement.text()?.replace(/\n/g, ' ').trim();
|
||||
|
||||
if (
|
||||
!title ||
|
||||
['RTX', series]
|
||||
.map((x) => title.toLowerCase().includes(x.toLowerCase()))
|
||||
.map((x) =>
|
||||
title.toLowerCase().includes(x.toLowerCase())
|
||||
)
|
||||
.filter((x) => !x).length > 0
|
||||
) {
|
||||
continue;
|
||||
|
||||
@@ -23,25 +23,29 @@ export const VsGamers: Store = {
|
||||
brand: 'amd',
|
||||
model: '5600x',
|
||||
series: 'ryzen5600',
|
||||
url: 'https://www.vsgamers.es/product/procesador-amd-ryzen-5-5600x-37-ghz'
|
||||
url:
|
||||
'https://www.vsgamers.es/product/procesador-amd-ryzen-5-5600x-37-ghz'
|
||||
},
|
||||
{
|
||||
brand: 'amd',
|
||||
model: '5800x',
|
||||
series: 'ryzen5800',
|
||||
url: 'https://www.vsgamers.es/product/procesador-amd-ryzen-7-5800x-38-ghz'
|
||||
url:
|
||||
'https://www.vsgamers.es/product/procesador-amd-ryzen-7-5800x-38-ghz'
|
||||
},
|
||||
{
|
||||
brand: 'amd',
|
||||
model: '5900x',
|
||||
series: 'ryzen5900',
|
||||
url: 'https://www.vsgamers.es/product/procesador-amd-ryzen-9-5900x-37-ghz'
|
||||
url:
|
||||
'https://www.vsgamers.es/product/procesador-amd-ryzen-9-5900x-37-ghz'
|
||||
},
|
||||
{
|
||||
brand: 'amd',
|
||||
model: '5950x',
|
||||
series: 'ryzen5950',
|
||||
url: 'https://www.vsgamers.es/product/procesador-amd-ryzen-9-5950x-34-ghz'
|
||||
url:
|
||||
'https://www.vsgamers.es/product/procesador-amd-ryzen-9-5950x-34-ghz'
|
||||
},
|
||||
{
|
||||
brand: 'zotac',
|
||||
|
||||
@@ -3,7 +3,8 @@ import {Store} from './store';
|
||||
export const Walmart: Store = {
|
||||
labels: {
|
||||
inStock: {
|
||||
container: '.button.spin-button.prod-ProductCTA--primary.button--primary',
|
||||
container:
|
||||
'.button.spin-button.prod-ProductCTA--primary.button--primary',
|
||||
text: ['add to cart']
|
||||
},
|
||||
maxPrice: {
|
||||
|
||||
@@ -20,7 +20,8 @@ export const Wipoid: Store = {
|
||||
brand: 'test:brand',
|
||||
model: 'test:model',
|
||||
series: 'test:series',
|
||||
url: 'https://www.wipoid.com/pny-geforce-rtx-1650-dual-fan-4gb-gddr6.html'
|
||||
url:
|
||||
'https://www.wipoid.com/pny-geforce-rtx-1650-dual-fan-4gb-gddr6.html'
|
||||
},
|
||||
{
|
||||
brand: 'gigabyte',
|
||||
|
||||
Vendored
+4
-1
@@ -9,7 +9,10 @@ declare module 'play-sound' {
|
||||
export interface PlaySound {
|
||||
player: string;
|
||||
|
||||
play: ((file: string, callback: (error: Error) => void) => PlayerProcess) &
|
||||
play: ((
|
||||
file: string,
|
||||
callback: (error: Error) => void
|
||||
) => PlayerProcess) &
|
||||
((
|
||||
file: string,
|
||||
options: PlayOptions,
|
||||
|
||||
Vendored
+20
-5
@@ -18,7 +18,10 @@ declare module '@jef/pushbullet' {
|
||||
export interface PushBulletStream {
|
||||
connect: () => void;
|
||||
close: () => void;
|
||||
on: ((event: 'connect' | 'close' | 'nop', callback: () => void) => void) &
|
||||
on: ((
|
||||
event: 'connect' | 'close' | 'nop',
|
||||
callback: () => void
|
||||
) => void) &
|
||||
((event: 'error', callback: (error: any) => void) => void) &
|
||||
((event: 'message', callback: (message: any) => void) => void) &
|
||||
((event: 'tickle', callback: (tickle: any) => void) => void) &
|
||||
@@ -30,7 +33,10 @@ declare module '@jef/pushbullet' {
|
||||
me(callback: PushBulletCallback);
|
||||
devices(options: ListOptions, callback: PushBulletCallback);
|
||||
devices(callback: PushBulletCallback);
|
||||
createDevice(options: Record<string, any>, callback: PushBulletCallback);
|
||||
createDevice(
|
||||
options: Record<string, any>,
|
||||
callback: PushBulletCallback
|
||||
);
|
||||
updateDevice(
|
||||
deviceIden: string,
|
||||
deviceOptions: Record<string, any>,
|
||||
@@ -65,8 +71,14 @@ declare module '@jef/pushbullet' {
|
||||
subscriptions(callback: PushBulletCallback);
|
||||
subscribe(channelTag: string, callback: PushBulletCallback);
|
||||
unsubscribe(subscriptionIden: string, callback: PushBulletCallback);
|
||||
muteSubscription(subscriptionIden: string, callback: PushBulletCallback);
|
||||
unmuteSubscription(subscriptionIden: string, callback: PushBulletCallback);
|
||||
muteSubscription(
|
||||
subscriptionIden: string,
|
||||
callback: PushBulletCallback
|
||||
);
|
||||
unmuteSubscription(
|
||||
subscriptionIden: string,
|
||||
callback: PushBulletCallback
|
||||
);
|
||||
channelInfo(channelTag: string, callback: PushBulletCallback);
|
||||
chats(options: ListOptions, callback: PushBulletCallback);
|
||||
chats(callback: PushBulletCallback);
|
||||
@@ -75,7 +87,10 @@ declare module '@jef/pushbullet' {
|
||||
muteChat(chatIden: string, callback: PushBulletCallback);
|
||||
unmuteChat(chatIden: string, callback: PushBulletCallback);
|
||||
sendSMS(options: Record<string, any>, callback: PushBulletCallback);
|
||||
sendClipboard(options: Record<string, any>, callback: PushBulletCallback);
|
||||
sendClipboard(
|
||||
options: Record<string, any>,
|
||||
callback: PushBulletCallback
|
||||
);
|
||||
dismissEphemeral(
|
||||
options: Record<string, any>,
|
||||
callback: PushBulletCallback
|
||||
|
||||
+3
-1
@@ -6,7 +6,9 @@ import {logger} from './logger';
|
||||
|
||||
export function getSleepTime(store: Store) {
|
||||
const minSleep = store.minPageSleep as number;
|
||||
return minSleep + Math.random() * ((store.maxPageSleep as number) - minSleep);
|
||||
return (
|
||||
minSleep + Math.random() * ((store.maxPageSleep as number) - minSleep)
|
||||
);
|
||||
}
|
||||
|
||||
export async function delay(ms: number) {
|
||||
|
||||
Reference in New Issue
Block a user