This is an autonomous image scraper developed using TypeScript, Deno, and GitHub Actions. It was purpose-built to document the historic Formula 1 track construction in Las Vegas, Nevada, slated to host the inaugural Heineken Silver Grand Prix on November 18th. The images will be stitched together to form timelapse videos of the track’s lifecycle.
📸 Latest • 🎬 Timelapse • 🗓️ Previous Images • ℹ️ Project Details • 🌟 Star It!
Since June 3rd, 2023 this project has collected nearly 20,000 images, all courtesy of a live-streaming construction camera provided by the track’s developers. This project is not affiliated with Formula 1.
Estimated Top Speed | Circuit Length | Corners | Straights | DRS Zones |
---|---|---|---|---|
212 mph • 342 km/h | 3.8 miles • 6.12 km | 17 | 3 | 2 |
Note: this video was created with images from 2023-08-15 - 2023-10-12
The first scrape happened on June 3rd, 2023. As of October 18th it has surpassed
18,500 commits, equivalent to over 1.2GB of image data. Photos are stored
in the ./assets
folder of this repository, and also persisted to a Deno KV
database backed by FoundationDB.
The origin of the scraped images is an real-time photo feed, sourced directly from the official Formula 1 website.
⚠️ This project is for educational purposes and is not affiliated with Formula 1.
Deno v1.37.2
TypeScript 5.2.2
GitHub Actions
Deno KV
(currently in beta)
ffmpeg
(timelapse feature is unstable)
AI-generated F1 art created with SDXL 1.0 and the prompt
"Formula 1 cars on the Las Vegas Strip"
The majority of the work happens in main.ts
, despite it only being
3 lines of code. It is responsible for invoking the scraper located in
src/scrape.ts
, and is ran every 10 minutes by a GitHub Action
defined by the workflow in main.yml
.
Images are named after their capture time as a JPEG
file in UTC. For
example, an image captured at 2023-07-09T04:28:57
would be saved as
./assets/2023-07-09/04_28_57.jpg
.
The latest image is always saved as ./assets/latest.jpg
for easy access.
deno task scrape
is executed, which runs the main.ts
file.main.ts
imports scrape()
from src/scrape.ts
,
which contains the read
and write
functions.read()
is called with IMAGE_URL
.
ATTEMPTS
times, with a short pause between each successive attempt.Image
class is returned.write()
is called with the new Image
.
Before writing the image, it runs through some checks:
Image.hash
is checked against the hash “table” in Deno KV.
latest.jpg
via
a timing-safe equality comparison, avoiding exposure to timing-based attacks.ATTEMPTS
are all used. If nothing is found by now, the job fails.Image.write()
persists the image to Deno KV.
The key is generated by the
Image
API, using the image timestamp.
This prevents later scrapes from duplicating this image. It also means
if you try to instantiate a new Image from an old hash, it will always
return the original image and its original timestamp.
Image.writeFile()
saves it to the local file system.
The filename is generated by the
Image
API, using the image timestamp.
Image.writeFile()
also saves it to ./assets/latest.jpg
,setOutput
helper pipes the image metadata
to the GitHub Actions runner, to be used in the commit step.