mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-11 17:30:00 +02:00
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:
12 files changed
+1876
-263
No files matched your search
@@ -8,7 +8,6 @@
|
||||
build/
|
||||
bin/.dart_tool
|
||||
bin/.packages
|
||||
bin/pubspec.lock
|
||||
ios/
|
||||
android/
|
||||
windows/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
@@ -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
@@ -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.
@@ -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
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user