Nettoyage massif côté frontend, grosse passe perf, app mobile v2.5.3
(écran qui ne s'éteint plus + fix build), extracteur Uqload HLS sur
extensions/userscript, redirection réseau-bloqué via passerelle
explicative et cast cross-receiver/cross-browser.
Nettoyage Firebase & code mort
- Drop firebase + @firebase/firestore (package.json + vite.config
optimizeDeps + alias)
- Suppression src/config/firebase.ts (jamais utilisé)
- Suppression services morts : adminService, commentService, logService,
notificationService + composants liés (AdminLogin, CommentSection,
CommentItem, ReactionBar) + types/Comment.ts
- Suppression scripts non-utilisés : bundle-report.mjs, publish-app.mjs
- Net : -3 449 lignes
Perf carrousels & TMDB images
- useTmdbImages : 1 seul fetch TMDB pour logo + poster (au lieu de 2),
prefetch idle au mount du carousel + dedup via inflight map (0 doublon
entre prefetch et hooks), include_image_language=fr,en,null pour
récupérer les versions FR-prioritisées
- EmblaCarousel : pré-décode des posters off-DOM (img.decode) en idle
pour éliminer le coût de décode pendant le scroll horizontal, priority
cap statique (eager + fetchpriority=high pour les N premières cards
selon viewport), suppression du tracking visibleSlides (state churn)
- content-visibility:auto sur slides hors viewport (skip layout/paint
natif), exclu des slides Top 10 pour ne pas clipper le digit débordant
- will-change:transform pré-promotion compositing layer (PC only via
hover:hover)
- Embla duration 25 → 15 (snap plus rapide, moins de frames composées)
- Boutons nav carousel : suppression backdrop-blur (cher), bg opaque
- LazyImage : width/height attrs pour éviter CLS + alléger placeholder
Top progress bar (style YouTube)
- TopProgressBar : asymptote vers 85% pendant chunk loads, fill 100%
smooth + fade out à la fin, 120ms grace period pour suppress flash
sur chunks cachés
- lazyWithRetry tracke les loads actifs + dispatch chunk:load:start /
chunk:load:end events sur window
- Routes loaders supportent { silent: true } pour skip le tracking sur
les prefetch (PrefetchLink hover + IDLE_PREFETCH au mount)
SW redirect → passerelle movix.health explicative
- buildMirrorUrl() factorise la construction d'URL miroir avec contexte
- handleNavigation passe ?from=&reason=unreachable&error=&via= à la
gateway pour qu'elle affiche une popup explicative au user au lieu
d'un redirect silencieux
- MOVIX_FORCE_REDIRECT message handler passe reason=api-errors
- blockDetection.ts transmet la dernière erreur axios au SW
- index.html : cache-bust du Cast SDK URL (cb=Date.now()) pour éviter
qu'un SDK stale ne reste coincé en cache navigateur/SW
Cast (Chromecast + AirPlay + Remote Playback API)
- loadMediaOnCastWithFallback : retry sur 3 MIME HLS différents
(application/vnd.apple.mpegurl, x-mpegurl, x-mpegURL) — certains
receivers rejettent le premier choix selon firmware
- Subtitles externes attachés au cast (CastSubtitleTrack) via
chrome.cast.media.Track + TextTrackStyle par défaut (50% black
background, edge outline) lisible sur la majorité des TV
- isRemotePlaybackSupported : fallback W3C Remote Playback API pour
Firefox / Edge avec cast extension bloquée / Brave avec shields →
device discovery + picker via video.remote.prompt()
- initializeAirPlay supporte désormais les deux paths (WebKit AirPlay
pour Safari + Remote Playback pour les autres)
- Détection castSdkBlocked : si le SDK Cast ne charge pas en 5s
(adblock, FAI, shield), affiche un message d'erreur explicite au
lieu du générique "aucun device trouvé"
- 7 nouvelles strings i18n FR + EN pour les états cast :
castUnavailable, castUnavailableNoDevices,
castUnavailableUnsupportedBrowser, castUnavailableSdkBlocked,
castUnavailableHelpChromecast, castUnavailableHelpAirPlay,
castUnavailableSeeHelp
App mobile Android v2.5.3 (versionCode 12)
- AndroidManifest : android:keepScreenOn="true" sur MainActivity →
l'écran ne s'éteint plus pendant le visionnage (avant le user devait
toucher l'écran toutes les 30s pour pas que le téléphone se lock en
plein film)
- build.gradle : exclude androidx.legacy:legacy-support-core-utils
(tiré transitivement par mediarouter → palette) qui embarquait ses
propres androidx.autofill.R$attr → "duplicate class" au mergeDexRelease
contre le module androidx.autofill:autofill:1.1.0 d'appcompat
- gradle.properties : android.nonTransitiveRClass=true pour empêcher
chaque lib de regénérer ses R classes transitivement (même cause
racine du duplicate class)
- version.json bumped 2.5.2 → 2.5.3, nouvel APK (-17KB), release notes
FR : "Correction extraction du lecteur Uqload" + "L'écran ne s'éteint
plus lors de l'utilisation de l'app"
- apkUrl repointé sur le repo Movix-STMG (au lieu de movixcorp)
Userscript + Extensions Chrome/Firefox — Uqload HLS
- extractUqload : préfère désormais le master.m3u8 multi-bitrate (qualité
adaptative) au v.mp4 single-quality. Regex tente d'abord
/master\.m3u8/, sinon n'importe quel .m3u8, et fallback sur l'ancien
pattern v.mp4 si rien trouvé. Les 3 cibles (Chrome MV3, Firefox MV2,
Tampermonkey) sont synchronisées sur la même logique.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| android | ||
| ios | ||
| scripts | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| app.json | ||
| babel.config.cjs | ||
| index.js | ||
| metro.config.cjs | ||
| movix-android.apk | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| version.json | ||
Movix — Application Mobile
Application iOS & Android pour Movix. WebView avec l'extension Movix intégrée (remplacement du userscript Tampermonkey) et changeur DNS 1.1.1.1.
⚠️ Statut iOS : non testé, non compilé
Je n'ai pas de Mac à disposition, donc la partie iOS (Xcode, CocoaPods,
NEDNSSettingsManager, entitlements, archive, signature, App Store) n'a jamais été buildée ni testée. Le code natif Swift/Objective-C et la configPodfilesont rédigés à l'aveugle à partir de la documentation Apple.Il est très probable qu'il y ait des erreurs de build, des permissions manquantes, du linking à corriger ou un bridging header à ajuster avant que l'app tourne sur un vrai device iOS.
Toute aide est la bienvenue : si tu as un Mac et un peu de temps, n'hésite pas à tester, ouvrir une issue ou soumettre une PR. La partie Android est elle fonctionnelle et testée localement.
Architecture
app/
├── src/
│ ├── App.tsx # Navigation (Browser + Settings)
│ ├── screens/
│ │ ├── BrowserScreen.tsx # WebView principal + toolbar
│ │ └── SettingsScreen.tsx # Toggle DNS + infos extension
│ ├── components/
│ │ ├── WebViewBrowser.tsx # WebView avec injection userscript
│ │ └── BrowserToolbar.tsx # Barre de navigation
│ ├── services/
│ │ ├── bridge.ts # Bridge RN ↔ WebView (remplace GM_xmlhttpRequest)
│ │ └── dns.ts # Wrapper module DNS natif
│ ├── injection/
│ │ ├── bridge-runtime.ts # JS injecté dans le WebView (API GM_*)
│ │ ├── inject.ts # Assembleur bridge + userscript
│ │ └── userscript-source.ts # Source du userscript (auto-généré)
│ └── config/
│ └── index.ts # Configuration de l'app
├── android/ # Code natif Android (VPN DNS)
├── ios/ # Code natif iOS (NEDNSSettings)
└── scripts/
└── build-userscript.js # Génère userscript-source.ts
Comment ça marche
- WebView charge
movix.cash - Bridge runtime est injecté AVANT le chargement de la page — fournit
GM_xmlhttpRequest,GM_getValue,GM_setValue,GM_deleteValue,unsafeWindow - Userscript original est injecté et fonctionne comme dans Tampermonkey
- Quand le userscript fait une requête via
GM_xmlhttpRequest, le bridge envoie un message à React Native - React Native fait la requête HTTP nativement (pas de CORS) et renvoie la réponse
- DNS 1.1.1.1 : sur Android via un VPN local, sur iOS via
NEDNSSettingsManager
Prérequis
- Node.js 18+
- React Native CLI (
npm install -g @react-native-community/cli) - Android : Android Studio, JDK 17, Android SDK 35
- iOS : Xcode 15+, CocoaPods (
gem install cocoapods)
Installation
cd app
# Installer les dépendances
npm install
# Générer le userscript source
node scripts/build-userscript.js
# iOS seulement
cd ios && pod install && cd ..
Lancement
# Android
npm run android
# iOS
npm run ios
# Metro bundler seul
npm run start
Build de production
Android (APK / AAB)
cd android
./gradlew assembleRelease # APK
./gradlew bundleRelease # AAB (Play Store)
L'APK sera dans android/app/build/outputs/apk/release/.
iOS
⚠️ Section non vérifiée — voir l'avertissement en haut du README. Les étapes ci-dessous sont les étapes Xcode standard pour un projet React Native, mais elles n'ont pas été exécutées sur ce projet.
- Ouvrir
ios/Movix.xcworkspacedans Xcode - Sélectionner le scheme "Movix" et la target device
- Product → Archive
DNS 1.1.1.1
Android
- Utilise
VpnServicepour créer un VPN local - Seules les requêtes DNS sont redirigées vers 1.1.1.1
- Aucune donnée ne transite par un serveur tiers
- L'utilisateur doit approuver la connexion VPN
iOS
- Utilise
NEDNSSettingsManager(iOS 14+) - DNS-over-HTTPS vers
cloudflare-dns.com - Nécessite l'entitlement
com.apple.developer.networking.dns-settings - Requiert un profil de provisioning avec cette capability
Mise à jour du userscript
Quand le userscript (../userscript/movix.user.js) est modifié :
node scripts/build-userscript.js
Puis rebuild l'app.
Notes
- Le
DnsPackage.ktdoit être enregistré dansMainApplication.kt(ajouté augetPackages()) - Pour iOS, le bridging header doit pointer vers
Movix-Bridging-Header.h - L'app exclut son propre trafic du VPN DNS pour éviter les boucles
- Le mode audio en arrière-plan est activé pour la lecture vidéo continue