fix showbox token not reading

This commit is contained in:
tapframe 2026-01-12 16:12:51 +05:30
parent 7bf3a344f3
commit f9c043ba32
5 changed files with 139 additions and 47 deletions

View file

@ -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,7 +40,6 @@
<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>
@ -54,12 +53,11 @@
Nuvio Media Hub is a crossplatform 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 crossplatform 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
[![Download APK](https://img.shields.io/badge/Download-APK-green?style=for-the-badge)](https://github.com/tapframe/NuvioStreaming/releases/latest) [![Download APK](https://img.shields.io/badge/Download-APK-green?style=for-the-badge)](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"> [![Join TestFlight](https://img.shields.io/badge/Join-TestFlight-blue?style=for-the-badge)](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"> [![Join TestFlight](https://img.shields.io/badge/Join-TestFlight-blue?style=for-the-badge)](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"> [![Add to AltStore](https://img.shields.io/badge/Add%20to-AltStore-blue?style=for-the-badge)](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"> [![Add to AltStore](https://img.shields.io/badge/Add%20to-AltStore-blue?style=for-the-badge)](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"> [![Add to SideStore](https://img.shields.io/badge/Add%20to-SideStore-green?style=for-the-badge)](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"> [![Add to SideStore](https://img.shields.io/badge/Add%20to-SideStore-green?style=for-the-badge)](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 opensource community amazing! Any contributions are greatly appreciated. Contributions make the opensource 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,7 +165,7 @@ 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

View file

@ -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' }
]; ];

View file

@ -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');

View file

@ -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>
); );
} }

View file

@ -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