12 Commits
20 changed files with 1797 additions and 1284 deletions

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
# PS5 Upload Suite v2.0.0 - Feature-Rich Release
## 🎉 What's New - 4 Major Features Added!
### 1. 📥 Download Files (PS5 → PC)
- Right-click any file → "⬇️ Download to PC"
- Save file dialog for destination
- Real-time progress with speed tracking
- Optimized with sendfile for maximum speed
### 2. 🔍 File Search
- Search box in PS5 Files panel
- Real-time filtering as you type
- Case-insensitive search
- Quick "Clear" button
### 3. ⭐ Favorites/Bookmarks
- Save frequently used PS5 paths
- Quick dropdown navigation
- Add/Remove favorite paths
- Persistent JSON storage
### 4. 🎮 Multi-PS5 Support
- Save multiple PS5 profiles (IP + name)
- Quick switch between consoles
- Dropdown profile selector
- Persistent profile storage
---
## 📦 Installation
### Server (PS5)
1. Copy `ps5_upload_server.elf` to `/data/etaHEN/payloads/`
2. Load with elfldr
3. Server starts on port 9113
### Client (Windows)
1. Download `PS5Upload.exe`
2. Run on Windows 10/11
3. Enter PS5 IP and connect
---
## 🚀 Performance
- **Upload Speed:** 100-120 MB/s (Gigabit Ethernet)
- **Download Speed:** Same high-speed protocol
- **Stability:** Zero connection drops (from v1.3.0)
- **Tested:** 42,801+ files uploaded successfully
---
## 🔧 Technical Details
### New Protocol Command
- `CMD_DOWNLOAD_FILE` (0x13) - Download files from PS5
### Server Changes
- Added sendfile-based download handler
- Fixed LIST_DIR to return actual file sizes
- Zero-copy file transfer
### Client Changes
- 4 new UI panels (Search, Favorites, Profiles, Download)
- JSON-based persistence (ps5_profiles.json, ps5_favorites.json)
- Custom dark theme for all ComboBox dropdowns
- ~500+ lines of new code
---
## ⬆️ Upgrading from v1.3.0
1. Replace server: Copy new `ps5_upload_server.elf` to PS5
2. Replace client: Download new `PS5Upload.exe`
3. Your settings will be preserved
**New files created:**
- `ps5_profiles.json` - Saved PS5 profiles
- `ps5_favorites.json` - Saved favorite paths
---
## 📋 Files in This Release
- `ps5_upload_server.elf` (129 KB) - PS5 server payload
- `PS5Upload.exe` (8.2 MB) - Windows client (self-contained)
---
## 🙏 Credits
**By Manos**
Special thanks to the PS5 homebrew community!
---
**Enjoy the new features!** 🚀
-263
View File
@@ -1,263 +0,0 @@
# GitHub Upload Instructions - PS5 Upload Suite
## 📁 Correct Folder to Upload
**Source Path:**
```
C:\Users\HACKMAN\Desktop\ps5 test\ps5_rom_keys\ps5_upload_suite\client\bin\Release\net6.0-windows\win-x64\
```
This folder contains the **complete, self-contained Windows executable** with all dependencies.
---
## 🗑️ Step 1: Delete Old Release on GitHub
1. Go to your GitHub repository
2. Navigate to **Releases** tab
3. Find the old/incorrect release
4. Click **Delete** on the old release
5. Confirm deletion
**Or delete via Git:**
```bash
# Delete old tag
git tag -d v1.0
git push origin :refs/tags/v1.0
# Delete old files from repository
git rm -r ps5upload-windows-x64/
git commit -m "Remove incorrect Windows build"
git push origin main
```
---
## 📦 Step 2: Create Release Package
### Option A: Via PowerShell (Automated)
```powershell
# Navigate to project root
cd "C:\Users\HACKMAN\Desktop\ps5 test\ps5_rom_keys\ps5_upload_suite"
# Create release directory
New-Item -ItemType Directory -Force -Path ".\github_release"
# Copy correct files
Copy-Item -Path ".\client\bin\Release\net6.0-windows\win-x64\*" -Destination ".\github_release\" -Recurse
# Copy payload
Copy-Item -Path ".\payload\ps5_upload_server.elf" -Destination ".\github_release\"
# Create ZIP
Compress-Archive -Path ".\github_release\*" -DestinationPath ".\PS5Upload-Windows-x64-v1.0.zip" -Force
Write-Host "Release package created: PS5Upload-Windows-x64-v1.0.zip"
```
### Option B: Manual
1. Create new folder: `PS5Upload-Windows-x64`
2. Copy **ALL files** from `win-x64\` folder
3. Add `ps5_upload_server.elf` from `payload\` folder
4. Create ZIP: `PS5Upload-Windows-x64-v1.0.zip`
---
## ⬆️ Step 3: Upload to GitHub
### Via GitHub Web Interface:
1. Go to your repository on GitHub
2. Click **Releases** → **Create a new release**
3. Fill in:
- **Tag:** `v1.0`
- **Title:** `PS5 Upload Suite v1.0 - Windows x64`
- **Description:**
```markdown
# PS5 Upload Suite v1.0
## Windows x64 Release
Self-contained executable for Windows 10/11 (64-bit)
No .NET Runtime installation required!
## What's Included:
- PS5Upload.exe (Windows GUI client)
- ps5_upload_server.elf (PS5 server payload)
- All required dependencies
## How to Use:
1. Extract ZIP file
2. Run PS5Upload.exe
3. Load ps5_upload_server.elf to PS5 (via etaHEN)
4. Connect and upload files!
## Requirements:
- Windows 10/11 (64-bit)
- PS5 with etaHEN 2.0+ or GoldHEN
- Network connection to PS5
## File Size:
- Full package: ~50 MB
- Includes all .NET 6.0 dependencies
```
4. **Attach files:**
- Upload `PS5Upload-Windows-x64-v1.0.zip`
5. Click **Publish release**
### Via Git Command Line:
```bash
# Navigate to repository
cd "C:\Users\HACKMAN\Desktop\ps5 test\ps5_rom_keys\ps5_upload_suite"
# Add correct files
git add client/bin/Release/net6.0-windows/win-x64/
git commit -m "Add correct Windows x64 build with all dependencies"
git push origin main
# Create and push tag
git tag -a v1.0 -m "PS5 Upload Suite v1.0 - Windows x64"
git push origin v1.0
# Upload release asset via GitHub CLI (if installed)
gh release create v1.0 PS5Upload-Windows-x64-v1.0.zip --title "PS5 Upload Suite v1.0" --notes "Self-contained Windows x64 release"
```
---
## 📝 Step 4: Update Repository README
Add download link to main README.md:
```markdown
## Download
### Latest Release: v1.0
**Windows (x64):**
- [PS5Upload-Windows-x64-v1.0.zip](https://github.com/YOUR_USERNAME/ps5_upload_suite/releases/download/v1.0/PS5Upload-Windows-x64-v1.0.zip)
- Size: ~50 MB
- Self-contained (no .NET installation required)
**PS5 Server:**
- Included in Windows package: `ps5_upload_server.elf`
- Load via etaHEN or GoldHEN
### System Requirements:
- **Windows:** 10/11 (64-bit)
- **PS5:** Firmware with etaHEN 2.0+ or GoldHEN
```
---
## ✅ Verification Checklist
Before uploading, verify:
- [ ] Folder contains `PS5Upload.exe` (8+ MB)
- [ ] Folder contains `PS5Upload.dll`
- [ ] Folder contains `PS5Upload.runtimeconfig.json`
- [ ] Folder contains all DLL dependencies (100+ files)
- [ ] `ps5_upload_server.elf` is included
- [ ] ZIP file is created correctly
- [ ] Test: Extract ZIP and run `PS5Upload.exe` - should work without errors
---
## 🐛 Common Issues
### "The application requires .NET Runtime"
**Problem:** Wrong folder uploaded (missing dependencies)
**Solution:** Use the `win-x64` folder, not `release` folder
### "Missing DLL files"
**Problem:** Incomplete upload
**Solution:** Make sure ALL files from `win-x64` folder are included
### "Application won't start"
**Problem:** Corrupted ZIP or missing files
**Solution:** Re-create ZIP from scratch, include all files
---
## 📊 File Structure for GitHub
```
PS5Upload-Windows-x64-v1.0.zip
├── PS5Upload.exe (Main executable)
├── PS5Upload.dll (Application library)
├── PS5Upload.runtimeconfig.json (Runtime configuration)
├── ps5_upload_server.elf (PS5 server payload)
├── Accessibility.dll (Dependency)
├── D3DCompiler_47_cor3.dll (Dependency)
├── DirectWriteForwarder.dll (Dependency)
├── Microsoft.*.dll (100+ Microsoft dependencies)
├── PresentationCore.dll (WPF dependency)
├── PresentationFramework.dll (WPF dependency)
├── ReachFramework.dll (WPF dependency)
├── System.*.dll (System dependencies)
├── UIAutomationClient.dll (UI dependency)
├── UIAutomationProvider.dll (UI dependency)
├── UIAutomationTypes.dll (UI dependency)
├── WindowsBase.dll (Windows dependency)
├── WindowsFormsIntegration.dll (Windows dependency)
├── api-ms-win-*.dll (Windows API dependencies)
├── clrcompression.dll (Compression)
├── clretwrc.dll (ETW)
├── clrjit.dll (JIT compiler)
├── coreclr.dll (CoreCLR runtime)
├── createdump.exe (Debug tool)
├── hostfxr.dll (Host)
├── hostpolicy.dll (Host policy)
├── mscordaccore.dll (DAC)
├── mscordaccore_amd64_amd64_*.dll (DAC)
├── mscordbi.dll (Debugger)
├── mscorlib.dll (Core library)
├── msquic.dll (QUIC)
├── ucrtbase.dll (C runtime)
├── vcruntime140.dll (VC runtime)
└── vcruntime140_cor3.dll (VC runtime)
```
**Total:** ~150 files, ~50 MB
---
## 🎯 Quick Commands Summary
```powershell
# 1. Create release package
cd "C:\Users\HACKMAN\Desktop\ps5 test\ps5_rom_keys\ps5_upload_suite"
Compress-Archive -Path ".\client\bin\Release\net6.0-windows\win-x64\*" -DestinationPath ".\PS5Upload-Windows-x64-v1.0.zip" -Force
# 2. Test locally
Expand-Archive -Path ".\PS5Upload-Windows-x64-v1.0.zip" -DestinationPath ".\test_extract" -Force
.\test_extract\PS5Upload.exe
# 3. Upload to GitHub (manual via web interface)
# Go to: https://github.com/YOUR_USERNAME/ps5_upload_suite/releases/new
# Upload: PS5Upload-Windows-x64-v1.0.zip
```
---
## ✅ Final Steps
1. **Delete old release** on GitHub
2. **Create ZIP** from `win-x64` folder
3. **Test ZIP** locally (extract and run)
4. **Upload to GitHub** as new release
5. **Update README** with download link
6. **Announce** the correct release
---
**The correct folder is:**
```
C:\Users\HACKMAN\Desktop\ps5 test\ps5_rom_keys\ps5_upload_suite\client\bin\Release\net6.0-windows\win-x64\
```
**This contains everything needed for a working Windows release!**
Binary file not shown.
Binary file not shown.
Binary file not shown.
+34 -6
View File
@@ -2,11 +2,11 @@
**By Manos**
**Version 1.3.0 - Stable Release**
**Version 2.0.0 - Feature-Rich Release**
Custom high-speed file transfer system for PS5 with etaHEN. Achieves **100+ MB/s** transfer speeds using a custom binary protocol.
⭐ **NEW in v1.3.0:** Complete stability overhaul - **42,801+ files uploaded with ZERO errors!**
⭐ **NEW in v2.0.0:** 4 Major Features Added - Download Files, File Search, Favorites/Bookmarks, Multi-PS5 Support!
![PS5 Upload Client](screenshots/screenshot1.png)
![Upload in Progress](screenshots/screenshot2.png)
@@ -86,6 +86,10 @@ Custom high-speed file transfer system for PS5 with etaHEN. Achieves **100+ MB/s
✅ **Real-time Progress** - Speed & percentage
✅ **Folder Upload** - Recursive directory upload
✅ **Storage Info** - Free space display
✅ **Download Files** - Download from PS5 to PC (NEW v2.0)
✅ **File Search** - Real-time filtering of PS5 files (NEW v2.0)
✅ **Favorites/Bookmarks** - Quick navigation to saved paths (NEW v2.0)
✅ **Multi-PS5 Support** - Save and switch between multiple PS5 profiles (NEW v2.0)
---
@@ -154,6 +158,7 @@ See [PROTOCOL.md](PROTOCOL.md) for detailed protocol documentation.
- `START_UPLOAD` - Begin file upload
- `UPLOAD_CHUNK` - Upload file chunk
- `END_UPLOAD` - Finish upload
- `DOWNLOAD_FILE` - Download file from PS5 (NEW v2.0)
- `SHUTDOWN` - Shutdown server
---
@@ -186,15 +191,38 @@ See [PROTOCOL.md](PROTOCOL.md) for detailed protocol documentation.
---
## 📝 What's New in v1.3.0
## 📝 What's New in v2.0.0
See [CHANGELOG.md](CHANGELOG.md) for complete list of all 15 bug fixes.
### 🎉 4 Major New Features:
### Highlights:
#### 1. 📥 Download Files (PS5 → PC)
- Right-click any file → "⬇️ Download to PC"
- Save file dialog for destination selection
- Real-time progress tracking with speed display
- Optimized with sendfile for maximum speed
#### 2. 🔍 File Search
- Search box in PS5 Files panel
- Real-time filtering as you type
- Case-insensitive search
- Quick "Clear" button to reset
#### 3. ⭐ Favorites/Bookmarks
- Save frequently used PS5 paths
- Quick dropdown navigation
- Add/Remove favorite paths
- Persistent storage in JSON
#### 4. 🎮 Multi-PS5 Support
- Save multiple PS5 profiles (IP + name)
- Quick switch between different PS5 consoles
- Dropdown profile selector
- Persistent profile storage
### Previous Stability (v1.3.0):
- ✅ **Zero connection drops** - 5 minute socket timeout + aggressive keepalive
- ✅ **Fully responsive UI** - Async updates + throttled logging
- ✅ **No memory leaks** - Proper resource disposal
- ✅ **Optimal stability** - 6 parallel single-connection uploads
- ✅ **Tested:** 42,801 files uploaded with 100% success rate
---
+166
View File
@@ -0,0 +1,166 @@
# 🎉 PS5 Upload Suite v2.0.0 - Feature-Rich Release
## 🚀 What's New
This is a **major feature release** adding 4 powerful new capabilities to the PS5 Upload Suite!
---
## ✨ New Features
### 1. 📥 Download Files (PS5 → PC)
Finally! You can now download files from your PS5 back to your PC.
**How to use:**
- Right-click any file in PS5 Files panel
- Select "⬇️ Download to PC"
- Choose where to save the file
- Watch the progress with real-time speed tracking
**Technical Details:**
- Uses sendfile optimization for maximum speed
- Zero-copy transfer on PS5 side
- Same high-speed protocol as uploads
- Full progress tracking
---
### 2. 🔍 File Search
Quickly find files in large directories without scrolling.
**How to use:**
- Type in the Search box below Current Path
- Files are filtered in real-time as you type
- Case-insensitive search
- Click "✖ Clear" to reset
**Perfect for:**
- Finding specific game saves
- Locating config files
- Searching through large mod folders
---
### 3. ⭐ Favorites/Bookmarks
Save your frequently used PS5 paths for instant navigation.
**How to use:**
- Navigate to any path (e.g., `/data/games`)
- Click "⭐ Add" to save it
- Use the Favorites dropdown to quickly jump to saved paths
- Click "🗑️ Remove" to delete a favorite
**Saved paths persist between sessions!**
---
### 4. 🎮 Multi-PS5 Support
Manage multiple PS5 consoles with ease.
**How to use:**
- Enter a PS5 IP address
- Click "💾 Save Profile" and give it a name (e.g., "Living Room PS5")
- Use the Profile dropdown to quickly switch between PS5s
- Click "🗑️ Delete Profile" to remove saved profiles
**Perfect for:**
- Users with multiple PS5 consoles
- Testing on different systems
- Switching between home and friend's PS5
---
## 🔧 Technical Improvements
### Server-Side (payload)
- Added `CMD_DOWNLOAD_FILE` (0x13) command
- Implemented sendfile-based download handler
- Fixed `LIST_DIR` to return actual file sizes (not 0)
- Zero-copy file transfer for downloads
### Client-Side
- Added `DownloadFileAsync()` method to Protocol
- Implemented search filtering with `ObservableCollection`
- Added JSON-based profile and favorites persistence
- Custom ComboBox templates for dark theme consistency
- Improved UI responsiveness
---
## 📊 Statistics
**Lines of Code Added:** ~500+ lines
**New Protocol Commands:** 1 (DOWNLOAD_FILE)
**New UI Elements:** 3 panels (Search, Favorites, Profiles)
**Persistent Storage Files:** 2 (ps5_profiles.json, ps5_favorites.json)
---
## 🎨 UI Improvements
- All ComboBox dropdowns now have proper dark theme
- All buttons show full text without cutoff
- Consistent styling across all new features
- Responsive layout that adapts to content
---
## 📦 Files Included
### Server
- `payload/ps5_upload_server.elf` - Updated with download support
### Client
- `client/bin/Release/net6.0-windows/win-x64/PS5Upload.exe` - Full v2.0 client
---
## ⬆️ Upgrading from v1.3.0
1. **Replace server payload:**
- Copy new `ps5_upload_server.elf` to `/data/etaHEN/payloads/`
- Reload with elfldr
2. **Replace client:**
- Close old PS5Upload.exe
- Replace with new version
- Your settings will be preserved
**Note:** v2.0 creates two new files:
- `ps5_profiles.json` - Saved PS5 profiles
- `ps5_favorites.json` - Saved favorite paths
---
## 🐛 Known Issues
None reported yet! This is a stable release built on top of the rock-solid v1.3.0 foundation.
---
## 🔮 Future Features (Not in v2.0)
Still on the roadmap:
- Disk Space Warning before upload
- Duplicate File Detection
- File Verification (SHA256)
- Resume Interrupted Uploads
- Queue Management (reorder, pause)
- Transfer History
- Scheduled Uploads
---
## 🙏 Thanks
Special thanks to the PS5 homebrew community for testing and feedback!
---
**Enjoy the new features!** 🚀
**- Manos**
+53
View File
@@ -1,8 +1,61 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace PS5Upload
{
public partial class App : Application
{
private static readonly string LogFilePath = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
$"ps5upload_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log");
private static readonly object _logLock = new object();
public App()
{
// Global exception handlers
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
LogToFile("=== Application Started ===");
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
LogToFile($"DISPATCHER EXCEPTION: {e.Exception}");
e.Handled = true; // Prevent crash, but log it
MessageBox.Show($"Error: {e.Exception.Message}\n\nCheck log file: {LogFilePath}",
"PS5 Upload Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
LogToFile($"UNHANDLED EXCEPTION: {ex}");
}
private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
{
LogToFile($"TASK EXCEPTION: {e.Exception}");
e.SetObserved(); // Prevent crash
}
public static void LogToFile(string message)
{
try
{
lock (_logLock)
{
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
File.AppendAllText(LogFilePath, $"[{timestamp}] {message}\n");
}
}
catch { /* Ignore logging errors */ }
}
}
}
+335 -55
View File
@@ -7,6 +7,12 @@
Icon="ps5_logo.png">
<Window.Resources>
<!-- Override system colors for ComboBox dropdown -->
<SolidColorBrush x:Key="{x:Static SystemColors.WindowBrushKey}" Color="#2D2D30"/>
<SolidColorBrush x:Key="{x:Static SystemColors.WindowColorKey}" Color="#2D2D30"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#2D2D30"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlColorKey}" Color="#2D2D30"/>
<Style TargetType="Button">
<Setter Property="Background" Value="#007ACC"/>
<Setter Property="Foreground" Value="White"/>
@@ -94,43 +100,128 @@
Padding="15"
Margin="0,0,0,15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="PS5 IP Address:"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Column="1"
x:Name="IpAddressTextBox"
Text="192.168.0.160"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<Button Grid.Column="2"
x:Name="ConnectButton"
Content="Connect"
Click="ConnectButton_Click"
Width="100"
Margin="0,0,10,0"/>
<StackPanel Grid.Column="3"
Orientation="Horizontal"
VerticalAlignment="Center">
<Ellipse x:Name="StatusIndicator"
Width="12"
Height="12"
Fill="#DC3545"
Margin="0,0,8,0"/>
<TextBlock x:Name="StatusText"
Text="Disconnected"
Foreground="#999999"/>
<!-- PS5 Profile Selection -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="PS5 Profile:"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<ComboBox x:Name="PS5ProfileComboBox"
Width="200"
VerticalAlignment="Center"
SelectionChanged="PS5ProfileComboBox_SelectionChanged"
Background="#2D2D30"
Foreground="White"
BorderBrush="#3E3E42">
<ComboBox.Template>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Name="ToggleButton"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"
Background="#2D2D30"
BorderBrush="#3E3E42"
BorderThickness="1"/>
<ContentPresenter Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="5,3,23,3"
VerticalAlignment="Center"
HorizontalAlignment="Left"/>
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border Name="DropDownBorder"
Background="#2D2D30"
BorderThickness="1"
BorderBrush="#3E3E42"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</ComboBox.Template>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Background" Value="#2D2D30"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Border"
Background="#2D2D30"
Padding="5">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Border" Property="Background" Value="#007ACC"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#007ACC"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<Button Content="💾 Save Profile"
Click="SaveProfileButton_Click"
Width="140"
Margin="10,0,0,0"
Background="#28A745"/>
<Button Content="🗑️ Delete Profile"
Click="DeleteProfileButton_Click"
Width="150"
Margin="5,0,0,0"
Background="#DC3545"/>
</StackPanel>
<!-- IP Address and Connect -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="PS5 IP Address:"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<TextBox Grid.Column="1"
x:Name="IpAddressTextBox"
Text="192.168.0.160"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<Button Grid.Column="2"
x:Name="ConnectButton"
Content="Connect"
Click="ConnectButton_Click"
Width="100"/>
</Grid>
</Grid>
</Border>
@@ -234,33 +325,145 @@
</Border>
<StackPanel Grid.Row="1"
Orientation="Horizontal"
Margin="10"
Background="#2D2D30">
<TextBlock Text="Current Path:"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<TextBox x:Name="CurrentPathTextBox"
Text="/data"
Width="200"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<Button Content="Go"
Click="GoButton_Click"
Width="60"/>
<StackPanel Orientation="Horizontal" Margin="0,0,0,5">
<TextBlock Text="Current Path:"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<TextBox x:Name="CurrentPathTextBox"
Text="/data"
Width="200"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<Button Content="Go"
Click="GoButton_Click"
Width="60"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,5">
<TextBlock Text="⭐ Favorites:"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<ComboBox x:Name="FavoritesComboBox"
Width="200"
VerticalAlignment="Center"
SelectionChanged="FavoritesComboBox_SelectionChanged"
Background="#2D2D30"
Foreground="White"
BorderBrush="#3E3E42">
<ComboBox.Template>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Name="ToggleButton"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"
Background="#2D2D30"
BorderBrush="#3E3E42"
BorderThickness="1"/>
<ContentPresenter Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="5,3,23,3"
VerticalAlignment="Center"
HorizontalAlignment="Left"/>
<Popup Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border Name="DropDownBorder"
Background="#2D2D30"
BorderThickness="1"
BorderBrush="#3E3E42"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</ComboBox.Template>
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Background" Value="#2D2D30"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Border"
Background="#2D2D30"
Padding="5">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Border" Property="Background" Value="#007ACC"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#007ACC"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<Button Content="⭐ Add"
Click="AddFavoriteButton_Click"
Width="90"
Margin="10,0,0,0"
Background="#28A745"/>
<Button Content="🗑️ Remove"
Click="RemoveFavoriteButton_Click"
Width="110"
Margin="5,0,0,0"
Background="#DC3545"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="🔍 Search:"
VerticalAlignment="Center"
Margin="0,0,10,0"/>
<TextBox x:Name="SearchTextBox"
Width="250"
VerticalAlignment="Center"
TextChanged="SearchTextBox_TextChanged"
Background="#1E1E1E"
Foreground="White"
BorderBrush="#3E3E42"/>
<Button Content="✖ Clear"
Click="ClearSearchButton_Click"
Width="100"
Margin="5,0,0,0"
Background="#3E3E42"/>
</StackPanel>
</StackPanel>
<ListBox Grid.Row="2"
x:Name="PS5FilesListBox"
BorderThickness="0"
SelectionMode="Extended"
MouseDoubleClick="PS5FilesListBox_MouseDoubleClick">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="⬇️ Download to PC" Click="DownloadMenuItem_Click"/>
<Separator/>
<MenuItem Header="📝 Rename" Click="RenameMenuItem_Click"/>
<MenuItem Header="📋 Copy" Click="CopyMenuItem_Click"/>
<MenuItem Header="✂️ Move" Click="MoveMenuItem_Click"/>
<Separator/>
<MenuItem Header="🗑️ Delete" Click="DeleteMenuItem_Click"/>
<MenuItem Header="🗑️ Delete Selected" Click="DeleteSelectedMenuItem_Click"/>
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.ItemTemplate>
@@ -281,14 +484,88 @@
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Row="3"
Margin="10">
<TextBlock x:Name="StorageInfoText"
Text="Storage: --"
FontSize="12"
Foreground="#999999"
HorizontalAlignment="Center"/>
</StackPanel>
<Border Grid.Row="3"
Background="#2D2D30"
BorderBrush="#3E3E42"
BorderThickness="1"
CornerRadius="4"
Margin="10"
Padding="10">
<StackPanel>
<TextBlock Text="💾 PS5 Storage"
FontSize="12"
FontWeight="Bold"
Foreground="#007ACC"
HorizontalAlignment="Center"
Margin="0,0,0,8"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Text="Free:"
FontSize="11"
Foreground="#999999"
Margin="0,0,8,4"/>
<TextBlock Grid.Row="0" Grid.Column="1"
x:Name="StorageFreeText"
Text="--"
FontSize="11"
Foreground="#4EC9B0"
FontWeight="Bold"
HorizontalAlignment="Right"
Margin="0,0,0,4"/>
<TextBlock Grid.Row="1" Grid.Column="0"
Text="Used:"
FontSize="11"
Foreground="#999999"
Margin="0,0,8,4"/>
<TextBlock Grid.Row="1" Grid.Column="1"
x:Name="StorageUsedText"
Text="--"
FontSize="11"
Foreground="#CE9178"
FontWeight="Bold"
HorizontalAlignment="Right"
Margin="0,0,0,4"/>
<TextBlock Grid.Row="2" Grid.Column="0"
Text="Total:"
FontSize="11"
Foreground="#999999"
Margin="0,0,8,4"/>
<TextBlock Grid.Row="2" Grid.Column="1"
x:Name="StorageTotalText"
Text="--"
FontSize="11"
Foreground="White"
FontWeight="Bold"
HorizontalAlignment="Right"
Margin="0,0,0,4"/>
<!-- Progress Bar -->
<ProgressBar Grid.Row="3" Grid.ColumnSpan="2"
x:Name="StorageProgressBar"
Height="6"
Margin="0,6,0,0"
Minimum="0"
Maximum="100"
Value="0"
Foreground="#CE9178"
Background="#3E3E42"/>
</Grid>
</StackPanel>
</Border>
</Grid>
</Border>
@@ -326,6 +603,9 @@
Padding="10"
TextWrapping="Wrap"
IsReadOnly="True"
IsReadOnlyCaretVisible="False"
Focusable="False"
Cursor="Arrow"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"/>
+867 -207
View File
File diff suppressed because it is too large. Load diff
+116 -12
View File
@@ -22,6 +22,7 @@ namespace PS5Upload
StartUpload = 0x10,
UploadChunk = 0x11,
EndUpload = 0x12,
DownloadFile = 0x13,
Shutdown = 0xFF
}
@@ -39,7 +40,7 @@ namespace PS5Upload
{
private TcpClient? _client;
private NetworkStream? _stream;
private const int BufferSize = 32 * 1024 * 1024; // 32MB for maximum throughput
private const int BufferSize = 4 * 1024 * 1024; // 4MB chunks - MUST match payload BUFFER_SIZE
public bool IsConnected => _client?.Connected ?? false;
@@ -130,7 +131,7 @@ namespace PS5Upload
return (response, data);
}
private async Task ReadExactAsync(byte[] buffer, int count, int timeoutMs = 30000)
private async Task ReadExactAsync(byte[] buffer, int count, int timeoutMs = 120000)
{
if (_stream == null) throw new InvalidOperationException("Not connected");
@@ -142,7 +143,13 @@ namespace PS5Upload
while (offset < count)
{
int read = await _stream.ReadAsync(buffer, offset, count - offset, cts.Token);
if (read == 0) throw new IOException("Connection closed");
if (read == 0)
{
// Give PS5 a moment to recover before declaring connection dead
await Task.Delay(100);
read = await _stream.ReadAsync(buffer, offset, count - offset, cts.Token);
if (read == 0) throw new IOException("Connection closed");
}
offset += read;
}
}
@@ -257,7 +264,7 @@ namespace PS5Upload
return response == Response.Ok;
}
public event Action<string> OnProgressMessage;
public event Action<string>? OnProgressMessage;
public async Task<bool> DeleteDirAsync(string path)
{
@@ -313,7 +320,8 @@ namespace PS5Upload
}
// Give server a moment to fully close the deletion thread
await Task.Delay(100);
// CRITICAL: Increased delay to prevent race condition with next delete
await Task.Delay(500);
return true;
}
@@ -405,7 +413,20 @@ namespace PS5Upload
if (_stream == null) return false;
await _stream.WriteAsync(sendBuffer, 0, 5 + bytesRead, cancellationToken);
// FIX: Add timeout to WriteAsync to prevent hanging if PS5 becomes unresponsive
// 30 second timeout per chunk write - should be more than enough for 4MB
using var writeTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(30));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, writeTimeout.Token);
try
{
await _stream.WriteAsync(sendBuffer, 0, 5 + bytesRead, linkedCts.Token);
}
catch (OperationCanceledException) when (writeTimeout.IsCancellationRequested)
{
// Write timeout - PS5 is unresponsive
return false;
}
totalSent += bytesRead;
bytesRemaining -= bytesRead;
@@ -435,18 +456,101 @@ namespace PS5Upload
}
}
// Send END_UPLOAD - fire-and-forget for maximum speed
// Don't wait for response to avoid PS5 payload bottleneck
// Send END_UPLOAD and wait for response
// CRITICAL: Must wait for response to avoid protocol desync on chunked uploads
try
{
await SendCommandAsync(Command.EndUpload);
// Immediately return success without waiting for response
// This eliminates the PS5 response handling bottleneck
return true;
var (endResponse, _) = await ReceiveResponseAsync();
return endResponse == Response.Ok;
}
catch
{
return true; // Assume success if connection issues
return false; // Connection issue means upload failed
}
}
public async Task<bool> DownloadFileAsync(string remotePath, string localPath, IProgress<UploadProgress>? progress = null, CancellationToken cancellationToken = default)
{
try
{
// Send download command
byte[] pathBytes = Encoding.UTF8.GetBytes(remotePath);
await SendCommandAsync(Command.DownloadFile, pathBytes);
// Receive response header (5 bytes: 1 response + 4 data_len)
byte[] header = new byte[5];
await ReadExactAsync(header, 5);
Response response = (Response)header[0];
uint dataLen = BitConverter.ToUInt32(header, 1);
// Check if error response
if (response == Response.Error)
{
if (dataLen > 0)
{
byte[] errorMsg = new byte[dataLen];
await ReadExactAsync(errorMsg, (int)dataLen);
}
return false;
}
// Expecting RESP_DATA with 8-byte file size
if (response != Response.Data || dataLen != 8)
{
return false;
}
// Read file size (8 bytes)
byte[] sizeBytes = new byte[8];
await ReadExactAsync(sizeBytes, 8);
long fileSize = BitConverter.ToInt64(sizeBytes, 0);
// Now read raw file data directly from socket
using var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.None, BufferSize);
byte[] buffer = new byte[BufferSize];
long totalReceived = 0;
var startTime = DateTime.Now;
while (totalReceived < fileSize)
{
if (cancellationToken.IsCancellationRequested) return false;
int toRead = (int)Math.Min(BufferSize, fileSize - totalReceived);
int received = await _stream!.ReadAsync(buffer, 0, toRead, cancellationToken);
if (received == 0) break;
await fs.WriteAsync(buffer, 0, received, cancellationToken);
totalReceived += received;
// Report progress every 5MB or at completion
if (totalReceived % (5 * 1024 * 1024) < BufferSize || totalReceived == fileSize)
{
var elapsed = DateTime.Now - startTime;
double speed = elapsed.TotalSeconds > 0 ? totalReceived / elapsed.TotalSeconds : 0;
progress?.Report(new UploadProgress
{
BytesSent = totalReceived,
TotalBytes = fileSize,
SpeedBytesPerSecond = speed,
AverageSpeedBytesPerSecond = speed,
ElapsedTime = elapsed,
EstimatedTimeRemaining = speed > 0 ? TimeSpan.FromSeconds((fileSize - totalReceived) / speed) : TimeSpan.Zero,
CurrentFileName = Path.GetFileName(localPath)
});
}
}
return totalReceived == fileSize;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Download error: {ex.Message}");
return false;
}
}
-160
View File
@@ -1,160 +0,0 @@
# PS5 Upload Suite - GitHub Release Package Creator
# Creates a clean, ready-to-upload ZIP file for GitHub releases
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "PS5 Upload Suite - Release Packager" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Configuration
$sourceFolder = ".\client\bin\Release\net6.0-windows\win-x64"
$payloadFile = ".\payload\ps5_upload_server.elf"
$outputZip = ".\PS5Upload-Windows-x64-v1.0.zip"
$tempFolder = ".\github_release_temp"
# Check if source folder exists
if (-not (Test-Path $sourceFolder)) {
Write-Host "[ERROR] Source folder not found: $sourceFolder" -ForegroundColor Red
Write-Host "Please build the project first!" -ForegroundColor Yellow
exit 1
}
Write-Host "[1/5] Checking source files..." -ForegroundColor Yellow
# Count files in source
$fileCount = (Get-ChildItem -Path $sourceFolder -File).Count
Write-Host " Found $fileCount files in source folder" -ForegroundColor Green
# Check for main executable
$mainExe = Join-Path $sourceFolder "PS5Upload.exe"
if (-not (Test-Path $mainExe)) {
Write-Host "[ERROR] PS5Upload.exe not found!" -ForegroundColor Red
exit 1
}
$exeSize = (Get-Item $mainExe).Length / 1MB
Write-Host " PS5Upload.exe: $([math]::Round($exeSize, 2)) MB" -ForegroundColor Green
# Check for payload
if (Test-Path $payloadFile) {
$payloadSize = (Get-Item $payloadFile).Length / 1KB
Write-Host " ps5_upload_server.elf: $([math]::Round($payloadSize, 2)) KB" -ForegroundColor Green
} else {
Write-Host " [WARN] ps5_upload_server.elf not found - will skip" -ForegroundColor Yellow
}
Write-Host ""
Write-Host "[2/5] Creating temporary folder..." -ForegroundColor Yellow
# Clean up old temp folder
if (Test-Path $tempFolder) {
Remove-Item -Path $tempFolder -Recurse -Force
}
# Create temp folder
New-Item -ItemType Directory -Path $tempFolder -Force | Out-Null
Write-Host " Created: $tempFolder" -ForegroundColor Green
Write-Host ""
Write-Host "[3/5] Copying files..." -ForegroundColor Yellow
# Copy all files from source
Copy-Item -Path "$sourceFolder\*" -Destination $tempFolder -Recurse -Force
Write-Host " Copied $fileCount files from win-x64 build" -ForegroundColor Green
# Copy payload if exists
if (Test-Path $payloadFile) {
Copy-Item -Path $payloadFile -Destination $tempFolder -Force
Write-Host " Copied ps5_upload_server.elf" -ForegroundColor Green
}
# Create README for the release
$readmeContent = @"
# PS5 Upload Suite v1.0 - Windows x64
## What's This?
Self-contained Windows application for uploading files to PS5 console via network.
## Requirements
- Windows 10/11 (64-bit)
- PS5 with etaHEN 2.0+ or GoldHEN
- Network connection between PC and PS5
## Installation
1. Extract all files to a folder
2. Run PS5Upload.exe
## First Time Setup
1. Load ps5_upload_server.elf to your PS5 (via etaHEN payload injector)
2. Note the IP address shown on PS5 screen
3. Open PS5Upload.exe on Windows
4. Enter PS5 IP address
5. Click Connect
## Usage
1. Click "Browse" to select files
2. Click "Upload" to transfer to PS5
3. Files will be saved to /data/ on PS5
## Troubleshooting
- **Connection failed:** Make sure PS5 server is running and IP is correct
- **Upload failed:** Check PS5 has enough free space
- **App won't start:** Make sure all files are extracted
## Support
GitHub: https://github.com/YOUR_USERNAME/ps5_upload_suite
Issues: https://github.com/YOUR_USERNAME/ps5_upload_suite/issues
## License
MIT License - See repository for details
"@
Set-Content -Path "$tempFolder\README.txt" -Value $readmeContent -Encoding UTF8
Write-Host " Created README.txt" -ForegroundColor Green
Write-Host ""
Write-Host "[4/5] Creating ZIP archive..." -ForegroundColor Yellow
# Remove old ZIP if exists
if (Test-Path $outputZip) {
Remove-Item -Path $outputZip -Force
Write-Host " Removed old ZIP file" -ForegroundColor Yellow
}
# Create ZIP
Compress-Archive -Path "$tempFolder\*" -DestinationPath $outputZip -CompressionLevel Optimal -Force
if (Test-Path $outputZip) {
$zipSize = (Get-Item $outputZip).Length / 1MB
Write-Host " Created: $outputZip" -ForegroundColor Green
Write-Host " Size: $([math]::Round($zipSize, 2)) MB" -ForegroundColor Green
} else {
Write-Host "[ERROR] Failed to create ZIP file!" -ForegroundColor Red
exit 1
}
Write-Host ""
Write-Host "[5/5] Cleaning up..." -ForegroundColor Yellow
# Remove temp folder
Remove-Item -Path $tempFolder -Recurse -Force
Write-Host " Removed temporary files" -ForegroundColor Green
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "SUCCESS!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Release package created: $outputZip" -ForegroundColor Green
Write-Host "Size: $([math]::Round($zipSize, 2)) MB" -ForegroundColor Green
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host "1. Test the ZIP file locally (extract and run PS5Upload.exe)" -ForegroundColor White
Write-Host "2. Go to GitHub: https://github.com/YOUR_USERNAME/ps5_upload_suite/releases/new" -ForegroundColor White
Write-Host "3. Create new release with tag 'v1.0'" -ForegroundColor White
Write-Host "4. Upload: $outputZip" -ForegroundColor White
Write-Host "5. Publish release" -ForegroundColor White
Write-Host ""
Write-Host "Press any key to exit..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
-33
View File
@@ -1,33 +0,0 @@
@echo off
cd /d "%~dp0"
"C:\Program Files\GitHub CLI\gh.exe" release create v1.2 PS5Upload-Windows-x64-v1.2-Complete.zip --title "PS5 Upload Suite v1.2 - Complete Bug Fix" --notes "# PS5 Upload Suite v1.2 - Complete Bug Fix Release
## What's Fixed:
### CLIENT FIXES:
- Bug #1: Connection timeout reduced to 5 seconds (fast fail on wrong IP)
- Bug #2: Folder deletion timeout increased to 60 seconds
### SERVER FIXES:
- Bug #3: Async folder deletion - NO MORE TIMEOUT on large folders!
- Server responds immediately
- Deletion happens in background thread
- PS5 notification when complete
## What's Included:
- PS5Upload.exe - Windows client with bug fixes
- ps5_upload_server.elf - PS5 server with async deletion
- All dependencies included
## Installation:
1. Extract ZIP file
2. Run PS5Upload.exe on Windows
3. Upload ps5_upload_server.elf to PS5 via FTP
4. Load with etaHEN payload injector
## IMPORTANT:
You MUST update BOTH files (client and server)
## Requirements:
- Windows 10/11 (64-bit)
- PS5 with etaHEN 2.0+ or GoldHEN"
-122
View File
@@ -1,122 +0,0 @@
# PS5 Upload Suite v1.1 - Bug Fix Release Package Creator
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "PS5 Upload Suite v1.1 - Bug Fix Release" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Configuration
$sourceFolder = ".\client\bin\Release\net6.0-windows\win-x64"
$payloadFile = ".\payload\ps5_upload_server.elf"
$outputZip = ".\PS5Upload-Windows-x64-v1.1-BugFix.zip"
$tempFolder = ".\github_release_v1.1_temp"
Write-Host "[INFO] Bug Fixes in v1.1:" -ForegroundColor Yellow
Write-Host " 1. Connection timeout: 5 seconds (fast fail on wrong IP)" -ForegroundColor Green
Write-Host " 2. Folder deletion timeout: 60 seconds (handles large folders)" -ForegroundColor Green
Write-Host ""
# Check if source folder exists
if (-not (Test-Path $sourceFolder)) {
Write-Host "[ERROR] Source folder not found: $sourceFolder" -ForegroundColor Red
exit 1
}
Write-Host "[1/5] Checking source files..." -ForegroundColor Yellow
$fileCount = (Get-ChildItem -Path $sourceFolder -File).Count
Write-Host " Found $fileCount files" -ForegroundColor Green
# Clean up old temp folder
if (Test-Path $tempFolder) {
Remove-Item -Path $tempFolder -Recurse -Force
}
Write-Host ""
Write-Host "[2/5] Creating temporary folder..." -ForegroundColor Yellow
New-Item -ItemType Directory -Path $tempFolder -Force | Out-Null
Write-Host ""
Write-Host "[3/5] Copying files..." -ForegroundColor Yellow
Copy-Item -Path "$sourceFolder\*" -Destination $tempFolder -Recurse -Force
Write-Host " Copied $fileCount files" -ForegroundColor Green
if (Test-Path $payloadFile) {
Copy-Item -Path $payloadFile -Destination $tempFolder -Force
Write-Host " Copied ps5_upload_server.elf" -ForegroundColor Green
}
# Create CHANGELOG
$changelogContent = @"
# PS5 Upload Suite v1.1 - Bug Fix Release
## What's Fixed:
### Bug #1: Connection Timeout
- **Problem:** Application took 30+ seconds to detect wrong IP address
- **Fix:** Added 5-second timeout for connection attempts
- **Result:** Fast failure on incorrect IP - immediate feedback
### Bug #2: Folder Deletion Timeout
- **Problem:** Deleting large game folders caused timeout errors
- **Fix:** Increased timeout to 60 seconds for folder operations
- **Result:** Successfully handles large folders (10GB+ games)
## Installation:
Same as v1.0 - extract and run PS5Upload.exe
## Upgrading from v1.0:
Simply replace your old PS5Upload.exe with the new one.
No other changes needed.
## Requirements:
- Windows 10/11 (64-bit)
- PS5 with etaHEN 2.0+ or GoldHEN
- Network connection
## Support:
GitHub: https://github.com/YOUR_USERNAME/ps5_upload_suite
"@
Set-Content -Path "$tempFolder\CHANGELOG.txt" -Value $changelogContent -Encoding UTF8
Write-Host " Created CHANGELOG.txt" -ForegroundColor Green
Write-Host ""
Write-Host "[4/5] Creating ZIP archive..." -ForegroundColor Yellow
if (Test-Path $outputZip) {
Remove-Item -Path $outputZip -Force
}
Compress-Archive -Path "$tempFolder\*" -DestinationPath $outputZip -CompressionLevel Optimal -Force
if (Test-Path $outputZip) {
$zipSize = (Get-Item $outputZip).Length / 1MB
Write-Host " Created: $outputZip" -ForegroundColor Green
Write-Host " Size: $([math]::Round($zipSize, 2)) MB" -ForegroundColor Green
} else {
Write-Host "[ERROR] Failed to create ZIP!" -ForegroundColor Red
exit 1
}
Write-Host ""
Write-Host "[5/5] Cleaning up..." -ForegroundColor Yellow
Remove-Item -Path $tempFolder -Recurse -Force
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "SUCCESS!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Release package created: $outputZip" -ForegroundColor Green
Write-Host "Size: $([math]::Round($zipSize, 2)) MB" -ForegroundColor Green
Write-Host ""
Write-Host "Bug Fixes:" -ForegroundColor Yellow
Write-Host " [FIXED] Connection timeout: 5 seconds" -ForegroundColor Green
Write-Host " [FIXED] Folder deletion timeout: 60 seconds" -ForegroundColor Green
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Yellow
Write-Host "1. Test locally: Extract and run PS5Upload.exe" -ForegroundColor White
Write-Host "2. Upload to GitHub as v1.1 release" -ForegroundColor White
Write-Host "3. Tag: v1.1" -ForegroundColor White
Write-Host ""
-199
View File
@@ -1,199 +0,0 @@
# PS5 Upload Suite v1.2 - Complete Bug Fix Release
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "PS5 Upload Suite v1.2 - Complete Fix" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# Configuration
$sourceFolder = ".\client\bin\Release\net6.0-windows\win-x64"
$payloadFile = ".\payload\ps5_upload_server.elf"
$outputZip = ".\PS5Upload-Windows-x64-v1.2-Complete.zip"
$tempFolder = ".\github_release_v1.2_temp"
Write-Host "[INFO] Bug Fixes in v1.2:" -ForegroundColor Yellow
Write-Host " CLIENT:" -ForegroundColor Cyan
Write-Host " 1. Connection timeout: 5 seconds (fast fail on wrong IP)" -ForegroundColor Green
Write-Host " 2. Folder deletion timeout: 60 seconds client-side" -ForegroundColor Green
Write-Host " SERVER:" -ForegroundColor Cyan
Write-Host " 3. Async folder deletion (no more timeout on large folders!)" -ForegroundColor Green
Write-Host ""
# Check files
if (-not (Test-Path $sourceFolder)) {
Write-Host "[ERROR] Client folder not found!" -ForegroundColor Red
exit 1
}
if (-not (Test-Path $payloadFile)) {
Write-Host "[ERROR] Server payload not found!" -ForegroundColor Red
exit 1
}
Write-Host "[1/5] Checking files..." -ForegroundColor Yellow
$fileCount = (Get-ChildItem -Path $sourceFolder -File).Count
$payloadSize = (Get-Item $payloadFile).Length / 1KB
Write-Host " Client files: $fileCount" -ForegroundColor Green
Write-Host " Server payload: $([math]::Round($payloadSize, 2)) KB" -ForegroundColor Green
# Clean up
if (Test-Path $tempFolder) {
Remove-Item -Path $tempFolder -Recurse -Force
}
Write-Host ""
Write-Host "[2/5] Creating package..." -ForegroundColor Yellow
New-Item -ItemType Directory -Path $tempFolder -Force | Out-Null
Write-Host ""
Write-Host "[3/5] Copying files..." -ForegroundColor Yellow
Copy-Item -Path "$sourceFolder\*" -Destination $tempFolder -Recurse -Force
Write-Host " Copied client files" -ForegroundColor Green
Copy-Item -Path $payloadFile -Destination $tempFolder -Force
Write-Host " Copied server payload" -ForegroundColor Green
# Create detailed changelog
$changelogContent = @"
# PS5 Upload Suite v1.2 - Complete Bug Fix Release
## What's Fixed:
### CLIENT FIXES:
#### Bug #1: Connection Timeout
- **Problem:** Application took 30+ seconds to detect wrong IP address
- **Fix:** Added 5-second connection timeout
- **Result:** Immediate feedback on connection failure
#### Bug #2: Client-Side Timeout
- **Problem:** Client timeout on folder operations
- **Fix:** Increased client timeout to 60 seconds
- **Result:** Better handling of server operations
### SERVER FIXES:
#### Bug #3: Folder Deletion Timeout (MAJOR FIX!)
- **Problem:** Deleting large game folders (10GB+) caused "Read timeout" error
- **Fix:** Folder deletion now runs asynchronously in background thread
- **How it works:**
1. Server responds immediately: "Deleting folder in background..."
2. Deletion happens in separate thread
3. PS5 notification appears when complete
- **Result:** NO MORE TIMEOUT! Works with any folder size!
## Installation:
1. Extract ZIP file
2. Run PS5Upload.exe on Windows
3. Upload ps5_upload_server.elf to PS5 (via FTP or USB)
4. Load ps5_upload_server.elf with etaHEN payload injector
5. Connect and enjoy!
## Upgrading from v1.0/v1.1:
Replace both:
- PS5Upload.exe (Windows client)
- ps5_upload_server.elf (PS5 server)
IMPORTANT: You MUST update BOTH files for the fixes to work!
## Testing the Fixes:
1. **Connection timeout:** Try wrong IP - should fail in 5 seconds
2. **Folder deletion:** Delete large game folder - should work without timeout
## Requirements:
- Windows 10/11 (64-bit)
- PS5 with etaHEN 2.0+ or GoldHEN
- Network connection
## Support:
GitHub: https://github.com/YOUR_USERNAME/ps5_upload_suite
Issues: Report bugs on GitHub Issues page
---
**Version:** 1.2
**Release Date:** January 12, 2026
**Build:** Complete Bug Fix Release
"@
Set-Content -Path "$tempFolder\CHANGELOG_v1.2.txt" -Value $changelogContent -Encoding UTF8
Write-Host " Created CHANGELOG_v1.2.txt" -ForegroundColor Green
# Create quick start guide
$quickStartContent = @"
# PS5 Upload Suite v1.2 - Quick Start
## Step 1: Load Server on PS5
1. Copy ps5_upload_server.elf to USB drive
2. Insert USB into PS5
3. Open etaHEN payload injector
4. Load ps5_upload_server.elf
5. Note the IP address shown on screen
## Step 2: Connect from Windows
1. Run PS5Upload.exe
2. Enter PS5 IP address
3. Click Connect
4. You're ready!
## Step 3: Upload Files
1. Click "Browse Folder" to select files
2. Click "Upload" to transfer
3. Files appear in /data/etaHEN/games on PS5
## Deleting Large Folders:
- Now works perfectly with async deletion!
- Server responds immediately
- Deletion happens in background
- PS5 notification when complete
Enjoy! 🎮
"@
Set-Content -Path "$tempFolder\QUICK_START.txt" -Value $quickStartContent -Encoding UTF8
Write-Host " Created QUICK_START.txt" -ForegroundColor Green
Write-Host ""
Write-Host "[4/5] Creating ZIP..." -ForegroundColor Yellow
if (Test-Path $outputZip) {
Remove-Item -Path $outputZip -Force
}
Compress-Archive -Path "$tempFolder\*" -DestinationPath $outputZip -CompressionLevel Optimal -Force
if (Test-Path $outputZip) {
$zipSize = (Get-Item $outputZip).Length / 1MB
Write-Host " Created: $outputZip" -ForegroundColor Green
Write-Host " Size: $([math]::Round($zipSize, 2)) MB" -ForegroundColor Green
} else {
Write-Host "[ERROR] Failed to create ZIP!" -ForegroundColor Red
exit 1
}
Write-Host ""
Write-Host "[5/5] Cleaning up..." -ForegroundColor Yellow
Remove-Item -Path $tempFolder -Recurse -Force
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host "SUCCESS!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "Release: $outputZip" -ForegroundColor Green
Write-Host "Size: $([math]::Round($zipSize, 2)) MB" -ForegroundColor Green
Write-Host ""
Write-Host "Bug Fixes Applied:" -ForegroundColor Yellow
Write-Host " [CLIENT] Connection timeout: 5 seconds" -ForegroundColor Green
Write-Host " [CLIENT] Folder deletion timeout: 60 seconds" -ForegroundColor Green
Write-Host " [SERVER] Async folder deletion (NO MORE TIMEOUT!)" -ForegroundColor Green
Write-Host ""
Write-Host "IMPORTANT: Update BOTH client and server!" -ForegroundColor Yellow
Write-Host ""
Write-Host "Next steps:" -ForegroundColor Cyan
Write-Host "1. Test locally" -ForegroundColor White
Write-Host "2. Upload ps5_upload_server.elf to PS5" -ForegroundColor White
Write-Host "3. Load with etaHEN" -ForegroundColor White
Write-Host "4. Test folder deletion with large folder" -ForegroundColor White
Write-Host "5. Upload to GitHub as v1.2" -ForegroundColor White
Write-Host ""
+1 -1
View File
@@ -8,7 +8,7 @@ echo ""
echo "[+] Compiling..."
rm -f ps5_upload_server.elf
/home/hackman/ps5sdk_copy/bin/prospero-clang -Wall -O3 -pthread -o ps5_upload_server.elf main.c
/opt/ps5-payload-sdk/bin/prospero-clang -Wall -O3 -pthread -o ps5_upload_server.elf main.c
if [ -f "ps5_upload_server.elf" ]; then
echo ""
+126 -31
View File
@@ -22,7 +22,7 @@
#include <ifaddrs.h>
#define SERVER_PORT 9113
#define BUFFER_SIZE (8 * 1024 * 1024)
#define BUFFER_SIZE (4 * 1024 * 1024) // 4MB - MUST match client BufferSize
#define MAX_PATH 2048
#define DISK_WORKER_COUNT 4
#define QUEUE_MAX_SIZE 32
@@ -107,6 +107,7 @@ void release_file_mutex(const char *path) {
#define CMD_START_UPLOAD 0x10
#define CMD_UPLOAD_CHUNK 0x11
#define CMD_END_UPLOAD 0x12
#define CMD_DOWNLOAD_FILE 0x13
#define CMD_SHUTDOWN 0xFF
// Protocol responses
@@ -508,22 +509,33 @@ void handle_list_dir(client_session_t *session, const char *path) {
break;
}
// Determine type - use d_type if available, otherwise fall back to stat()
// Determine type and get file size
uint8_t type = 0;
uint64_t size = 0;
uint64_t timestamp = 0;
snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
struct stat st;
if (entry->d_type == DT_DIR) {
type = 1;
} else if (entry->d_type == DT_UNKNOWN) {
// d_type not supported on this filesystem - use stat() as fallback
snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
struct stat st;
if (stat(full_path, &st) == 0 && S_ISDIR(st.st_mode)) {
type = 1;
if (stat(full_path, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
type = 1;
} else {
size = st.st_size;
timestamp = st.st_mtime;
}
}
} else {
// Regular file - get size
if (stat(full_path, &st) == 0) {
size = st.st_size;
timestamp = st.st_mtime;
}
}
// else: DT_REG or other = file (type = 0)
uint64_t size = 0; // Don't need file size for browsing
uint64_t timestamp = 0; // Don't need timestamp for browsing
*ptr++ = type;
memcpy(ptr, &name_len, 2);
@@ -821,29 +833,47 @@ void handle_start_upload(client_session_t *session, const uint8_t *data, uint32_
pthread_mutex_lock(session->file_mutex);
// Open file for writing
// For chunked uploads, we need to pre-allocate the file on first chunk
// and open with r+b for subsequent chunks
if (chunk_offset > 0) {
// Chunk mode: open existing file or create if needed
// Subsequent chunk: open existing file
session->upload_fp = fopen(path, "r+b");
if (!session->upload_fp) {
// File doesn't exist, create it with full size
session->upload_fp = fopen(path, "wb");
if (session->upload_fp) {
// Allocate full file size
if (fseeko(session->upload_fp, file_size - 1, SEEK_SET) == 0) {
fputc(0, session->upload_fp);
fflush(session->upload_fp);
}
fclose(session->upload_fp);
session->upload_fp = fopen(path, "r+b");
}
}
if (session->upload_fp) {
// Seek to chunk offset
fseeko(session->upload_fp, chunk_offset, SEEK_SET);
}
} else {
// Normal mode: create new file
// First chunk or small file: create new file
// Check if this is a chunked upload (file_size > chunk that will be sent)
// We pre-allocate for large files to ensure r+b works for subsequent chunks
session->upload_fp = fopen(path, "wb");
if (session->upload_fp && file_size > 100 * 1024 * 1024) {
// Large file - pre-allocate full size for chunked upload
// FIX: Check if pre-allocation succeeds (disk might be full!)
int prealloc_ok = 0;
if (fseeko(session->upload_fp, file_size - 1, SEEK_SET) == 0) {
if (fputc(0, session->upload_fp) != EOF) {
if (fflush(session->upload_fp) == 0) {
prealloc_ok = 1;
}
}
}
if (!prealloc_ok) {
// Pre-allocation failed - likely disk full
fclose(session->upload_fp);
session->upload_fp = NULL;
pthread_mutex_unlock(session->file_mutex);
release_file_mutex(path);
session->file_mutex = NULL;
unlink(path); // Remove partial file
send_error(session->sock, "Disk full - cannot pre-allocate file");
return;
}
// Seek back to beginning
fseeko(session->upload_fp, 0, SEEK_SET);
}
}
pthread_mutex_unlock(session->file_mutex);
@@ -855,7 +885,7 @@ void handle_start_upload(client_session_t *session, const uint8_t *data, uint32_
return;
}
// Use HUGE buffer (8MB) for maximum write speed
// Use 4MB buffer for write speed
setvbuf(session->upload_fp, NULL, _IOFBF, BUFFER_SIZE);
strncpy(session->upload_path, path, sizeof(session->upload_path) - 1);
@@ -863,7 +893,7 @@ void handle_start_upload(client_session_t *session, const uint8_t *data, uint32_
session->upload_received = chunk_offset;
// Increase socket receive buffer for this upload session
int huge_buf = 8 * 1024 * 1024; // 8MB receive buffer
int huge_buf = 4 * 1024 * 1024; // 4MB receive buffer - matches client
setsockopt(session->sock, SOL_SOCKET, SO_RCVBUF, &huge_buf, sizeof(huge_buf));
send_response(session->sock, RESP_READY, NULL, 0);
@@ -923,6 +953,66 @@ void handle_end_upload(client_session_t *session) {
send_ok(session->sock, "Upload complete");
}
// Handle DOWNLOAD_FILE
void handle_download_file(client_session_t *session, const char *path) {
int fd = open(path, O_RDONLY);
if (fd < 0) {
send_error(session->sock, "Cannot open file");
return;
}
struct stat st;
if (fstat(fd, &st) != 0) {
close(fd);
send_error(session->sock, "Cannot stat file");
return;
}
// Send file size first
uint64_t file_size = st.st_size;
send_response(session->sock, RESP_DATA, &file_size, sizeof(file_size));
// Use sendfile for zero-copy transfer (same as FTP server optimization)
#ifdef __FreeBSD__
off_t offset = 0;
off_t sbytes = 0;
// Send in chunks for progress tracking
const off_t CHUNK_SIZE = 100 * 1024 * 1024; // 100MB chunks
while (offset < file_size) {
off_t to_send = (file_size - offset > CHUNK_SIZE) ? CHUNK_SIZE : (file_size - offset);
sbytes = 0;
int result = sendfile(fd, session->sock, offset, to_send, NULL, &sbytes, 0);
if (result < 0 && errno != EAGAIN) {
close(fd);
return;
}
offset += sbytes;
if (sbytes == 0) break;
}
#else
// Fallback for non-FreeBSD systems
char *buffer = malloc(BUFFER_SIZE);
if (buffer) {
ssize_t n;
while ((n = read(fd, buffer, BUFFER_SIZE)) > 0) {
ssize_t sent = 0;
while (sent < n) {
ssize_t s = send(session->sock, buffer + sent, n - sent, 0);
if (s <= 0) break;
sent += s;
}
if (sent != n) break;
}
free(buffer);
}
#endif
close(fd);
}
// Handle client
void *client_thread(void *arg) {
client_session_t *session = (client_session_t *)arg;
@@ -1025,6 +1115,11 @@ void *client_thread(void *arg) {
case CMD_END_UPLOAD:
handle_end_upload(session);
break;
case CMD_DOWNLOAD_FILE:
if (data) {
handle_download_file(session, (const char *)data);
}
break;
case CMD_SHUTDOWN:
send_ok(session->sock, "Shutting down");
free(buffer);
@@ -1074,8 +1169,8 @@ int main() {
int no_sigpipe = 1;
setsockopt(server_sock, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe));
// 8MB buffers for sustained high throughput
int buf_size = 8 * 1024 * 1024;
// 4MB buffers - matches client
int buf_size = 4 * 1024 * 1024;
setsockopt(server_sock, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size));
setsockopt(server_sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size));
@@ -1128,8 +1223,8 @@ int main() {
// Aggressive TCP socket options for sustained high speed
setsockopt(client_sock, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe));
// Increase buffers to 8MB for maximum throughput
int large_buf = 8 * 1024 * 1024;
// Increase buffers to 4MB - matches client
int large_buf = 4 * 1024 * 1024;
setsockopt(client_sock, SOL_SOCKET, SO_RCVBUF, &large_buf, sizeof(large_buf));
setsockopt(client_sock, SOL_SOCKET, SO_SNDBUF, &large_buf, sizeof(large_buf));
Binary file not shown.
-195
View File
@@ -1,195 +0,0 @@
#!/usr/bin/env python3
"""
GitHub Release Uploader for PS5 Upload Suite
Uploads v1.2 release to GitHub using GitHub API
"""
import os
import sys
import json
import requests
from pathlib import Path
# GitHub Configuration
GITHUB_TOKEN = "YOUR_GITHUB_TOKEN_HERE" # Replace with your token
GITHUB_REPO = "manos555555/PS5-Upload-Suite"
RELEASE_TAG = "v1.2"
RELEASE_NAME = "PS5 Upload Suite v1.2 - Complete Bug Fix"
RELEASE_BODY = """# PS5 Upload Suite v1.2 - Complete Bug Fix Release
## 🐛 What's Fixed:
### CLIENT FIXES:
- **Bug #1:** Connection timeout reduced to 5 seconds (fast fail on wrong IP)
- **Bug #2:** Folder deletion timeout increased to 60 seconds
### SERVER FIXES:
- **Bug #3:** Async folder deletion - NO MORE TIMEOUT on large folders! ✅
- Server responds immediately
- Deletion happens in background thread
- PS5 notification when complete
## 📦 What's Included:
- `PS5Upload.exe` - Windows client with bug fixes
- `ps5_upload_server.elf` - PS5 server with async deletion
- All dependencies included
- Self-contained (no .NET installation required)
## 🚀 Installation:
1. Extract ZIP file
2. Run `PS5Upload.exe` on Windows
3. Upload `ps5_upload_server.elf` to PS5 via FTP
4. Load with etaHEN payload injector
5. Connect and enjoy!
## ⚠️ IMPORTANT:
**You MUST update BOTH files:**
- Windows client: `PS5Upload.exe`
- PS5 server: `ps5_upload_server.elf`
## 💡 Testing:
- **Connection timeout:** Try wrong IP - fails in 5 seconds
- **Folder deletion:** Delete large game folder - works without timeout!
## 📋 Requirements:
- Windows 10/11 (64-bit)
- PS5 with etaHEN 2.0+ or GoldHEN
- Network connection
## 🔗 Links:
- [Report Issues](https://github.com/manos555555/PS5-Upload-Suite/issues)
- [Documentation](https://github.com/manos555555/PS5-Upload-Suite/blob/main/README.md)
---
**Version:** 1.2
**Release Date:** January 12, 2026
**Build:** Complete Bug Fix Release
"""
def create_github_release(token, repo, tag, name, body):
"""Create a GitHub release"""
url = f"https://api.github.com/repos/{repo}/releases"
headers = {
"Authorization": f"token {token}",
"Accept": "application/vnd.github.v3+json"
}
data = {
"tag_name": tag,
"name": name,
"body": body,
"draft": False,
"prerelease": False
}
print(f"Creating release {tag}...")
response = requests.post(url, headers=headers, json=data)
if response.status_code == 201:
print(f"✅ Release created successfully!")
return response.json()
else:
print(f"❌ Failed to create release: {response.status_code}")
print(f"Response: {response.text}")
return None
def upload_release_asset(token, upload_url, file_path):
"""Upload a file to GitHub release"""
# Remove the {?name,label} template from upload_url
upload_url = upload_url.split("{")[0]
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path) / (1024 * 1024) # MB
print(f"\nUploading {file_name} ({file_size:.2f} MB)...")
headers = {
"Authorization": f"token {token}",
"Content-Type": "application/zip"
}
params = {"name": file_name}
with open(file_path, 'rb') as f:
response = requests.post(
upload_url,
headers=headers,
params=params,
data=f
)
if response.status_code == 201:
print(f"✅ {file_name} uploaded successfully!")
return True
else:
print(f"❌ Failed to upload {file_name}: {response.status_code}")
print(f"Response: {response.text}")
return False
def main():
print("=" * 70)
print("PS5 Upload Suite - GitHub Release Uploader")
print("=" * 70)
print()
# Check token
if GITHUB_TOKEN == "YOUR_GITHUB_TOKEN_HERE":
print("❌ ERROR: Please set your GitHub token in the script!")
print()
print("To get a token:")
print("1. Go to: https://github.com/settings/tokens")
print("2. Generate new token (classic)")
print("3. Select 'repo' scope")
print("4. Copy token and paste in this script")
return 1
# Check if release file exists
release_file = Path("PS5Upload-Windows-x64-v1.2-Complete.zip")
if not release_file.exists():
print(f"❌ ERROR: Release file not found: {release_file}")
return 1
print(f"📦 Release file: {release_file}")
print(f"📊 Size: {release_file.stat().st_size / (1024*1024):.2f} MB")
print()
# Create release
release_data = create_github_release(
GITHUB_TOKEN,
GITHUB_REPO,
RELEASE_TAG,
RELEASE_NAME,
RELEASE_BODY
)
if not release_data:
return 1
# Upload asset
upload_url = release_data.get("upload_url")
if not upload_url:
print("❌ ERROR: No upload URL in release response")
return 1
success = upload_release_asset(
GITHUB_TOKEN,
upload_url,
str(release_file)
)
if success:
print()
print("=" * 70)
print("✅ SUCCESS! Release published to GitHub")
print("=" * 70)
print()
print(f"🔗 Release URL: {release_data.get('html_url')}")
print()
return 0
else:
return 1
if __name__ == "__main__":
sys.exit(main())