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 -->
<div align="center">
<a id="readme-top"></a>
@ -8,10 +10,7 @@
[![Issues][issues-shield]][issues-url]
[![License][license-shield]][license-url]
<br />
<br />
<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 />
@ -31,6 +30,7 @@
<!-- TABLE OF CONTENTS -->
<details>
<summary>Table of Contents</summary>
<ol>
<li>
<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="#contributing">Contributing</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="#legal">Legal</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>
</details>
<!-- ABOUT THE PROJECT -->
## About The Project
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
### Android
[![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)
@ -67,20 +65,21 @@ Download the latest APK from [GitHub Releases](https://github.com/tapframe/Nuvio
### iOS
#### 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
<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
<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`
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- GETTING STARTED -->
## Getting Started
@ -89,29 +88,23 @@ Follow the steps below to run the app locally for development. For detailed setu
### Development Build
<details>
<summary>Build from Source</summary>
<summary>Build from Source</summary>
```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
```
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
```bash
npx expo prebuild
npx expo run:android # Android
npx expo run:ios # iOS
```
npx expo prebuild
npx expo run:android # Android
npx expo run:ios # iOS
</details>
<p align="right">(<a href="#readme-top">back to top</a>)</p>
## Contributing
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
**Project Links:**
* GitHub: `https://github.com/tapframe`
* Issues: `https://github.com/tapframe/NuvioStreaming/issues`
@ -171,13 +165,13 @@ For comprehensive legal information, including our full disclaimer, third-party
<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" />
<img src="https://skillicons.dev/icons?i=react,typescript,nodejs,expo,github,githubactions&theme=light&perline=6" alt="Skills Icons" />
</a>
<br/>
React Native • Expo • TypeScript
</p>
</p>
## Star History
## Star History
<a href="https://www.star-history.com/#tapframe/NuvioStreaming&type=date&legend=top-left">
<picture>
@ -199,4 +193,4 @@ For comprehensive legal information, including our full disclaimer, third-party
[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
[license-url]: http://www.gnu.org/licenses/gpl-3.0.en.html

View file

@ -5,5 +5,6 @@ export const LOCALES = [
{ code: 'de', key: 'german' },
{ code: 'ar', key: 'arabic' },
{ 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) {
setShowboxScraperId(sb.id);
const s = await pluginService.getScraperSettings(sb.id);
setShowboxUiToken(s.uiToken || '');
setShowboxSavedToken(s.uiToken || '');
// Check for multiple possible key names for the token
const token = s.uiToken || s.cookie || s.token || '';
setShowboxUiToken(token);
setShowboxSavedToken(token);
setShowboxTokenVisible(false);
} else {
setShowboxScraperId(null);
@ -1926,7 +1928,12 @@ const PluginsScreen: React.FC = () => {
style={[styles.button, styles.primaryButton]}
onPress={async () => {
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);
openAlert('Saved', 'ShowBox settings updated');

View file

@ -389,7 +389,22 @@ const SettingsScreen: React.FC = () => {
return <ContentDiscoverySettingsContent isTablet={isTablet} />;
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':
return <IntegrationsSettingsContent isTablet={isTablet} />;
@ -571,6 +586,65 @@ const SettingsScreen: React.FC = () => {
actions={alertActions}
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 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[]> {
try {
// Get URL validation setting from storage
const settingsData = await mmkvStorage.getItem('app_settings');
const settings = settingsData ? JSON.parse(settingsData) : {};
const urlValidationEnabled = settings.enableScraperUrlValidation ?? true;
// Load per-scraper settings for this run
const allScraperSettingsRaw = await mmkvStorage.getItem(this.SCRAPER_SETTINGS_KEY);
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]
: (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
const moduleExports: any = {};
const moduleObj = { exports: moduleExports };
@ -1292,12 +1304,16 @@ class LocalScraperService {
'SCRAPER_ID',
`
// Make env vars available globally for backward compatibility
if (typeof global !== 'undefined') {
global.PRIMARY_KEY = PRIMARY_KEY;
global.TMDB_API_KEY = TMDB_API_KEY;
global.SCRAPER_SETTINGS = SCRAPER_SETTINGS;
global.SCRAPER_ID = SCRAPER_ID;
global.URL_VALIDATION_ENABLED = URL_VALIDATION_ENABLED;
const globalScope = typeof global !== 'undefined' ? global : (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : this));
if (globalScope) {
globalScope.PRIMARY_KEY = PRIMARY_KEY;
globalScope.TMDB_API_KEY = TMDB_API_KEY;
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