mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-01 13:14:50 +00:00
fix showbox token not reading
This commit is contained in:
parent
7bf3a344f3
commit
f9c043ba32
5 changed files with 139 additions and 47 deletions
54
README.md
54
README.md
|
|
@ -1,3 +1,5 @@
|
||||||
|
# 🎬 Nuvio Media Hub
|
||||||
|
|
||||||
<!-- PROJECT LOGO -->
|
<!-- PROJECT LOGO -->
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a id="readme-top"></a>
|
<a id="readme-top"></a>
|
||||||
|
|
@ -8,10 +10,7 @@
|
||||||
[![Issues][issues-shield]][issues-url]
|
[![Issues][issues-shield]][issues-url]
|
||||||
[![License][license-shield]][license-url]
|
[![License][license-shield]][license-url]
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<img src="assets/titlelogo.png" alt="Nuvio Logo" width="120" />
|
<img src="assets/titlelogo.png" alt="Nuvio Logo" width="120" />
|
||||||
<h1 align="center">🎬 Nuvio Media Hub</h1>
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
A modern media hub built with React Native and Expo
|
A modern media hub built with React Native and Expo
|
||||||
<br />
|
<br />
|
||||||
|
|
@ -31,6 +30,7 @@
|
||||||
<!-- TABLE OF CONTENTS -->
|
<!-- TABLE OF CONTENTS -->
|
||||||
<details>
|
<details>
|
||||||
<summary>Table of Contents</summary>
|
<summary>Table of Contents</summary>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
<a href="#about-the-project">About The Project</a>
|
<a href="#about-the-project">About The Project</a>
|
||||||
|
|
@ -40,26 +40,24 @@
|
||||||
<li><a href="#getting-started">Getting Started</a></li>
|
<li><a href="#getting-started">Getting Started</a></li>
|
||||||
<li><a href="#contributing">Contributing</a></li>
|
<li><a href="#contributing">Contributing</a></li>
|
||||||
<li><a href="#support">Support</a></li>
|
<li><a href="#support">Support</a></li>
|
||||||
<li><a href="#support">Support</a></li>
|
|
||||||
<li><a href="#license">License</a></li>
|
<li><a href="#license">License</a></li>
|
||||||
<li><a href="#legal">Legal</a></li>
|
<li><a href="#legal">Legal</a></li>
|
||||||
<li><a href="#contact">Contact</a></li>
|
<li><a href="#contact">Contact</a></li>
|
||||||
<li><a href="#acknowledgments">Acknowledgments</a></li>
|
<li><a href="#acknowledgments">Acknowledgments</a></li>
|
||||||
<li><a href="#built-with">Built With</a></li>
|
<li><a href="#built-with">Built With</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<!-- ABOUT THE PROJECT -->
|
<!-- ABOUT THE PROJECT -->
|
||||||
## About The Project
|
## About The Project
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- INSTALLATION -->
|
<!-- INSTALLATION -->
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Android
|
### Android
|
||||||
|
|
||||||
[](https://github.com/tapframe/NuvioStreaming/releases/latest)
|
[](https://github.com/tapframe/NuvioStreaming/releases/latest)
|
||||||
|
|
||||||
Download the latest APK from [GitHub Releases](https://github.com/tapframe/NuvioStreaming/releases/latest)
|
Download the latest APK from [GitHub Releases](https://github.com/tapframe/NuvioStreaming/releases/latest)
|
||||||
|
|
@ -67,20 +65,21 @@ Download the latest APK from [GitHub Releases](https://github.com/tapframe/Nuvio
|
||||||
### iOS
|
### iOS
|
||||||
|
|
||||||
#### TestFlight (Recommended)
|
#### TestFlight (Recommended)
|
||||||
<img src="https://upload.wikimedia.org/wikipedia/fr/b/bc/TestFlight-icon.png" width="24" height="24" align="left"> [](https://testflight.apple.com/join/QkKMGRqp)
|
|
||||||
|
<img src="https://upload.wikimedia.org/wikipedia/fr/b/bc/TestFlight-icon.png" width="24" height="24" align="left" alt="TestFlight Icon"> [](https://testflight.apple.com/join/QkKMGRqp)
|
||||||
|
|
||||||
#### AltStore
|
#### AltStore
|
||||||
<img src="https://upload.wikimedia.org/wikipedia/commons/2/20/AltStore_logo.png" width="24" height="24" align="left"> [](https://tinyurl.com/NuvioAltstore)
|
|
||||||
|
<img src="https://upload.wikimedia.org/wikipedia/commons/2/20/AltStore_logo.png" width="24" height="24" align="left" alt="AltStore Logo"> [](https://tinyurl.com/NuvioAltstore)
|
||||||
|
|
||||||
#### SideStore
|
#### SideStore
|
||||||
<img src="https://github.com/SideStore/assets/blob/main/icon.png?raw=true" width="24" height="24" align="left"> [](https://tinyurl.com/NuvioSidestore)
|
|
||||||
|
<img src="https://github.com/SideStore/assets/blob/main/icon.png?raw=true" width="24" height="24" align="left" alt="SideStore Logo"> [](https://tinyurl.com/NuvioSidestore)
|
||||||
|
|
||||||
**Manual URL:** `https://raw.githubusercontent.com/tapframe/NuvioStreaming/main/nuvio-source.json`
|
**Manual URL:** `https://raw.githubusercontent.com/tapframe/NuvioStreaming/main/nuvio-source.json`
|
||||||
|
|
||||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- GETTING STARTED -->
|
<!-- GETTING STARTED -->
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
|
@ -91,27 +90,21 @@ Follow the steps below to run the app locally for development. For detailed setu
|
||||||
<details>
|
<details>
|
||||||
<summary>Build from Source</summary>
|
<summary>Build from Source</summary>
|
||||||
|
|
||||||
```bash
|
git clone https://github.com/tapframe/NuvioStreaming.git
|
||||||
git clone https://github.com/tapframe/NuvioStreaming.git
|
cd NuvioStreaming
|
||||||
cd NuvioStreaming
|
npm install
|
||||||
npm install
|
# If you hit peer dependency conflicts:
|
||||||
# If you hit peer dependency conflicts:
|
# npm install --legacy-peer-deps
|
||||||
# npm install --legacy-peer-deps
|
npx expo start
|
||||||
npx expo start
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
npx expo prebuild
|
||||||
npx expo prebuild
|
npx expo run:android # Android
|
||||||
npx expo run:android # Android
|
npx expo run:ios # iOS
|
||||||
npx expo run:ios # iOS
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions make the open‑source community amazing! Any contributions are greatly appreciated.
|
Contributions make the open‑source community amazing! Any contributions are greatly appreciated.
|
||||||
|
|
@ -151,6 +144,7 @@ For comprehensive legal information, including our full disclaimer, third-party
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
**Project Links:**
|
**Project Links:**
|
||||||
|
|
||||||
* GitHub: `https://github.com/tapframe`
|
* GitHub: `https://github.com/tapframe`
|
||||||
* Issues: `https://github.com/tapframe/NuvioStreaming/issues`
|
* Issues: `https://github.com/tapframe/NuvioStreaming/issues`
|
||||||
|
|
||||||
|
|
@ -171,13 +165,13 @@ For comprehensive legal information, including our full disclaimer, third-party
|
||||||
|
|
||||||
<p align="left">
|
<p align="left">
|
||||||
<a href="https://skillicons.dev">
|
<a href="https://skillicons.dev">
|
||||||
<img src="https://skillicons.dev/icons?i=react,typescript,nodejs,expo,github,githubactions&theme=light&perline=6" />
|
<img src="https://skillicons.dev/icons?i=react,typescript,nodejs,expo,github,githubactions&theme=light&perline=6" alt="Skills Icons" />
|
||||||
</a>
|
</a>
|
||||||
<br/>
|
<br/>
|
||||||
React Native • Expo • TypeScript
|
React Native • Expo • TypeScript
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
|
|
||||||
<a href="https://www.star-history.com/#tapframe/NuvioStreaming&type=date&legend=top-left">
|
<a href="https://www.star-history.com/#tapframe/NuvioStreaming&type=date&legend=top-left">
|
||||||
<picture>
|
<picture>
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,6 @@ export const LOCALES = [
|
||||||
{ code: 'de', key: 'german' },
|
{ code: 'de', key: 'german' },
|
||||||
{ code: 'ar', key: 'arabic' },
|
{ code: 'ar', key: 'arabic' },
|
||||||
{ code: 'fr', key: 'french' },
|
{ code: 'fr', key: 'french' },
|
||||||
{ code: 'it', key: 'italian' }
|
{ code: 'it', key: 'italian' },
|
||||||
|
{ code: 'es', key: 'spanish' }
|
||||||
];
|
];
|
||||||
|
|
@ -1231,8 +1231,10 @@ const PluginsScreen: React.FC = () => {
|
||||||
if (sb) {
|
if (sb) {
|
||||||
setShowboxScraperId(sb.id);
|
setShowboxScraperId(sb.id);
|
||||||
const s = await pluginService.getScraperSettings(sb.id);
|
const s = await pluginService.getScraperSettings(sb.id);
|
||||||
setShowboxUiToken(s.uiToken || '');
|
// Check for multiple possible key names for the token
|
||||||
setShowboxSavedToken(s.uiToken || '');
|
const token = s.uiToken || s.cookie || s.token || '';
|
||||||
|
setShowboxUiToken(token);
|
||||||
|
setShowboxSavedToken(token);
|
||||||
setShowboxTokenVisible(false);
|
setShowboxTokenVisible(false);
|
||||||
} else {
|
} else {
|
||||||
setShowboxScraperId(null);
|
setShowboxScraperId(null);
|
||||||
|
|
@ -1926,7 +1928,12 @@ const PluginsScreen: React.FC = () => {
|
||||||
style={[styles.button, styles.primaryButton]}
|
style={[styles.button, styles.primaryButton]}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
if (showboxScraperId) {
|
if (showboxScraperId) {
|
||||||
await pluginService.setScraperSettings(showboxScraperId, { uiToken: showboxUiToken });
|
// Save with multiple keys to ensure the scraper finds it regardless of what key it checks
|
||||||
|
await pluginService.setScraperSettings(showboxScraperId, {
|
||||||
|
uiToken: showboxUiToken,
|
||||||
|
cookie: showboxUiToken,
|
||||||
|
token: showboxUiToken
|
||||||
|
});
|
||||||
}
|
}
|
||||||
setShowboxSavedToken(showboxUiToken);
|
setShowboxSavedToken(showboxUiToken);
|
||||||
openAlert('Saved', 'ShowBox settings updated');
|
openAlert('Saved', 'ShowBox settings updated');
|
||||||
|
|
|
||||||
|
|
@ -389,7 +389,22 @@ const SettingsScreen: React.FC = () => {
|
||||||
return <ContentDiscoverySettingsContent isTablet={isTablet} />;
|
return <ContentDiscoverySettingsContent isTablet={isTablet} />;
|
||||||
|
|
||||||
case 'appearance':
|
case 'appearance':
|
||||||
return <AppearanceSettingsContent isTablet={isTablet} />;
|
return (
|
||||||
|
<>
|
||||||
|
<SettingsCard title="GENERAL" isTablet={isTablet}>
|
||||||
|
<SettingItem
|
||||||
|
title={t('settings.language')}
|
||||||
|
description={t(`settings.${LOCALES.find(l => l.code === i18n.language)?.key}`)}
|
||||||
|
icon="globe"
|
||||||
|
renderControl={() => <ChevronRight />}
|
||||||
|
onPress={() => languageSheetRef.current?.present()}
|
||||||
|
isLast={true}
|
||||||
|
isTablet={isTablet}
|
||||||
|
/>
|
||||||
|
</SettingsCard>
|
||||||
|
<AppearanceSettingsContent isTablet={isTablet} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
case 'integrations':
|
case 'integrations':
|
||||||
return <IntegrationsSettingsContent isTablet={isTablet} />;
|
return <IntegrationsSettingsContent isTablet={isTablet} />;
|
||||||
|
|
@ -571,6 +586,65 @@ const SettingsScreen: React.FC = () => {
|
||||||
actions={alertActions}
|
actions={alertActions}
|
||||||
onClose={() => setAlertVisible(false)}
|
onClose={() => setAlertVisible(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<BottomSheetModal
|
||||||
|
ref={languageSheetRef}
|
||||||
|
index={0}
|
||||||
|
snapPoints={['65%']}
|
||||||
|
enablePanDownToClose={true}
|
||||||
|
backdropComponent={renderBackdrop}
|
||||||
|
backgroundStyle={{
|
||||||
|
backgroundColor: currentTheme.colors.darkGray || '#0A0C0C',
|
||||||
|
borderTopLeftRadius: 16,
|
||||||
|
borderTopRightRadius: 16,
|
||||||
|
}}
|
||||||
|
handleIndicatorStyle={{
|
||||||
|
backgroundColor: currentTheme.colors.mediumGray,
|
||||||
|
width: 40,
|
||||||
|
}}
|
||||||
|
onChange={onChange(languageSheetRef)}
|
||||||
|
onDismiss={onDismiss(languageSheetRef)}
|
||||||
|
>
|
||||||
|
<View style={[styles.bottomSheetHeader, { backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }]}>
|
||||||
|
<Text style={[styles.bottomSheetTitle, { color: currentTheme.colors.white }]}>
|
||||||
|
{t('settings.select_language')}
|
||||||
|
</Text>
|
||||||
|
<TouchableOpacity onPress={() => languageSheetRef.current?.dismiss()}>
|
||||||
|
<Feather name="x" size={24} color={currentTheme.colors.lightGray} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
<BottomSheetScrollView
|
||||||
|
style={{ backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }}
|
||||||
|
contentContainerStyle={[styles.bottomSheetContent, { paddingBottom: insets.bottom + 16 }]}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
LOCALES.sort((a,b) => a.key.localeCompare(b.key)).map(l =>
|
||||||
|
<TouchableOpacity
|
||||||
|
key={l.key}
|
||||||
|
style={[
|
||||||
|
styles.languageOption,
|
||||||
|
i18n.language === l.code && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||||
|
]}
|
||||||
|
onPress={() => {
|
||||||
|
i18n.changeLanguage(l.code);
|
||||||
|
languageSheetRef.current?.dismiss();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text style={[
|
||||||
|
styles.languageText,
|
||||||
|
{ color: currentTheme.colors.highEmphasis },
|
||||||
|
i18n.language === l.code && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||||
|
]}>
|
||||||
|
{t(`settings.${l.key}`)}
|
||||||
|
</Text>
|
||||||
|
{i18n.language === l.code && (
|
||||||
|
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</BottomSheetScrollView>
|
||||||
|
</BottomSheetModal>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1162,21 +1162,33 @@ class LocalScraperService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Execute scraper code with full access to app environment (non-sandboxed)
|
|
||||||
private async executePlugin(code: string, params: any, consoleOverride?: any): Promise<LocalScraperResult[]> {
|
private async executePlugin(code: string, params: any, consoleOverride?: any): Promise<LocalScraperResult[]> {
|
||||||
try {
|
try {
|
||||||
// Get URL validation setting from storage
|
|
||||||
const settingsData = await mmkvStorage.getItem('app_settings');
|
const settingsData = await mmkvStorage.getItem('app_settings');
|
||||||
const settings = settingsData ? JSON.parse(settingsData) : {};
|
const settings = settingsData ? JSON.parse(settingsData) : {};
|
||||||
const urlValidationEnabled = settings.enableScraperUrlValidation ?? true;
|
const urlValidationEnabled = settings.enableScraperUrlValidation ?? true;
|
||||||
|
|
||||||
// Load per-scraper settings for this run
|
|
||||||
const allScraperSettingsRaw = await mmkvStorage.getItem(this.SCRAPER_SETTINGS_KEY);
|
const allScraperSettingsRaw = await mmkvStorage.getItem(this.SCRAPER_SETTINGS_KEY);
|
||||||
const allScraperSettings = allScraperSettingsRaw ? JSON.parse(allScraperSettingsRaw) : {};
|
const allScraperSettings = allScraperSettingsRaw ? JSON.parse(allScraperSettingsRaw) : {};
|
||||||
const perScraperSettings = (params && params.scraperId && allScraperSettings[params.scraperId])
|
let perScraperSettings = (params && params.scraperId && allScraperSettings[params.scraperId])
|
||||||
? allScraperSettings[params.scraperId]
|
? allScraperSettings[params.scraperId]
|
||||||
: (params?.settings || {});
|
: (params?.settings || {});
|
||||||
|
|
||||||
|
if (params?.scraperId?.toLowerCase().includes('showbox')) {
|
||||||
|
const token = perScraperSettings.uiToken || perScraperSettings.cookie || perScraperSettings.token;
|
||||||
|
if (token) {
|
||||||
|
perScraperSettings = {
|
||||||
|
...perScraperSettings,
|
||||||
|
uiToken: token,
|
||||||
|
cookie: token,
|
||||||
|
token: token
|
||||||
|
};
|
||||||
|
if (params) {
|
||||||
|
params.settings = perScraperSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Module exports for CommonJS compatibility
|
// Module exports for CommonJS compatibility
|
||||||
const moduleExports: any = {};
|
const moduleExports: any = {};
|
||||||
const moduleObj = { exports: moduleExports };
|
const moduleObj = { exports: moduleExports };
|
||||||
|
|
@ -1292,12 +1304,16 @@ class LocalScraperService {
|
||||||
'SCRAPER_ID',
|
'SCRAPER_ID',
|
||||||
`
|
`
|
||||||
// Make env vars available globally for backward compatibility
|
// Make env vars available globally for backward compatibility
|
||||||
if (typeof global !== 'undefined') {
|
const globalScope = typeof global !== 'undefined' ? global : (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : this));
|
||||||
global.PRIMARY_KEY = PRIMARY_KEY;
|
|
||||||
global.TMDB_API_KEY = TMDB_API_KEY;
|
if (globalScope) {
|
||||||
global.SCRAPER_SETTINGS = SCRAPER_SETTINGS;
|
globalScope.PRIMARY_KEY = PRIMARY_KEY;
|
||||||
global.SCRAPER_ID = SCRAPER_ID;
|
globalScope.TMDB_API_KEY = TMDB_API_KEY;
|
||||||
global.URL_VALIDATION_ENABLED = URL_VALIDATION_ENABLED;
|
globalScope.SCRAPER_SETTINGS = SCRAPER_SETTINGS;
|
||||||
|
globalScope.SCRAPER_ID = SCRAPER_ID;
|
||||||
|
globalScope.URL_VALIDATION_ENABLED = URL_VALIDATION_ENABLED;
|
||||||
|
} else {
|
||||||
|
logger.error('[Plugin Sandbox] Could not find global scope to inject settings');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plugin code
|
// Plugin code
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue