mirror of
https://github.com/ssyyhhrr/stewardle.git
synced 2025-11-08 10:33:46 -05:00
329 lines
11 KiB
JavaScript
329 lines
11 KiB
JavaScript
const axios = require("axios")
|
|
const _ = require("lodash")
|
|
const fs = require("fs")
|
|
const schedule = require("node-schedule")
|
|
const express = require("express")
|
|
const favicon = require("serve-favicon")
|
|
const morgan = require("morgan")
|
|
const dayjs = require("dayjs")
|
|
const process = require("process")
|
|
const {v4: uuidv4} = require("uuid")
|
|
|
|
const version = uuidv4()
|
|
|
|
const driversPath = "./assets/drivers.json"
|
|
const statsPath = "./assets/stats.json"
|
|
|
|
const flag = {
|
|
"British": "gb",
|
|
"Spanish": "es",
|
|
"Polish": "pl",
|
|
"Japanese": "jp",
|
|
"Mexican": "mx",
|
|
"Australian": "au",
|
|
"Russian": "ru",
|
|
"Dutch": "nl",
|
|
"Belgian": "be",
|
|
"Canadian": "ca",
|
|
"New Zealander": "nz",
|
|
"Thai": "th",
|
|
"Finnish": "fi",
|
|
"Brazilian": "br",
|
|
"German": "de",
|
|
"French": "fr",
|
|
"Venezuelan": "ve",
|
|
"Danish": "dk",
|
|
"Swedish": "se",
|
|
"American": "us",
|
|
"Indonesian": "id",
|
|
"Italian": "it",
|
|
"Monegasque": "mc",
|
|
"Chinese": "cn"
|
|
}
|
|
|
|
const team = {
|
|
"McLaren": "mclaren",
|
|
"Alpine F1 Team": "alpine",
|
|
"Mercedes": "mercedes",
|
|
"Sauber": "sauber",
|
|
"Haas F1 Team": "haas",
|
|
"Lotus F1": "lotus",
|
|
"Marussia": "marussia",
|
|
"Manor Marussia": "marussia",
|
|
"Renault": "renault",
|
|
"Alfa Romeo": "alfa",
|
|
"Williams": "williams",
|
|
"Aston Martin": "aston",
|
|
"Caterham": "caterham",
|
|
"Red Bull": "red",
|
|
"Toro Rosso": "toro",
|
|
"AlphaTauri": "alpha",
|
|
"Ferrari": "ferrari"
|
|
}
|
|
|
|
let stats = {
|
|
"visits": 0,
|
|
"guesses": 0
|
|
}
|
|
|
|
let drivers = {}
|
|
let driver
|
|
|
|
let year = new Date().getFullYear()
|
|
|
|
axios.get("https://ergast.com/api/f1/1950/driverStandings.json?limit=1000").then(async () => {
|
|
await updateDrivers()
|
|
}).catch(() => {
|
|
console.log("API is unreachable! Not updating drivers...")
|
|
if (fs.existsSync(driversPath)) {
|
|
let data = fs.readFileSync(driversPath)
|
|
drivers = JSON.parse(data)
|
|
} else {
|
|
throw "Ergast API is unreachable and the drivers.json cache has not been built. Please try again when the Ergast API is online."
|
|
}
|
|
}).catch(err => {
|
|
console.log(err)
|
|
return process.exit(1)
|
|
}).then(() => {
|
|
dotd()
|
|
server()
|
|
})
|
|
|
|
schedule.scheduleJob("59 23 * * *", async () => {
|
|
axios.get("https://ergast.com/api/f1/1950/driverStandings.json?limit=1000").then(async () => {
|
|
await updateDrivers()
|
|
}).catch(() => {
|
|
console.log("API is unreachable! Not updating drivers...")
|
|
drivers = JSON.parse(fs.readFileSync(driversPath))
|
|
})
|
|
})
|
|
|
|
schedule.scheduleJob("0 0 * * *", () => {
|
|
dotd()
|
|
})
|
|
|
|
schedule.scheduleJob("* * * * *", () => {
|
|
processStats()
|
|
})
|
|
|
|
async function updateDrivers() {
|
|
drivers = {}
|
|
for (let i = 2000; i <= year; i++) {
|
|
console.log(`Scraping F1 ${i} Season...`)
|
|
try {
|
|
await axios.get(`http://ergast.com/api/f1/${i}/driverStandings.json?limit=1000`).then(res => {
|
|
res.data.MRData.StandingsTable.StandingsLists[0].DriverStandings.forEach(driver => {
|
|
if (driver.Driver.driverId in drivers) {
|
|
drivers[driver.Driver.driverId].wins += parseInt(driver.wins)
|
|
if (drivers[driver.Driver.driverId].constructors[drivers[driver.Driver.driverId].constructors.length - 1] !== team[driver.Constructors[0].name] || drivers[driver.Driver.driverId].constructors.length === 0) drivers[driver.Driver.driverId].constructors.push(team[driver.Constructors[0].name])
|
|
} else if (driver.Driver.hasOwnProperty("permanentNumber")) {
|
|
drivers[driver.Driver.driverId] = {
|
|
"firstName": driver.Driver.givenName,
|
|
"lastName": driver.Driver.familyName,
|
|
"code": driver.Driver.code,
|
|
"nationality": flag[driver.Driver.nationality],
|
|
"constructors": [team[driver.Constructors[0].name]],
|
|
"permanentNumber": driver.Driver.permanentNumber,
|
|
"age": getAge(driver.Driver.dateOfBirth),
|
|
"firstYear": i,
|
|
"wins": parseInt(driver.wins),
|
|
}
|
|
}
|
|
})
|
|
})
|
|
} catch (e) {
|
|
if (i !== year) throw ""
|
|
}
|
|
}
|
|
|
|
if (fs.existsSync("assets/drivers.json")) {
|
|
console.log("Deleting drivers.json...")
|
|
fs.unlinkSync("assets/drivers.json")
|
|
}
|
|
|
|
console.log(`Writing ${_.keys(drivers).length} Drivers to drivers.json...`)
|
|
fs.writeFileSync("assets/drivers.json", JSON.stringify(drivers), (error) => {
|
|
if (error) throw error
|
|
})
|
|
}
|
|
|
|
function processStats(dotd = false) {
|
|
const date = dayjs().format("YYYY-MM-DD");
|
|
console.log(`[DEBUG] processStats Date is ${date}`)
|
|
|
|
let statsFile = {};
|
|
if (fs.existsSync(statsPath)) {
|
|
statsFile = JSON.parse(fs.readFileSync(statsPath));
|
|
}
|
|
|
|
console.log(`[DEBUG] statsFile ${statsFile}`)
|
|
|
|
if (dotd) {
|
|
console.log(`[DEBUG] dotd TRUE`)
|
|
statsFile[date] = {
|
|
visits: stats.visits,
|
|
guesses: stats.guesses,
|
|
driver: stats.driver,
|
|
};
|
|
console.log(`[DEBUG] statsFile[date] ${statsFile[date]}`)
|
|
|
|
} else if (statsFile.hasOwnProperty(date)) {
|
|
console.log(`[DEBUG] statsFile.hasOwnProperty(date) TRUE`)
|
|
if (statsFile[date].visits > stats.visits) {
|
|
console.log(`[DEBUG] statsFile[date].visits > stats.visits`)
|
|
statsFile[date].visits += stats.visits
|
|
stats.visits = statsFile[date].visits
|
|
}
|
|
else statsFile[date].visits = stats.visits
|
|
if (statsFile[date].guesses > stats.guesses) {
|
|
console.log(`[DEBUG] statsFile[date].guesses > stats.guesses`)
|
|
statsFile[date].guesses += stats.guesses
|
|
stats.guesses = statsFile[date].guesses
|
|
}
|
|
else statsFile[date].guesses = stats.guesses
|
|
} else return
|
|
|
|
console.log(`[DEBUG] Writing ${statsFile} to ${statsPath}`)
|
|
fs.writeFileSync(statsPath, JSON.stringify(statsFile));
|
|
}
|
|
|
|
function dotd() {
|
|
console.log("Selecting Driver of the Day...")
|
|
let date = dayjs().format("YYYY-MM-DD")
|
|
console.log(`dotd Date is ${date}`)
|
|
let pastDrivers = []
|
|
let pastDates = []
|
|
if (fs.existsSync(statsPath)) {
|
|
let statsFile = JSON.parse(fs.readFileSync(statsPath))
|
|
pastDates = Object.keys(statsFile)
|
|
pastDrivers = Object.values(statsFile).map(x => x.driver).filter((x) => { return typeof x === "string"})
|
|
console.log(`[DEBUG] pastDates ${pastDates}`)
|
|
console.log(`[DEBUG] pastDrivers ${pastDrivers}`)
|
|
}
|
|
if (pastDrivers.length > 0 && pastDates.length > 0 && pastDates[pastDates.length - 1] === date) {
|
|
console.log(`[DEBUG] Date is TODAY`)
|
|
driver = pastDrivers[pastDrivers.length - 1]
|
|
console.log(`[DEBUG] driver ${driver}`)
|
|
} else {
|
|
let newDriver = getRandomProperty(drivers)
|
|
console.log(`[DEBUG] newDriver ${newDriver}`)
|
|
if (pastDrivers.slice(-7).includes(newDriver)) {
|
|
console.log("Driver was picked recently, re-selecting...")
|
|
return dotd()
|
|
}
|
|
driver = newDriver
|
|
}
|
|
stats = {
|
|
"visits": 0,
|
|
"guesses": 0,
|
|
"driver": driver
|
|
}
|
|
console.log(`[DEBUG] stats ${stats}`)
|
|
processStats(true)
|
|
console.log(`Driver of the Day is ${driver}!`)
|
|
console.log(drivers[driver])
|
|
}
|
|
|
|
function getRandomProperty(obj) {
|
|
let keys = Object.keys(obj)
|
|
return keys[Math.floor(Math.random() * keys.length)]
|
|
}
|
|
|
|
function getAge(dateString) {
|
|
var today = new Date();
|
|
var birthDate = new Date(dateString);
|
|
var age = today.getFullYear() - birthDate.getFullYear();
|
|
var m = today.getMonth() - birthDate.getMonth();
|
|
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
|
|
age--;
|
|
}
|
|
return age;
|
|
}
|
|
|
|
function server() {
|
|
var app = express()
|
|
|
|
app.enable("trust proxy")
|
|
|
|
app.use(express.urlencoded({ extended: true }))
|
|
app.use(express.static("assets"))
|
|
app.use(favicon('assets/favicon.ico'))
|
|
app.use(morgan("combined"))
|
|
|
|
app.set("views", "views")
|
|
app.set("view engine", "ejs")
|
|
|
|
app.get("/", (req, res) => {
|
|
res.render("index")
|
|
stats.visits++
|
|
})
|
|
|
|
app.get("/version", (req, res) => {
|
|
res.send(version)
|
|
})
|
|
|
|
app.get("/winner", (req, res) => {
|
|
if (req.headers.authorization !== "Bearer kRyX3RYMRY$&yEc8") return res.end()
|
|
res.json({
|
|
"winner": drivers[driver].firstName + " " + drivers[driver].lastName,
|
|
})
|
|
})
|
|
|
|
app.get("/driver", (req, res) => {
|
|
if (!req.query.driver) return res.statusSend(400)
|
|
let search = false
|
|
let response = []
|
|
for (let query in drivers) {
|
|
if (req.query.driver === drivers[query].firstName + " " + drivers[query].lastName) {
|
|
search = true
|
|
let guess = drivers[query]
|
|
let actual = drivers[driver]
|
|
|
|
// nationality
|
|
if (guess.nationality === actual.nationality) response.push(1) // correct nationality
|
|
else response.push(3) // incorrect nationality
|
|
|
|
// constructors
|
|
if (guess.constructors[guess.constructors.length - 1] === actual.constructors[actual.constructors.length - 1]) response.push(1) // correct constructor
|
|
else if (actual.constructors.includes(guess.constructors[guess.constructors.length - 1])) response.push(4) // previous constructor
|
|
else response.push(3) // incorrect constructor
|
|
|
|
// permanent number
|
|
if (parseInt(guess.permanentNumber) > parseInt(actual.permanentNumber)) response.push(0) // go down
|
|
else if (parseInt(guess.permanentNumber) === parseInt(actual.permanentNumber)) response.push(1) // stay the same
|
|
else if (parseInt(guess.permanentNumber) < parseInt(actual.permanentNumber)) response.push(2) // go up
|
|
|
|
// age
|
|
if (parseInt(guess.age) > parseInt(actual.age)) response.push(0) // go down
|
|
else if (parseInt(guess.age) === parseInt(actual.age)) response.push(1) // stay the same
|
|
else if (parseInt(guess.age) < parseInt(actual.age)) response.push(2) // go up
|
|
|
|
// first year
|
|
if (parseInt(guess.firstYear) > parseInt(actual.firstYear)) response.push(0) // go down
|
|
else if (parseInt(guess.firstYear) === parseInt(actual.firstYear)) response.push(1) // stay the same
|
|
else if (parseInt(guess.firstYear) < parseInt(actual.firstYear)) response.push(2) // go up
|
|
|
|
// wins
|
|
if (parseInt(guess.wins) > parseInt(actual.wins)) response.push(0) // go down
|
|
else if (parseInt(guess.wins) === parseInt(actual.wins)) response.push(1) // stay the same
|
|
else if (parseInt(guess.wins) < parseInt(actual.wins)) response.push(2) // go up
|
|
}
|
|
}
|
|
if (!search) return res.sendStatus(400)
|
|
res.json({
|
|
"nationality": response[0],
|
|
"constructor": response[1],
|
|
"permanentNumber": response[2],
|
|
"age": response[3],
|
|
"firstYear": response[4],
|
|
"wins": response[5],
|
|
"version": version
|
|
})
|
|
stats.guesses++
|
|
})
|
|
|
|
let port = 3000
|
|
app.listen(port, () => {
|
|
console.log(`Listening on port ${port}!`)
|
|
})
|
|
} |