From 476f02924d5a14df82f7c0204b9488ebcd284341 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:00:51 +0200 Subject: [PATCH 01/20] Switch Free Games Claimer upstream --- free_games_claimer/build.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/free_games_claimer/build.json b/free_games_claimer/build.json index 0c0dfd3e63..9ab49f15ee 100644 --- a/free_games_claimer/build.json +++ b/free_games_claimer/build.json @@ -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" } } From 4c068c6792df83d8b681e69edc2124c165088e5d Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:01:09 +0200 Subject: [PATCH 02/20] Configure remaster runtime --- free_games_claimer/config.yaml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/free_games_claimer/config.yaml b/free_games_claimer/config.yaml index 438d051921..6b353a9554 100644 --- a/free_games_claimer/config.yaml +++ b/free_games_claimer/config.yaml @@ -1,9 +1,9 @@ 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 +73,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]" From 8eb51526a1996356218a65d79e6a8a91f246dafc Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:01:50 +0200 Subject: [PATCH 03/20] Build Free Games Claimer Remaster --- free_games_claimer/Dockerfile | 223 ++++++++++++++++++++-------------- 1 file changed, 129 insertions(+), 94 deletions(-) diff --git a/free_games_claimer/Dockerfile b/free_games_claimer/Dockerfile index 45869b4e87..85da3927f3 100644 --- a/free_games_claimer/Dockerfile +++ b/free_games_claimer/Dockerfile @@ -1,91 +1,13 @@ #============================# # 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 BUILD_ARCH ARG BUILD_DATE ARG BUILD_DESCRIPTION @@ -93,28 +15,141 @@ 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 DEBIAN_FRONTEND="noninteractive" \ + 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" + +# 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}" From cc8b4029424d2046b69f3a7c76454eb0c425d96a Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:02:23 +0200 Subject: [PATCH 04/20] Adapt launcher for remaster --- .../rootfs/etc/cont-init.d/99-run.sh | 186 +++++++++++------- 1 file changed, 120 insertions(+), 66 deletions(-) diff --git a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh index e7dc2759c1..d5505d417f 100755 --- a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh +++ b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh @@ -1,85 +1,139 @@ #!/usr/bin/env bashio # shellcheck shell=bash -set -e +set -euo pipefail -############## -# Initialize # -############## +CONFIG_FILE="$(bashio::config 'CONFIG_LOCATION')" +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="/fgc/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 "*) + selected="$(append_store "epic" "${selected}")" + ;; + *prime-gaming*|*primegaming*|*" prime "*|*" amazon "*) + selected="$(append_store "prime" "${selected}")" + ;; + *steam-games*|*" 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="$(bashio::config 'STORES')" +if [ -n "${STORES_OPTION}" ]; then + export STORES="${STORES_OPTION}" +elif [ -z "${STORES:-}" ]; then + CMD_ARGUMENTS="$(bashio::config 'CMD_ARGUMENTS')" + 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) +if bashio::config.true 'RUN_ONCE'; 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[@]}" From 324dc560c2837ff106169683eda005c6ef493214 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:03:00 +0200 Subject: [PATCH 05/20] Migrate legacy claim history --- .../usr/local/bin/migrate_vogler_data.py | 248 ++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py diff --git a/free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py b/free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py new file mode 100644 index 0000000000..1c11bf6e3b --- /dev/null +++ b/free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py @@ -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()) From 408f9ee05b0211f95a5148a6c007072b0e962072 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:03:12 +0200 Subject: [PATCH 06/20] Update remaster configuration template --- .../rootfs/templates/config.env | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/free_games_claimer/rootfs/templates/config.env b/free_games_claimer/rootfs/templates/config.env index 2f89573aeb..eef9136db2 100644 --- a/free_games_claimer/rootfs/templates/config.env +++ b/free_games_claimer/rootfs/templates/config.env @@ -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= From a240dd8d00e30bc47ec9491ca3b7c7273660e304 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:03:20 +0200 Subject: [PATCH 07/20] Track remaster upstream --- free_games_claimer/updater.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/free_games_claimer/updater.json b/free_games_claimer/updater.json index f0df127f39..4ace3cb402 100644 --- a/free_games_claimer/updater.json +++ b/free_games_claimer/updater.json @@ -1,10 +1,10 @@ { - "dockerhub_by_date": true, + "dockerhub_by_date": false, "dockerhub_list_size": 2, - "last_update": "17-05-2025", + "last_update": "17-07-2026", "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" } From 0019b52f4a8511a40b467c04ac3f946994ef8a36 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:03:54 +0200 Subject: [PATCH 08/20] Document remaster migration --- free_games_claimer/README.md | 169 ++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 73 deletions(-) diff --git a/free_games_claimer/README.md b/free_games_claimer/README.md index db1bfdcb73..5773c3283b 100644 --- a/free_games_claimer/README.md +++ b/free_games_claimer/README.md @@ -1,128 +1,151 @@ -## ⚠ 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 (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: - -- **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. +The external noVNC port remains `6080`, although the standalone remaster image +normally uses port `7080`. ## 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). From e32a134ee207f85fbcb0b23af326ee0005e7eaba Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:04:11 +0200 Subject: [PATCH 09/20] Update Free Games Claimer changelog --- free_games_claimer/CHANGELOG.md | 44 ++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/free_games_claimer/CHANGELOG.md b/free_games_claimer/CHANGELOG.md index 9c68a0ac5d..74d984ba3a 100644 --- a/free_games_claimer/CHANGELOG.md +++ b/free_games_claimer/CHANGELOG.md @@ -1,20 +1,51 @@ -- 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. +- 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 +59,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 From a55c410b9c2f12c5a71734a3b207382d86a1145a Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:06:57 +0200 Subject: [PATCH 10/20] Relax legacy config parsing --- free_games_claimer/rootfs/etc/cont-init.d/99-run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh index d5505d417f..982e822961 100755 --- a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh +++ b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bashio # shellcheck shell=bash -set -euo pipefail +set -eo pipefail CONFIG_FILE="$(bashio::config 'CONFIG_LOCATION')" CONFIG_DIR="$(dirname "${CONFIG_FILE}")" From 49fbbbf59c3d0f7302b4be1a2f2a2793dc2cc0af Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:08:09 +0200 Subject: [PATCH 11/20] Improve legacy store mapping --- free_games_claimer/rootfs/etc/cont-init.d/99-run.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh index 982e822961..72a5cf13f6 100755 --- a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh +++ b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh @@ -75,13 +75,13 @@ legacy_commands_to_stores() { for command in "${command_list[@]}"; do normalized="${command,,}" case "${normalized}" in - *epic-games*|*epicgames*|*" epic "*) + *epic-games*|*epicgames*|*" epic"*|epic*) selected="$(append_store "epic" "${selected}")" ;; - *prime-gaming*|*primegaming*|*" prime "*|*" amazon "*) + *prime-gaming*|*primegaming*|*" prime"*|prime*|*" amazon"*|amazon*) selected="$(append_store "prime" "${selected}")" ;; - *steam-games*|*" steam "*) + *steam-games*|*" steam"*|steam*) selected="$(append_store "steam" "${selected}")" ;; *gamerpower*) From 766abd5ec3d93c4629b8e64766f7522d7ef66832 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:09:59 +0200 Subject: [PATCH 12/20] Trigger add-on validation --- free_games_claimer/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/free_games_claimer/config.yaml b/free_games_claimer/config.yaml index 6b353a9554..04ba1a1288 100644 --- a/free_games_claimer/config.yaml +++ b/free_games_claimer/config.yaml @@ -1,3 +1,4 @@ +# Free Games Claimer Remaster arch: - aarch64 - amd64 From 923215692452544b31c28ec8035e99d975356db1 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:11:01 +0200 Subject: [PATCH 13/20] Fix remaster browser profile path --- free_games_claimer/rootfs/etc/cont-init.d/99-run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh index 72a5cf13f6..507426abd7 100755 --- a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh +++ b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh @@ -45,7 +45,7 @@ export VNC_PORT="5900" # 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="/fgc/data/browser" + export BROWSER_DIR="data/browser" fi if [ "${SCREENSHOTS_DIR:-}" = "/data/data/screenshots" ]; then export SCREENSHOTS_DIR="/fgc/data/screenshots" From 1f177e26f42679c784a4c18d7807c5039dc7a399 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:13:13 +0200 Subject: [PATCH 14/20] Preserve defaults for existing installs --- .../rootfs/etc/cont-init.d/99-run.sh | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh index 507426abd7..e1cf0aa3dc 100755 --- a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh +++ b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh @@ -2,7 +2,10 @@ # shellcheck shell=bash set -eo pipefail -CONFIG_FILE="$(bashio::config 'CONFIG_LOCATION')" +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" @@ -98,11 +101,17 @@ legacy_commands_to_stores() { # 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="$(bashio::config 'STORES')" +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="$(bashio::config 'CMD_ARGUMENTS')" + 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 @@ -114,7 +123,11 @@ bashio::log.info "Enabled stores: ${STORES:-epic,prime,gog}" /usr/local/bin/migrate_vogler_data.py APP_COMMAND=(python3 /fgc/main.py) -if bashio::config.true 'RUN_ONCE'; then +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)" From 101c252b716635f769512955446e36b60bf8962e Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:18:58 +0200 Subject: [PATCH 15/20] Harden remaster build metadata --- free_games_claimer/Dockerfile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/free_games_claimer/Dockerfile b/free_games_claimer/Dockerfile index 85da3927f3..f35c71a8d7 100644 --- a/free_games_claimer/Dockerfile +++ b/free_games_claimer/Dockerfile @@ -8,6 +8,7 @@ FROM ${BUILD_FROM} SHELL ["/bin/bash", "-o", "pipefail", "-c"] +ARG DEBIAN_FRONTEND="noninteractive" ARG BUILD_ARCH ARG BUILD_DATE ARG BUILD_DESCRIPTION @@ -18,8 +19,7 @@ ARG BUILD_VERSION ARG UPSTREAM_REPOSITORY="P-Adamiec/Free-Games-Claimer-Remaster" ARG UPSTREAM_REF="cca4992354215cef8807b748575af797606627f4" -ENV DEBIAN_FRONTEND="noninteractive" \ - S6_CMD_WAIT_FOR_SERVICES="1" \ +ENV S6_CMD_WAIT_FOR_SERVICES="1" \ S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0" \ S6_SERVICES_GRACETIME="0" \ VNC_PORT="5900" \ @@ -27,7 +27,10 @@ ENV DEBIAN_FRONTEND="noninteractive" \ WIDTH="1280" \ HEIGHT="720" \ DEPTH="24" \ - SHOW="1" + 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 From fa83755108ee55d118495e9d1c975e6cc82d6f98 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:19:12 +0200 Subject: [PATCH 16/20] Pause unsafe automatic upstream bumps --- free_games_claimer/updater.json | 1 + 1 file changed, 1 insertion(+) diff --git a/free_games_claimer/updater.json b/free_games_claimer/updater.json index 4ace3cb402..fe2dd30949 100644 --- a/free_games_claimer/updater.json +++ b/free_games_claimer/updater.json @@ -2,6 +2,7 @@ "dockerhub_by_date": false, "dockerhub_list_size": 2, "last_update": "17-07-2026", + "paused": true, "repository": "alexbelgium/hassio-addons", "slug": "free_games_claimer", "source": "github", From feaf4f5c92e8b740e4e6f0053c6e48b1ecc03848 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:20:10 +0200 Subject: [PATCH 17/20] Document controlled upstream updates --- free_games_claimer/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/free_games_claimer/README.md b/free_games_claimer/README.md index 5773c3283b..e12eea312f 100644 --- a/free_games_claimer/README.md +++ b/free_games_claimer/README.md @@ -130,6 +130,19 @@ upgrade. The old Firefox profile is retained and is never deleted. The external noVNC port remains `6080`, although the standalone remaster image normally uses port `7080`. +## 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 1. Add this add-on repository to the Home Assistant add-on store. From 25945f5a37eb112943d998d620121f63d103d7c9 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:20:45 +0200 Subject: [PATCH 18/20] Document pinned upstream policy --- free_games_claimer/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/free_games_claimer/CHANGELOG.md b/free_games_claimer/CHANGELOG.md index 74d984ba3a..05c250e1b9 100644 --- a/free_games_claimer/CHANGELOG.md +++ b/free_games_claimer/CHANGELOG.md @@ -13,6 +13,8 @@ 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 automatic upstream + 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. From 865e1c8e6dd73dd06c841c5e4eb0d4f2c66f2dce Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:21:32 +0200 Subject: [PATCH 19/20] Run final add-on validation --- free_games_claimer/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/free_games_claimer/config.yaml b/free_games_claimer/config.yaml index 04ba1a1288..7fa2606bf5 100644 --- a/free_games_claimer/config.yaml +++ b/free_games_claimer/config.yaml @@ -1,4 +1,4 @@ -# Free Games Claimer Remaster +# Free Games Claimer Remaster add-on arch: - aarch64 - amd64 From 6f693f39dc0d2ac7aa1e03f7a70f0fa1bfc8f774 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:23:51 +0200 Subject: [PATCH 20/20] Validate Free Games Claimer migration --- free_games_claimer/CHANGELOG.md | 2 +- free_games_claimer/config.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/free_games_claimer/CHANGELOG.md b/free_games_claimer/CHANGELOG.md index 05c250e1b9..d2be5a5acc 100644 --- a/free_games_claimer/CHANGELOG.md +++ b/free_games_claimer/CHANGELOG.md @@ -13,7 +13,7 @@ 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 automatic upstream +- 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` diff --git a/free_games_claimer/config.yaml b/free_games_claimer/config.yaml index 7fa2606bf5..9dcef313e2 100644 --- a/free_games_claimer/config.yaml +++ b/free_games_claimer/config.yaml @@ -1,4 +1,4 @@ -# Free Games Claimer Remaster add-on +# Free Games Claimer Remaster add-on (pinned source) arch: - aarch64 - amd64