mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
changes
This commit is contained in:
parent
019f99c956
commit
b1494e8a1d
7 changed files with 153 additions and 95 deletions
|
|
@ -1,8 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Check if the correct number of arguments are provided
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Usage: $0 <runtimeVersion> <xavia-ota-url>"
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <xavia-ota-url>"
|
||||
echo "Example: $0 https://grim-reyna-tapframe-69970143.koyeb.app"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -10,52 +11,150 @@ fi
|
|||
commitHash=$(git rev-parse HEAD)
|
||||
commitMessage=$(git log -1 --pretty=%B)
|
||||
|
||||
# Check if app.json exists
|
||||
if [ ! -f "app.json" ]; then
|
||||
echo "Error: app.json not found in current directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Auto-detect runtime version from app.json
|
||||
runtimeVersion=$(jq -r '.expo.runtimeVersion' app.json)
|
||||
if [ "$runtimeVersion" = "null" ] || [ -z "$runtimeVersion" ]; then
|
||||
echo "Error: Could not find runtimeVersion in app.json"
|
||||
echo "Please ensure app.json contains: \"runtimeVersion\": \"your-version\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Assign arguments to variables
|
||||
runtimeVersion=$1
|
||||
serverHost=$2
|
||||
serverHost=$1
|
||||
|
||||
# Validate server URL format
|
||||
if [[ ! "$serverHost" =~ ^https?:// ]]; then
|
||||
echo "Error: Server URL must start with http:// or https://"
|
||||
echo "Example: https://grim-reyna-tapframe-69970143.koyeb.app"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate a timestamp for the output folder
|
||||
timestamp=$(date -u +%Y%m%d%H%M%S)
|
||||
outputFolder="ota-builds/$timestamp"
|
||||
|
||||
# Ask the user to confirm the hash, commit message, runtime version, and output folder
|
||||
echo "Output Folder: $outputFolder"
|
||||
echo "Runtime Version: $runtimeVersion"
|
||||
echo "Commit Hash: $commitHash"
|
||||
echo "Commit Message: $commitMessage"
|
||||
# Display build information
|
||||
echo "🚀 Nuvio OTA Build & Deploy Script"
|
||||
echo "=================================="
|
||||
echo "📁 Output Folder: $outputFolder"
|
||||
echo "📱 Runtime Version: $runtimeVersion"
|
||||
echo "🔗 Commit Hash: $commitHash"
|
||||
echo "📝 Commit Message: $commitMessage"
|
||||
echo "🌐 Server URL: $serverHost"
|
||||
echo ""
|
||||
|
||||
read -p "Do you want to proceed with these values? (y/n): " confirm
|
||||
|
||||
if [ "$confirm" != "y" ]; then
|
||||
echo "Operation cancelled by the user."
|
||||
echo "❌ Operation cancelled by the user."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔨 Starting build process..."
|
||||
|
||||
# Clean up any existing output folder
|
||||
rm -rf $outputFolder
|
||||
mkdir -p $outputFolder
|
||||
|
||||
# Run expo export with the specified output folder
|
||||
npx expo export --output-dir $outputFolder
|
||||
echo "📦 Exporting Expo bundle..."
|
||||
if ! npx expo export --output-dir $outputFolder; then
|
||||
echo "❌ Error: Expo export failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract expo config property from app.json and save to expoconfig.json
|
||||
echo "⚙️ Extracting Expo configuration..."
|
||||
jq '.expo' app.json > $outputFolder/expoconfig.json
|
||||
|
||||
|
||||
# Zip the output folder
|
||||
echo "📦 Creating deployment package..."
|
||||
cd $outputFolder
|
||||
zip -q -r ${timestamp}.zip .
|
||||
|
||||
if ! zip -q -r ${timestamp}.zip .; then
|
||||
echo "❌ Error: Failed to create zip file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Upload the zip file to the server
|
||||
curl -X POST $serverHost/api/upload -F "file=@${timestamp}.zip" -F "runtimeVersion=$runtimeVersion" -F "commitHash=$commitHash" -F "commitMessage=$commitMessage"
|
||||
echo "🚀 Uploading to server..."
|
||||
echo "📊 File size: $(du -h ${timestamp}.zip | cut -f1)"
|
||||
|
||||
# Check server health before upload
|
||||
echo "🔍 Checking server status..."
|
||||
if ! curl --max-time 10 --connect-timeout 5 -s -o /dev/null "$serverHost/api/manifest"; then
|
||||
echo "⚠️ Warning: Server may be slow or unresponsive"
|
||||
echo "💡 Proceeding with upload anyway..."
|
||||
else
|
||||
echo "✅ Server is responding"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "Uploaded to $serverHost/api/upload"
|
||||
# Try upload with extended timeout and retry logic
|
||||
max_retries=3
|
||||
retry_count=0
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
echo "🔄 Upload attempt $((retry_count + 1))/$max_retries..."
|
||||
|
||||
response=$(curl --max-time 300 --connect-timeout 30 -X POST $serverHost/api/upload \
|
||||
-F "file=@${timestamp}.zip" \
|
||||
-F "runtimeVersion=$runtimeVersion" \
|
||||
-F "commitHash=$commitHash" \
|
||||
-F "commitMessage=$commitMessage" \
|
||||
--write-out "HTTP_CODE:%{http_code}" \
|
||||
--silent \
|
||||
--show-error)
|
||||
|
||||
# Extract HTTP code from response
|
||||
http_code=$(echo "$response" | grep -o "HTTP_CODE:[0-9]*" | cut -d: -f2)
|
||||
|
||||
# Check if we got a valid HTTP code
|
||||
if [ -z "$http_code" ] || ! [[ "$http_code" =~ ^[0-9]+$ ]]; then
|
||||
echo "❌ Failed to extract HTTP status code from response"
|
||||
echo "Response: $response"
|
||||
http_code="000"
|
||||
fi
|
||||
|
||||
echo "HTTP Status: $http_code"
|
||||
|
||||
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
|
||||
echo ""
|
||||
echo "✅ Successfully uploaded to $serverHost/api/upload"
|
||||
break
|
||||
else
|
||||
retry_count=$((retry_count + 1))
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
echo "⚠️ Upload attempt $retry_count failed, retrying in 5 seconds..."
|
||||
sleep 5
|
||||
else
|
||||
echo "❌ Error: Upload failed after $max_retries attempts"
|
||||
echo "📊 Final HTTP Status: $http_code"
|
||||
if [ "$http_code" = "524" ]; then
|
||||
echo "💡 Error 524: Server timeout - try again later or check server capacity"
|
||||
elif [ "$http_code" = "413" ]; then
|
||||
echo "💡 Error 413: File too large - consider reducing bundle size"
|
||||
elif [ "$http_code" = "500" ]; then
|
||||
echo "💡 Error 500: Server error - check server logs"
|
||||
else
|
||||
echo "💡 Check server status and try again"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
cd ..
|
||||
|
||||
# Remove the output folder and zip file
|
||||
echo "🧹 Cleaning up temporary files..."
|
||||
rm -rf $outputFolder
|
||||
|
||||
echo "Removed $outputFolder"
|
||||
echo "Done"
|
||||
echo "🎉 Build and deployment completed successfully!"
|
||||
echo "📱 Runtime Version: $runtimeVersion"
|
||||
echo "🔗 Commit: $commitHash"
|
||||
|
|
|
|||
7
manifest_response.json
Normal file
7
manifest_response.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
----------------------------568300859475270590089014
|
||||
Content-Disposition: form-data; name="directive"
|
||||
Content-Type: application/json
|
||||
content-type: application/json; charset=utf-8
|
||||
|
||||
{"type":"noUpdateAvailable"}
|
||||
----------------------------568300859475270590089014--
|
||||
7
manifest_response_old.json
Normal file
7
manifest_response_old.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
----------------------------694338510290346396309710
|
||||
Content-Disposition: form-data; name="directive"
|
||||
Content-Type: application/json
|
||||
content-type: application/json; charset=utf-8
|
||||
|
||||
{"type":"noUpdateAvailable"}
|
||||
----------------------------694338510290346396309710--
|
||||
|
|
@ -72,7 +72,7 @@ const UpdatePopup: React.FC<UpdatePopupProps> = ({
|
|||
<View style={[
|
||||
styles.popup,
|
||||
{
|
||||
backgroundColor: currentTheme.colors.elevation1 || '#1a1a1a',
|
||||
backgroundColor: currentTheme.colors.darkBackground || '#1a1a1a',
|
||||
borderColor: currentTheme.colors.elevation2 || '#333333',
|
||||
marginTop: insets.top + 20,
|
||||
marginBottom: insets.bottom + 20,
|
||||
|
|
@ -173,8 +173,8 @@ const UpdatePopup: React.FC<UpdatePopupProps> = ({
|
|||
styles.button,
|
||||
styles.secondaryButton,
|
||||
{
|
||||
backgroundColor: currentTheme.colors.elevation2,
|
||||
borderColor: currentTheme.colors.elevation3,
|
||||
backgroundColor: currentTheme.colors.darkBackground || '#2a2a2a',
|
||||
borderColor: currentTheme.colors.elevation3 || '#444444',
|
||||
}
|
||||
]}
|
||||
onPress={handleUpdateLater}
|
||||
|
|
@ -194,8 +194,8 @@ const UpdatePopup: React.FC<UpdatePopupProps> = ({
|
|||
styles.button,
|
||||
styles.secondaryButton,
|
||||
{
|
||||
backgroundColor: currentTheme.colors.elevation2,
|
||||
borderColor: currentTheme.colors.elevation3,
|
||||
backgroundColor: currentTheme.colors.darkBackground || '#2a2a2a',
|
||||
borderColor: currentTheme.colors.elevation3 || '#444444',
|
||||
}
|
||||
]}
|
||||
onPress={handleDismiss}
|
||||
|
|
@ -239,7 +239,7 @@ const styles = StyleSheet.create({
|
|||
width: Math.min(width - 40, 400),
|
||||
borderRadius: 20,
|
||||
borderWidth: 1,
|
||||
backgroundColor: '#1a1a1a', // Fallback solid background
|
||||
backgroundColor: '#1a1a1a', // Solid background - not transparent
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 10 },
|
||||
shadowOpacity: 0.5,
|
||||
|
|
@ -297,7 +297,7 @@ const styles = StyleSheet.create({
|
|||
marginTop: 8,
|
||||
padding: 12,
|
||||
borderRadius: 8,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
||||
},
|
||||
description: {
|
||||
fontSize: 14,
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
flex: 1,
|
||||
},
|
||||
section: {
|
||||
backgroundColor: colors.elevation1,
|
||||
backgroundColor: colors.darkBackground,
|
||||
marginBottom: 16,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
|
|
@ -181,7 +181,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
lineHeight: 20,
|
||||
},
|
||||
textInput: {
|
||||
backgroundColor: colors.elevation1,
|
||||
backgroundColor: colors.darkBackground,
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
color: colors.white,
|
||||
|
|
@ -369,7 +369,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
},
|
||||
// New styles for improved UX
|
||||
collapsibleSection: {
|
||||
backgroundColor: colors.elevation1,
|
||||
backgroundColor: colors.darkBackground,
|
||||
marginBottom: 16,
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
|
|
@ -392,7 +392,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
searchContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.elevation1,
|
||||
backgroundColor: colors.darkBackground,
|
||||
borderRadius: 12,
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 12,
|
||||
|
|
@ -489,7 +489,7 @@ const createStyles = (colors: any) => StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: colors.elevation1,
|
||||
backgroundColor: colors.darkBackground,
|
||||
borderRadius: 16,
|
||||
padding: 24,
|
||||
margin: 20,
|
||||
|
|
@ -750,10 +750,7 @@ const PluginsScreen: React.FC = () => {
|
|||
const [currentRepositoryId, setCurrentRepositoryId] = useState<string>('');
|
||||
const [showAddRepositoryModal, setShowAddRepositoryModal] = useState(false);
|
||||
const [newRepositoryUrl, setNewRepositoryUrl] = useState('');
|
||||
const [newRepositoryName, setNewRepositoryName] = useState('');
|
||||
const [newRepositoryDescription, setNewRepositoryDescription] = useState('');
|
||||
const [switchingRepository, setSwitchingRepository] = useState<string | null>(null);
|
||||
const [fetchingRepoName, setFetchingRepoName] = useState(false);
|
||||
|
||||
// New UX state
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
|
@ -837,29 +834,8 @@ const PluginsScreen: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleUrlChange = async (url: string) => {
|
||||
const handleUrlChange = (url: string) => {
|
||||
setNewRepositoryUrl(url);
|
||||
// Auto-populate repository name if it's empty and URL is valid
|
||||
if (!newRepositoryName.trim() && url.trim()) {
|
||||
setFetchingRepoName(true);
|
||||
try {
|
||||
// Try to fetch name from manifest first
|
||||
const manifestName = await localScraperService.fetchRepositoryNameFromManifest(url.trim());
|
||||
setNewRepositoryName(manifestName);
|
||||
} catch (error) {
|
||||
// Fallback to URL extraction if manifest fetch fails
|
||||
try {
|
||||
const extractedName = localScraperService.extractRepositoryName(url.trim());
|
||||
if (extractedName !== 'Unknown Repository') {
|
||||
setNewRepositoryName(extractedName);
|
||||
}
|
||||
} catch (extractError) {
|
||||
// Ignore errors, just don't auto-populate
|
||||
}
|
||||
} finally {
|
||||
setFetchingRepoName(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddRepository = async () => {
|
||||
|
|
@ -873,7 +849,7 @@ const PluginsScreen: React.FC = () => {
|
|||
if (!url.startsWith('https://raw.githubusercontent.com/') && !url.startsWith('http://')) {
|
||||
Alert.alert(
|
||||
'Invalid URL Format',
|
||||
'Please use a valid GitHub raw URL format:\n\nhttps://raw.githubusercontent.com/username/repo/branch/\n\nExample:\nhttps://raw.githubusercontent.com/tapframe/nuvio-providers/main/'
|
||||
'Please use a valid GitHub raw URL format:\n\nhttps://raw.githubusercontent.com/username/repo/refs/heads/branch\n\nExample:\nhttps://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/master'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -881,9 +857,9 @@ const PluginsScreen: React.FC = () => {
|
|||
try {
|
||||
setIsLoading(true);
|
||||
const repoId = await localScraperService.addRepository({
|
||||
name: newRepositoryName.trim(), // Let the service fetch from manifest if empty
|
||||
name: '', // Let the service fetch from manifest
|
||||
url,
|
||||
description: newRepositoryDescription.trim(),
|
||||
description: '',
|
||||
enabled: true
|
||||
});
|
||||
|
||||
|
|
@ -895,9 +871,6 @@ const PluginsScreen: React.FC = () => {
|
|||
await loadScrapers();
|
||||
|
||||
setNewRepositoryUrl('');
|
||||
setNewRepositoryName('');
|
||||
setNewRepositoryDescription('');
|
||||
setFetchingRepoName(false);
|
||||
setShowAddRepositoryModal(false);
|
||||
Alert.alert('Success', 'Repository added and refreshed successfully');
|
||||
} catch (error) {
|
||||
|
|
@ -1016,7 +989,7 @@ const PluginsScreen: React.FC = () => {
|
|||
if (!url.startsWith('https://raw.githubusercontent.com/') && !url.startsWith('http://')) {
|
||||
Alert.alert(
|
||||
'Invalid URL Format',
|
||||
'Please use a valid GitHub raw URL format:\n\nhttps://raw.githubusercontent.com/username/repo/branch/\n\nExample:\nhttps://raw.githubusercontent.com/tapframe/nuvio-providers/main/'
|
||||
'Please use a valid GitHub raw URL format:\n\nhttps://raw.githubusercontent.com/username/repo/refs/heads/branch\n\nExample:\nhttps://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/master'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1051,7 +1024,7 @@ const PluginsScreen: React.FC = () => {
|
|||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
Alert.alert(
|
||||
'Repository Error',
|
||||
`Failed to refresh repository: ${errorMessage}\n\nPlease ensure your URL is correct and follows this format:\nhttps://raw.githubusercontent.com/username/repo/branch/`
|
||||
`Failed to refresh repository: ${errorMessage}\n\nPlease ensure your URL is correct and follows this format:\nhttps://raw.githubusercontent.com/username/repo/refs/heads/branch`
|
||||
);
|
||||
} finally {
|
||||
setIsRefreshing(false);
|
||||
|
|
@ -1135,7 +1108,7 @@ const PluginsScreen: React.FC = () => {
|
|||
};
|
||||
|
||||
const handleUseDefaultRepo = () => {
|
||||
const defaultUrl = 'https://raw.githubusercontent.com/tapframe/nuvio-providers/main';
|
||||
const defaultUrl = 'https://raw.githubusercontent.com/tapframe/nuvio-providers/refs/heads/master';
|
||||
setRepositoryUrl(defaultUrl);
|
||||
};
|
||||
|
||||
|
|
@ -1731,53 +1704,24 @@ const PluginsScreen: React.FC = () => {
|
|||
<View style={styles.modalContent}>
|
||||
<Text style={styles.modalTitle}>Add New Repository</Text>
|
||||
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 8 }}>
|
||||
<Text style={styles.settingTitle}>Repository Name</Text>
|
||||
{fetchingRepoName && (
|
||||
<ActivityIndicator size="small" color={colors.primary} style={{ marginLeft: 8 }} />
|
||||
)}
|
||||
</View>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
value={newRepositoryName}
|
||||
onChangeText={setNewRepositoryName}
|
||||
placeholder="Enter repository name"
|
||||
placeholderTextColor={colors.mediumGray}
|
||||
autoCapitalize="words"
|
||||
/>
|
||||
|
||||
<Text style={[styles.settingTitle, { marginBottom: 8 }]}>Repository URL</Text>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
value={newRepositoryUrl}
|
||||
onChangeText={handleUrlChange}
|
||||
placeholder="https://raw.githubusercontent.com/username/repo/branch/"
|
||||
placeholder="https://raw.githubusercontent.com/username/repo/refs/heads/branch"
|
||||
placeholderTextColor={colors.mediumGray}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
keyboardType="url"
|
||||
/>
|
||||
|
||||
<Text style={[styles.settingTitle, { marginBottom: 8 }]}>Description (Optional)</Text>
|
||||
<TextInput
|
||||
style={[styles.textInput, { height: 80 }]}
|
||||
value={newRepositoryDescription}
|
||||
onChangeText={setNewRepositoryDescription}
|
||||
placeholder="Enter repository description"
|
||||
placeholderTextColor={colors.mediumGray}
|
||||
multiline={true}
|
||||
numberOfLines={3}
|
||||
/>
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<TouchableOpacity
|
||||
style={[styles.button, styles.secondaryButton, { flex: 1 }]}
|
||||
onPress={() => {
|
||||
setShowAddRepositoryModal(false);
|
||||
setNewRepositoryUrl('');
|
||||
setNewRepositoryName('');
|
||||
setNewRepositoryDescription('');
|
||||
setFetchingRepoName(false);
|
||||
}}
|
||||
>
|
||||
<Text style={styles.secondaryButtonText}>Cancel</Text>
|
||||
|
|
|
|||
|
|
@ -410,6 +410,7 @@ const UpdateScreen: React.FC = () => {
|
|||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit ba2fe779d75a8ed285c5d37f05532c3ff4acce22
|
||||
Subproject commit ef5455acaa04404d816a6bffc25a259e28189918
|
||||
Loading…
Reference in a new issue