Migrate Free Games Claimer to remaster upstream
This commit is contained in:
Alexandre
2026-07-17 09:27:19 +02:00
committed by GitHub
9 changed files with 719 additions and 254 deletions

View File

@@ -1,20 +1,53 @@
- Added support for configuring extra environment variables via the `env_vars` add-on option alongside config.yaml. See https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2 for details.
## 2.0.0 (2026-07-17)
- Replaced the abandoned `vogler/free-games-claimer` upstream with
`P-Adamiec/Free-Games-Claimer-Remaster`.
- Reworked the image build for the remaster's Python, Chromium, TurboVNC, and
noVNC runtime on both amd64 and aarch64.
- Preserved the previous default one-shot behavior and Epic, Prime Gaming, and
GOG store selection.
- Kept noVNC on port 6080 for upgrade compatibility.
- Added `RUN_ONCE` and `STORES` options while retaining `CMD_ARGUMENTS` as a
deprecated compatibility input.
- Added an automatic, idempotent migration of legacy Epic, Prime Gaming, and
GOG JSON claim history into the remaster SQLite database.
- Preserved legacy files for rollback and documented the required one-time
Chromium login when a Firefox session cannot be migrated.
- Pinned the reviewed upstream source commit and paused generic automatic
updates so the add-on's independent `2.x` version cannot regress to `1.x`.
- Updated the configuration template, upstream metadata, and documentation.
- Added support for configuring extra environment variables via the `env_vars`
add-on option.
## 1.8 (2025-05-17)
- Update to latest version from vogler/free-games-claimer (changelog : https://github.com/vogler/free-games-claimer/releases)
- Update to latest version from vogler/free-games-claimer (changelog: https://github.com/vogler/free-games-claimer/releases)
## 1.7 (2025-03-08)
- Update to latest version from vogler/free-games-claimer (changelog : https://github.com/vogler/free-games-claimer/releases)
- Update to latest version from vogler/free-games-claimer (changelog: https://github.com/vogler/free-games-claimer/releases)
## 1.6-6 (2024-12-29)
- Minor bugs fixed
## 1.6-5 (2024-12-13)
- Minor bugs fixed
## 1.6-4 (2024-12-07)
- ⚠ MAJOR CHANGE : switch to the new config logic from homeassistant. Your configuration files will have migrated from /config/hassio_addons/free_games_claimer in a folder only accessible from my Filebrowser addon called /addon_configs/db21ed7f_free_games_claimer. This avoids the addon to mess with your homeassistant configuration folder, and allows to backup the options. For more information, see here : https://developers.home-assistant.io/blog/2023/11/06/public-addon-config/
- Major change: switch to the new Home Assistant add-on configuration logic.
Configuration files were migrated from
`/config/hassio_addons/free_games_claimer` to the private add-on configuration
directory available through compatible file browser add-ons.
## 1.6-3 (2024-12-05)
- Minor bugs fixed
## 1.6-2 (2024-12-05)
- Minor bugs fixed
## 1.6 (2023-12-30)
@@ -28,18 +61,23 @@
## 1.4 (2023-05-27)
- Update to latest version from vogler/free-games-claimer
## 1.4-5 (2023-05-26)
- Minor bugs fixed
## 1.4-4 (2023-05-26)
- Minor bugs fixed
## 1.4-3 (2023-05-26)
- Minor bugs fixed
## 1.4-2 (2023-05-25)
- Minor bugs fixed
## NOT_WORKING (2023-05-22)
- Minor bugs fixed

View File

@@ -1,91 +1,14 @@
#============================#
# ALEXBELGIUM'S DOCKERFILE #
#============================#
# _.------.
# _.-` ('>.-`"""-.
# '.--'` _'` _ .--.)
# -' '-.-';` `
# ' - _.' ``'--.
# '---` .-'""`
# /`
#=== Home Assistant Addon ===#
#=== Home Assistant Add-on ===#
#################
# 1 Build Image #
#################
ARG BUILD_FROM
ARG BUILD_VERSION
ARG BUILD_FROM="debian:bookworm-slim"
FROM ${BUILD_FROM}
##################
# 2 Modify Image #
##################
# Set S6 wait time
ENV S6_CMD_WAIT_FOR_SERVICES=1 \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
S6_SERVICES_GRACETIME=0
##################
# 3 Install apps #
##################
# Add rootfs
COPY rootfs/ /
RUN find . -type f \( -name "*.sh" -o -name "run" -o -name "finish" \) -print -exec chmod +x {} \;
# Uses /bin for compatibility purposes
# hadolint ignore=DL4005
RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \
if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi
# Modules
ARG MODULES="00-banner.sh 01-custom_script.sh"
# Automatic modules download
COPY ha_automodules.sh /ha_automodules.sh
RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh
# Manual apps
ENV PACKAGES=""
# Automatic apps & bashio
COPY ha_autoapps.sh /ha_autoapps.sh
RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh
################
# 4 Entrypoint #
################
# Add entrypoint
ENV S6_STAGE2_HOOK=/ha_entrypoint.sh
COPY ha_entrypoint.sh /ha_entrypoint.sh
RUN chmod 777 /ha_entrypoint.sh
# Install bashio
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
RUN \
# Change data folder
sed -i "s|/fgc|/data|g" /usr/local/bin/docker-entrypoint.sh && \
# Run scripts only once
sed -i "1a if [ -f /done ]; then exit 0; fi && touch /done" /ha_entrypoint.sh && \
sed -i "s=x11vnc=[[ \"\$(ps aux | grep \"x11vnc\" | grep -v grep)\" ]] || x11vnc=g" /usr/local/bin/docker-entrypoint.sh && \
# Update playwright
npx playwright install-deps && \
npx playwright install
WORKDIR /data
ENTRYPOINT [ "/usr/bin/env" ]
CMD [ "/ha_entrypoint.sh" ]
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
############
# 5 Labels #
############
ARG DEBIAN_FRONTEND="noninteractive"
ARG BUILD_ARCH
ARG BUILD_DATE
ARG BUILD_DESCRIPTION
@@ -93,28 +16,143 @@ ARG BUILD_NAME
ARG BUILD_REF
ARG BUILD_REPOSITORY
ARG BUILD_VERSION
ENV BUILD_VERSION="${BUILD_VERSION}"
ARG UPSTREAM_REPOSITORY="P-Adamiec/Free-Games-Claimer-Remaster"
ARG UPSTREAM_REF="cca4992354215cef8807b748575af797606627f4"
ENV S6_CMD_WAIT_FOR_SERVICES="1" \
S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0" \
S6_SERVICES_GRACETIME="0" \
VNC_PORT="5900" \
NOVNC_PORT="6080" \
WIDTH="1280" \
HEIGHT="720" \
DEPTH="24" \
SHOW="1" \
COMMIT="${UPSTREAM_REF}" \
BRANCH="main" \
NOW="${BUILD_DATE}"
# Install the dependencies used by Free Games Claimer Remaster. The upstream
# Dockerfile supports both amd64 (Google Chrome) and arm64 (Chromium), so the
# add-on keeps its existing multi-architecture support.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
dos2unix \
gnupg \
gzip \
jq \
python3 \
python3-pip \
tar \
tini \
&& mkdir -p /etc/apt/keyrings \
&& curl --proto "=https" --tlsv1.2 -fsSL https://packagecloud.io/dcommander/virtualgl/gpgkey \
| gpg --dearmor -o /etc/apt/trusted.gpg.d/VirtualGL.gpg \
&& curl --proto "=https" --tlsv1.2 -fsSL https://packagecloud.io/dcommander/turbovnc/gpgkey \
| gpg --dearmor -o /etc/apt/trusted.gpg.d/TurboVNC.gpg \
&& curl --proto "=https" --tlsv1.2 -fsSL https://raw.githubusercontent.com/VirtualGL/repo/main/VirtualGL.list \
> /etc/apt/sources.list.d/VirtualGL.list \
&& curl --proto "=https" --tlsv1.2 -fsSL https://raw.githubusercontent.com/TurboVNC/repo/main/TurboVNC.list \
> /etc/apt/sources.list.d/TurboVNC.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
novnc \
ratpoison \
turbovnc \
virtualgl \
websockify \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libatspi2.0-0 \
libcairo2 \
libcups2 \
libgbm1 \
libnspr4 \
libnss3 \
libpango-1.0-0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxkbcommon0 \
&& if [ "$(dpkg --print-architecture)" = "amd64" ]; then \
curl -fsSL https://dl.google.com/linux/linux_signing_key.pub \
| gpg --dearmor -o /etc/apt/keyrings/google-chrome.gpg; \
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.gpg] https://dl.google.com/linux/chrome/deb/ stable main" \
> /etc/apt/sources.list.d/google-chrome.list; \
apt-get update; \
apt-get install -y --no-install-recommends google-chrome-stable; \
else \
apt-get install -y --no-install-recommends chromium; \
fi \
&& ln -sf /usr/share/novnc/vnc_auto.html /usr/share/novnc/index.html \
&& ln -sf /usr/bin/python3 /usr/bin/python \
&& apt-get purge -y gnupg \
&& apt-get autoremove -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /var/cache/* /var/tmp/* /tmp/* /usr/share/doc/*
# Install a deterministic snapshot of the replacement upstream. Updating the
# upstream reference is intentionally explicit so image contents cannot change
# without an add-on version bump.
WORKDIR /fgc
RUN curl --proto "=https" --tlsv1.2 -fsSL \
"https://github.com/${UPSTREAM_REPOSITORY}/archive/${UPSTREAM_REF}.tar.gz" \
-o /tmp/free-games-claimer-remaster.tar.gz \
&& tar -xzf /tmp/free-games-claimer-remaster.tar.gz --strip-components=1 -C /fgc \
&& python3 -m pip install --no-cache-dir --break-system-packages -r requirements.txt \
&& dos2unix ./*.sh \
&& chmod +x ./*.sh \
&& cp docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh \
&& chmod 0755 /usr/local/bin/docker-entrypoint.sh \
&& rm -f /tmp/free-games-claimer-remaster.tar.gz \
&& rm -rf /fgc/data \
&& ln -s /data /fgc/data
# Add Home Assistant integration files and shared helper modules.
COPY rootfs/ /
RUN find /etc/cont-init.d /usr/local/bin -type f -name "*.sh" -exec chmod 0755 {} + \
&& chmod 0755 /usr/local/bin/migrate_vogler_data.py
ARG MODULES="00-banner.sh 01-custom_script.sh"
COPY ha_automodules.sh /ha_automodules.sh
RUN chmod 0755 /ha_automodules.sh \
&& /ha_automodules.sh "${MODULES}" \
&& rm /ha_automodules.sh
ENV PACKAGES=""
COPY ha_autoapps.sh /ha_autoapps.sh
RUN chmod 0755 /ha_autoapps.sh \
&& /ha_autoapps.sh "${PACKAGES}" \
&& rm /ha_autoapps.sh
ENV S6_STAGE2_HOOK="/ha_entrypoint.sh"
COPY ha_entrypoint.sh /ha_entrypoint.sh
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
RUN chmod 0755 /ha_entrypoint.sh /usr/local/lib/bashio-standalone.sh
EXPOSE 5900 6080
ENTRYPOINT ["/usr/bin/env"]
CMD ["/ha_entrypoint.sh"]
LABEL \
io.hass.name="${BUILD_NAME}" \
io.hass.description="${BUILD_DESCRIPTION}" \
io.hass.arch="${BUILD_ARCH}" \
io.hass.type="addon" \
io.hass.version=${BUILD_VERSION} \
io.hass.version="${BUILD_VERSION}" \
maintainer="alexbelgium (https://github.com/alexbelgium)" \
org.opencontainers.image.title="${BUILD_NAME}" \
org.opencontainers.image.description="${BUILD_DESCRIPTION}" \
org.opencontainers.image.vendor="Home Assistant Add-ons" \
org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.url="https://github.com/alexbelgium" \
org.opencontainers.image.licenses="AGPL-3.0" \
org.opencontainers.image.url="https://github.com/${BUILD_REPOSITORY}" \
org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \
org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \
org.opencontainers.image.created=${BUILD_DATE} \
org.opencontainers.image.revision=${BUILD_REF} \
org.opencontainers.image.version=${BUILD_VERSION}
####################
# 6 HealthcheckNOT #
####################
# Can't be implemented as container is optimized for memory usage, so the webserver and Node are spun down during idle
org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/master/free_games_claimer/README.md" \
org.opencontainers.image.created="${BUILD_DATE}" \
org.opencontainers.image.revision="${BUILD_REF}" \
org.opencontainers.image.version="${BUILD_VERSION}" \
io.hass.upstream="https://github.com/${UPSTREAM_REPOSITORY}/tree/${UPSTREAM_REF}"

View File

@@ -1,128 +1,164 @@
## ⚠ VNC not working on several machines. Please use config.env to execute the script
# Home Assistant add-on: Free Games Claimer
# Home assistant add-on: Free Games Claimer
I maintain this and other Home Assistant add-ons in my free time: keeping up with upstream changes, HA changes, and testing on real hardware takes a lot of time (and some money). I use around 5-10 of my >110 addons so regularly I install test machines (and purchase some test services such as vpn) that I don't use myself to troubleshoot and improve the addons
If this add-on saves you time or makes your setup easier, I would be very grateful for your support!
I maintain this and other Home Assistant add-ons in my free time. Keeping up
with upstream changes, Home Assistant changes, and testing on real hardware
takes a significant amount of time.
[![Buy me a coffee][donation-badge]](https://www.buymeacoffee.com/alexbelgium)
[![Donate via PayPal][paypal-badge]](https://www.paypal.com/donate/?hosted_button_id=DZFULJZTP3UQA)
## Addon informations
## Add-on information
![Version](https://img.shields.io/badge/dynamic/yaml?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Ffree_games_claimer%2Fconfig.yaml)
![Ingress](https://img.shields.io/badge/dynamic/yaml?label=Ingress&query=%24.ingress&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Ffree_games_claimer%2Fconfig.yaml)
![Arch](https://img.shields.io/badge/dynamic/yaml?color=success&label=Arch&query=%24.arch&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Ffree_games_claimer%2Fconfig.yaml)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9c6cf10bdbba45ecb202d7f579b5be0e)](https://www.codacy.com/gh/alexbelgium/hassio-addons/dashboard?utm_source=github.com&utm_medium=referral&utm_content=alexbelgium/hassio-addons&utm_campaign=Badge_Grade)
[![GitHub Super-Linter](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/weekly-supelinter.yaml?label=Lint%20code%20base)](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly-supelinter.yaml)
[![Builder](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/onpush_builder.yaml?label=Builder)](https://github.com/alexbelgium/hassio-addons/actions/workflows/onpush_builder.yaml)
[donation-badge]: https://img.shields.io/badge/Buy%20me%20a%20coffee-%23d32f2f?logo=buy-me-a-coffee&style=flat&logoColor=white
[paypal-badge]: https://img.shields.io/badge/Donate%20via%20PayPal-0070BA?logo=paypal&style=flat&logoColor=white
_Thanks to everyone having starred my repo! To star it click on the image below, then it will be on top right. Thanks!_
[![Stargazers repo roster for @alexbelgium/hassio-addons](https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.github/stars2.svg)](https://github.com/alexbelgium/hassio-addons/stargazers)
![downloads evolution](https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/free_games_claimer/stats.png)
## About
[Free Games Claimer](https://github.com/vogler/free-games-claimer) : Claims free games periodically on
This add-on is based on
[Free Games Claimer Remaster](https://github.com/P-Adamiec/Free-Games-Claimer-Remaster).
It can claim free games from:
- Epic Games Store
- Amazon Prime Gaming
- GOG
- Live Games with Gold - planned
- Steam
- GamerPower-supported stores, when explicitly enabled
This addon is based on the docker image https://github.com/vogler/free-games-claimer
For compatibility with previous add-on releases, the default store selection
remains Epic Games, Prime Gaming, and GOG.
## Configuration
## Web interface
Webui can be found at <http://homeassistant:6080> (NoVNC interface - currently has issues on some machines).
The noVNC interface remains available on port `6080`:
### Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `CMD_ARGUMENTS` | str | `node epic-games ; node prime-gaming ; node gog` | Commands to run for claiming games |
| `CONFIG_LOCATION` | str | `/config/config.env` | Location of the configuration file |
### Example Configuration
```yaml
CMD_ARGUMENTS: "node epic-games ; node prime-gaming ; node gog"
CONFIG_LOCATION: "/config/config.env"
```text
http://homeassistant:6080
```
### Environment Configuration
It can be used for initial sign-in, CAPTCHA handling, or other manual browser
interaction. Set `VNC_PASSWORD` in `config.env` to protect the VNC session.
All main configuration is done via the `config.env` file located at `/config/addons_config/free_games_claimer/config.env`.
## Add-on options
If this file doesn't exist, it will be created at first boot with default settings.
| Option | Default | Description |
|--------|---------|-------------|
| `CONFIG_LOCATION` | `/config/config.env` | Persistent environment configuration file |
| `RUN_ONCE` | `true` | Run all selected claimers once, then stop the add-on as previous releases did |
| `STORES` | empty | Optional comma-separated override, such as `epic,prime,gog,steam` |
| `CMD_ARGUMENTS` | `node epic-games ; node prime-gaming ; node gog` | Deprecated compatibility option; recognized legacy command names are converted to `STORES` |
| `env_vars` | `[]` | Additional environment variables passed to the add-on |
### Required Environment Variables
### Run modes
Add these to your `config.env` file:
With `RUN_ONCE: true`, the add-on performs one claiming pass and stops. This is
the default and preserves the behavior of the former vogler-based add-on.
With `RUN_ONCE: false`, the remaster remains running and uses its internal
scheduler. Set `SCHEDULER_HOURS` in `config.env` to control the interval.
## Environment configuration
The add-on keeps its configuration in `CONFIG_LOCATION`, which defaults to
`/config/config.env`. From Home Assistant this is stored in the add-on's
private `addon_configs` directory and can be edited with a compatible file
browser add-on.
A template is created on first start. Common examples are:
```env
# Epic Games Store
# Preserve the former default selection
STORES=epic,prime,gog
# Epic Games
EG_EMAIL=your-email@example.com
EG_PASSWORD=your-password
EG_OTPKEY=
# Amazon Prime Gaming
PG_EMAIL=your-amazon-email@example.com
PG_PASSWORD=your-amazon-password
PG_PASSWORD=your-password
PG_OTPKEY=
# GOG (optional)
# GOG
GOG_EMAIL=your-gog-email@example.com
GOG_PASSWORD=your-gog-password
GOG_PASSWORD=your-password
# Notifications (optional)
EMAIL_SMTP_HOST=smtp.gmail.com
EMAIL_SMTP_PORT=587
EMAIL_USER=notifications@example.com
EMAIL_PASS=your-app-password
EMAIL_TO=recipient@example.com
# Optional Steam support
STEAM_USERNAME=your-steam-username
STEAM_PASSWORD=your-password
# Optional notifications
NOTIFY=tgram://bot-token/chat-id
# DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
```
### Additional Options
Existing variables such as `EG_EMAIL`, `EG_PASSWORD`, `PG_EMAIL`,
`PG_PASSWORD`, `PG_OTPKEY`, `GOG_EMAIL`, `GOG_PASSWORD`, `SHOW`, `WIDTH`,
`HEIGHT`, `TIMEOUT`, `LOGIN_TIMEOUT`, `DRYRUN`, and `NOTIFY` remain compatible.
See the
[upstream configuration reference](https://github.com/P-Adamiec/Free-Games-Claimer-Remaster#configuration)
for all available settings.
For complete configuration options and advanced settings, see: https://github.com/vogler/free-games-claimer#configuration--options
## Upgrade from version 1.8
### Important Notes
Version 2.0 changes the application engine from
`vogler/free-games-claimer` (Node.js, Playwright, and Firefox) to
`P-Adamiec/Free-Games-Claimer-Remaster` (Python, nodriver, and Chromium).
The add-on performs the following migration automatically on first start:
- **VNC Issues**: The NoVNC web interface is currently not working reliably on several machines
- **Recommended**: Use the `config.env` file for configuration instead of the web interface
- **Security**: Store credentials securely and consider using app-specific passwords where available
1. The existing `config.env` remains at the same configured location.
2. Legacy `epic-games.json`, `prime-gaming.json`, and `gog.json` claim history
is imported into the remaster SQLite database at `/data/fgc.db`.
3. Existing database rows are detected and are not duplicated if migration is
retried.
4. A pre-migration database backup is created when an existing `fgc.db` is
present.
5. All old files remain under `/data/data` for rollback or manual recovery.
### Custom Scripts and Environment Variables
Browser sessions cannot be converted because the old add-on used a shared
Firefox profile while the remaster uses separate Chromium profiles per store.
Credentials remain available through `config.env`, but accounts that require
interactive authentication may need a one-time login through noVNC after the
upgrade. The old Firefox profile is retained and is never deleted.
This addon supports custom scripts and environment variables through the `addon_config` mapping:
The external noVNC port remains `6080`, although the standalone remaster image
normally uses port `7080`.
- **Custom scripts**: See [Running Custom Scripts in Addons](https://github.com/alexbelgium/hassio-addons/wiki/Running-custom-scripts-in-Addons)
- **env_vars option**: Use the add-on `env_vars` option to pass extra environment variables (uppercase or lowercase names). See https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2 for details.
## Upstream update policy
The image is built from an explicit upstream commit in the Dockerfile. This
keeps amd64 and aarch64 images reproducible and prevents an upstream branch or
container tag from changing without an add-on review and version bump.
The repository updater is intentionally paused for this add-on because the
add-on uses its own `2.x` version series while the replacement upstream uses a
`1.x` version series. An automatic replacement would risk a Home Assistant
version regression and would not safely update the pinned commit. A maintainer
upstream update must therefore update `UPSTREAM_REF`, `upstream_version`, the
add-on version, and `CHANGELOG.md` together.
## Installation
The installation of this add-on is pretty straightforward and not different in comparison to installing any other add-on.
1. Add this add-on repository to the Home Assistant add-on store.
2. Install **Free Games Claimer**.
3. Configure the add-on options as needed.
4. Start the add-on and review its log.
5. Open noVNC if an account needs manual authentication.
1. Add my add-ons repository to your home assistant instance (in supervisor addons store at top right, or click button below if you have configured my HA)
[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons)
1. Install this add-on.
1. Click the `Save` button to store your configuration.
1. Set the add-on options to your preferences
1. Start the add-on.
1. Check the logs of the add-on to see if everything went well.
1. Open the webUI and adapt the software options
[![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons)
## Custom scripts and environment variables
- [Running custom scripts in add-ons](https://github.com/alexbelgium/hassio-addons/wiki/Running-custom-scripts-in-Addons)
- [Passing environment variables to an add-on](https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2)
## Support
Create an issue on github
[repository]: https://github.com/alexbelgium/hassio-addons
Open an issue in the
[add-on repository](https://github.com/alexbelgium/hassio-addons/issues).

View File

@@ -1,6 +1,6 @@
{
"build_from": {
"aarch64": "ghcr.io/vogler/free-games-claimer:latest",
"amd64": "ghcr.io/vogler/free-games-claimer:latest"
"aarch64": "debian:bookworm-slim",
"amd64": "debian:bookworm-slim"
}
}

View File

@@ -1,9 +1,10 @@
# Free Games Claimer Remaster add-on (pinned source)
arch:
- aarch64
- amd64
description:
automatically claims free games on the Epic Games Store, Amazon Prime
Gaming and GOG
description: >-
Automatically claims free games from Epic Games Store, Amazon Prime Gaming,
GOG, Steam, and optional GamerPower-supported stores.
devices:
- /dev/dri
- /dev/dri/card0
@@ -73,25 +74,29 @@ init: false
map:
- addon_config:rw
- homeassistant_config:rw
name: Free Games Claimer (NoVNC not working)
name: Free Games Claimer
options:
env_vars: []
CMD_ARGUMENTS: node epic-games ; node prime-gaming ; node gog
STORES: ""
RUN_ONCE: true
CONFIG_LOCATION: /config/config.env
ports:
5900/tcp: null
6080/tcp: 6080
ports_description:
5900/tcp: VNC port
6080/tcp: NOVNC port
6080/tcp: noVNC web interface
schema:
env_vars:
- name: match(^[A-Za-z0-9_]+$)
value: str?
CMD_ARGUMENTS: str
CMD_ARGUMENTS: str?
STORES: str?
RUN_ONCE: bool
CONFIG_LOCATION: str
slug: free_games_claimer
udev: true
url: https://github.com/alexbelgium/hassio-addons
version: "1.8"
version: "2.0.0"
webui: "[PROTO:ssl]://[HOST]:[PORT:6080]"

View File

@@ -1,85 +1,152 @@
#!/usr/bin/env bashio
# shellcheck shell=bash
set -e
set -eo pipefail
##############
# Initialize #
##############
CONFIG_FILE="/config/config.env"
if bashio::config.has_value 'CONFIG_LOCATION'; then
CONFIG_FILE="$(bashio::config 'CONFIG_LOCATION')"
fi
CONFIG_DIR="$(dirname "${CONFIG_FILE}")"
RUNTIME_CONFIG="/data/config.env"
CONFIG_HOME="$(bashio::config "CONFIG_LOCATION")"
CONFIG_HOME="$(dirname "$CONFIG_HOME")"
mkdir -p "${CONFIG_DIR}" /data
# Use new config file
if [ ! -f "$CONFIG_HOME/config.env" ]; then
# Copy default config.env
cp /templates/config.env "$CONFIG_HOME/"
chmod 755 "$CONFIG_HOME/config.env"
bashio::log.warning "A default config.env file was copied to $CONFIG_HOME. Please customize according to https://github.com/vogler/free-games-claimer/tree/main#configuration--options and restart the add-on"
# Recover from an old add-on bug that could create config.env as a directory.
if [ -d "${CONFIG_FILE}" ]; then
bashio::log.warning "Found a directory at ${CONFIG_FILE}; replacing it with a configuration file"
rm -rf "${CONFIG_FILE}"
fi
if [ ! -f "${CONFIG_FILE}" ]; then
install -m 0600 /templates/config.env "${CONFIG_FILE}"
bashio::log.warning \
"Created ${CONFIG_FILE}. Add account credentials there and restart the add-on if automatic login is required."
else
bashio::log.info "Using existing config.env file in $CONFIG_HOME. Please customize according to https://github.com/vogler/free-games-claimer/tree/main#configuration--options and restart the add-on"
bashio::log.info "Using configuration from ${CONFIG_FILE}"
fi
# Remove erroneous folder named config.env (bug fix for looping issue)
if [ -d "$CONFIG_HOME/config.env" ]; then
bashio::log.warning "Found directory named config.env, deleting it..."
rm -rf "$CONFIG_HOME/config.env" # Fix: Ensures directory removal even if it exists
cp /templates/config.env "$CONFIG_HOME/config.env" # Recreate as a valid file
chmod 755 "$CONFIG_HOME/config.env"
fi
# The remaster reads /fgc/data/config.env. /fgc/data is linked to Home
# Assistant's persistent /data volume by the Dockerfile.
install -m 0600 "${CONFIG_FILE}" "${RUNTIME_CONFIG}"
sed -i 's/\r$//' "${RUNTIME_CONFIG}"
# Copy new file
mkdir -p /data/data
cp "$CONFIG_HOME/config.env" /data/data/
# Permissions
chmod -R 755 "$CONFIG_HOME"
# Export variables
# Export values needed by the VNC entrypoint as well as by the Python app.
set -a
echo ""
bashio::log.info "Sourcing variables from $CONFIG_HOME/config.env"
cp "$CONFIG_HOME"/config.env /config.env
# Remove previous instance
sed -i "s|export ||g" /config.env
# Add export for non empty lines
sed -i '/\S/s/^/export /' /config.env
# Delete lines starting with #
sed -i '/export #/d' /config.env
# Get variables
# shellcheck source=/dev/null
source /config.env
rm /config.env
source "${RUNTIME_CONFIG}"
set +a
##############
# Launch App #
##############
# The Home Assistant port mapping is intentionally kept at 6080 for a seamless
# upgrade from the previous add-on, even though the new upstream defaults to 7080.
if [ -n "${NOVNC_PORT:-}" ] && [ "${NOVNC_PORT}" != "6080" ]; then
bashio::log.warning "NOVNC_PORT=${NOVNC_PORT} is not supported by the add-on port mapping; using 6080"
fi
export NOVNC_PORT="6080"
export VNC_PORT="5900"
# Go to folder
cd /data || true
# Absolute paths from the former image pointed to its Firefox profile. The
# replacement uses Chromium profiles and must start with a separate directory.
if [ "${BROWSER_DIR:-}" = "/data/data/browser" ]; then
bashio::log.warning "Remapping legacy Firefox BROWSER_DIR to the remaster Chromium profile directory"
export BROWSER_DIR="data/browser"
fi
if [ "${SCREENSHOTS_DIR:-}" = "/data/data/screenshots" ]; then
export SCREENSHOTS_DIR="/fgc/data/screenshots"
fi
# Fetch commands
CMD_ARGUMENTS="$(bashio::config "CMD_ARGUMENTS")"
IFS=';'
read -ar strarr <<< "$CMD_ARGUMENTS"
append_store() {
local store="${1}"
local current="${2}"
# Sanitizes commands
trim() {
local var="$*"
var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}"
printf '%s' "$var"
if [[ ",${current}," == *",${store},"* ]]; then
printf '%s' "${current}"
elif [ -n "${current}" ]; then
printf '%s,%s' "${current}" "${store}"
else
printf '%s' "${store}"
fi
}
# Add docker-entrypoint command
for val in "${strarr[@]}"; do
val="$(trim "$val")"
echo " "
bashio::log.info "Starting the app with arguments \"$val\""
echo " "
echo "$val" | xargs docker-entrypoint.sh || true
done
legacy_commands_to_stores() {
local commands="${1}"
local selected=""
local command=""
local normalized=""
local command_list=()
bashio::log.info "All actions concluded. Stopping in 10 seconds."
sleep 10
bashio::addon.stop
IFS=';' read -ra command_list <<< "${commands}"
for command in "${command_list[@]}"; do
normalized="${command,,}"
case "${normalized}" in
*epic-games*|*epicgames*|*" epic"*|epic*)
selected="$(append_store "epic" "${selected}")"
;;
*prime-gaming*|*primegaming*|*" prime"*|prime*|*" amazon"*|amazon*)
selected="$(append_store "prime" "${selected}")"
;;
*steam-games*|*" steam"*|steam*)
selected="$(append_store "steam" "${selected}")"
;;
*gamerpower*)
selected="$(append_store "gamerpower" "${selected}")"
;;
*" gog"*|gog*)
selected="$(append_store "gog" "${selected}")"
;;
esac
done
printf '%s' "${selected}"
}
# A non-empty STORES add-on option takes priority. Otherwise retain a STORES
# value from config.env, then fall back to translating the legacy commands.
STORES_OPTION=""
if bashio::config.has_value 'STORES'; then
STORES_OPTION="$(bashio::config 'STORES')"
fi
if [ -n "${STORES_OPTION}" ]; then
export STORES="${STORES_OPTION}"
elif [ -z "${STORES:-}" ]; then
CMD_ARGUMENTS=""
if bashio::config.has_value 'CMD_ARGUMENTS'; then
CMD_ARGUMENTS="$(bashio::config 'CMD_ARGUMENTS')"
fi
STORES="$(legacy_commands_to_stores "${CMD_ARGUMENTS}")"
export STORES="${STORES:-epic,prime,gog}"
fi
bashio::log.info "Enabled stores: ${STORES:-epic,prime,gog}"
# Import claim history from vogler/free-games-claimer once. Legacy files and
# browser data are retained under /data/data for rollback and manual recovery.
/usr/local/bin/migrate_vogler_data.py
APP_COMMAND=(python3 /fgc/main.py)
RUN_ONCE="true"
if bashio::config.has_value 'RUN_ONCE' && ! bashio::config.true 'RUN_ONCE'; then
RUN_ONCE="false"
fi
if [ "${RUN_ONCE}" = "true" ]; then
APP_COMMAND+=(--once)
bashio::log.info "Starting a single claiming run (legacy-compatible mode)"
set +e
/usr/local/bin/docker-entrypoint.sh "${APP_COMMAND[@]}"
exit_code=$?
set -e
if [ "${exit_code}" -ne 0 ]; then
bashio::log.error "Free Games Claimer exited with status ${exit_code}"
else
bashio::log.info "Claiming run completed"
fi
bashio::log.info "Stopping the add-on"
sleep 2
bashio::addon.stop
exit "${exit_code}"
fi
bashio::log.info "Starting the built-in scheduler"
exec /usr/local/bin/docker-entrypoint.sh "${APP_COMMAND[@]}"

View File

@@ -1,7 +1,39 @@
HEIGHT=1280
LOGIN_TIMEOUT=180
NOTIFY_TITLE='Free Games Claimer'
# List of environment variables, see : https://github.com/vogler/free-games-claimer#configuration--options
# Free Games Claimer Remaster configuration
# Complete option reference:
# https://github.com/P-Adamiec/Free-Games-Claimer-Remaster#configuration
# Browser and noVNC
SHOW=1
TIMEOUT=60
WIDTH=1280
HEIGHT=720
TIMEOUT=60
LOGIN_TIMEOUT=180
VNC_LOGIN_TIMEOUT=180
NOVNC_PORT=6080
# Keep the previous add-on's default stores. Add steam or gamerpower if wanted.
STORES=epic,prime,gog
# Used only when RUN_ONCE is disabled in the add-on options.
SCHEDULER_HOURS=12
# Common credentials can be used as fallbacks for all stores.
# EMAIL=
# PASSWORD=
# Store-specific credentials take priority over EMAIL/PASSWORD.
# EG_EMAIL=
# EG_PASSWORD=
# EG_OTPKEY=
# EG_PARENTALPIN=
# PG_EMAIL=
# PG_PASSWORD=
# PG_OTPKEY=
# GOG_EMAIL=
# GOG_PASSWORD=
# STEAM_USERNAME=
# STEAM_PASSWORD=
# Notifications (Apprise or Discord)
# NOTIFY=
# DISCORD_WEBHOOK=

View File

@@ -0,0 +1,248 @@
#!/usr/bin/env python3
"""Migrate legacy vogler/free-games-claimer JSON history to the remaster DB."""
from __future__ import annotations
import json
import os
import shutil
import sqlite3
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Iterator
DATA_DIR = Path(os.environ.get("FGC_DATA_DIR", "/data"))
LEGACY_DIR = DATA_DIR / "data"
DATABASE = DATA_DIR / "fgc.db"
MARKER = DATA_DIR / ".vogler-remaster-migrated-v1.json"
BACKUP = DATA_DIR / "fgc.db.pre-vogler-migration"
SOURCES = {
"epic": "epic-games.json",
"prime": "prime-gaming.json",
"gog": "gog.json",
}
def log(message: str) -> None:
print(f"[legacy migration] {message}", flush=True)
def locate_source(filename: str) -> Path | None:
"""Prefer the old nested data directory, with a root fallback."""
for candidate in (LEGACY_DIR / filename, DATA_DIR / filename):
if candidate.is_file():
return candidate
return None
def normalize_timestamp(value: Any) -> str:
if isinstance(value, str) and value.strip():
raw = value.strip().replace("Z", "+00:00")
try:
parsed = datetime.fromisoformat(raw)
if parsed.tzinfo is not None:
parsed = parsed.astimezone(timezone.utc).replace(tzinfo=None)
return parsed.isoformat(sep=" ", timespec="seconds")
except ValueError:
pass
return datetime.now(timezone.utc).replace(tzinfo=None).isoformat(
sep=" ", timespec="seconds"
)
def clean(value: Any, *, default: str = "", limit: int | None = None) -> str:
result = default if value is None else str(value)
if limit is not None:
result = result[:limit]
return result
def iter_records(store: str, payload: Any, source: Path) -> Iterator[dict[str, Any]]:
if not isinstance(payload, dict):
raise ValueError(f"{source} does not contain a JSON object")
for user, games in payload.items():
if not isinstance(games, dict):
continue
for legacy_id, value in games.items():
record = value if isinstance(value, dict) else {}
title = clean(record.get("title"), default=clean(legacy_id), limit=512)
game_id = clean(legacy_id, default=title, limit=256)
if not game_id:
game_id = title[:256] or "unknown"
legacy_store = record.get("store")
extra = {
"migration_source": str(source),
"legacy_store": legacy_store,
"legacy_time": record.get("time") or record.get("timestamp"),
}
extra = {key: val for key, val in extra.items() if val not in (None, "")}
yield {
"store": store,
"user": clean(user, default="unknown", limit=128) or "unknown",
"game_id": game_id,
"title": title or game_id,
"url": clean(record.get("url"), limit=None) or None,
"status": clean(record.get("status"), default="unknown", limit=64)
or "unknown",
"code": clean(record.get("code"), limit=128) or None,
"extra": json.dumps(extra, ensure_ascii=False) if extra else None,
"created_at": normalize_timestamp(
record.get("time") or record.get("timestamp")
),
}
def ensure_schema(connection: sqlite3.Connection) -> None:
connection.executescript(
"""
CREATE TABLE IF NOT EXISTS claimed_games (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
store VARCHAR(32) NOT NULL,
user VARCHAR(128) NOT NULL,
game_id VARCHAR(256) NOT NULL,
title VARCHAR(512) NOT NULL,
url TEXT,
status VARCHAR(64) NOT NULL DEFAULT 'unknown',
code VARCHAR(128),
extra TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS ix_claimed_games_store ON claimed_games (store);
CREATE INDEX IF NOT EXISTS ix_claimed_games_user ON claimed_games (user);
CREATE INDEX IF NOT EXISTS ix_claimed_games_game_id ON claimed_games (game_id);
"""
)
def migrate() -> int:
DATA_DIR.mkdir(parents=True, exist_ok=True)
if MARKER.exists():
log("Legacy claim history was already migrated")
return 0
sources = {
store: source
for store, filename in SOURCES.items()
if (source := locate_source(filename)) is not None
}
legacy_browser = LEGACY_DIR / "browser"
if not sources:
if legacy_browser.exists():
log(
"Legacy Firefox browser data was found but cannot be converted to "
"the remaster Chromium profile; a one-time login may be required"
)
MARKER.write_text(
json.dumps(
{
"migrated_at": datetime.now(timezone.utc).isoformat(),
"imported": 0,
"sources": [],
},
indent=2,
),
encoding="utf-8",
)
log("No legacy claim-history files were found")
return 0
if DATABASE.exists() and not BACKUP.exists():
shutil.copy2(DATABASE, BACKUP)
log(f"Backed up the existing database to {BACKUP}")
imported = 0
skipped = 0
errors: list[str] = []
try:
with sqlite3.connect(DATABASE) as connection:
ensure_schema(connection)
for store, source in sources.items():
try:
payload = json.loads(source.read_text(encoding="utf-8"))
source_imported = 0
for record in iter_records(store, payload, source):
exists = connection.execute(
"""
SELECT 1 FROM claimed_games
WHERE store = ? AND user = ? AND game_id = ?
LIMIT 1
""",
(record["store"], record["user"], record["game_id"]),
).fetchone()
if exists:
skipped += 1
continue
connection.execute(
"""
INSERT INTO claimed_games (
store, user, game_id, title, url, status, code,
extra, created_at, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
record["store"],
record["user"],
record["game_id"],
record["title"],
record["url"],
record["status"],
record["code"],
record["extra"],
record["created_at"],
record["created_at"],
),
)
imported += 1
source_imported += 1
connection.commit()
log(f"Imported {source_imported} record(s) from {source}")
except (OSError, ValueError, json.JSONDecodeError, sqlite3.Error) as err:
connection.rollback()
message = f"Failed to import {source}: {err}"
errors.append(message)
log(message)
except sqlite3.Error as err:
log(f"Database migration failed: {err}")
return 1
if legacy_browser.exists():
log(
"Legacy Firefox browser data remains in /data/data/browser. It is "
"not compatible with Chromium, so use noVNC for a one-time login if needed."
)
if errors:
log("Migration was incomplete and will be retried on the next start")
return 0
MARKER.write_text(
json.dumps(
{
"migrated_at": datetime.now(timezone.utc).isoformat(),
"imported": imported,
"skipped_existing": skipped,
"sources": [str(path) for path in sources.values()],
},
indent=2,
),
encoding="utf-8",
)
log(f"Migration complete: {imported} imported, {skipped} already present")
return 0
if __name__ == "__main__":
sys.exit(migrate())

View File

@@ -1,10 +1,11 @@
{
"dockerhub_by_date": true,
"dockerhub_by_date": false,
"dockerhub_list_size": 2,
"last_update": "17-05-2025",
"last_update": "17-07-2026",
"paused": true,
"repository": "alexbelgium/hassio-addons",
"slug": "free_games_claimer",
"source": "github",
"upstream_repo": "vogler/free-games-claimer",
"upstream_version": "1.8"
"upstream_repo": "P-Adamiec/Free-Games-Claimer-Remaster",
"upstream_version": "1.1"
}