Merge pull request #10 from R0m1k3/claude/nettoyage-qualite

Qualité : builds reproductibles (lockfiles), CI durcie, publication chaînée, docs remises à jour
This commit is contained in:
LogiFlow authored and GitHub committed 2026-08-28 08:57:13 +02:00
commit 4e453850ae
12 files changed
+1876 -263

No files matched your search

-1
View File
@@ -8,7 +8,6 @@
build/
bin/.dart_tool
bin/.packages
bin/pubspec.lock
ios/
android/
windows/
+13 -1
View File
@@ -6,6 +6,12 @@ on:
pull_request:
branches: [main]
# Un push qui en suit un autre annule le run précédent : inutile de
# consommer un runner pour un commit déjà obsolète.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
frontend:
runs-on: ubuntu-latest
@@ -13,7 +19,13 @@ jobs:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
# Version épinglée : `channel: stable` seul fait dériver le SDK au
# fil du temps (une release Flutter peut casser la CI sans aucun
# changement dans le dépôt). Le cache évite de retélécharger SDK et
# dépendances pub à chaque run.
flutter-version: 3.38.4
channel: stable
cache: true
- run: flutter pub get
# Infos (pre-existing withOpacity/dart:html deprecations) are not
# fatal; errors and warnings still fail the build.
@@ -30,7 +42,7 @@ jobs:
- uses: actions/checkout@v4
- uses: dart-lang/setup-dart@v1
with:
sdk: stable
sdk: 3.13.2
- run: dart pub get
- run: dart analyze
- run: dart test
+14 -2
View File
@@ -1,7 +1,12 @@
name: Docker Publish
# Chaîné sur la CI : l'image :latest n'est publiée que si analyze/test/build
# sont verts sur main. L'ancien déclencheur `push: [main]` tournait en
# parallèle de la CI et pouvait publier une image cassée.
on:
push:
workflow_run:
workflows: [CI]
types: [completed]
branches: [main]
workflow_dispatch:
@@ -11,11 +16,18 @@ env:
jobs:
build-and-push:
runs-on: ubuntu-latest
if: >-
github.event_name == 'workflow_dispatch' ||
github.event.workflow_run.conclusion == 'success'
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
with:
# Sur workflow_run, github.sha pointe sur le commit du workflow
# par défaut : construire exactement le commit validé par la CI.
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
- uses: docker/setup-buildx-action@v3
@@ -34,6 +46,6 @@ jobs:
push: true
tags: |
${{ env.IMAGE_NAME }}:latest
${{ env.IMAGE_NAME }}:${{ github.sha }}
${{ env.IMAGE_NAME }}:${{ github.event.workflow_run.head_sha || github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
+3
View File
@@ -49,4 +49,7 @@ app.*.map.json
# Hive data (local development)
*.hive
*.lock
# Les lockfiles pub sont versionnés : sans eux, chaque build Docker/CI
# résout des versions différentes (builds non reproductibles).
!pubspec.lock
.claude/settings.local.json
+7
View File
@@ -2,6 +2,13 @@
## Non publié
### 🧰 Qualité / Infra
- **Builds reproductibles** : `pubspec.lock` (frontend et backend) désormais versionnés et utilisés par le Dockerfile — chaque build résolvait jusqu'ici des versions fraîches
- **CI durcie** : versions Flutter/Dart épinglées, cache pub, annulation des runs obsolètes (`concurrency`) ; `docker-publish` ne publie plus `:latest` qu'après une CI verte sur main (il tournait en parallèle et pouvait publier une image cassée)
- **docker-compose** : défaut `RECORDINGS_PATH` porté à `./data/recordings` (l'ancien défaut était un chemin unRAID spécifique à une machine), variable `TZ` ajoutée
- **README réécrit** : il décrivait une architecture disparue (Hive/IndexedDB, SHA-256, dhttpd port 8080) — remplacé par l'état réel (SQLite serveur, bcrypt, binaire natif port 8089, enregistrements, CI)
- `DEPLOYMENT_CHECKLIST.md` archivé et avertissement ajouté sur `docs/archive/` (plusieurs documents s'y déclarent « COMPLETE » à tort)
### ✨ Fonctionnalités
- **Guide TV et Season Passes de retour** : l'onglet Enregistrements retrouve ses 3 vues (Guide TV pour programmer depuis l'EPG, liste des enregistrements, Season Passes) — le code existait mais n'était plus branché depuis une refonte
- **Favoris enfin utilisables** : bouton cœur sur les tuiles chaînes (desktop et mobile) ; le filtre « Favoris » affichait toujours vide faute de moyen d'en ajouter
+4 -3
View File
@@ -12,9 +12,10 @@ ENV FLUTTER_NO_ANALYTICS=1
RUN flutter config --enable-web && flutter precache --web
# 2. Dependency Resolution (ONLY UPDATES IF PUBSPEC CHANGES)
COPY pubspec.yaml ./
COPY bin/pubspec.yaml ./bin/
# Note: No .lock files found locally, so we fetch fresh ones here
# Les lockfiles sont versionnés : le build résout exactement les versions
# committées au lieu d'en chercher de nouvelles à chaque build.
COPY pubspec.yaml pubspec.lock ./
COPY bin/pubspec.yaml bin/pubspec.lock ./bin/
RUN flutter pub get && cd bin && dart pub get
# 3. Source Code Copy (CHANGES OFTEN)
+76 -255
View File
@@ -1,282 +1,103 @@
# XtremFlow - IPTV Web Application
# XtremFlow — Application Web IPTV
High-performance, containerized IPTV Web Application using Flutter Web and Xtream Codes API.
Application IPTV auto-hébergée : frontend Flutter Web + serveur Dart natif, empaquetés dans une seule image Docker. Se connecte à un abonnement Xtream Codes et ajoute le magnétoscope (enregistrements planifiés, season passes), l'EPG avec repli XMLTV, et le transcodage FFmpeg à la demande.
## Features
## Fonctionnalités
✅ **Local Authentication System**
- Default admin user (`admin`/`admin`)
- Secure salt-based password hashing (SHA-256)
- No public signup - private app only
- **Live TV, Films, Séries** : catalogues Xtream avec catégories, recherche, favoris, reprise de lecture
- **Guide TV (EPG)** : panneau de l'abonné en priorité, repli automatique sur un dump XMLTV quand le panneau est figé
- **Enregistrements TV** : planification depuis le guide, capture FFmpeg (`-c copy`), reprise après coupure amont ou redémarrage du serveur, fusion automatique des parties
- **Season Passes** : enregistrement automatique de toutes les diffusions d'une émission (scan EPG toutes les 4 h)
- **Transcodage à la demande** : `source | high | medium | low` (live et VOD), `source` = zéro transcodage ; NVENC optionnel
- **Multi-utilisateurs** : comptes locaux (bcrypt), playlists par utilisateur, panneau d'administration
✅ **Multi-Playlist Management**
- Centralized Xtream credentials management
- Playlist assignment to users
- Easy switching between playlists
## Stack
✅ **High-Performance Dashboard (60fps)**
- Category-based pagination (100 items/page for Live TV, 50 for Movies)
- Lazy loading with `ListView.builder` / `GridView.builder`
- Image caching with `cached_network_image`
| Couche | Techno |
|---|---|
| Frontend | Flutter Web (Riverpod, GoRouter), players HTML (hls.js / mpegts.js vendorisés) |
| Backend | Dart compilé en natif (`dart compile exe`), shelf |
| Base | SQLite côté serveur (`/app/data/xtremflow.db`) |
| Capture/Transcodage | FFmpeg (build BtbN, NVENC inclus) |
| Conteneur | Debian slim multi-stage, port **8089** |
✅ **Live TV with EPG**
- Electronic Program Guide (EPG) overlay
- "Now & Next" program display
- Real-time progress bar
✅ **VOD & Series**
- Movies and Series organized by categories
- Grid layout with posters
- Optimized ratings display (1 decimal place)
✅ **Docker Deployment**
- Multi-stage build with Flutter and Dart
- Custom Dart Server (`bin/server.dart`)
- **FFmpeg Transcoding** for mobile compatibility
- **Cache Management** system for temporary files
- External network support (`nginx_default`)
## Tech Stack
- **Framework**: Flutter Web
- **State Management**: Riverpod
- **Local Database**: Hive (Web IndexedDB) with AES encryption
- **Networking**: Dio with cache interceptors
- **Routing**: GoRouter with auth guards
- **Video Player**: `video_player` + `chewie`
- **UI**: Google Fonts, Material Design 3
## Prerequisites
- Docker & Docker Compose
- Existing `nginx_default` network (for reverse proxy routing)
- Flutter SDK (for local development only)
## Quick Start (Docker)
### 1. Build the Docker image
## Démarrage rapide (Docker)
```bash
docker-compose build
docker-compose up -d --build
# Application sur http://localhost:8089
```
### 2. Start the container
```bash
docker-compose up -d
```
### 3. Access via reverse proxy
Configure your reverse proxy (Nginx/Traefik) to route traffic to:
- **Container**: `xtremflow`
- **Internal Port**: `8080`
- **Network**: `nginx_default`
Example Nginx configuration:
```nginx
location /iptv {
proxy_pass http://xtremflow:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
```
### 4. Login
- **URL**: `http://your-domain/iptv`
- **Default Credentials**:
- Username: `admin`
- Password: `admin`
⚠️ **Change the admin password immediately after first login!**
## Local Development
### Install dependencies
Au premier démarrage, un compte `admin` est créé avec un **mot de passe aléatoire affiché une seule fois dans les logs** (`docker logs xtremflow`), sauf si `ADMIN_INITIAL_PASSWORD` est défini. Changez-le après la première connexion.
### Variables d'environnement (docker-compose.yml)
| Variable | Défaut | Rôle |
|---|---|---|
| `RECORDINGS_PATH` | `./data/recordings` | Dossier hôte des enregistrements |
| `TZ` | `Europe/Paris` | Fuseau du conteneur (les enregistrements sont stockés en UTC) |
| `MAX_CONCURRENT_RECORDINGS` | `2` | Enregistrements simultanés |
| `EPG_XMLTV_URLS` | dump FR | Sources XMLTV de repli (vide = aucun appel sortant) |
| `NVIDIA_GPU` | `false` | Transcodage NVENC |
| `ADMIN_INITIAL_PASSWORD` | *(généré)* | Mot de passe initial du compte admin |
| `MIN_FREE_DISK_MB` | `500` | Espace libre minimal pour démarrer une capture |
| `RECORDINGS_QUOTA_GB` | `0` (off) | Quota du dossier d'enregistrements (rotation des plus anciens terminés) |
| `TRUSTED_PROXIES` | loopback + RFC1918 | IPs de reverse proxy dont `X-Forwarded-For` est honoré |
## Développement local
```bash
# Frontend
flutter pub get
flutter analyze && flutter test
flutter run -d chrome # nécessite le backend lancé pour les routes /api
# Backend
cd bin
dart pub get
dart analyze && dart test
dart run server.dart --port 8089 --path ../build/web
```
### Generate Hive adapters (if modified)
Le build Windows natif est documenté dans `BUILD.md`.
```bash
flutter pub run build_runner build --delete-conflicting-outputs
```
### Run web app
```bash
flutter run -d chrome
```
## Project Structure
## Structure du projet
```
lib/
├── core/
│ ├── database/
│ │ └── hive_service.dart # Hive initialization & encryption
│ ├── models/
│ │ ├── app_user.dart # User model (Hive)
│ │ ├── playlist_config.dart # Playlist credentials (Hive)
│ │ └── iptv_models.dart # Channel, VOD, Series, EPG models
│ ├── router/
│ │ └── app_router.dart # GoRouter configuration
│ └── utils/
│ └── crypto_utils.dart # Password hashing utilities
├── features/
│ ├── auth/
│ │ ├── providers/
│ │ │ └── auth_provider.dart # Authentication state
│ │ └── screens/
│ │ └── login_screen.dart
│ ├── admin/
│ │ └── screens/
│ │ └── admin_panel.dart # User & Playlist CRUD
│ └── iptv/
│ ├── services/
│ │ └── xtream_service.dart # Xtream API client
│ ├── providers/
│ │ └── xtream_provider.dart # Riverpod providers
│ ├── screens/
│ │ └── player_screen.dart # Video player
│ └── widgets/
│ ├── live_tv_tab.dart # Live TV with pagination
│ ├── movies_tab.dart # Movies grid
│ ├── series_tab.dart # Series grid
│ └── epg_overlay.dart # EPG display
└── main.dart
bin/ Serveur Dart
├── server.dart Point d'entrée, routage, arrêt gracieux
├── api/ Handlers HTTP (auth, playlists, recordings, EPG, proxy…)
├── services/ Scheduler d'enregistrement, sessions FFmpeg, XMLTV
├── database/ SQLite (schéma, migrations)
├── middleware/ Auth (session), sécurité (rate limit, honeypot, logs redactés)
└── test/ Tests backend (dart test)
lib/ Frontend Flutter
├── core/ Modèles, thème, router, clients API
├── features/ auth / admin / iptv (desktop)
└── mobile/ Variantes d'écrans mobiles
web/ Players HTML + libs vendorisées (hls.js, mpegts.js)
```
## Security Features
## Sécurité
### Password Storage
- **Algorithm**: SHA-256 with random UUID-based salt
- **Format**: `salt:hash` (stored in Hive)
- **Legacy Support**: Fallback to unsalted comparison for migration
- Mots de passe **bcrypt** (migration lazy depuis les anciens hashes au login)
- Les credentials Xtream ne quittent jamais le serveur : passerelle `/api/xtream-api` et proxy `/api/xtream` (authentifié par session) avec injection côté serveur
- Redaction des credentials dans tous les logs ; anti-SSRF avec revalidation des redirections
- Cookie de session HttpOnly ; rate limiting global + limite de tentatives de login par IP
### Database Encryption
- **Hive AES Cipher** (256-bit key)
- Key stored in `FlutterSecureStorage`
- Automatic key generation on first run
## CI / Publication
### Authentication Flow
1. User enters credentials
2. System retrieves stored hash
3. Input password is hashed with same salt
4. Constant-time comparison prevents timing attacks
`ci.yml` (analyze + tests + build web/backend) tourne sur chaque PR et push main ; `docker-publish.yml` publie `ghcr.io/r0m1k3/xtremflow:latest` **uniquement après une CI verte** sur main.
## Performance Optimizations
## Dépannage
### Memory Management (20k+ channels)
- **Grouping**: Channels organized by category
- **Pagination**: 100 items per page (Live TV), 50 per page (Movies)
- **Lazy Loading**: Only render visible items
- **Image Caching**: Disk/memory cache with `cached_network_image`
- **Logs** : `docker logs xtremflow` (les URLs y sont redactées)
- **Mot de passe admin perdu** : supprimer le volume `xtremflow-data` recrée la base et affiche un nouveau mot de passe (⚠ efface utilisateurs et historique d'enregistrements)
- **EPG vide** : vérifier `EPG_XMLTV_URLS` et que la chaîne a un `epg_channel_id` ; l'en-tête `X-Epg-Source` des réponses `/api/epg/<id>` indique la source utilisée
- **Enregistrement échoué** : bouton « Logs » sur la ligne de l'enregistrement ; la raison (`error_reason`) est affichée sous le titre
### Network Optimization
- **Dio Cache Interceptor**: 1-hour cache for API responses
- **EPG Cache**: 5-minute refresh for program data
- **Hive Disk Store**: Persistent cache across sessions
## Licence
### Rendering (60fps Target)
- `ListView.builder` with fixed `itemExtent`
- `AutomaticKeepAliveClientMixin` for tab state
- Expansion panels for category navigation
- Grid with fixed `crossAxisCount` and `childAspectRatio`
## Xtream API Integration
### Supported Endpoints
| Endpoint | Purpose | Caching |
|----------|---------|---------|
| `player_api.php` | Authentication | 1 hour |
| `get_live_streams` | Live TV channels | 1 hour |
| `get_vod_streams` | Movies | 1 hour |
| `get_series` | Series | 1 hour |
| `get_short_epg` | EPG data | 5 minutes |
### Stream URL Formats
```dart
// Live TV
http://[dns]/live/[username]/[password]/[stream_id].m3u8
// Movies
http://[dns]/movie/[username]/[password]/[stream_id].[container_extension]
// Series
http://[dns]/series/[username]/[password]/[stream_id].[container_extension]
```
## Docker Configuration
### Dockerfile (Multi-Stage)
**Stage 1: Builder**
- Base: `cirrusci/flutter:stable`
- Build: `flutter build web --release --web-renderer html`
**Stage 2: Runtime**
- Base: `dart:stable`
- Server: `dhttpd --host 0.0.0.0 --port 8080`
- Size: ~150MB (compressed)
### docker-compose.yml
```yaml
services:
iptv-web:
build: .
container_name: xtremflow
restart: unless-stopped
networks:
- nginx_default
networks:
nginx_default:
external: true
```
**No port mapping** - Access via reverse proxy only.
## Troubleshooting
### Container won't start
```bash
# Check logs
docker logs xtremflow
# Verify network exists
docker network ls | grep nginx_default
# Create network if missing
docker network create nginx_default
```
### Login fails with admin/admin
- Check Hive database initialization in logs
- Verify `HiveService.init()` completed successfully
- Default admin is seeded only if `users` box is empty
### EPG not displaying
- EPG is optional and gracefully degrades
- Check if Xtream server supports `get_short_epg`
- Verify stream has `epg_channel_id`
### Performance issues (FPS drops)
- Reduce `_itemsPerPage` constant (currently 100 for Live TV)
- Disable image caching temporarily
- Check browser DevTools Performance tab
## License
Proprietary - Private Use Only
## Support
For Xtream API documentation, consult your IPTV provider.
Propriétaire — usage privé uniquement.
+477
View File
@@ -0,0 +1,477 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "9a3386eea899815698dd55995277cf7cb8572ee52b399a6edfb7ae2b50e5fc19"
url: "https://pub.dev"
source: hosted
version: "105.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: "62993bed6eadbe9596c5c20d5c167e7bc563c5fe266657a04ddeb93bdb84f4c9"
url: "https://pub.dev"
source: hosted
version: "14.1.0"
args:
dependency: "direct main"
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
name: async
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
url: "https://pub.dev"
source: hosted
version: "2.13.1"
bcrypt:
dependency: "direct main"
description:
name: bcrypt
sha256: "6073a700cbbc59f1d4ab27cd532755e3de5e676c4941f535f351374df849270b"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
cli_config:
dependency: transitive
description:
name: cli_config
sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec
url: "https://pub.dev"
source: hosted
version: "0.2.0"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
coverage:
dependency: transitive
description:
name: coverage
sha256: "956a3de0725ca232ad353565a8290d3357592bf4250f6f298a185e2d949c5d3d"
url: "https://pub.dev"
source: hosted
version: "1.15.1"
crypto:
dependency: "direct main"
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
url: "https://pub.dev"
source: hosted
version: "3.0.7"
equatable:
dependency: "direct main"
description:
name: equatable
sha256: "3bce007a596ff8b3119c45d68aaef631272537c03d30e5d4534dd24bf4c5eaa2"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
ffi:
dependency: transitive
description:
name: ffi
sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
file:
dependency: transitive
description:
name: file
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
url: "https://pub.dev"
source: hosted
version: "7.0.1"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev"
source: hosted
version: "1.1.1"
frontend_server_client:
dependency: transitive
description:
name: frontend_server_client
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "4.0.0"
glob:
dependency: transitive
description:
name: glob
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.3"
hive:
dependency: "direct main"
description:
name: hive
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
url: "https://pub.dev"
source: hosted
version: "2.2.3"
http:
dependency: "direct main"
description:
name: http
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.dev"
source: hosted
version: "1.6.0"
http_methods:
dependency: transitive
description:
name: http_methods
sha256: "6bccce8f1ec7b5d701e7921dca35e202d425b57e317ba1a37f2638590e29e566"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
io:
dependency: transitive
description:
name: io
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.5"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd"
url: "https://pub.dev"
source: hosted
version: "0.12.20"
meta:
dependency: transitive
description:
name: meta
sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
node_preamble:
dependency: transitive
description:
name: node_preamble
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
package_config:
dependency: transitive
description:
name: package_config
sha256: ffcf4cf3d6c0b74ac43708d9f56625506e8a68aa935abe9d267a7330f320eb5d
url: "https://pub.dev"
source: hosted
version: "3.0.0"
path:
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
petitparser:
dependency: transitive
description:
name: petitparser
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
url: "https://pub.dev"
source: hosted
version: "7.0.2"
pool:
dependency: transitive
description:
name: pool
sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d"
url: "https://pub.dev"
source: hosted
version: "1.5.2"
pub_semver:
dependency: transitive
description:
name: pub_semver
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
shelf:
dependency: "direct main"
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
shelf_router:
dependency: "direct main"
description:
name: shelf_router
sha256: f5e5d492440a7fb165fe1e2e1a623f31f734d3370900070b2b1e0d0428d59864
url: "https://pub.dev"
source: hosted
version: "1.1.4"
shelf_static:
dependency: "direct main"
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
source_maps:
dependency: transitive
description:
name: source_maps
sha256: "14c2945847669b44089bb1222f66873d7ff7103c58911917f2a63c5a62327898"
url: "https://pub.dev"
source: hosted
version: "0.10.14"
source_span:
dependency: transitive
description:
name: source_span
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
url: "https://pub.dev"
source: hosted
version: "1.10.2"
sqlite3:
dependency: "direct main"
description:
name: sqlite3
sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2"
url: "https://pub.dev"
source: hosted
version: "2.9.4"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test:
dependency: "direct dev"
description:
name: test
sha256: "0d5ba5602ec3baa28c8ce365e1efc5575969c765f45c554a3e167dc7945b9c30"
url: "https://pub.dev"
source: hosted
version: "1.31.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "475610b2aa23c19687cce2961e44b0cc57cafe220f67c2b80201231b2a07fbe7"
url: "https://pub.dev"
source: hosted
version: "0.7.13"
test_core:
dependency: transitive
description:
name: test_core
sha256: a39c204a4fc7a7ccb04a2b985e359fda3cc37e45e0b8ac61c3fb1a05aa832132
url: "https://pub.dev"
source: hosted
version: "0.6.19"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
uuid:
dependency: "direct main"
description:
name: uuid
sha256: "9b129329f58692f6e6578329498a8fe9fbe98f090beb764ffbb8ee2eadd01dcd"
url: "https://pub.dev"
source: hosted
version: "4.6.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "5f37239c4851efcef929cea7824e76df7f2f0970aef85d66bbc430afa40e72f0"
url: "https://pub.dev"
source: hosted
version: "15.3.0"
watcher:
dependency: transitive
description:
name: watcher
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
web_socket:
dependency: transitive
description:
name: web_socket
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
name: webkit_inspection_protocol
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
xml:
dependency: "direct main"
description:
name: xml
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
url: "https://pub.dev"
source: hosted
version: "6.6.1"
yaml:
dependency: transitive
description:
name: yaml
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.3"
sdks:
dart: ">=3.11.0 <4.0.0"
+4 -1
View File
@@ -13,8 +13,11 @@ services:
# Pour changer: modifiez le chemin avant les deux points ":"
# Exemple Windows : - D:\MesVideos\TV:/app/recordings
# Exemple Linux : - /mnt/nas/videos:/app/recordings
- ${RECORDINGS_PATH:-/mnt/user/Data/Sport}:/app/recordings
- ${RECORDINGS_PATH:-./data/recordings}:/app/recordings
environment:
# Fuseau horaire du conteneur (affichage des logs ; les enregistrements
# sont stockés en UTC quoi qu'il arrive)
- TZ=${TZ:-Europe/Paris}
# Origine externe autorisée pour CORS (optionnel — l'app est servie
# same-origin, ne définir que si un autre domaine doit appeler l'API)
- ALLOWED_ORIGIN=${ALLOWED_ORIGIN:-}
File renamed without changes.
+12
View File
@@ -0,0 +1,12 @@
# Archives — documents historiques
⚠️ **Les documents de ce dossier sont historiques et ne décrivent pas l'état actuel du code.**
Ils datent de phases de conception ou de refontes antérieures. Plusieurs se déclarent « COMPLETE » ou « production-ready » alors que le travail décrit n'a jamais été intégré (ou a été remplacé depuis) :
- `RECORDING_SYSTEM_UPGRADE.txt` — décrit un remplacement du scheduler par `SimpleRecorder` qui n'a jamais été branché ; le système réel est `bin/services/recording_scheduler.dart`.
- `THEME_REDESIGN_SUMMARY.md` — la « Phase 4: Integration » n'a pas eu lieu ; les widgets qu'il liste n'existent plus.
- `ANALYSIS_AND_IMPROVEMENTS.md` — plan d'améliorations dont une partie seulement a été réalisée.
- `DEPLOYMENT_CHECKLIST.md` — référence des fichiers et versions de dépendances qui n'ont jamais existé dans le dépôt.
Pour l'état actuel du projet, se référer au `README.md` racine et au `CHANGELOG.md`.
+1266
View File
File diff suppressed because it is too large. Load diff