Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 9 additions & 30 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,48 +1,27 @@
# ─── TV Guide — configuration ────────────────────────────────────────────────
# Copiez ce fichier vers .env puis ajustez les valeurs.
# cp .env.example .env
# TV Guide configuration. Copy to .env and adjust as needed.

# Fuseau horaire d'affichage par défaut (modifiable ensuite dans l'administration).
TZ=Europe/Paris

# Port HTTP publié sur l'hôte (le conteneur écoute toujours sur 8080).
APP_PORT=8080

# Répertoire de persistance DANS le conteneur. Ne pas modifier sauf besoin précis :
# le volume est monté sur /data dans compose.yml.
DATA_DIR=/data

# Verbosité des logs : DEBUG, INFO, WARNING, ERROR
LOG_LEVEL=INFO

# Mot de passe de l'administration.
# - vide (défaut) : administration ouverte — réservez ce mode à un LAN de confiance ;
# - renseigné : la consultation reste publique, mais Sources/Chaînes/Affichage
# exigent une connexion (jeton de session de 24 h, anti-brute-force intégré).
# OBLIGATOIRE si l'application est exposée sur Internet. Utilisez HTTPS (reverse proxy).
# Protect administration when exposed outside a trusted LAN.
ADMIN_PASSWORD=

# Autoriser des sources XMLTV pointant vers des adresses privées (LAN, loopback).
# Laisser à false sur une instance exposée : protège contre les attaques SSRF.
# Passer à true si votre fichier XMLTV est servi par une machine de votre LAN.
# Set to true only when XMLTV files are served from your private network.
ALLOW_PRIVATE_XMLTV_SOURCES=false

# Taille maximale d'un téléchargement XMLTV (fichier compressé ou non), en Mo.
XMLTV_MAX_DOWNLOAD_MB=100

# Taille maximale après décompression GZIP, en Mo (protection contre les bombes gzip/zip/xz).
XMLTV_MAX_UNCOMPRESSED_MB=500

# Timeout des requêtes HTTP vers les sources XMLTV, en secondes.
XMLTV_HTTP_TIMEOUT_SECONDS=30
XMLTV_DOWNLOAD_RETRIES=3

# Nombre maximal d'imports XMLTV simultanés. 1 est recommandé avec SQLite :
# évite de multiplier les pics RAM/CPU et les écritures concurrentes.
# Keep one worker with SQLite to minimize concurrent RAM/CPU peaks.
XMLTV_SYNC_WORKERS=1
XMLTV_USER_AGENT=tvguide/1.0

# Nombre maximal d'arènes de l'allocateur glibc. La valeur 2 évite que la
# décompression 7z conserve durablement son pic RAM après les imports.
# Reduce retained native allocator arenas after archive decompression.
MALLOC_ARENA_MAX=2

# User-Agent envoyé lors du téléchargement des sources XMLTV.
#XMLTV_USER_AGENT=tvguide/1.0
# Restrict this to your reverse proxy IP when the container port is exposed.
FORWARDED_ALLOW_IPS=*
12 changes: 11 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,21 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Log in to Docker Hub
if: startsWith(github.ref, 'refs/tags/v')
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Image metadata
if: startsWith(github.ref, 'refs/tags/v')
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
images: |
ghcr.io/${{ github.repository }}
${{ secrets.DOCKERHUB_USERNAME }}/tvguide
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
Expand All @@ -109,5 +118,6 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=gha
cache-to: type=gha,mode=max
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,3 @@ data/

# Frontend build copied into the backend (Docker build artifact)
backend/app/static/
.claude/
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@
Ce projet suit [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et
[SemVer](https://semver.org/lang/fr/).

## [1.17.0] — 2026-07-18

### Internationalization

- Added complete English and French user interfaces, including navigation,
administration, programme metadata, dates, durations, and accessibility text.
- The saved language takes priority; first visits use the primary browser
language (`fr*` selects French, all other languages fall back to English).
- Added an accessible EN/FR selector and tests for detection, persistence,
fallback, and interpolation.

### Documentation and distribution

- English README is now the default, with a linked French README.
- Added complete Docker Hub documentation, Compose example, environment
reference, and a dedicated `compose.dockerhub.yml`.
- Stable release tags now publish the same multi-platform image to GHCR and
Docker Hub; the English Docker Hub overview is tracked in `DOCKERHUB.md`.

## [1.16.2] — 2026-07-18

### Performance et mémoire
Expand Down
74 changes: 74 additions & 0 deletions DOCKERHUB.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# TV Guide

Lightweight, self-hosted XMLTV schedule browser with live, evening, grid, and full-text search views.

- English and French UI with browser-language detection
- XML, GZIP, ZIP, 7-Zip, XZ, and BZIP2 imports
- Atomic imports and smart source synchronization
- SQLite FTS5 search
- Administration password support
- Non-root, read-only compatible container
- `linux/amd64` and `linux/arm64`

Source, issues, and release notes: [github.com/cerede2000/tvguide](https://github.com/cerede2000/tvguide)

## Docker Compose

```yaml
services:
tvguide:
image: cerede2000/tvguide:latest
container_name: tvguide
restart: unless-stopped
ports:
- "8080:8080"
environment:
TZ: Europe/Paris
ADMIN_PASSWORD: change-this-password
XMLTV_SYNC_WORKERS: 1
MALLOC_ARENA_MAX: 2
volumes:
- ./data:/data
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:size=16m,mode=1777
```

```bash
mkdir -p data/imports
chown -R 1000:1000 data
docker compose up -d
```

Open `http://localhost:8080`, then add an XMLTV source from **Administration → XMLTV sources**.

## Environment variables

| Variable | Default | Description |
| --- | --- | --- |
| `TZ` | `Europe/Paris` | Default display and XMLTV fallback timezone. |
| `ADMIN_PASSWORD` | empty | Protects administration when set. |
| `LOG_LEVEL` | `INFO` | Logging level. |
| `ALLOW_PRIVATE_XMLTV_SOURCES` | `false` | Allows private/loopback XMLTV URLs. |
| `XMLTV_MAX_DOWNLOAD_MB` | `100` | Maximum download size. |
| `XMLTV_MAX_UNCOMPRESSED_MB` | `500` | Maximum decompressed size. |
| `XMLTV_HTTP_TIMEOUT_SECONDS` | `30` | Download timeout. |
| `XMLTV_DOWNLOAD_RETRIES` | `3` | Download retry count. |
| `XMLTV_SYNC_WORKERS` | `1` | Concurrent imports; keep `1` for lower RAM/CPU. |
| `XMLTV_USER_AGENT` | `tvguide/1.0` | XMLTV download User-Agent. |
| `MALLOC_ARENA_MAX` | `2` | Limits retained native allocator arenas. |
| `FORWARDED_ALLOW_IPS` | `*` | Trusted reverse-proxy IPs. |

The container listens on port `8080`, runs as UID/GID `1000`, stores all persistent data under `/data`, and exposes `GET /api/health`.

## Tags

- `latest`: latest stable release
- `1.17.0`: exact release
- `1.17`: latest patch in the release line

Pin an exact version for controlled deployments. Database migrations run automatically at startup; back up `/data/app.db` before upgrades.

Full documentation: [English](https://github.com/cerede2000/tvguide/blob/main/README.md) · [Français](https://github.com/cerede2000/tvguide/blob/main/README.fr.md)
120 changes: 120 additions & 0 deletions README.fr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Guide TV

[English](README.md) · [Français](README.fr.md)

Application web légère et auto-hébergée pour consulter une ou plusieurs sources XMLTV. Elle fournit uniquement le programme : aucun lecteur IPTV, M3U, enregistrement ou flux vidéo.

## Fonctionnalités

- Programmes en cours avec progression, temps restant et émissions suivantes.
- Vues Ce soir et 2e partie avec plages horaires configurables.
- Grille proportionnelle, navigation par date, zoom et interface responsive.
- Recherche rapide SQLite FTS5 dans les titres, sous-titres et descriptions.
- Sources XMLTV par URL ou fichier local, imports atomiques et planification intelligente.
- Ordre des chaînes, noms/logos personnalisés et configuration portable.
- Thèmes clair, sombre et système.
- Interface anglaise et française : préférence mémorisée, sinon langue du navigateur.
- Image multi-architecture `linux/amd64` et `linux/arm64`.

Formats acceptés : XML, GZIP, ZIP, 7-Zip, XZ et BZIP2, détectés depuis le contenu.

## Démarrage rapide avec Docker Compose

```yaml
services:
tvguide:
image: cerede2000/tvguide:latest
container_name: tvguide
restart: unless-stopped
ports:
- "8080:8080"
environment:
TZ: Europe/Paris
ADMIN_PASSWORD: changez-ce-mot-de-passe
XMLTV_SYNC_WORKERS: 1
MALLOC_ARENA_MAX: 2
volumes:
- ./data:/data
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:size=16m,mode=1777
```

```bash
mkdir -p data/imports
chown -R 1000:1000 data
docker compose up -d
```

Ouvrez <http://localhost:8080>, puis allez dans **Administration → Sources XMLTV → Ajouter une source**. Le premier import démarre immédiatement.

La même image est disponible sur `ghcr.io/cerede2000/tvguide:latest`.

## Variables d’environnement

| Variable | Défaut | Description |
| --- | --- | --- |
| `TZ` | `Europe/Paris` | Fuseau d’affichage par défaut et fuseau de secours des dates XMLTV sans offset. |
| `APP_PORT` | `8080` | Port hôte des fichiers Compose. Le conteneur écoute sur `8080`. |
| `DATA_DIR` | `/data` | Répertoire persistant dans le conteneur. |
| `LOG_LEVEL` | `INFO` | `DEBUG`, `INFO`, `WARNING` ou `ERROR`. |
| `ADMIN_PASSWORD` | vide | Protège l’administration. Fortement recommandé hors d’un LAN de confiance. |
| `ALLOW_PRIVATE_XMLTV_SOURCES` | `false` | Autorise les URL privées ou loopback. |
| `XMLTV_MAX_DOWNLOAD_MB` | `100` | Taille maximale téléchargée. |
| `XMLTV_MAX_UNCOMPRESSED_MB` | `500` | Taille maximale décompressée. |
| `XMLTV_HTTP_TIMEOUT_SECONDS` | `30` | Timeout HTTP des téléchargements. |
| `XMLTV_DOWNLOAD_RETRIES` | `3` | Nombre de nouvelles tentatives. |
| `XMLTV_SYNC_WORKERS` | `1` | Imports simultanés. Gardez `1` avec SQLite pour limiter RAM/CPU. |
| `XMLTV_USER_AGENT` | `tvguide/1.0` | User-Agent envoyé aux serveurs XMLTV. |
| `MALLOC_ARENA_MAX` | `2` | Limite les arènes de l’allocateur natif après les pics d’import. |
| `FORWARDED_ALLOW_IPS` | `*` | IP des reverse proxies autorisés à fournir les en-têtes forwarded. |

Les réglages d’affichage sont gérés dans l’application et stockés en base.

## Fichier XMLTV local

```bash
cp guide.xml.gz ./data/imports/
```

Configurez ensuite une source locale avec `imports/guide.xml.gz`. Les chemins hors de `/data` sont refusés.

## Mise à jour et sauvegarde

```bash
docker compose pull
docker compose up -d
docker compose logs -f tvguide
```

Les migrations s’exécutent automatiquement au démarrage. Sauvegardez `data/app.db` avant une mise à jour :

```bash
docker compose exec tvguide python -c \
"import sqlite3; sqlite3.connect('/data/app.db').execute(\"VACUUM INTO '/data/backup.db'\")"
```

Depuis `1.16.1`, un index FTS5 est créé automatiquement. Prévoyez temporairement un espace libre proche de la taille de la base lors de la première migration. Le WAL est checkpointé et tronqué après les migrations et les imports réussis.

## Construction depuis les sources

```bash
git clone https://github.com/cerede2000/tvguide.git
cd tvguide
cp .env.example .env
mkdir -p data/imports
chown -R 1000:1000 data
docker compose up -d --build
```

## Reverse proxy et sécurité

L’application sert du HTTP sur le port `8080` et accepte les en-têtes `X-Forwarded-*`. Utilisez HTTPS et un `ADMIN_PASSWORD` fort pour toute exposition Internet. Les vues de consultation restent publiques ; les endpoints d’administration nécessitent un jeton quand un mot de passe est défini.

Toutes les données persistantes sont sous `/data`. Le healthcheck est disponible sur `GET /api/health` et les logs sont écrits sur stdout/stderr.

## Licence

[MIT](LICENSE)
Loading
Loading