feat: add authenticated live podcasts and simplify native video playback
Include podcast capture, ingestion and replay, dependency and installer updates, and native video positioning after navigation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
d9b183c500
commit
4fc91cec3e
45 changed files with 2330 additions and 378 deletions
|
|
@ -175,10 +175,19 @@ affichées dans la barre de statut, sans les masquer par une déduction MIME.
|
|||
Les types `video/*` ouvrent `VideoPage` via `App.PushPageAsync` sur desktop.
|
||||
Cette page contient un `LibVLCSharp.Avalonia.VideoView`, lecture/pause et
|
||||
une action d'ouverture externe. Le lecteur et ses ressources natives sont
|
||||
arrêtés et libérés à la sortie de la page. **LibVLC doit être installé**
|
||||
arrêtés et libérés à la sortie de la page. La lecture utilise directement
|
||||
`new LibVLC()`, `new MediaPlayer(libVlc)` et `Play(media)`, sans options
|
||||
spécifiques à Linux ni détection VAAPI/VDPAU. Le média est libéré après
|
||||
`Play` comme dans l'exemple officiel ; le lecteur conserve sa référence native.
|
||||
**LibVLC doit être installé**
|
||||
sur le poste (par exemple `libvlc5` et les plugins VLC sur Linux ; les
|
||||
bibliothèques natives adaptées sont nécessaires sous Windows/macOS).
|
||||
Une absence de LibVLC ou une erreur de décodage est signalée dans la page.
|
||||
Le navigateur ne s'ouvre que sur demande explicite, jamais en repli automatique.
|
||||
Après la navigation, `TryUpdateNativeControlPosition()` synchronise la surface
|
||||
native à la priorité `Loaded`, une fois la mise en page effectuée :
|
||||
les transformations de transition ne déclenchent pas de changement de `Bounds`.
|
||||
Le rappel est ignoré si le lecteur a été libéré ou remplacé entre-temps.
|
||||
Sur Android et Browser, où ce contrôle natif desktop n'est pas disponible,
|
||||
les vidéos sont ouvertes dans le navigateur, comme les autres fichiers
|
||||
(images liées, PDF, téléchargements) et les liens externes.
|
||||
|
|
@ -231,6 +240,58 @@ faut *deux* enregistrements : la page en `AddTransient` (ou
|
|||
de `ViewLocator.Build`. Si l'un manque, l'app affiche
|
||||
"No view for X" sans crash.
|
||||
|
||||
## Podcasts : capture, direct et replay
|
||||
|
||||
`PodcastsPageViewModel` est accessible depuis l'accueil Desktop Windows/Linux.
|
||||
`CameraStreamer` detecte les cameras DirectShow/V4L2 et les microphones
|
||||
(DirectShow sous Windows, source PulseAudio par defaut sous Linux).
|
||||
`PodcastBroadcaster` utilise uniquement LibVLC : encodage H.264/AAC, sortie
|
||||
`livehttp`, segments MPEG-TS d'environ deux secondes. Un segment n'est
|
||||
envoye que lorsque l'index local LibVLC le declare complet.
|
||||
|
||||
`PodcastApiClient` reutilise le transport bearer et son rafraichissement
|
||||
des jetons. Les PUT sont numerotes a partir de zero ; une nouvelle tentative
|
||||
doit avoir exactement les memes octets et la meme duree. Le client supprime
|
||||
un segment local seulement apres acquittement, et envoie le dernier segment
|
||||
ferme par LibVLC avant de terminer le direct. La navigation et la deconnexion
|
||||
arretent la camera. Les erreurs restent visibles ; les fichiers non envoyes
|
||||
restent disponibles localement pour recuperation manuelle.
|
||||
|
||||
`ILiveProcessor` est un singleton dans Yavsc.Api. Il stocke les metadonnees
|
||||
et empreintes SHA-256 dans un index JSON remplace atomiquement, avec des
|
||||
segments immuables accessibles uniquement via les endpoints authentifies.
|
||||
Deux receptions au plus sont tamponnees en parallele ; les validations de
|
||||
sequence, de proprietaire et de quota sont serialisees avant commit.
|
||||
Un index ne reference jamais un segment en cours d'ecriture.
|
||||
|
||||
| Route sous `api/v1/podcasts` | Role |
|
||||
| --- | --- |
|
||||
| `GET /`, `POST /` | Catalogue ou creation d'une emission |
|
||||
| `GET /{id}` | Metadonnees et segments ordonnes |
|
||||
| `PUT /{id}/segments/{sequence}?duration=...` | Ingestion `video/mp2t`, auteur uniquement |
|
||||
| `POST /{id}/complete` | Finalisation idempotente du replay |
|
||||
| `GET /{id}/index.m3u8` | Playlist HLS EVENT, ENDLIST apres fin/interruption |
|
||||
| `GET /{id}/segments/{sequence}.ts` | Segment engage, lecture authentifiee |
|
||||
| `DELETE /{id}` | Suppression d'une emission terminee, auteur uniquement |
|
||||
|
||||
Toutes les routes requierent la politique `ApiScope`. La lecture est ouverte
|
||||
a tous les utilisateurs authentifies avec ce scope, pas seulement a l'auteur.
|
||||
`PodcastMediaInput` alimente LibVLC en octets MPEG-TS via les requetes
|
||||
authentifiees existantes, sans transmettre de jeton dans une URL ou un
|
||||
processus externe. Les rappels natifs ne laissent echapper aucune exception :
|
||||
l'erreur est remontee a la page de lecture.
|
||||
|
||||
Un direct inactif devient `Interrupted` lors de la prochaine lecture de
|
||||
l'index ; au redemarrage, tous les anciens directs sont interrompus.
|
||||
Les segments engages constituent le replay, sans transcodage serveur.
|
||||
Le stockage exige un seul processus par racine et les quotas podcast sont
|
||||
independants de ceux des fichiers utilisateur. Voir
|
||||
[INSTALL.md](../../INSTALL.md#podcast-live-broadcasts-and-replays) pour
|
||||
les limites et le deploiement ; [Podcast.http](../../src/Yavsc.Api/Podcast.http)
|
||||
pour les requetes.
|
||||
Le document OpenAPI dedie est `/openapi/podcasts.json`, accessible en
|
||||
developpement aux administrateurs comme les autres documents de l'API.
|
||||
|
||||
## Composition root (`App.axaml.cs`)
|
||||
|
||||
`App.OnFrameworkInitializationCompleted` est le seul endroit où
|
||||
|
|
|
|||
|
|
@ -73,6 +73,30 @@ HTTP, on stub `IAuthorizationService` directement (cf.
|
|||
`BlogspotController` dans `Yavsc.Org.Tests/NonRegression/`)
|
||||
pour éviter de monter un host complet.
|
||||
|
||||
## Tests cibles des podcasts
|
||||
|
||||
Avec le runner Microsoft.Testing.Platform du depot (.NET 10, xUnit v3) :
|
||||
|
||||
```bash
|
||||
dotnet test --project src/test/Yavsc.Api.Tests/Yavsc.Api.Tests.csproj \
|
||||
--filter-class '*LiveProcessorTests' --filter-class '*PodcastControllerTests'
|
||||
dotnet test --project src/PostIt/PostIt.Tests/PostIt.Tests.csproj \
|
||||
--filter-class '*PodcastTests' --filter-class '*PodcastNativeCaptureTests'
|
||||
```
|
||||
|
||||
Les tests serveur couvrent HTTP/authentification, proprietaire, sequences,
|
||||
reprises idempotentes, limites exactes, concurrence et persistance des replays
|
||||
apres interruption/redemarrage, dans des dossiers temporaires isoles.
|
||||
|
||||
Les tests natifs sont explicitement ignores sans `POSTIT_TEST_MEDIA`.
|
||||
Pour les activer, installer LibVLC avec ses encodeurs H.264/AAC et definir
|
||||
cette variable sur un fichier video local d'environ huit secondes contenant
|
||||
une piste audio. Ils exercent la segmentation LibVLC reelle, l'envoi et la
|
||||
reprise apres acquittement perdu, le dernier segment apres arret et le
|
||||
decodage authentifie du replay. Aucun FFmpeg n'est requis par ces tests ni
|
||||
par l'application (le fichier d'entree peut provenir de n'importe quelle source).
|
||||
Les tests materiels camera/microphone Windows/Linux restent manuels.
|
||||
|
||||
## Quand ne PAS écrire de test
|
||||
|
||||
Un test qui ne détecte rien n'est pas un test. Si l'invariant
|
||||
|
|
|
|||
Loading…
Reference in a new issue