Skip to content

Commit

Permalink
feat: enhance race and sprint data processing with new utility functi…
Browse files Browse the repository at this point in the history
…ons and components
  • Loading branch information
Rafacv23 committed Jan 14, 2025
2 parents 197341f + ca0578a commit 417e716
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 10 deletions.
6 changes: 5 additions & 1 deletion components/buttons/BackBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import Link from "next/link"
import initTranslations from "@/app/i18n"
import { buttonVariants } from "@/components/ui/button"

export async function BackBtn({ locale }: { locale: string }) {
interface BackBtnProps extends React.HTMLAttributes<HTMLButtonElement> {
locale: string
}

export async function BackBtn({ locale }: BackBtnProps) {
const { t } = await initTranslations(locale, ["common"])

return (
Expand Down
10 changes: 7 additions & 3 deletions components/buttons/CopyBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import { Button } from "@/components/ui/button"
import { Check, Copy } from "lucide-react"
import { copyUrlToClipboard } from "@/lib/utils"
import { cn, copyUrlToClipboard } from "@/lib/utils"
import { useState } from "react"

interface CopyBtnProps extends React.HTMLAttributes<HTMLButtonElement> {
text: string
className?: string
}

export default function CopyBtn({ text }: CopyBtnProps) {
export default function CopyBtn({ text, className }: CopyBtnProps) {
const [copied, setCopied] = useState(false)

const handleCopy = async () => {
Expand All @@ -23,7 +24,10 @@ export default function CopyBtn({ text }: CopyBtnProps) {
}

return (
<Button className="flex gap-2 items-center" onClick={handleCopy}>
<Button
className={cn("flex items-center gap-2", className)}
onClick={handleCopy}
>
{copied ? "Copied!" : "Copy Link"}
{copied ? <Check size={16} /> : <Copy size={16} />}
</Button>
Expand Down
8 changes: 6 additions & 2 deletions lib/scrap/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ import { chromium } from "playwright"
import { getRaceResults } from "./race.js"
import { getQualyResults } from "./qualy.js"
import { getPracticeResults } from "./fp.js"
import { getSprintRaceResults } from "./sprint/race.js"
import { getSprintQualyResults } from "./sprint/qualy.js"
;(async () => {
const browser = await chromium.launch({ headless: false })
const context = await browser.newContext()

const page = await context.newPage()
const year = 2024
const race = "abu-dhabi"
const race = "qatar"

//await getPracticeResults(year, race, page)
//await getQualyResults(year, race, page)
await getRaceResults(year, race, page)
//await getSprintQualyResults(year, race, page)
//await getSprintRaceResults(year, race, page)
//await getRaceResults(year, race, page)

await context.close()
await browser.close()
Expand Down
47 changes: 45 additions & 2 deletions lib/scrap/race.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ export const getRaceResults = async (year, race, page) => {
const driver = columns[1]?.innerText.trim().toLowerCase() || null
const team = columns[5]?.innerText.trim().toLowerCase() || null
const gridPosition = columns[6]?.innerText.split("\n")[0].trim() || null
const fastLap =
columns[8]
?.querySelector(`span[aria-hidden="true"]`)
?.innerText.trim() || // Try `aria-hidden`
columns[8]?.querySelector(`span.visually-hidden`)?.innerText.trim() || // Fallback to `visually-hidden`
null

const lapTime = fastLap ? fastLap.match(/\d+:\d+\.\d+/)?.[0] : null

const raceTime =
columns[10]
?.querySelector(`span[aria-hidden="true"]`)
Expand All @@ -39,6 +48,8 @@ export const getRaceResults = async (year, race, page) => {
raceTime,
points,
gridPosition,
lapTime,
fastLap,
})
})

Expand All @@ -53,11 +64,33 @@ export const getRaceResults = async (year, race, page) => {
Finishing_Position: result.position,
Grid_Position: result.gridPosition,
Race_Time: result.raceTime,
Points_Obtained: parseInt(result.points), // Asumiendo que los puntos siempre son numéricos y en el formato "X"
Points_Obtained: parseInt(result.points),
fast_lap: result.lapTime,
}
})

// we want to retrieve the fastest overall lap of the race

const fastestLap = results.reduce(
(acc, result) => {
// Check if the lapTime exists and is a valid lap time
if (result.lapTime) {
const lapTime = result.lapTime

// Compare lap time only if it's the fastest one
if (!acc.lapTime || lapTime < acc.lapTime) {
acc.lapTime = lapTime
acc.driverId = formatDriver(result.driver)
acc.teamId = formatTeam(result.team)
}
}
return acc
},
{ lapTime: null, driverId: null, teamId: null }
)

console.log(formattedResults)
console.log(fastestLap)
;(async () => {
const RaceResults = await formattedResults
// Ensure the data is an array and has items before inserting
Expand All @@ -81,9 +114,19 @@ export const getRaceResults = async (year, race, page) => {
}
try {
await clientWriter.execute({
sql: `UPDATE Races SET Winner_ID = :Winner_ID, Team_Winner_ID = :Team_Winner_ID WHERE Race_ID = :Race_ID`,
sql: `UPDATE Races
SET
Winner_ID = :Winner_ID,
fast_lap = :fast_lap,
fast_lap_driver_id = :fast_lap_driver_id,
fast_lap_team_id = :fast_lap_team_id,
Team_Winner_ID = :Team_Winner_ID
WHERE Race_ID = :Race_ID`,
args: {
Winner_ID: formattedResults[0].Driver_ID,
fast_lap: fastestLap.lapTime,
fast_lap_driver_id: fastestLap.driverId,
fast_lap_team_id: fastestLap.teamId,
Team_Winner_ID: formattedResults[0].Team_ID,
Race_ID: raceId,
},
Expand Down
85 changes: 85 additions & 0 deletions lib/scrap/sprint/qualy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//import { db } from "@/db/index.js"
import { generateRaceId, formatDriver, formatTeam } from "../utils.js"

export const getSprintQualyResults = async (year, race, page) => {
//const raceId = generateRaceId(race, year)
const raceId = "qatar_2024"
const raceNumber = 1251 // Refers to the race number of the grand prix, its the id of the f1 page
const url = `https://www.formula1.com/en/results/${year}/races/${raceNumber}/${race}/sprint-qualifying`

await page.goto(url)

await page.waitForSelector(
'table[class="f1-table f1-table-with-data w-full"]'
)

const results = await page.evaluate(() => {
const table = document.querySelector(
'table[class="f1-table f1-table-with-data w-full"]'
)
const rows = table?.querySelectorAll("tbody tr")
const data = []

rows?.forEach((row) => {
const columns = row.querySelectorAll("td p")
const gridPosition = columns[0]?.innerText.split("\n")[0].trim() || null
const driver = columns[2]?.innerText.trim().toLowerCase() || null
const team = columns[3]?.innerText.trim().toLowerCase() || null
const sq1 = columns[4]?.innerText.split("\n")[0].trim() || null
const sq2 = columns[5]?.innerText.split("\n")[0].trim() || null
const sq3 = columns[6]?.innerText.split("\n")[0].trim() || null

data.push({
gridPosition,
driver,
team,
sq1,
sq2,
sq3,
})
})

return data
})

const formattedResults = results.map((result) => {
return {
Race_ID: raceId,
Driver_ID: formatDriver(result.driver),
Team_ID: formatTeam(result.team, result.driver),
Grid_Position: result.gridPosition,
SQ1: result.sq1,
SQ2: result.sq2,
SQ3: result.sq3,
}
})

console.log(formattedResults)
// ;async () => {
// const sprintRaceResults = await mergedResults

// if (Array.isArray(sprintRaceResults) && sprintRaceResults.length > 0) {
// for (const result of sprintRaceResults) {
// try {
// await db
// .insert(Sprint_Race)
// .values({
// Race_ID: raceId,
// Driver_ID: result.Driver_ID,
// Team_ID: result.Team_ID,
// Finishing_Position: result.Finishing_Position,
// laps: result.laps,
// Race_Time: result.Race_Time,
// Points_Obtained: result.Points_Obtained,
// Grid_Position: result.Grid_Position,
// })
// .onConflictDoNothing()

// console.log("Sprint Race inserted correctly")
// } catch (error) {
// console.error(error)
// }
// }
// }
// }
}
138 changes: 138 additions & 0 deletions lib/scrap/sprint/race.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//import { db } from "@/db/index.js"
import { generateRaceId, formatDriver, formatTeam } from "../utils.js"

export const getSprintRaceResults = async (year, race, page) => {
//const raceId = generateRaceId(race, year)
const raceId = "qatar_2024"
const raceNumber = 1251 // Refers to the race number of the grand prix, its the id of the f1 page
const url = `https://www.formula1.com/en/results/${year}/races/${raceNumber}/${race}/sprint-results`

await page.goto(url)

await page.waitForSelector(
'table[class="f1-table f1-table-with-data w-full"]'
)

const results = await page.evaluate(() => {
const table = document.querySelector(
'table[class="f1-table f1-table-with-data w-full"]'
)
const rows = table?.querySelectorAll("tbody tr")
const data = []

rows?.forEach((row) => {
const columns = row.querySelectorAll("td p")
const position = columns[0]?.innerText.split("\n")[0].trim() || null
const driver = columns[2]?.innerText.trim().toLowerCase() || null
const team = columns[3]?.innerText.trim().toLowerCase() || null
const laps = columns[4]?.innerText.trim().toLowerCase() || null
const raceTime = columns[5]?.innerText.split("\n")[0].trim() || null
const points = columns[6]?.innerText.split("\n")[0].trim() || null

data.push({
position,
driver,
team,
laps,
raceTime,
points,
})
})

return data
})

// now we need to get the sprint grid position
const sprintUrl = `https://www.formula1.com/en/results/${year}/races/${raceNumber}/${race}/sprint-grid`
await page.goto(sprintUrl)

await page.waitForSelector(
'table[class="f1-table f1-table-with-data w-full"]'
)

const qualyResults = await page.evaluate(() => {
const table = document.querySelector(
'table[class="f1-table f1-table-with-data w-full"]'
)
const rows = table?.querySelectorAll("tbody tr")
const data = []

rows?.forEach((row) => {
const columns = row.querySelectorAll("td p")
const gridPosition = columns[0]?.innerText.split("\n")[0].trim() || null
const driver = columns[2]?.innerText.trim().toLowerCase() || null

data.push({
gridPosition,
driver,
})
})

return data
})

const sprintQualyResults = qualyResults.map((result) => {
return {
driverId: formatDriver(result.driver),
gridPosition: result.gridPosition,
}
})

const formattedResults = results.map((result) => {
return {
Race_ID: raceId,
Driver_ID: formatDriver(result.driver),
Team_ID: formatTeam(result.team, result.driver),
Finishing_Position: result.position,
laps: result.laps,
Race_Time: result.raceTime,
Points_Obtained: parseInt(result.points), // Asumiendo que los puntos siempre son numéricos y en el formato "X"
}
})

// now, with the sprint grid and the sprint race results, we can merge them in one

const mergedResults = formattedResults.map((result) => {
// Find the matching sprint grid result for the driver
const sprintQualy = sprintQualyResults.find(
(qualy) => qualy.driverId === result.Driver_ID
)

// Return a new object with the merged data
return {
...result, // Keep all existing properties
Grid_Position: sprintQualy?.gridPosition || null, // Add grid position if found, else null
}
})

console.log(mergedResults)
// ;async () => {
// const sprintRaceResults = await mergedResults

// if (Array.isArray(sprintRaceResults) && sprintRaceResults.length > 0) {
// for (const result of sprintRaceResults) {
// try {
// await db
// .insert(Sprint_Race)
// .values({
// Race_ID: raceId,
// Driver_ID: result.Driver_ID,
// Team_ID: result.Team_ID,
// Finishing_Position: result.Finishing_Position,
// laps: result.laps,
// Race_Time: result.Race_Time,
// Points_Obtained: result.Points_Obtained,
// Grid_Position: result.Grid_Position,
// })
// .onConflictDoNothing()

// also, we need to update the standings with the new points

// console.log("Sprint Race inserted correctly")
// } catch (error) {
// console.error(error)
// }
// }
// }
// }
}
Loading

0 comments on commit 417e716

Please sign in to comment.