Compare commits
224 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4daab74e27 | ||
|
|
a7fbd567fd | ||
|
|
f90752bdb7 | ||
|
|
c5590639b1 | ||
|
|
098ab73ba1 | ||
|
|
060b0b927b | ||
|
|
786e06b27f | ||
|
|
ef1c34a9c0 | ||
|
|
b97481f2d9 | ||
|
|
8d74b7e7ce | ||
|
|
635c97b1ad | ||
|
|
673c96c917 | ||
|
|
15fc49d84d | ||
|
|
54cfd194f1 | ||
|
|
be561c6d9f | ||
|
|
dc8c27dfc4 | ||
|
|
ce7f92b540 | ||
|
|
f0271cd395 | ||
|
|
2a4c076854 | ||
|
|
c852c56231 | ||
|
|
614ffc12c0 | ||
|
|
d9b2545cdd | ||
|
|
1ae6b4f108 | ||
|
|
373efa0564 | ||
|
|
6c464abdd4 | ||
|
|
5d5d77ae1b | ||
|
|
b2cfc19e96 | ||
|
|
e40e8bb7c5 | ||
|
|
a3158be2bd | ||
|
|
e305dee777 | ||
|
|
415efd4e03 | ||
|
|
f027788266 | ||
|
|
23acda3167 | ||
|
|
a8b4dc5a01 | ||
|
|
fd4efe6c7f | ||
|
|
68340eac9e | ||
|
|
175d47f71f | ||
|
|
0b764412b2 | ||
|
|
f7c0c670d7 | ||
|
|
18bd6ff3ca | ||
|
|
ac5326ba3f | ||
|
|
c5af56537b | ||
|
|
17cdd503e9 | ||
|
|
688950d0c2 | ||
|
|
eb3082cddb | ||
|
|
32bec08f30 | ||
|
|
a7f850d577 | ||
|
|
08f356cfa4 | ||
|
|
6e975ffe26 | ||
|
|
64981dd110 | ||
|
|
b5156bcc69 | ||
|
|
9ab99a1225 | ||
|
|
d5edec025c | ||
|
|
ef43463b99 | ||
|
|
ca2e95e6f4 | ||
|
|
559c50fa87 | ||
|
|
2ca0a05636 | ||
|
|
363de47313 | ||
|
|
bdb2803371 | ||
|
|
6eae438300 | ||
|
|
707ceb711a | ||
|
|
024646579e | ||
|
|
f895428e3d | ||
|
|
698456c205 | ||
|
|
43cf907a2e | ||
|
|
0a04ba5743 | ||
|
|
8b1a40d2e2 | ||
|
|
51ae0784cf | ||
|
|
efa5d3f629 | ||
|
|
fd5861026d | ||
|
|
1535ef9aac | ||
|
|
bb6f1f32a0 | ||
|
|
3effdee5c0 | ||
|
|
bf15c5fb45 | ||
|
|
5c3ba9e0d8 | ||
|
|
ce0b39d48b | ||
|
|
71e3498876 | ||
|
|
e8ec05bd51 | ||
|
|
2303c32940 | ||
|
|
e9d54bf0d6 | ||
|
|
e435a68aea | ||
|
|
d55143e6fb | ||
|
|
e2719c373d | ||
|
|
b1e9f9b3f8 | ||
|
|
2d512053a8 | ||
|
|
6cfddb68bb | ||
|
|
12d04e84d8 | ||
|
|
829e569ccd | ||
|
|
7e300e8789 | ||
|
|
6a6a93aec4 | ||
|
|
13cba764cc | ||
|
|
5263005e92 | ||
|
|
1a12a6c10c | ||
|
|
0b134f9266 | ||
|
|
07233ba9ae | ||
|
|
92aaae40f6 | ||
|
|
faeeaf5ecf | ||
|
|
edfbc2d937 | ||
|
|
ab8f870e73 | ||
|
|
2a5798c107 | ||
|
|
92441110bf | ||
|
|
1a9d59e804 | ||
|
|
9e7b9c5fe4 | ||
|
|
615172d29c | ||
|
|
5671323bc1 | ||
|
|
c0263eb3c3 | ||
|
|
a5a5358f7b | ||
|
|
2599fd85d7 | ||
|
|
84a308e5dc | ||
|
|
569d50f25b | ||
|
|
93221b9760 | ||
|
|
81a7f63782 | ||
|
|
1c7fd533c7 | ||
|
|
a0d9420be2 | ||
|
|
544dc8b639 | ||
|
|
68f02bbc80 | ||
|
|
1660b0a75b | ||
|
|
d691189973 | ||
|
|
03da6c9a0c | ||
|
|
46b0ed44bd | ||
|
|
362000d6df | ||
|
|
fb8b65e61b | ||
|
|
03bded3775 | ||
|
|
f605dd3d49 | ||
|
|
303c4c909e | ||
|
|
8178dfc215 | ||
|
|
714226b6a5 | ||
|
|
383ac95e90 | ||
|
|
67232f5a8e | ||
|
|
d399c8f774 | ||
|
|
4e3c9c208f | ||
|
|
fb316d9f37 | ||
|
|
0c14d8641d | ||
|
|
7dceb23e3d | ||
|
|
704c642a8f | ||
|
|
230afd7414 | ||
|
|
f146f6a312 | ||
|
|
69d9885e30 | ||
|
|
ea3fe35790 | ||
|
|
a67c34f8f6 | ||
|
|
b5b61d05f8 | ||
|
|
581e912d4c | ||
|
|
f31942efdf | ||
|
|
238f08192f | ||
|
|
42c236e235 | ||
|
|
14163513e3 | ||
|
|
563208689b | ||
|
|
106461b2b2 | ||
|
|
0f5fbdf296 | ||
|
|
cfa6bb8689 | ||
|
|
ec23dcc3cb | ||
|
|
13d72338a5 | ||
|
|
25988bdb7b | ||
|
|
0a840b1cb0 | ||
|
|
ce292ce9d3 | ||
|
|
90ab5e6577 | ||
|
|
b15b569fce | ||
|
|
15ab70b524 | ||
|
|
6db159e944 | ||
|
|
35d3096ce4 | ||
|
|
cc2e0308d7 | ||
|
|
ca52a81141 | ||
|
|
4f1b8103d0 | ||
|
|
71487fce59 | ||
|
|
ff1b406c48 | ||
|
|
61418186b2 | ||
|
|
9d54ec44e4 | ||
|
|
60e27da57d | ||
|
|
5668d40bc1 | ||
|
|
33720c5079 | ||
|
|
88313e6d06 | ||
|
|
6d4edabb46 | ||
|
|
bfacc4a1ee | ||
|
|
f72404e22a | ||
|
|
340d109e72 | ||
|
|
87aa913f5f | ||
|
|
5a22ab54fb | ||
|
|
90f99985a0 | ||
|
|
6c8502d8fe | ||
|
|
64c2129b1d | ||
|
|
7a64851256 | ||
|
|
c358c794ec | ||
|
|
028c6d2823 | ||
|
|
96da369f62 | ||
|
|
43d4db022c | ||
|
|
221794026e | ||
|
|
16c460cdc2 | ||
|
|
89416bd714 | ||
|
|
56654e1ced | ||
|
|
7de8a86869 | ||
|
|
3220e91f1c | ||
|
|
2da663ecd1 | ||
|
|
2a89695b0b | ||
|
|
7ca74b3b0d | ||
|
|
b0b309b0f1 | ||
|
|
5e22f3b0da | ||
|
|
9d32c483eb | ||
|
|
78130a54aa | ||
|
|
1f49de9b27 | ||
|
|
1f085604ee | ||
|
|
4f593459b1 | ||
|
|
b8d3d68b65 | ||
|
|
004ee178a4 | ||
|
|
07eab50848 | ||
|
|
b3b6bdee4e | ||
|
|
eea003c170 | ||
|
|
1ca8813e58 | ||
|
|
64c9919e28 | ||
|
|
04f6a0b6be | ||
|
|
35ace0214a | ||
|
|
bbbc22f30f | ||
|
|
9ae0a7010c | ||
|
|
7fa4d20da0 | ||
|
|
b49514f52b | ||
|
|
92973c1c7b | ||
|
|
271126b665 | ||
|
|
ebb7d4cec6 | ||
|
|
f86e6256a7 | ||
|
|
ebf2ea50ed | ||
|
|
a877f5ac13 | ||
|
|
cbd2283bf8 | ||
|
|
fca3c46372 | ||
|
|
b43957e6f9 | ||
|
|
57036aaffb |
4
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: [tapframe]
|
||||
ko_fi: tapframe
|
||||
28
.gitignore
vendored
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
# dependencies
|
||||
node_modules/
|
||||
!node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
|
||||
|
||||
# Expo
|
||||
.expo/
|
||||
|
|
@ -40,11 +41,14 @@ release_announcement.md
|
|||
ALPHA_BUILD_2_ANNOUNCEMENT.md
|
||||
CHANGELOG.md
|
||||
.env.local
|
||||
android/
|
||||
# Android build artifacts (but keep source files)
|
||||
android/app/build/
|
||||
android/build/
|
||||
android/.gradle/
|
||||
android/app/libs/*.aar
|
||||
!android/app/libs/lib-decoder-ffmpeg-release.aar
|
||||
HEATING_OPTIMIZATIONS.md
|
||||
|
||||
android
|
||||
sliderreadme.md
|
||||
# sliderreadme.md
|
||||
.cursor/mcp.json
|
||||
local-scrapers-repo
|
||||
worki.json
|
||||
|
|
@ -54,4 +58,18 @@ hackintosh-emulator-fix.sh
|
|||
src/screens/xavio.md
|
||||
/nuvio-providers
|
||||
/KSPlayer
|
||||
/exobase
|
||||
/exobase
|
||||
# ffmpegreadme.md
|
||||
toast.md
|
||||
ffmpegreadme.md
|
||||
sliderreadme.md
|
||||
bottomsheet.md
|
||||
fastimage.md
|
||||
|
||||
# Backup directories
|
||||
backup_sdk54_upgrade/
|
||||
SDK54_UPGRADE_SUMMARY.md
|
||||
SDK54_UPGRADE_SUMMARY.md
|
||||
build-and-publish-app-releases.sh
|
||||
bottomnav.md
|
||||
/TrailerServices
|
||||
|
|
|
|||
1
.vscode/settings.json
vendored
|
|
@ -1,2 +1,3 @@
|
|||
{
|
||||
"java.compile.nullAnalysis.mode": "automatic"
|
||||
}
|
||||
78
App.tsx
|
|
@ -10,7 +10,8 @@ import {
|
|||
View,
|
||||
StyleSheet,
|
||||
I18nManager,
|
||||
Platform
|
||||
Platform,
|
||||
LogBox
|
||||
} from 'react-native';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
|
|
@ -27,8 +28,11 @@ import { GenreProvider } from './src/contexts/GenreContext';
|
|||
import { TraktProvider } from './src/contexts/TraktContext';
|
||||
import { ThemeProvider, useTheme } from './src/contexts/ThemeContext';
|
||||
import { TrailerProvider } from './src/contexts/TrailerContext';
|
||||
import { DownloadsProvider } from './src/contexts/DownloadsContext';
|
||||
import SplashScreen from './src/components/SplashScreen';
|
||||
import UpdatePopup from './src/components/UpdatePopup';
|
||||
import MajorUpdateOverlay from './src/components/MajorUpdateOverlay';
|
||||
import { useGithubMajorUpdate } from './src/hooks/useGithubMajorUpdate';
|
||||
import { useUpdatePopup } from './src/hooks/useUpdatePopup';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import * as Sentry from '@sentry/react-native';
|
||||
|
|
@ -36,6 +40,7 @@ import UpdateService from './src/services/updateService';
|
|||
import { memoryMonitorService } from './src/services/memoryMonitorService';
|
||||
import { aiService } from './src/services/aiService';
|
||||
import { AccountProvider, useAccount } from './src/contexts/AccountContext';
|
||||
import { ToastProvider } from './src/contexts/ToastContext';
|
||||
|
||||
Sentry.init({
|
||||
dsn: 'https://1a58bf436454d346e5852b7bfd3c95e8@o4509536317276160.ingest.de.sentry.io/4509536317734992',
|
||||
|
|
@ -58,6 +63,12 @@ Sentry.init({
|
|||
I18nManager.allowRTL(false);
|
||||
I18nManager.forceRTL(false);
|
||||
|
||||
// Suppress duplicate key warnings app-wide
|
||||
LogBox.ignoreLogs([
|
||||
'Warning: Encountered two children with the same key',
|
||||
'Keys should be unique so that components maintain their identity across updates'
|
||||
]);
|
||||
|
||||
// This fixes many navigation layout issues by using native screen containers
|
||||
enableScreens(true);
|
||||
|
||||
|
|
@ -84,6 +95,9 @@ const ThemedApp = () => {
|
|||
handleUpdateLater,
|
||||
handleDismiss,
|
||||
} = useUpdatePopup();
|
||||
|
||||
// GitHub major/minor release overlay
|
||||
const githubUpdate = useGithubMajorUpdate();
|
||||
|
||||
// Check onboarding status and initialize services
|
||||
useEffect(() => {
|
||||
|
|
@ -144,37 +158,39 @@ const ThemedApp = () => {
|
|||
const shouldShowApp = isAppReady && hasCompletedOnboarding !== null;
|
||||
const initialRouteName = hasCompletedOnboarding ? 'MainTabs' : 'Onboarding';
|
||||
|
||||
const NavigationWithRef = () => {
|
||||
const { navigationRef } = useAccount() as any;
|
||||
return (
|
||||
<NavigationContainer
|
||||
ref={navigationRef as any}
|
||||
theme={customNavigationTheme}
|
||||
linking={undefined}
|
||||
>
|
||||
<View style={[styles.container, { backgroundColor: currentTheme.colors.darkBackground }]}>
|
||||
<StatusBar style="light" />
|
||||
{!isAppReady && <SplashScreen onFinish={handleSplashComplete} />}
|
||||
{shouldShowApp && <AppNavigator initialRouteName={initialRouteName} />}
|
||||
{Platform.OS === 'ios' && (
|
||||
<UpdatePopup
|
||||
visible={showUpdatePopup}
|
||||
updateInfo={updateInfo}
|
||||
onUpdateNow={handleUpdateNow}
|
||||
onUpdateLater={handleUpdateLater}
|
||||
onDismiss={handleDismiss}
|
||||
isInstalling={isInstalling}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</NavigationContainer>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<AccountProvider>
|
||||
<PaperProvider theme={customDarkTheme}>
|
||||
<NavigationWithRef />
|
||||
<NavigationContainer
|
||||
theme={customNavigationTheme}
|
||||
linking={undefined}
|
||||
>
|
||||
<DownloadsProvider>
|
||||
<View style={[styles.container, { backgroundColor: currentTheme.colors.darkBackground }]}>
|
||||
<StatusBar style="light" />
|
||||
{!isAppReady && <SplashScreen onFinish={handleSplashComplete} />}
|
||||
{shouldShowApp && <AppNavigator initialRouteName={initialRouteName} />}
|
||||
{Platform.OS === 'ios' && (
|
||||
<UpdatePopup
|
||||
visible={showUpdatePopup}
|
||||
updateInfo={updateInfo}
|
||||
onUpdateNow={handleUpdateNow}
|
||||
onUpdateLater={handleUpdateLater}
|
||||
onDismiss={handleDismiss}
|
||||
isInstalling={isInstalling}
|
||||
/>
|
||||
)}
|
||||
<MajorUpdateOverlay
|
||||
visible={githubUpdate.visible}
|
||||
latestTag={githubUpdate.latestTag}
|
||||
releaseNotes={githubUpdate.releaseNotes}
|
||||
releaseUrl={githubUpdate.releaseUrl}
|
||||
onDismiss={githubUpdate.onDismiss}
|
||||
onLater={githubUpdate.onLater}
|
||||
/>
|
||||
</View>
|
||||
</DownloadsProvider>
|
||||
</NavigationContainer>
|
||||
</PaperProvider>
|
||||
</AccountProvider>
|
||||
);
|
||||
|
|
@ -188,7 +204,9 @@ function App(): React.JSX.Element {
|
|||
<TraktProvider>
|
||||
<ThemeProvider>
|
||||
<TrailerProvider>
|
||||
<ThemedApp />
|
||||
<ToastProvider>
|
||||
<ThemedApp />
|
||||
</ToastProvider>
|
||||
</TrailerProvider>
|
||||
</ThemeProvider>
|
||||
</TraktProvider>
|
||||
|
|
|
|||
232
README.md
|
|
@ -1,86 +1,184 @@
|
|||
# Nuvio Media Hub
|
||||
<!-- Improved compatibility of back to top link -->
|
||||
<a id="readme-top"></a>
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/titlelogo.png" alt="Nuvio Logo" width="300"/>
|
||||
</p>
|
||||
<!-- PROJECT SHIELDS -->
|
||||
[![Contributors][contributors-shield]][contributors-url]
|
||||
[![Forks][forks-shield]][forks-url]
|
||||
[![Stargazers][stars-shield]][stars-url]
|
||||
[![Issues][issues-shield]][issues-url]
|
||||
[![License][license-shield]][license-url]
|
||||
|
||||
<p align="center">
|
||||
A modern media hub built with React Native and Expo, featuring comprehensive addon integration and content synchronization.
|
||||
</p>
|
||||
<!-- PROJECT LOGO -->
|
||||
<br />
|
||||
<div align="center">
|
||||
<img src="assets/titlelogo.png" alt="Nuvio Logo" width="120" />
|
||||
<h1 align="center">🎬 Nuvio Media Hub</h1>
|
||||
<p align="center">
|
||||
A modern media hub built with React Native and Expo
|
||||
<br />
|
||||
Stremio Addon ecosystem • Cross‑platform • Offline metadata & sync
|
||||
<br />
|
||||
<br />
|
||||
<a href="#getting-started"><strong>Get Started »</strong></a>
|
||||
<br />
|
||||
<br />
|
||||
<a href="#demo">View Screenshots</a>
|
||||
·
|
||||
<a href="https://github.com/tapframe/NuvioStreaming/issues/new?labels=bug&template=bug_report.md">Report Bug</a>
|
||||
·
|
||||
<a href="https://github.com/tapframe/NuvioStreaming/issues/new?labels=enhancement&template=feature_request.md">Request Feature</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
---
|
||||
<!-- TABLE OF CONTENTS -->
|
||||
<details>
|
||||
<summary>Table of Contents</summary>
|
||||
<ol>
|
||||
<li>
|
||||
<a href="#about-the-project">About The Project</a>
|
||||
</li>
|
||||
<li><a href="#demo">Screenshots</a></li>
|
||||
<li>
|
||||
<a href="#getting-started">Getting Started</a>
|
||||
<ul>
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#build">Build</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#contributing">Contributing</a></li>
|
||||
<li><a href="#support">Support</a></li>
|
||||
<li><a href="#license">License</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
<li><a href="#acknowledgments">Acknowledgments</a></li>
|
||||
<li><a href="#built-with">Built With</a></li>
|
||||
</ol>
|
||||
</details>
|
||||
|
||||
## Installation
|
||||
<!-- ABOUT THE PROJECT -->
|
||||
## About The Project
|
||||
|
||||
### AltStore
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/2/20/AltStore_logo.png" width="32" height="32" align="left"> [](https://tinyurl.com/NuvioAltstore)
|
||||
Nuvio Media Hub is a cross‑platform app for managing, discovering, and streaming your media via a flexible addon ecosystem. Built with React Native + Expo, it integrates providers and sync services while keeping a simple, fast UI.
|
||||
|
||||
### SideStore
|
||||
<img src="https://github.com/SideStore/assets/blob/main/icon.png?raw=true" width="32" height="32" align="left"> [](https://tinyurl.com/NuvioSidestore)
|
||||
|
||||
|
||||
**Manual URL:** `https://raw.githubusercontent.com/tapframe/NuvioStreaming/main/nuvio-source.json`
|
||||
|
||||
---
|
||||
|
||||
## Screenshots
|
||||
<!-- DEMO / SCREENSHOTS -->
|
||||
## Demo
|
||||
<a id="demo"></a>
|
||||
|
||||
| Home | Details |
|
||||
|:----:|:-------:|
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
---
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
## Tech Stack
|
||||
<!-- GETTING STARTED -->
|
||||
## Getting Started
|
||||
|
||||
Follow the steps below to run the app locally.
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
git clone https://github.com/tapframe/NuvioStreaming.git
|
||||
cd NuvioStreaming
|
||||
npm install
|
||||
# If you hit peer dependency conflicts:
|
||||
# npm install --legacy-peer-deps
|
||||
npx expo start
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
npx expo prebuild
|
||||
npx expo run:android # Android
|
||||
npx expo run:ios # iOS
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Alternative iOS Installation</summary>
|
||||
|
||||
### AltStore
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/2/20/AltStore_logo.png" width="24" height="24" align="left"> [](https://tinyurl.com/NuvioAltstore)
|
||||
|
||||
### SideStore
|
||||
<img src="https://github.com/SideStore/assets/blob/main/icon.png?raw=true" width="24" height="24" align="left"> [](https://tinyurl.com/NuvioSidestore)
|
||||
|
||||
**Manual URL:** `https://raw.githubusercontent.com/tapframe/NuvioStreaming/main/nuvio-source.json`
|
||||
|
||||
</details>
|
||||
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions make the open‑source community amazing! Any contributions are greatly appreciated.
|
||||
|
||||
1. Fork the project
|
||||
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
## Support
|
||||
|
||||
If you find Nuvio helpful, consider supporting development:
|
||||
|
||||
* **Ko‑Fi** – `https://ko-fi.com/tapframe`
|
||||
* **GitHub Star** – Star the repo to show support
|
||||
* **Share** – Tell others about the project
|
||||
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the GNU GPLv3 License. See `LICENSE` for more information.
|
||||
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
## Contact
|
||||
|
||||
**Project Links:**
|
||||
* GitHub: `https://github.com/tapframe`
|
||||
* Issues: `https://github.com/tapframe/NuvioStreaming/issues`
|
||||
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
* [React Native](https://reactnative.dev/)
|
||||
* [Expo](https://expo.dev/)
|
||||
* [TypeScript](https://www.typescriptlang.org/)
|
||||
* Community contributors and testers
|
||||
|
||||
**Disclaimer:** This application functions as a media hub with addon/plugin support. It does not contain any built‑in content or host media content. Content access is only available through user‑installed plugins and addons. Any legal concerns should be directed to the specific websites providing the content.
|
||||
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
## Built With
|
||||
|
||||
<p align="left">
|
||||
<a href="https://skillicons.dev">
|
||||
<img src="https://skillicons.dev/icons?i=react,typescript,nodejs,expo,github,githubactions&theme=light&perline=6" />
|
||||
</a>
|
||||
</p>
|
||||
<br/>
|
||||
React Native • Expo • TypeScript
|
||||
</p>
|
||||
|
||||
---
|
||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||
|
||||
## Development
|
||||
|
||||
### Setup
|
||||
```bash
|
||||
git clone https://github.com/tapframe/NuvioStreaming.git
|
||||
cd NuvioStreaming
|
||||
npm install
|
||||
npx expo start
|
||||
```
|
||||
|
||||
### Build
|
||||
```bash
|
||||
npx expo run:android # Android
|
||||
npx expo run:ios # iOS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes
|
||||
4. Submit a pull request
|
||||
|
||||
---
|
||||
|
||||
## Issues
|
||||
|
||||
Report bugs and request features via [GitHub Issues](https://github.com/tapframe/NuvioStreaming/issues)
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
[](http://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
This project is licensed under the GNU General Public License v3.0.
|
||||
|
||||
---
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This application functions as a media hub with addon/plugin support. It does not contain any built-in content or host media content. Content access is only available through user-installed plugins and addons. Any legal concerns should be directed to the specific websites providing the content.
|
||||
<!-- MARKDOWN LINKS & IMAGES -->
|
||||
[contributors-shield]: https://img.shields.io/github/contributors/tapframe/NuvioStreaming.svg?style=for-the-badge
|
||||
[contributors-url]: https://github.com/tapframe/NuvioStreaming/graphs/contributors
|
||||
[forks-shield]: https://img.shields.io/github/forks/tapframe/NuvioStreaming.svg?style=for-the-badge
|
||||
[forks-url]: https://github.com/tapframe/NuvioStreaming/network/members
|
||||
[stars-shield]: https://img.shields.io/github/stars/tapframe/NuvioStreaming.svg?style=for-the-badge
|
||||
[stars-url]: https://github.com/tapframe/NuvioStreaming/stargazers
|
||||
[issues-shield]: https://img.shields.io/github/issues/tapframe/NuvioStreaming.svg?style=for-the-badge
|
||||
[issues-url]: https://github.com/tapframe/NuvioStreaming/issues
|
||||
[license-shield]: https://img.shields.io/github/license/tapframe/NuvioStreaming.svg?style=for-the-badge
|
||||
[license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
|
|
@ -14,6 +14,7 @@ react {
|
|||
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
|
||||
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
||||
|
||||
enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean()
|
||||
// Use Expo CLI to bundle the app, this ensures the Metro config
|
||||
// works correctly with Expo projects.
|
||||
cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
|
||||
|
|
@ -63,9 +64,9 @@ react {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||
* Set this to true in release builds to optimize the app using [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization).
|
||||
*/
|
||||
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
|
||||
def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean()
|
||||
|
||||
/**
|
||||
* The preferred build flavor of JavaScriptCore (JSC)
|
||||
|
|
@ -78,9 +79,9 @@ def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInRelea
|
|||
* give correct results when using with locales other than en-US. Note that
|
||||
* this variant is about 6MiB larger per architecture than default.
|
||||
*/
|
||||
def jscFlavor = 'org.webkit:android-jsc:+'
|
||||
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
||||
|
||||
apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle")
|
||||
// apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle")
|
||||
|
||||
android {
|
||||
ndkVersion rootProject.ext.ndkVersion
|
||||
|
|
@ -93,16 +94,39 @@ android {
|
|||
applicationId 'com.nuvio.app'
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 16
|
||||
versionName "1.2.1"
|
||||
versionCode 21
|
||||
versionName "1.2.6"
|
||||
|
||||
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
|
||||
}
|
||||
|
||||
|
||||
// Split APKs by architecture only for smaller downloads
|
||||
splits {
|
||||
abi {
|
||||
reset()
|
||||
enable true
|
||||
universalApk false // If true, also generate a universal APK
|
||||
include "arm64-v8a", "armeabi-v7a", "x86", "x86_64"
|
||||
reset()
|
||||
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
universalApk true
|
||||
}
|
||||
density {
|
||||
enable false
|
||||
}
|
||||
}
|
||||
|
||||
// Generate unique version codes for each split APK
|
||||
def abiVersionCodes = ['armeabi-v7a': 1, 'arm64-v8a': 2, 'x86': 3, 'x86_64': 4]
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def baseVersionCode = 21 // Current versionCode 21 from defaultConfig
|
||||
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
|
||||
|
||||
def versionCode = baseVersionCode * 100 // Base multiplier
|
||||
|
||||
if (abiName != null) {
|
||||
versionCode += abiVersionCodes.get(abiName)
|
||||
}
|
||||
|
||||
output.versionCodeOverride = versionCode
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
|
|
@ -121,15 +145,18 @@ android {
|
|||
// Caution! In production, you need to generate your own keystore file.
|
||||
// see https://reactnative.dev/docs/signed-apk-android.
|
||||
signingConfig signingConfigs.debug
|
||||
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
|
||||
minifyEnabled enableProguardInReleaseBuilds
|
||||
def enableShrinkResources = findProperty('android.enableShrinkResourcesInReleaseBuilds') ?: 'false'
|
||||
shrinkResources enableShrinkResources.toBoolean()
|
||||
minifyEnabled enableMinifyInReleaseBuilds
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
|
||||
def enablePngCrunchInRelease = findProperty('android.enablePngCrunchInReleaseBuilds') ?: 'true'
|
||||
crunchPngs enablePngCrunchInRelease.toBoolean()
|
||||
}
|
||||
}
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
|
||||
def enableLegacyPackaging = findProperty('expo.useLegacyPackaging') ?: 'false'
|
||||
useLegacyPackaging enableLegacyPackaging.toBoolean()
|
||||
}
|
||||
}
|
||||
androidResources {
|
||||
|
|
@ -167,15 +194,15 @@ dependencies {
|
|||
|
||||
if (isGifEnabled) {
|
||||
// For animated gif support
|
||||
implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}")
|
||||
implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}")
|
||||
}
|
||||
|
||||
if (isWebpEnabled) {
|
||||
// For webp support
|
||||
implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}")
|
||||
implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}")
|
||||
if (isWebpAnimatedEnabled) {
|
||||
// Animated webp support
|
||||
implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}")
|
||||
implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -184,4 +211,7 @@ dependencies {
|
|||
} else {
|
||||
implementation jscFlavor
|
||||
}
|
||||
|
||||
// Include only FFmpeg decoder AAR to avoid duplicates with Maven Media3
|
||||
implementation files("libs/lib-decoder-ffmpeg-release.aar")
|
||||
}
|
||||
|
|
|
|||
BIN
android/app/libs/lib-decoder-ffmpeg-release.aar
Normal file
14
android/app/proguard-rules.pro
vendored
|
|
@ -12,3 +12,17 @@
|
|||
-keep class com.facebook.react.turbomodule.** { *; }
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# Media3 / ExoPlayer keep (extensions and reflection)
|
||||
-keep class androidx.media3.** { *; }
|
||||
-dontwarn androidx.media3.**
|
||||
|
||||
# FastImage / Glide ProGuard rules
|
||||
-keep public class com.dylanvann.fastimage.* {*;}
|
||||
-keep public class com.dylanvann.fastimage.** {*;}
|
||||
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||
-keep public class * extends com.bumptech.glide.module.AppGlideModule
|
||||
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
}
|
||||
|
|
|
|||
7
android/app/src/debugOptimized/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
|
||||
</manifest>
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
<data android:scheme="https"/>
|
||||
</intent>
|
||||
</queries>
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:enableOnBackInvokedCallback="false">
|
||||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="@string/expo_runtime_version"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ERROR_RECOVERY_ONLY"/>
|
||||
|
|
@ -29,7 +29,6 @@
|
|||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="nuvio"/>
|
||||
<data android:scheme="com.nuvio.app"/>
|
||||
<data android:scheme="exp+nuvio"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import android.content.res.Configuration
|
|||
|
||||
import com.facebook.react.PackageList
|
||||
import com.facebook.react.ReactApplication
|
||||
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
|
||||
import com.facebook.react.ReactNativeHost
|
||||
import com.facebook.react.ReactPackage
|
||||
import com.facebook.react.ReactHost
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
|
||||
import com.facebook.react.common.ReleaseLevel
|
||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
|
||||
import com.facebook.react.defaults.DefaultReactNativeHost
|
||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
||||
import com.facebook.soloader.SoLoader
|
||||
|
||||
import expo.modules.ApplicationLifecycleDispatcher
|
||||
import expo.modules.ReactNativeHostWrapper
|
||||
|
|
@ -19,21 +19,19 @@ import expo.modules.ReactNativeHostWrapper
|
|||
class MainApplication : Application(), ReactApplication {
|
||||
|
||||
override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
|
||||
this,
|
||||
object : DefaultReactNativeHost(this) {
|
||||
override fun getPackages(): List<ReactPackage> {
|
||||
val packages = PackageList(this).packages
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// packages.add(new MyReactNativePackage());
|
||||
return packages
|
||||
}
|
||||
this,
|
||||
object : DefaultReactNativeHost(this) {
|
||||
override fun getPackages(): List<ReactPackage> =
|
||||
PackageList(this).packages.apply {
|
||||
// Packages that cannot be autolinked yet can be added manually here, for example:
|
||||
// add(MyReactNativePackage())
|
||||
}
|
||||
|
||||
override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
|
||||
|
||||
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
||||
|
||||
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
||||
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -42,11 +40,12 @@ class MainApplication : Application(), ReactApplication {
|
|||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
SoLoader.init(this, OpenSourceMergedSoMapping)
|
||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||
load()
|
||||
DefaultNewArchitectureEntryPoint.releaseLevel = try {
|
||||
ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase())
|
||||
} catch (e: IllegalArgumentException) {
|
||||
ReleaseLevel.STABLE
|
||||
}
|
||||
loadReactNative(this)
|
||||
ApplicationLifecycleDispatcher.onApplicationCreate(this)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 7 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 28 KiB |
|
|
@ -3,5 +3,5 @@
|
|||
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
|
||||
<string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string>
|
||||
<string name="expo_system_ui_user_interface_style" translatable="false">dark</string>
|
||||
<string name="expo_runtime_version">1.2.1</string>
|
||||
<string name="expo_runtime_version">1.2.6</string>
|
||||
</resources>
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:editTextStyle">@style/ResetEditText</item>
|
||||
<style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="android:enforceNavigationBarContrast" tools:targetApi="29">true</item>
|
||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="android:statusBarColor">#020404</item>
|
||||
<item name="android:windowBackground">@color/activityBackground</item>
|
||||
</style>
|
||||
<style name="ResetEditText" parent="@android:style/Widget.EditText">
|
||||
<item name="android:padding">0dp</item>
|
||||
<item name="android:textColorHint">#c8c8c8</item>
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
</style>
|
||||
<style name="Theme.App.SplashScreen" parent="AppTheme">
|
||||
<item name="android:windowBackground">@drawable/ic_launcher_background</item>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,41 +1,24 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
|
||||
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
|
||||
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
|
||||
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
|
||||
kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.25'
|
||||
|
||||
ndkVersion = "26.1.10909125"
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath('com.android.tools.build:gradle')
|
||||
classpath('com.facebook.react:react-native-gradle-plugin')
|
||||
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath('com.android.tools.build:gradle')
|
||||
classpath('com.facebook.react:react-native-gradle-plugin')
|
||||
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "com.facebook.react.rootproject"
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven {
|
||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||
url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
|
||||
}
|
||||
maven {
|
||||
// Android JSC is installed from npm
|
||||
url(new File(['node', '--print', "require.resolve('jsc-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), '../dist'))
|
||||
}
|
||||
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: "expo-root-project"
|
||||
apply plugin: "com.facebook.react.rootproject"
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@
|
|||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
|
||||
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
|
||||
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
|
|
@ -41,6 +41,11 @@ newArchEnabled=true
|
|||
# If set to false, you will be using JSC instead.
|
||||
hermesEnabled=true
|
||||
|
||||
# Use this property to enable edge-to-edge display support.
|
||||
# This allows your app to draw behind system bars for an immersive UI.
|
||||
# Note: Only works with ReactActivity and should not be used with custom Activity.
|
||||
edgeToEdgeEnabled=true
|
||||
|
||||
# Enable GIF support in React Native images (~200 B increase)
|
||||
expo.gif.enabled=true
|
||||
# Enable webp support in React Native images (~85 KB increase)
|
||||
|
|
@ -54,7 +59,7 @@ EX_DEV_CLIENT_NETWORK_INSPECTOR=true
|
|||
|
||||
# Use legacy packaging to compress native libraries in the resulting APK.
|
||||
expo.useLegacyPackaging=false
|
||||
android.minSdkVersion=26
|
||||
|
||||
# Whether the app is configured to use edge-to-edge via the app config or `react-native-edge-to-edge` plugin
|
||||
expo.edgeToEdgeEnabled=false
|
||||
# Specifies whether the app is configured to use edge-to-edge via the app config or plugin
|
||||
# WARNING: This property has been deprecated and will be removed in Expo SDK 55. Use `edgeToEdgeEnabled` or `react.edgeToEdgeEnabled` to determine whether the project is using edge-to-edge.
|
||||
expo.edgeToEdgeEnabled=true
|
||||
|
|
|
|||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
|
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
|||
7
android/gradlew
vendored
|
|
@ -86,8 +86,7 @@ done
|
|||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
|
@ -115,7 +114,7 @@ case "$( uname )" in #(
|
|||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
|
|
@ -214,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
|
|
|||
4
android/gradlew.bat
vendored
|
|
@ -70,11 +70,11 @@ goto fail
|
|||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
|
|
|||
|
|
@ -1,38 +1,39 @@
|
|||
pluginManagement {
|
||||
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().toString())
|
||||
def reactNativeGradlePlugin = new File(
|
||||
providers.exec {
|
||||
workingDir(rootDir)
|
||||
commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
|
||||
}.standardOutput.asText.get().trim()
|
||||
).getParentFile().absolutePath
|
||||
includeBuild(reactNativeGradlePlugin)
|
||||
|
||||
def expoPluginsPath = new File(
|
||||
providers.exec {
|
||||
workingDir(rootDir)
|
||||
commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
|
||||
}.standardOutput.asText.get().trim(),
|
||||
"../android/expo-gradle-plugin"
|
||||
).absolutePath
|
||||
includeBuild(expoPluginsPath)
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.facebook.react.settings")
|
||||
id("expo-autolinking-settings")
|
||||
}
|
||||
plugins { id("com.facebook.react.settings") }
|
||||
|
||||
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
|
||||
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
|
||||
ex.autolinkLibrariesFromCommand()
|
||||
} else {
|
||||
def command = [
|
||||
'node',
|
||||
'--no-warnings',
|
||||
'--eval',
|
||||
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
|
||||
'react-native-config',
|
||||
'--json',
|
||||
'--platform',
|
||||
'android'
|
||||
].toList()
|
||||
ex.autolinkLibrariesFromCommand(command)
|
||||
ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand)
|
||||
}
|
||||
}
|
||||
expoAutolinking.useExpoModules()
|
||||
|
||||
rootProject.name = 'Nuvio'
|
||||
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
reactAndroidLibs {
|
||||
from(files(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../gradle/libs.versions.toml")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
|
||||
useExpoModules()
|
||||
expoAutolinking.useExpoVersionCatalog()
|
||||
|
||||
include ':app'
|
||||
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile())
|
||||
includeBuild(expoAutolinking.reactNativeGradlePlugin)
|
||||
|
|
|
|||
13
app.json
|
|
@ -2,7 +2,7 @@
|
|||
"expo": {
|
||||
"name": "Nuvio",
|
||||
"slug": "nuvio",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.6",
|
||||
"orientation": "default",
|
||||
"backgroundColor": "#020404",
|
||||
"icon": "./assets/ios/AppIcon.appiconset/Icon-App-60x60@3x.png",
|
||||
|
|
@ -10,14 +10,14 @@
|
|||
"scheme": "nuvio",
|
||||
"newArchEnabled": true,
|
||||
"splash": {
|
||||
"image": "./assets/splash-icon.png",
|
||||
"image": "./src/assets/splash-icon-new.png",
|
||||
"resizeMode": "contain",
|
||||
"backgroundColor": "#020404"
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"icon": "./assets/ios/AppIcon.appiconset/Icon-App-60x60@3x.png",
|
||||
"buildNumber": "16",
|
||||
"buildNumber": "21",
|
||||
"infoPlist": {
|
||||
"NSAppTransportSecurity": {
|
||||
"NSAllowsArbitraryLoads": true
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
"WAKE_LOCK"
|
||||
],
|
||||
"package": "com.nuvio.app",
|
||||
"versionCode": 16,
|
||||
"versionCode": 21,
|
||||
"architectures": [
|
||||
"arm64-v8a",
|
||||
"armeabi-v7a",
|
||||
|
|
@ -86,7 +86,8 @@
|
|||
"localNetworkPermission": "Allow $(PRODUCT_NAME) to access your local network",
|
||||
"supportsBackgroundPlayback": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"react-native-bottom-tabs"
|
||||
],
|
||||
"updates": {
|
||||
"enabled": true,
|
||||
|
|
@ -94,6 +95,6 @@
|
|||
"fallbackToCacheTimeout": 30000,
|
||||
"url": "https://grim-reyna-tapframe-69970143.koyeb.app/api/manifest"
|
||||
},
|
||||
"runtimeVersion": "1.2.1"
|
||||
"runtimeVersion": "1.2.6"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
app/Streams.tsx
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
BIN
assets/AppIcons/android/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4 KiB |
BIN
assets/AppIcons/android/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/AppIcons/android/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
assets/AppIcons/android/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/AppIcons/android/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 8 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 85 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#151515</color>
|
||||
<color name="ic_launcher_background">#2f2f2f</color>
|
||||
</resources>
|
||||
BIN
assets/bootsplash/android/drawable-hdpi/bootsplash_logo.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
assets/bootsplash/android/drawable-mdpi/bootsplash_logo.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
assets/bootsplash/android/drawable-xhdpi/bootsplash_logo.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
assets/bootsplash/android/drawable-xxhdpi/bootsplash_logo.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
assets/bootsplash/android/drawable-xxxhdpi/bootsplash_logo.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 111 KiB |
BIN
assets/icon.png
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 785 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 280 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 280 KiB |
|
Before Width: | Height: | Size: 423 KiB After Width: | Height: | Size: 583 KiB |
|
|
@ -3,7 +3,8 @@ module.exports = function (api) {
|
|||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
plugins: [
|
||||
'react-native-reanimated/plugin',
|
||||
'react-native-worklets/plugin',
|
||||
'react-native-boost/plugin',
|
||||
],
|
||||
env: {
|
||||
production: {
|
||||
|
|
|
|||
173
backup_sdk54_upgrade/NATIVE_MODIFICATIONS_GUIDE.md
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
# Native Modifications Guide - SDK 54 Upgrade
|
||||
|
||||
**Created:** October 14, 2025
|
||||
**From SDK:** 52
|
||||
**To SDK:** 54
|
||||
|
||||
## Overview
|
||||
|
||||
This document records all custom native modifications made to the Nuvio app that need to be preserved during the Expo SDK 54 upgrade.
|
||||
|
||||
---
|
||||
|
||||
## iOS Modifications
|
||||
|
||||
### 1. KSPlayer Bridge Integration
|
||||
|
||||
**Purpose:** Custom video player for iOS using KSPlayer library
|
||||
|
||||
**Files Added/Modified:**
|
||||
- `ios/KSPlayerManager.m` - Objective-C bridge header
|
||||
- `ios/KSPlayerModule.swift` - Swift module for KSPlayer
|
||||
- `ios/KSPlayerView.swift` - Main player view implementation
|
||||
- `ios/KSPlayerViewManager.swift` - React Native view manager
|
||||
|
||||
**Location in Xcode Project:**
|
||||
- Files are in `ios/Nuvio/` directory
|
||||
- Referenced in `ios/Nuvio.xcodeproj/project.pbxproj`
|
||||
|
||||
**Podfile Dependencies (lines 52-56):**
|
||||
```ruby
|
||||
# KSPlayer dependencies
|
||||
pod 'KSPlayer',:git => 'https://github.com/kingslay/KSPlayer.git', :branch => 'main', :modular_headers => true
|
||||
pod 'DisplayCriteria',:git => 'https://github.com/kingslay/KSPlayer.git', :branch => 'main', :modular_headers => true
|
||||
pod 'FFmpegKit',:git => 'https://github.com/kingslay/FFmpegKit.git', :branch => 'main', :modular_headers => true
|
||||
pod 'Libass',:git => 'https://github.com/kingslay/FFmpegKit.git', :branch => 'main', :modular_headers => true
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Custom video player with multi-codec support
|
||||
- Audio track selection
|
||||
- Subtitle track selection
|
||||
- Advanced playback controls
|
||||
- Header injection for streaming
|
||||
- Multi-channel audio downmixing
|
||||
|
||||
**Restoration Steps:**
|
||||
1. Copy KSPlayer bridge files to `ios/` directory after prebuild
|
||||
2. Add Podfile dependencies
|
||||
3. Run `pod install`
|
||||
4. Ensure files are linked in Xcode project
|
||||
|
||||
---
|
||||
|
||||
## Android Modifications
|
||||
|
||||
### 1. FFmpeg Audio Decoder Extension
|
||||
|
||||
**Purpose:** Enable ExoPlayer to play AC3, E-AC3, DTS, TrueHD audio codecs via FFmpeg
|
||||
|
||||
**Files Added:**
|
||||
- `android/app/libs/lib-decoder-ffmpeg-release.aar` - FFmpeg decoder AAR from Media3
|
||||
|
||||
**build.gradle Modifications (line 189):**
|
||||
```gradle
|
||||
// Include only FFmpeg decoder AAR to avoid duplicates with Maven Media3
|
||||
implementation files("libs/lib-decoder-ffmpeg-release.aar")
|
||||
```
|
||||
|
||||
**proguard-rules.pro Additions (lines 16-18):**
|
||||
```proguard
|
||||
# Media3 / ExoPlayer keep (extensions and reflection)
|
||||
-keep class androidx.media3.** { *; }
|
||||
-dontwarn androidx.media3.**
|
||||
```
|
||||
|
||||
**Node Modules Modification:**
|
||||
- File: `node_modules/react-native-video/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java`
|
||||
- Change: Set extension renderer mode to PREFER to use FFmpeg decoders
|
||||
```java
|
||||
new DefaultRenderersFactory(getContext())
|
||||
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER)
|
||||
```
|
||||
|
||||
**Important Notes:**
|
||||
- FFmpeg module provides AUDIO decoders only (AC3, E-AC3, DTS, TrueHD)
|
||||
- Does NOT provide video decoders (HEVC/Dolby Vision rely on device hardware or VLC fallback)
|
||||
- The AAR is from Just Player base (`exobase/app/libs`)
|
||||
|
||||
**Restoration Steps:**
|
||||
1. Copy `lib-decoder-ffmpeg-release.aar` to `android/app/libs/`
|
||||
2. Add implementation line to `android/app/build.gradle`
|
||||
3. Add keep rules to `android/app/proguard-rules.pro`
|
||||
4. Modify `ReactExoplayerView.java` in node_modules (after npm install)
|
||||
|
||||
---
|
||||
|
||||
## Application Logic Changes
|
||||
|
||||
### Player Fallback Strategy
|
||||
|
||||
**Modified Files:**
|
||||
- `src/screens/StreamsScreen.tsx` - Removed MKV pre-forcing to VLC
|
||||
- `src/components/player/AndroidVideoPlayer.tsx` - Error handler toggles `forceVlc`
|
||||
|
||||
**Behavior:**
|
||||
- Start with ExoPlayer + FFmpeg audio decoders by default
|
||||
- On decoder errors (codec not supported), automatically switch to VLC
|
||||
- Do not pre-force VLC based on file extension
|
||||
|
||||
---
|
||||
|
||||
## Backup Location
|
||||
|
||||
All backups are stored in: `/Users/nayifnoushad/Documents/Projects/NuvioStreaming/backup_sdk54_upgrade/`
|
||||
|
||||
**Backup Contents:**
|
||||
- `android_original/` - Complete Android directory
|
||||
- `ios_original/` - Complete iOS directory (partial - Pods symlinks failed)
|
||||
- `KSPlayerManager.m` - iOS bridge file
|
||||
- `KSPlayerModule.swift` - iOS module file
|
||||
- `KSPlayerView.swift` - iOS view file
|
||||
- `KSPlayerViewManager.swift` - iOS view manager file
|
||||
- `lib-decoder-ffmpeg-release.aar` - FFmpeg AAR
|
||||
- `build.gradle.backup` - Android build.gradle
|
||||
- `proguard-rules.pro.backup` - ProGuard rules
|
||||
- `Podfile.backup` - iOS Podfile
|
||||
- `package.json.backup` - Original package.json
|
||||
- `ReactExoplayerView.java.backup` - Modified react-native-video file
|
||||
|
||||
---
|
||||
|
||||
## SDK 54 Upgrade Process
|
||||
|
||||
### Pre-Upgrade Checklist
|
||||
- ✅ All native files backed up
|
||||
- ✅ Custom modifications documented
|
||||
- ✅ FFmpeg AAR preserved
|
||||
- ✅ KSPlayer bridge files preserved
|
||||
- ✅ Build configuration files backed up
|
||||
|
||||
### Upgrade Steps
|
||||
1. Update package.json to SDK 54
|
||||
2. Run `npx expo install` to update compatible packages
|
||||
3. Run `npx expo prebuild --clean` to regenerate native projects
|
||||
4. Restore Android FFmpeg integration
|
||||
5. Restore iOS KSPlayer integration
|
||||
6. Test builds on both platforms
|
||||
|
||||
### Post-Upgrade Verification
|
||||
- [ ] Android: FFmpeg audio decoders working (test AC3/DTS stream)
|
||||
- [ ] iOS: KSPlayer bridge working
|
||||
- [ ] Audio track selection functional
|
||||
- [ ] Subtitle track selection functional
|
||||
- [ ] VLC fallback working on decoder errors
|
||||
- [ ] App builds successfully for both platforms
|
||||
|
||||
---
|
||||
|
||||
## Critical Notes
|
||||
|
||||
1. **react-native-video modification:** This must be reapplied after every `npm install` or package update
|
||||
2. **FFmpeg limitations:** Audio codecs only - video codecs require hardware decoder or VLC
|
||||
3. **KSPlayer Podfile:** Uses git branches, may need version pinning for stability
|
||||
4. **Xcode project:** KSPlayer files must be linked in project.pbxproj after prebuild
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- FFmpeg integration guide: `ffmpegreadme.md`
|
||||
- KSPlayer repo: https://github.com/kingslay/KSPlayer
|
||||
- Expo SDK 54 changelog: https://expo.dev/changelog/2025/
|
||||
|
||||