Skip to content

Instantly share code, notes, and snippets.

@khobiziilyes
Last active December 18, 2024 06:01
Show Gist options
  • Save khobiziilyes/9fde648df010b5ac0dc812e64181be27 to your computer and use it in GitHub Desktop.
Save khobiziilyes/9fde648df010b5ac0dc812e64181be27 to your computer and use it in GitHub Desktop.
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