Free Games Tracker

A to Z Guide

How this project works, from data collection to GitHub Pages.

This page documents the project architecture, scripts, workflow, data files, and deployment path so anyone opening the repository can understand the full system quickly.

Overview

What this project does

The project tracks free game promotions from Epic Games and Steam, stores structured JSON snapshots, sends notifications through email, Telegram, and Discord when lineups change, updates the README automatically, and exposes the latest offers through this GitHub Pages site.

System Flow

End-to-end flow

1. Fetch

`epic.PY` calls Epic's promotion endpoint and `steam.py` gathers Steam deals from web/API sources.

2. Normalize

Each script converts the results into predictable JSON records with title, link, image, type, and timing fields.

3. Detect changes

A signature is built from the offer list so emails only send when the lineup actually changes.

4. Persist

The latest state is saved into `free.json` and `free-steam.json` for downstream consumers.

5. Publish

`generate_readme.py` refreshes the README while GitHub Pages serves the JSON-backed website, and `start.py` runs both notifiers locally in sequence.

Repository

Main files

`epic.PY`Epic fetcher, email sender, JSON state writer.
`steam.py`Steam fetcher, weekend title resolver, JSON state writer.
`start.py`Runs `epic.PY` and `steam.py` one after another.
`generate_readme.py`README auto-section generator.
`config.json`Notification toggles and secrets-file settings.
`secrets.json`Optional local JSON secrets source.
`free.json`Epic current and upcoming free game snapshot.
`free-steam.json`Steam free-offer snapshot.
`index.html`GitHub Pages homepage for the games dashboard.
`SITE/docs.html`Full documentation page.

Data

JSON structure

The site expects these repository files:

free.json
{
  "signature": "...",
  "updated_at": "...",
  "current_games": [{ "title": "", "link": "", "image": "", "start": "", "end": "" }],
  "upcoming_games": [{ "title": "", "link": "", "image": "", "start": "", "end": "" }]
}

free-steam.json
{
  "signature": "...",
  "updated_at": "...",
  "games": [{ "type": "", "title": "", "link": "", "image": "", "time": "" }]
}

Delivery

Notification channels

The project can notify through email, Telegram, and Discord. Each channel can be enabled or disabled independently inside config.json.

{
  "secrets": {
    "use_hardcoded_secrets": false,
    "secrets_file": "secrets.json"
  },
  "notifications": {
    "email": true,
    "telegram": true,
    "discord": true
  }
}

Email, Telegram, and Discord all support multiple targets separated by commas. Email supports up to 30 recipients per run, for example first@example.com,second@example.com. Telegram and Discord support comma-separated chat or channel IDs like -1003918180986,1845799450 and 123456789012345678,987654321098765432.

{
  "email": {
    "email": "you@gmail.com",
    "password": "your-app-password",
    "to_email": "first@example.com,second@example.com,third@example.com"
  },
  "telegram": {
    "bot_token": "123456:telegram-bot-token",
    "chat_id": "-1003918180986,1845799450"
  },
  "discord": {
    "bot_token": "YOUR_DISCORD_BOT_TOKEN",
    "channel_id": "123456789012345678,987654321098765432"
  }
}

Automation

GitHub Actions

The workflow runs every 6 hours and can also be triggered manually. It installs dependencies, runs both fetcher scripts, regenerates the README, and commits updated JSON snapshots.

Deployment

GitHub Pages setup

The public entry lives at the repository root in index.html, while shared site assets and the documentation page live in the SITE/ folder. This keeps GitHub Pages happy while still grouping the website files cleanly.

Setup

How to run locally

pip install requests beautifulsoup4

$env:EMAIL="you@example.com"
$env:PASSWORD="your-app-password"
$env:TO_EMAIL="first@example.com,second@example.com"
$env:TELEGRAM_BOT_TOKEN="123456:telegram-bot-token"
$env:TELEGRAM_CHAT_ID="-1003918180986,1845799450"
$env:DISCORD_BOT_TOKEN="your-discord-bot-token"
$env:DISCORD_CHANNEL_ID="123456789012345678,987654321098765432"

python start.py
python generate_readme.py

Extend

How to grow the project

You can add more storefronts by following the same pattern: fetch data, normalize it into JSON, generate a signature, save a state file, and teach the site how to render the new data source.