diff --git a/src/core/parsers/betika/index.ts b/src/core/parsers/betika/index.ts index fbacca1..d8b7979 100644 --- a/src/core/parsers/betika/index.ts +++ b/src/core/parsers/betika/index.ts @@ -77,7 +77,7 @@ export class BetikaParser extends BaseParser { throw new Error(`Unknown bet type provided for provider: ${this.betProvider.name}`); } - if (results2.result == "success") { + if (results2.result === "success") { logger.info("Successfully fetched games: ", results2.value); } else { logger.error("Failed to parse html into games: ", { diff --git a/src/core/parsers/betika/parser_types.ts b/src/core/parsers/betika/parser_types.ts index e9128f2..641b8c4 100644 --- a/src/core/parsers/betika/parser_types.ts +++ b/src/core/parsers/betika/parser_types.ts @@ -28,7 +28,7 @@ export function processBetikaTwoWayGamesHtml(html: string): Result }); return {result: "success", value: gameEvents}; } catch (e: any) { - logger.error('An error occurred while parsing Betika two way html data: ', e.message); + logger.error("An error occurred while parsing Betika two way html data: ", e.message); return {result: "error", value: new Error(e.message)}; } } @@ -55,7 +55,7 @@ export function processBetikaThreeWayGamesHtml(html: string): Result> { + const getBetProviderConfigResult = await this.betProvider.getConfig(); + if (getBetProviderConfigResult.result === "error") { + logger.error("HTML parse failed to load config for provider: ", this.betProvider.name); + return getBetProviderConfigResult; + } + + const getRedisSubscriberResult = await RedisSingleton.getSubscriber(); + if (getRedisSubscriberResult.result === "success") { + const betProviderConfig = getBetProviderConfigResult.value; + const results = betProviderConfig.games.map(async game => { + await getRedisSubscriberResult.value.subscribe(getRedisHtmlParserChannelName(this.betProvider, game), message => { + const parsedMessage = JSON.parse(message) as RawHtmlForProcessingMessage; + logger.trace("Redis subscriber message received.", { + betProviderName: parsedMessage.betProviderName, + betType: parsedMessage.betType, + fromUrl: parsedMessage.fromUrl, + gameName: parsedMessage.gameName + }); + this.processRawHtmlMessage(parsedMessage); + }); + return true; + }); + await Promise.all(results); + return {result: "success", value: true}; + } else { + logger.error("HTML parser failed to connect to redis subscriber for bet provider: ", this.betProvider.name); + return getRedisSubscriberResult; + } + } + + private processRawHtmlMessage(parsedMessage: RawHtmlForProcessingMessage): void { + let results2; + switch (parsedMessage.betType) { + case BetTypes.THREE_WAY: + results2 = processOrbitThreeWayGamesHtml(parsedMessage.rawHtml); + break; + default: + const message = "Unknown bet type provided"; + logger.error(message, { + betProviderName: parsedMessage.betProviderName, + betType: parsedMessage.betType, + fromUrl: parsedMessage.fromUrl, + gameName: parsedMessage.gameName + }); + throw new Error(`Unknown bet type provided for provider: ${this.betProvider.name}`); + } + + if (results2.result === "success") { + logger.info("Successfully fetched games", results2.value); + } else { + logger.error("Failed to parse html into games: ", { + betProviderName: parsedMessage.betProviderName, + betType: parsedMessage.betType, + fromUrl: parsedMessage.fromUrl, + gameName: parsedMessage.gameName, + errorMessage: results2.value.message + }); + } + } +} diff --git a/src/core/parsers/orbit/parser_types.ts b/src/core/parsers/orbit/parser_types.ts new file mode 100644 index 0000000..8c59cd1 --- /dev/null +++ b/src/core/parsers/orbit/parser_types.ts @@ -0,0 +1,74 @@ +import * as cheerio from "cheerio"; +import _ from "lodash"; + +import { getConfig } from "../../.."; +import { Result } from "../../../utils/types/result_type"; + +const {logger} = getConfig(); + +export function processOrbitThreeWayGamesHtml(html: string): Result { + const gameEvents: any[] = []; + + const $ = cheerio.load(html); + try { + + $("div.rowsContainer").each((_,element) => { + const data = $(element).find("div.biab_group-markets-table-row"); + + data.each((_, element_1) => { + const teamNames = $(element_1).find("div > div.biab_market-title-team-names"); + const clubA = $(teamNames).find("p:nth-child(1)").text().trim(); + const clubB = $(teamNames).find("p:nth-child(2)").text().trim(); + + const numBets = Number($(element_1).find("div > span.cursor-help").text().trim()); + + const oddsWrapper = $(element_1).find("div.styles_betContent__wrapper__25jEo"); + const odds = $(oddsWrapper).find("div.styles_contents__Kf8LQ > button > span > div > span.styles_betOdds__bxapE"); + const oddsArray: any[] = []; + odds.each((_, element_2) => { + oddsArray.push($(element_2).text().trim()); + }); + + gameEvents.push({ + clubA, + clubB, + numBets, + oddsArray + }); + }); + }); + + const validationAdded = gameEvents.map(event => { + let valid = true; + //@ts-ignore + event.oddsArray.forEach(potentialOdd => { + if (potentialOdd === "") { + valid = false; + } + }); + return {...event, ...{valid: valid}}; + }); + + // Remove game vents without 6 complete odds + const filteredEvents = _.filter(validationAdded, {valid: true}); + + let finalMapping = filteredEvents.map(event => { + //@ts-ignore + const oddsToNumber = event.oddsArray.map(item => { + return Number(item); + }) + return {...event, ...{oddsArray: oddsToNumber}}; + }); + + finalMapping = finalMapping.filter(event => { + return event.numBets > 9; + }); + + logger.trace(finalMapping); + + return {result: "success", value: finalMapping}; + } catch(e: any) { + logger.error("An error occurred while parsing Orbit three way html data: ", e.message); + return {result: "error", value: new Error(e.message)}; + } +} \ No newline at end of file diff --git a/src/core/scrapping/orbit/index.ts b/src/core/scrapping/orbit/index.ts index d65d39e..347b419 100644 --- a/src/core/scrapping/orbit/index.ts +++ b/src/core/scrapping/orbit/index.ts @@ -54,13 +54,12 @@ export class OrbitScrapper extends BaseScrapper { PuppeteerPageLoadPolicy.LOAD, ".biab_body.contentWrap", // scrollingElementSelector 2000, // delayBeforeNextScrollAttemptMillis - 30, // numScrollAttempts + 60, // numScrollAttempts 150 // scrollDelta ); if (getHtmlResult.result === "success") { logger.info("Successfully fetched html for url. ", metadata); - logger.info(getHtmlResult.value.html); this.publishRawHtmlToRedis( getRedisPublisherResult.value, getRedisHtmlParserChannelName(this.betProvider, game), diff --git a/src/testbed/testbed_2.ts b/src/testbed/testbed_2.ts index ab99669..8577af2 100644 --- a/src/testbed/testbed_2.ts +++ b/src/testbed/testbed_2.ts @@ -1,4 +1,4 @@ -import { BetikaParser } from "../core/parsers/betika"; +import { OrbitParser } from "../core/parsers/orbit"; -const betikaParser = new BetikaParser() -betikaParser.subscribeToChannels(); +const parser = new OrbitParser() +parser.subscribeToChannels();