diff --git a/build-and-publish-app-release.sh b/build-and-publish-app-release.sh index e17ceae..3e19ea2 100644 --- a/build-and-publish-app-release.sh +++ b/build-and-publish-app-release.sh @@ -1,8 +1,9 @@ #!/bin/bash # Check if the correct number of arguments are provided -if [ "$#" -ne 2 ]; then - echo "Usage: $0 " +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + 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" diff --git a/manifest_response.json b/manifest_response.json new file mode 100644 index 0000000..bfa7037 --- /dev/null +++ b/manifest_response.json @@ -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-- diff --git a/manifest_response_old.json b/manifest_response_old.json new file mode 100644 index 0000000..f64773e --- /dev/null +++ b/manifest_response_old.json @@ -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-- diff --git a/src/components/UpdatePopup.tsx b/src/components/UpdatePopup.tsx index 104e6eb..0e0e9ed 100644 --- a/src/components/UpdatePopup.tsx +++ b/src/components/UpdatePopup.tsx @@ -72,7 +72,7 @@ const UpdatePopup: React.FC = ({ = ({ 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 = ({ 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, diff --git a/src/screens/PluginsScreen.tsx b/src/screens/PluginsScreen.tsx index 02eaadd..17a58a0 100644 --- a/src/screens/PluginsScreen.tsx +++ b/src/screens/PluginsScreen.tsx @@ -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(''); const [showAddRepositoryModal, setShowAddRepositoryModal] = useState(false); const [newRepositoryUrl, setNewRepositoryUrl] = useState(''); - const [newRepositoryName, setNewRepositoryName] = useState(''); - const [newRepositoryDescription, setNewRepositoryDescription] = useState(''); const [switchingRepository, setSwitchingRepository] = useState(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 = () => { Add New Repository - - Repository Name - {fetchingRepoName && ( - - )} - - - Repository URL - Description (Optional) - - { setShowAddRepositoryModal(false); setNewRepositoryUrl(''); - setNewRepositoryName(''); - setNewRepositoryDescription(''); - setFetchingRepoName(false); }} > Cancel diff --git a/src/screens/UpdateScreen.tsx b/src/screens/UpdateScreen.tsx index 1c87f8f..9ff651c 100644 --- a/src/screens/UpdateScreen.tsx +++ b/src/screens/UpdateScreen.tsx @@ -410,6 +410,7 @@ const UpdateScreen: React.FC = () => { )} + diff --git a/xavia-ota b/xavia-ota index ba2fe77..ef5455a 160000 --- a/xavia-ota +++ b/xavia-ota @@ -1 +1 @@ -Subproject commit ba2fe779d75a8ed285c5d37f05532c3ff4acce22 +Subproject commit ef5455acaa04404d816a6bffc25a259e28189918