Prvotní nástřel pizza parseru
This commit is contained in:
1
server/.gitignore
vendored
Normal file
1
server/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/node_modules
|
||||
22
server/package.json
Normal file
22
server/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "luncher-server",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.ts",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "ts-node src/index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/request-promise": "^4.1.48",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"request": "^2.88.2",
|
||||
"request-promise": "^4.2.6",
|
||||
"socket.io": "^4.6.1"
|
||||
}
|
||||
}
|
||||
106
server/src/chefie.ts
Normal file
106
server/src/chefie.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import $ from 'cheerio';
|
||||
import rp from 'request-promise';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
type PizzaSize = {
|
||||
size: string,
|
||||
pizzaPrice: string,
|
||||
boxPrice: number,
|
||||
price: number
|
||||
}
|
||||
|
||||
type Pizza = {
|
||||
name: string,
|
||||
ingredients: string[],
|
||||
sizes: PizzaSize[],
|
||||
}
|
||||
|
||||
// TODO mělo by být konfigurovatelné proměnnou z prostředí s tímhle jako default
|
||||
const baseUrl = 'https://www.pizzachefie.cz';
|
||||
const pizzyUrl = `${baseUrl}/pizzy.html?pobocka=plzen`;
|
||||
|
||||
const buildPizzaUrl = (pizzaUrl: string) => {
|
||||
return `${baseUrl}/${pizzaUrl}`;
|
||||
}
|
||||
|
||||
// Ceny krabic dle velikosti
|
||||
const boxPrices = {
|
||||
"30cm": 13,
|
||||
"35cm": 15,
|
||||
"40cm": 18,
|
||||
"50cm": 25
|
||||
}
|
||||
|
||||
/**
|
||||
* Stáhne a scrapne aktuální pizzy ze stránek Pizza Chefie.
|
||||
*/
|
||||
const downloadPizzy = async () => {
|
||||
// Získáme seznam pizz
|
||||
const html = await rp(pizzyUrl);
|
||||
const links = $('.vypisproduktu > div > h4 > a', html)
|
||||
const urls = [];
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
if (links[i].name === 'a' && links[i].attribs?.href) {
|
||||
const pizzaUrl = links[i].attribs?.href;
|
||||
urls.push(buildPizzaUrl(pizzaUrl));
|
||||
}
|
||||
}
|
||||
// Scrapneme jednotlivé pizzy
|
||||
const result: Pizza[] = [];
|
||||
for (let i = 0; i < urls.length; i++) {
|
||||
const pizzaUrl = urls[i];
|
||||
const pizzaHtml = await rp(pizzaUrl);
|
||||
// Název
|
||||
const name = $('.produkt > h2', pizzaHtml).first().text()
|
||||
// Přísady
|
||||
const ingredients = []
|
||||
const ingredientsHtml = $('.prisady > li', pizzaHtml);
|
||||
ingredientsHtml.each((i, elm) => {
|
||||
ingredients.push($(elm).text());
|
||||
})
|
||||
// Velikosti
|
||||
const sizes = [];
|
||||
const a = $('.varianty > li > a', pizzaHtml);
|
||||
a.each((i, elm) => {
|
||||
const size = $('span', elm).text();
|
||||
const priceKc = $(elm).text().split(size).pop().trim();
|
||||
const price = Number.parseInt(priceKc.split(" Kč")[0]);
|
||||
sizes.push({ size: size, pizzaPrice: price, boxPrice: boxPrices[size], price: price + boxPrices[size] });
|
||||
})
|
||||
result.push({
|
||||
name: name,
|
||||
ingredients: ingredients,
|
||||
sizes: sizes,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrátí pizzy z tempu, nebo čerstvě stažené, pokud v tempu nejsou.
|
||||
*/
|
||||
export const fetchPizzy = async () => {
|
||||
const tmpDir = os.tmpdir();
|
||||
const date_ob = new Date();
|
||||
const date = ("0" + date_ob.getDate()).slice(-2);
|
||||
const month = ("0" + (date_ob.getMonth() + 1)).slice(-2);
|
||||
const year = date_ob.getFullYear();
|
||||
const dateStr = year + "-" + month + "-" + date;
|
||||
const dataPath = path.join(tmpDir, `chefie-${dateStr}.json`);
|
||||
|
||||
if (fs.existsSync(dataPath)) {
|
||||
console.log(`Soubor pro ${dataPath} již existuje, bude použit.`);
|
||||
const rawdata = fs.readFileSync(dataPath);
|
||||
return JSON.parse(rawdata.toString());
|
||||
} else {
|
||||
console.log(`Soubor pro ${dataPath} neexistuje, stahuji...`);
|
||||
const pizzy = await downloadPizzy();
|
||||
fs.writeFileSync(dataPath, JSON.stringify(pizzy));
|
||||
console.log(`Zapsán ${dataPath}`);
|
||||
return pizzy;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
66
server/src/index.ts
Normal file
66
server/src/index.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import express from "express";
|
||||
import { Server } from "socket.io";
|
||||
import bodyParser from "body-parser";
|
||||
import { fetchPizzy } from "./chefie";
|
||||
|
||||
const app = express();
|
||||
const server = require("http").createServer(app);
|
||||
const io = new Server(server, {
|
||||
cors: {
|
||||
origin: "*",
|
||||
},
|
||||
});
|
||||
|
||||
// Body-parser middleware for parsing JSON
|
||||
app.use(bodyParser.json());
|
||||
|
||||
const cors = require('cors');
|
||||
app.use(cors({
|
||||
origin: '*'
|
||||
}));
|
||||
|
||||
app.get("/api/pizza", (req, res) => {
|
||||
fetchPizzy().then(pizzaList => {
|
||||
console.log("Výsledek", pizzaList);
|
||||
res.status(200).json(pizzaList);
|
||||
});
|
||||
});
|
||||
|
||||
app.post("/api/zprava", (req, res) => {
|
||||
const { username, message } = req.body;
|
||||
|
||||
if (
|
||||
typeof username !== "string" ||
|
||||
typeof message !== "string" ||
|
||||
username.length > 500 ||
|
||||
message.length > 500
|
||||
) {
|
||||
return res.status(400).json({ error: "Invalid input" });
|
||||
}
|
||||
console.log(`posílám ${username} ${message} `);
|
||||
io.emit("externalMessage", `${username} -> ${message}`);
|
||||
res.status(200).json({ success: "Message sent" });
|
||||
});
|
||||
|
||||
io.on("connection", (socket) => {
|
||||
console.log(`New client connected: ${socket.id}`);
|
||||
|
||||
socket.on("message", (message) => {
|
||||
io.emit("message", message);
|
||||
});
|
||||
|
||||
socket.on("jduKafe", ({ username, timeString }) => {
|
||||
console.log(`Received message: ${username}`);
|
||||
socket.broadcast.emit("jduKafe", `${timeString}: ${username} -> jdu Kafe`);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log(`Client disconnected: ${socket.id}`);
|
||||
});
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3001;
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`Server listening on port ${PORT}`);
|
||||
});
|
||||
8
server/tsconfig.json
Normal file
8
server/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2016",
|
||||
"module": "CommonJS",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
}
|
||||
}
|
||||
1114
server/yarn.lock
Normal file
1114
server/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user