Last active
December 18, 2024 06:01
-
-
Save khobiziilyes/9fde648df010b5ac0dc812e64181be27 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const initialHeaders = { | |
"Cache-Control": "no-cache", | |
Pragma: "no-cache", | |
Expires: "0", | |
"User-Agent": | |
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36", | |
Accept: | |
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", | |
"Accept-Encoding": "gzip, deflate, br", | |
}; | |
const resetColor = "\x1b[0m"; | |
const regexes = { | |
phone: /(05[0-9]{8})/g, | |
colHeader: /holder-header expandable/g, | |
rows: /<a href=".{0,1}".+?<!-- \/credit/gs, | |
row: { | |
title: /[^>]*?(?=<\/a>)/s, | |
quantity: /price-unit">(.*?)</s, | |
unit: /currency">(.*?)</s, | |
validity: /au (.+?)</s, | |
}, | |
} as const; | |
void safeFetchOoredoo().then(parseData).then(logData); | |
async function safeFetchOoredoo() { | |
for (let i = 0; i < 30; i++) { | |
try { | |
return await fetchOoredoo(); | |
} catch (error) { | |
if (error.code !== 23) throw error; // Not a timeout error | |
} | |
} | |
throw new Error("TimeoutError"); | |
} | |
function fetchOoredoo() { | |
return fetch("http://choof.ooredoo.dz/header", { | |
headers: initialHeaders, | |
redirect: "manual", | |
signal: AbortSignal.timeout(1000), | |
}) | |
.then(async initialResponse => { | |
let response = initialResponse; | |
while (true) { | |
const statusCode = response.status; | |
if (statusCode === 200) break; | |
const location = response.headers.get("Location"); | |
if (!location) throw new Error("Location not found"); | |
const cookies = response.headers.get("Set-Cookie") || ""; | |
const headers = { | |
...initialHeaders, | |
Cookie: cookies, | |
}; | |
response = await fetch(location + "&language=fr", { | |
headers, | |
redirect: "manual", | |
signal: AbortSignal.timeout(2000), | |
}); | |
} | |
return response; | |
}) | |
.then(response => response.text()); | |
} | |
function parseData(text: string) { | |
const colHeaders = [...text.matchAll(regexes.colHeader)]; | |
const colHeadersIndices = colHeaders.map(header => header.index); | |
const cols = colHeadersIndices.map((colFrom, i) => { | |
const nextIndex = colHeadersIndices[i + 1] || text.length; | |
const textSlice = text.slice(colFrom, nextIndex); | |
const rows = [...textSlice.matchAll(regexes.rows)].map(row => row[0]); | |
const offers = rows.map(row => { | |
const title = safeTrim(row.match(regexes.row.title)?.[0]); | |
const quantity = safeTrim(row.match(regexes.row.quantity)?.[1]); | |
const unit = safeTrim(row.match(regexes.row.unit)?.[1]); | |
const validity = safeTrim(row.match(regexes.row.validity)?.[1]); | |
return { title, quantity, unit, validity }; | |
}); | |
return offers; | |
}); | |
const phone = text.match(regexes.phone)![1]; | |
return { phone, cols }; | |
} | |
function logData(data: ReturnType<typeof parseData>) { | |
console.log("\x1b[34m", `Phone: ${data.phone}\n`, resetColor); | |
const logText = data.cols | |
.map(col => | |
col | |
.map(offer => { | |
let logText = ""; | |
logText += `\x1b[36m- ${offer.title}${resetColor}: \x1b[35m${offer.quantity}${resetColor}`; | |
if (offer.unit) logText += `\x1b[35m ${offer.unit}${resetColor}`; | |
if (offer.validity) | |
logText += ` Until \x1b[32m${offer.validity}${resetColor}`; | |
return logText; | |
}) | |
.join("\n") | |
) | |
.join("\n\n-------------\n\n"); | |
console.log(logText); | |
} | |
function safeTrim(str: string | null | undefined): string { | |
if (!str) return ""; | |
return str.trim(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment