mirror of
https://github.com/manos555555/PS5-Suite.git
synced 2026-10-06 14:00:26 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
264ad6210d | ||
|
|
db48bc6fb2 | ||
|
|
4ac43ebb8b | ||
|
|
20caced5f4 | ||
|
|
285279788f | ||
|
|
70d174cecc | ||
|
|
f128c6a6b4 | ||
|
|
c211c086ac | ||
|
|
4ca30876c7 | ||
|
|
5ae3c1709e | ||
|
|
3374e87bfe | ||
|
|
c21d73f41d | ||
|
|
5ce9d470bc | ||
|
|
0eb159bf88 | ||
|
|
4ff160232f | ||
|
|
a5e40ce245 | ||
|
|
bb7d90411c | ||
|
|
00013aae76 | ||
|
|
6d8d802962 | ||
|
|
f3a1d5e436 | ||
|
|
bad3029e32 | ||
|
|
a51fffef83 | ||
|
|
f89eaf4e31 |
No files matched your search
-60
@@ -1,60 +0,0 @@
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio cache/options
|
||||
.vs/
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
*.dll
|
||||
*.exe
|
||||
*.pdb
|
||||
*.cache
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# Files built by Visual Studio
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Caches
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.log
|
||||
*.bak
|
||||
*.old
|
||||
|
||||
# PowerShell script
|
||||
convert_to_ico.ps1
|
||||
@@ -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!**
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
# PS5 Upload Protocol Specification
|
||||
|
||||
## Overview
|
||||
Custom binary protocol for high-speed file transfers between PC and PS5.
|
||||
Port: 9113
|
||||
|
||||
## Message Format
|
||||
|
||||
All messages follow this structure:
|
||||
```
|
||||
[Command (1 byte)][Data Length (4 bytes)][Data (variable)]
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
### Client → Server
|
||||
|
||||
| Command | Value | Description | Data Format |
|
||||
|---------|-------|-------------|-------------|
|
||||
| PING | 0x01 | Test connection | None |
|
||||
| LIST_STORAGE | 0x02 | Get storage info | None |
|
||||
| LIST_DIR | 0x03 | List directory | Path (null-terminated string) |
|
||||
| CREATE_DIR | 0x04 | Create directory | Path (null-terminated string) |
|
||||
| DELETE_FILE | 0x05 | Delete file | Path (null-terminated string) |
|
||||
| DELETE_DIR | 0x06 | Delete directory | Path (null-terminated string) |
|
||||
| START_UPLOAD | 0x10 | Start file upload | Path (null-terminated) + File size (8 bytes) |
|
||||
| UPLOAD_CHUNK | 0x11 | Upload file chunk | Chunk data (raw bytes) |
|
||||
| END_UPLOAD | 0x12 | Finish upload | None |
|
||||
| SHUTDOWN | 0xFF | Shutdown server | None |
|
||||
|
||||
### Server → Client
|
||||
|
||||
| Response | Value | Description | Data Format |
|
||||
|----------|-------|-------------|-------------|
|
||||
| OK | 0x01 | Success | Optional message |
|
||||
| ERROR | 0x02 | Error occurred | Error message (null-terminated) |
|
||||
| DATA | 0x03 | Response data | Variable format |
|
||||
| READY | 0x04 | Ready for next chunk | None |
|
||||
| PROGRESS | 0x05 | Upload progress | Bytes written (8 bytes) |
|
||||
|
||||
## Data Formats
|
||||
|
||||
### LIST_STORAGE Response
|
||||
```
|
||||
[Drive count (4 bytes)]
|
||||
For each drive:
|
||||
[Path length (2 bytes)][Path][Total space (8 bytes)][Free space (8 bytes)]
|
||||
```
|
||||
|
||||
### LIST_DIR Response
|
||||
```
|
||||
[Entry count (4 bytes)]
|
||||
For each entry:
|
||||
[Type (1 byte: 0=file, 1=dir)][Name length (2 bytes)][Name][Size (8 bytes)][Timestamp (8 bytes)]
|
||||
```
|
||||
|
||||
## Flow Examples
|
||||
|
||||
### Upload File
|
||||
```
|
||||
Client: START_UPLOAD "/data/test.bin" size=1048576
|
||||
Server: READY
|
||||
Client: UPLOAD_CHUNK [4MB data]
|
||||
Server: PROGRESS bytes=4194304
|
||||
Client: UPLOAD_CHUNK [remaining data]
|
||||
Server: PROGRESS bytes=1048576
|
||||
Client: END_UPLOAD
|
||||
Server: OK
|
||||
```
|
||||
|
||||
### List Directory
|
||||
```
|
||||
Client: LIST_DIR "/data"
|
||||
Server: DATA [directory listing]
|
||||
```
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
- 4MB socket buffers
|
||||
- SO_NOSIGPIPE enabled
|
||||
- TCP_NODELAY for low latency
|
||||
- Direct disk writes (no temp files)
|
||||
- Streaming chunks (no full file buffering)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,14 +2,16 @@
|
||||
|
||||
**By Manos**
|
||||
|
||||
**Version 1.3.0 - Stable Release**
|
||||
**Version 3.1.0 - Parallel Chunked Uploads & Real-time Progress**
|
||||
|
||||
Custom high-speed file transfer system for PS5 with etaHEN. Achieves **100+ MB/s** transfer speeds using a custom binary protocol.
|
||||
Custom high-speed file transfer system for PS5 with etaHEN. Achieves **104+ MB/s** upload speeds for large files using parallel chunked uploads!
|
||||
|
||||
⭐ **NEW in v1.3.0:** Complete stability overhaul - **42,801+ files uploaded with ZERO errors!**
|
||||
⭐ **NEW in v3.1.0:** Parallel chunked uploads (2x faster!), real-time speed/ETA display, storage improvements!
|
||||
|
||||

|
||||

|
||||
📱 **Android Mobile Client available!**
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||
@@ -20,24 +22,43 @@ Custom high-speed file transfer system for PS5 with etaHEN. Achieves **100+ MB/s
|
||||
- **Port:** 9113
|
||||
- **Protocol:** Custom binary (optimized for speed)
|
||||
- **Features:**
|
||||
- 4MB socket buffers
|
||||
- 16MB socket buffers (optimized for maximum throughput)
|
||||
- SO_NOSIGPIPE enabled
|
||||
- TCP_NODELAY for low latency
|
||||
- Direct disk writes (no temp files)
|
||||
- Direct `write()` syscalls (bypasses stdio buffering for 80-110 MB/s upload)
|
||||
- Per-file mutex locking (parallel writes without race conditions)
|
||||
- File pre-allocation for large files (reduces fragmentation)
|
||||
- Multi-threaded client handling
|
||||
|
||||
### 2. Windows GUI Client
|
||||
- **File:** `client/bin/Release/net6.0-windows/win-x64/publish/PS5Upload.exe`
|
||||
- **Framework:** .NET 6.0 WPF
|
||||
- **Features:**
|
||||
- Modern dark theme UI
|
||||
- Modern dark theme UI (opens maximized for better visibility)
|
||||
- Drag & drop file/folder upload
|
||||
- Browse PS5 filesystem
|
||||
- Real-time upload progress
|
||||
- Speed indicator (MB/s)
|
||||
- Real-time upload progress with speed tracking
|
||||
- 8 parallel large file uploads (optimal aggregate throughput)
|
||||
- 128MB TCP buffers for maximum network performance
|
||||
- Transfer History with success/failed tracking
|
||||
- Auto-clear history on startup option
|
||||
- Storage space display
|
||||
- Recursive folder upload
|
||||
|
||||
### 3. 📱 Android Mobile Client (NEW in v2.2.0)
|
||||
- **File:** `mobile/bin/Release/net6.0-android/publish/com.ps5tools.uploadsuite-Signed.apk`
|
||||
- **Framework:** .NET MAUI
|
||||
- **Features:**
|
||||
- **Multi-PS5 Profiles** - Save multiple PS5 with different IPs
|
||||
- Upload files from phone to PS5
|
||||
- Download files from PS5 to phone
|
||||
- Browse PS5 filesystem
|
||||
- Delete files/folders
|
||||
- Favorites for quick navigation
|
||||
- Debug Log with Copy function
|
||||
- Transfer History
|
||||
- Share downloaded files
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
@@ -80,32 +101,44 @@ Custom high-speed file transfer system for PS5 with etaHEN. Achieves **100+ MB/s
|
||||
✅ **Robust Error Handling** - Graceful failures
|
||||
|
||||
### Windows Client
|
||||
✅ **Modern UI** - Dark theme, clean design
|
||||
✅ **Modern UI** - Dark theme, maximized window for better visibility
|
||||
✅ **Drag & Drop** - Files and folders
|
||||
✅ **Browse PS5** - Navigate filesystem
|
||||
✅ **Real-time Progress** - Speed & percentage
|
||||
✅ **Real-time Progress** - Speed & percentage tracking
|
||||
✅ **Optimized Upload** - 8 parallel connections for 88-110 MB/s aggregate speed (NEW v2.1)
|
||||
✅ **Transfer History** - Track all uploads/downloads with success/failed status (NEW v2.1)
|
||||
✅ **Auto-Clear History** - Optional auto-clear on startup (NEW v2.1)
|
||||
✅ **Folder Upload** - Recursive directory upload
|
||||
✅ **Storage Info** - Free space display
|
||||
✅ **Download Files** - Download from PS5 to PC (v2.0)
|
||||
✅ **File Search** - Real-time filtering of PS5 files (v2.0)
|
||||
✅ **Favorites/Bookmarks** - Quick navigation to saved paths (v2.0)
|
||||
✅ **Multi-PS5 Support** - Save and switch between multiple PS5 profiles (v2.0)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Performance
|
||||
|
||||
### v1.3.0 Tested Results:
|
||||
- ✅ **42,801 files** uploaded successfully
|
||||
- ✅ **Zero errors** - 100% success rate
|
||||
- ✅ **60-150 MB/s** sustained throughput
|
||||
- ✅ **Peak:** 190 MB/s per connection
|
||||
### v3.1.0 Optimized Results:
|
||||
- ✅ **104+ MB/s** upload speed for large files (parallel chunked uploads)
|
||||
- ✅ **4 parallel chunk connections** for maximum throughput
|
||||
- ✅ **500MB chunks** - optimal size for PS5 disk performance
|
||||
- ✅ **Real-time progress** - Speed/ETA updates during upload
|
||||
- ✅ **Zero chunk failures** - Fixed race conditions
|
||||
- ✅ **Fully responsive UI** throughout upload
|
||||
- ✅ **No memory leaks** - stable operation
|
||||
|
||||
| Network | Expected Speed |
|
||||
|---------|----------------|
|
||||
| **Gigabit Ethernet** | 100-120 MB/s |
|
||||
| **WiFi 6 (5GHz)** | 60-80 MB/s |
|
||||
| **WiFi 5 (5GHz)** | 40-60 MB/s |
|
||||
### Previous Results (v1.3.0):
|
||||
- ✅ **42,801 files** uploaded successfully
|
||||
- ✅ **60-150 MB/s** sustained throughput
|
||||
|
||||
**Note:** Speeds depend on network quality and PS5 disk performance.
|
||||
| Network | Expected Upload Speed | Expected Download Speed |
|
||||
|---------|----------------------|------------------------|
|
||||
| **Gigabit Ethernet** | 88-110 MB/s (aggregate) | 100-120 MB/s |
|
||||
| **WiFi 6 (5GHz)** | 32-70 MB/s (aggregate) | 60-80 MB/s |
|
||||
| **WiFi 5 (5GHz)** | 20-50 MB/s (aggregate) | 40-60 MB/s |
|
||||
|
||||
**Note:** Upload speeds depend on network quality and PS5 disk write performance. WiFi has ~40-60% overhead compared to Ethernet.
|
||||
|
||||
---
|
||||
|
||||
@@ -154,6 +187,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 +220,125 @@ See [PROTOCOL.md](PROTOCOL.md) for detailed protocol documentation.
|
||||
|
||||
---
|
||||
|
||||
## 📝 What's New in v1.3.0
|
||||
## 📝 What's New in v3.1.0
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for complete list of all 15 bug fixes.
|
||||
### 🚀 Performance Improvements:
|
||||
|
||||
### Highlights:
|
||||
#### 1. ⚡ Parallel Chunked Uploads (104 MB/s!)
|
||||
- **Large files (>100MB)** are now split into 500MB chunks
|
||||
- **4 parallel connections** upload chunks simultaneously
|
||||
- **Result:** ~104 MB/s upload speed (2x faster than before!)
|
||||
- **Fixed race condition:** First chunk creates file before others start
|
||||
- **Fixed closure bug:** Correct offset/size capture for parallel tasks
|
||||
|
||||
#### 2. 📊 Real-time Progress Display
|
||||
- **Speed display** now updates in real-time during chunked uploads
|
||||
- **ETA display** shows accurate time remaining
|
||||
- **Progress bar** correctly shows 0-100% for chunked files
|
||||
- No more speed dropping to 0 during large file uploads
|
||||
|
||||
#### 3. 💾 Storage Display Improvements
|
||||
- **Changed label** to "Data Storage (/data)" for clarity
|
||||
- **Uses statfs with f_bavail** for more accurate available space
|
||||
- **Real-time updates** every 5 seconds when connected
|
||||
|
||||
---
|
||||
|
||||
## 📝 What's New in v3.0.0
|
||||
|
||||
### 🐛 Critical Bug Fixes:
|
||||
|
||||
#### 1. 🔧 Path Normalization Fix
|
||||
- **Fixed:** Double-slash paths (`//mnt/ext1/...`) that caused directory creation to fail
|
||||
- **Affected:** All file operations (upload, download, delete, rename, copy, move)
|
||||
- **Solution:** Added `NormalizePath()` function in both client and server
|
||||
- **Result:** 100% reliable directory creation and file uploads
|
||||
|
||||
#### 2. 📱 Android Mobile Client
|
||||
- **NEW:** Full-featured Android app for PS5 file management
|
||||
- **Multi-PS5 Profiles** - Save and switch between multiple PS5 consoles
|
||||
- Upload files from phone to PS5
|
||||
- Download files from PS5 with Share option
|
||||
- Browse PS5 filesystem
|
||||
- Favorites for quick navigation
|
||||
- Debug Log with Copy to clipboard
|
||||
- Transfer History tracking
|
||||
|
||||
#### 3. 🛠️ Server Improvements
|
||||
- Path normalization in all handler functions
|
||||
- More robust error handling
|
||||
- Improved stability for parallel uploads
|
||||
|
||||
---
|
||||
|
||||
## 📝 What's New in v2.1.0
|
||||
|
||||
### 🚀 Performance Optimizations:
|
||||
|
||||
#### 1. ⚡ Massive Upload Speed Boost (88-110 MB/s)
|
||||
- **Server-side:** Replaced `fwrite()` with direct `write()` syscalls
|
||||
- **Client-side:** 8 parallel large file uploads (optimal for PS5 disk)
|
||||
- **Result:** 80-110 MB/s aggregate upload speed on Gigabit Ethernet
|
||||
- **Peak bursts:** Up to 2.05 GB/s when hitting disk cache
|
||||
- **Per-file:** 11-14 MB/s sustained per connection
|
||||
|
||||
#### 2. 📊 Transfer History
|
||||
- Complete history of all uploads and downloads
|
||||
- Success/Failed status tracking with error messages
|
||||
- Speed statistics (average, min, max)
|
||||
- Export to CSV/JSON for analysis
|
||||
- Persistent storage across sessions
|
||||
|
||||
#### 3. 🔄 Auto-Clear History on Startup
|
||||
- Optional checkbox to clear history automatically
|
||||
- Useful for keeping UI clean between sessions
|
||||
- Setting saved in `ps5_upload_settings.json`
|
||||
|
||||
#### 4. 🖥️ Maximized Window UI
|
||||
- Application opens in full-screen mode by default
|
||||
- Better visibility for large file transfers
|
||||
- Can be resized/restored as needed
|
||||
|
||||
### Technical Improvements:
|
||||
- ✅ **16MB socket buffers** (up from 4MB) for maximum throughput
|
||||
- ✅ **Per-file mutex locking** - Parallel writes without race conditions
|
||||
- ✅ **File pre-allocation** - Reduces disk fragmentation for large files
|
||||
- ✅ **Direct syscalls** - Bypasses stdio buffering overhead
|
||||
|
||||
---
|
||||
|
||||
## 📝 What's New in v2.0.0
|
||||
|
||||
### 🎉 4 Major New Features:
|
||||
|
||||
#### 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
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
# 🚀 PS5 Upload Suite v2.1.0 - Performance & UX Release
|
||||
|
||||
**Release Date:** January 19, 2026
|
||||
**By Manos**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
Version 2.1.0 brings **massive performance improvements** to upload speeds and several quality-of-life enhancements. Upload speeds have been optimized to achieve **88-110 MB/s aggregate throughput** on Gigabit Ethernet, with peak bursts up to **2.05 GB/s**.
|
||||
|
||||
---
|
||||
|
||||
## ⚡ What's New
|
||||
|
||||
### 1. 🚀 Massive Upload Speed Boost (88-110 MB/s)
|
||||
|
||||
**The Problem:**
|
||||
- Previous versions achieved 60-150 MB/s download speeds but only 4-12 MB/s upload speeds
|
||||
- Upload was bottlenecked by stdio buffering (`fwrite()`) and single-threaded disk writes
|
||||
|
||||
**The Solution:**
|
||||
- **Server-side:** Replaced `fwrite()` with direct `write()` syscalls
|
||||
- Bypasses stdio buffering overhead
|
||||
- Eliminates unnecessary memory copies
|
||||
- Direct kernel I/O for maximum performance
|
||||
|
||||
- **Client-side:** Optimized to 8 parallel large file uploads
|
||||
- Leverages PS5 disk's parallel write capacity
|
||||
- 128MB TCP buffers for maximum network throughput
|
||||
- Intelligent queuing system for large files (>100MB)
|
||||
|
||||
**Results:**
|
||||
- ✅ **88-110 MB/s** aggregate upload speed (Gigabit Ethernet)
|
||||
- ✅ **11-14 MB/s** per file sustained
|
||||
- ✅ **Peak bursts:** 610 MB/s - 2.05 GB/s (disk cache hits)
|
||||
- ✅ **WiFi 6:** 32-70 MB/s aggregate (still 3-5x faster than before)
|
||||
|
||||
### 2. 📊 Transfer History
|
||||
|
||||
**New Feature:** Complete tracking of all file transfers
|
||||
|
||||
- **Success/Failed Tracking:** Every upload and download is logged with status
|
||||
- **Speed Statistics:** Average, min, and max speeds for each transfer
|
||||
- **Error Messages:** Detailed error information for failed transfers
|
||||
- **Persistent Storage:** History saved to `ps5_transfer_history.json`
|
||||
- **Export Options:** Export to CSV or JSON for analysis
|
||||
- **Tabs:**
|
||||
- **All:** Complete transfer history
|
||||
- **Completed:** Only successful transfers
|
||||
- **Failed:** Only failed transfers (with retry/remove options)
|
||||
|
||||
**Use Cases:**
|
||||
- Verify all files uploaded successfully
|
||||
- Identify problematic files
|
||||
- Track transfer performance over time
|
||||
- Audit file operations
|
||||
|
||||
### 3. 🔄 Auto-Clear History on Startup
|
||||
|
||||
**New Feature:** Optional automatic history clearing
|
||||
|
||||
- **Checkbox:** "🔄 Auto Clear on Startup" in Transfer History section
|
||||
- **Persistent Setting:** Saved to `ps5_upload_settings.json`
|
||||
- **Use Case:** Keep UI clean between sessions without manual clearing
|
||||
- **Flexible:** Can be toggled on/off at any time
|
||||
|
||||
### 4. 🖥️ Maximized Window UI
|
||||
|
||||
**Improvement:** Better default window size
|
||||
|
||||
- Application now opens in **maximized mode** by default
|
||||
- Better visibility for large file transfers and logs
|
||||
- More space for Transfer History and file lists
|
||||
- Can still be resized/restored as needed
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Technical Improvements
|
||||
|
||||
### Server (ps5_upload_server.elf)
|
||||
|
||||
1. **Direct Syscalls for Upload:**
|
||||
```c
|
||||
// OLD: fwrite() + fflush() (slow)
|
||||
fwrite(data, 1, data_len, upload_fp);
|
||||
fflush(upload_fp);
|
||||
|
||||
// NEW: direct write() syscall (fast)
|
||||
write(upload_fd, data, data_len);
|
||||
```
|
||||
|
||||
2. **16MB Socket Buffers:**
|
||||
- Increased from 4MB to 16MB
|
||||
- `SO_RCVBUF` and `SO_SNDBUF` set to 16MB
|
||||
- Reduces TCP stalls and retransmissions
|
||||
|
||||
3. **Per-File Mutex Locking:**
|
||||
- Each file has its own mutex
|
||||
- Parallel writes to different files without race conditions
|
||||
- Maximum disk throughput utilization
|
||||
|
||||
4. **File Pre-Allocation:**
|
||||
- Large files (>100MB) are pre-allocated on first chunk
|
||||
- Reduces disk fragmentation
|
||||
- Improves sustained write performance
|
||||
|
||||
### Client (PS5Upload.exe)
|
||||
|
||||
1. **8 Parallel Large File Uploads:**
|
||||
- Optimal balance for PS5 disk performance
|
||||
- `MAX_PARALLEL_LARGE_FILES = 8`
|
||||
- Intelligent queuing for files >100MB
|
||||
|
||||
2. **128MB TCP Buffers:**
|
||||
- `ReceiveBufferSize = 128MB`
|
||||
- `SendBufferSize = 128MB`
|
||||
- Maximum network throughput
|
||||
|
||||
3. **Transfer History System:**
|
||||
- `ObservableCollection` for real-time UI updates
|
||||
- JSON serialization for persistent storage
|
||||
- Separate collections for completed/failed transfers
|
||||
|
||||
4. **Settings Management:**
|
||||
- New settings file: `ps5_upload_settings.json`
|
||||
- Extensible for future preferences
|
||||
- Auto-loads on startup
|
||||
|
||||
---
|
||||
|
||||
## 📊 Performance Comparison
|
||||
|
||||
| Metric | v2.0.0 | v2.1.0 | Improvement |
|
||||
|--------|--------|--------|-------------|
|
||||
| **Upload Speed (Ethernet)** | 4-12 MB/s | 88-110 MB/s | **~10x faster** |
|
||||
| **Upload Speed (WiFi 6)** | 2-8 MB/s | 32-70 MB/s | **~8x faster** |
|
||||
| **Download Speed** | 100-120 MB/s | 100-120 MB/s | Same |
|
||||
| **Peak Burst** | 190 MB/s | 2.05 GB/s | **~10x faster** |
|
||||
|
||||
---
|
||||
|
||||
## 📦 Files Included in Release
|
||||
|
||||
### Client Application:
|
||||
- `PS5Upload.exe` - Main executable (self-contained, no .NET runtime needed)
|
||||
- `ps5_logo.png` - Application icon
|
||||
- All required DLLs bundled
|
||||
|
||||
### Server Payload:
|
||||
- `ps5_upload_server.elf` - Optimized PS5 payload for etaHEN
|
||||
|
||||
### Documentation:
|
||||
- `README.md` - Complete documentation
|
||||
- `PROTOCOL.md` - Protocol specification
|
||||
- `RELEASE_NOTES_v2.1.0.md` - This file
|
||||
|
||||
### Tools:
|
||||
- `check_transfer_log.py` - Python script to analyze transfer logs (drag & drop)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
### PS5 Server:
|
||||
1. Copy `ps5_upload_server.elf` to `/data/etaHEN/payloads/`
|
||||
2. Load with elfldr
|
||||
3. Notification will show: "PS5 Upload Server: 192.168.0.XXX:9113 - By Manos"
|
||||
|
||||
### Windows Client:
|
||||
1. Extract `PS5Upload.exe` to any folder
|
||||
2. Run `PS5Upload.exe`
|
||||
3. Enter PS5 IP address and click Connect
|
||||
|
||||
**No installation required!** Both are portable executables.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Upgrading from v2.0.0
|
||||
|
||||
1. **Replace server payload:** Upload new `ps5_upload_server.elf` to PS5
|
||||
2. **Restart server:** Load the new payload with elfldr
|
||||
3. **Replace client:** Overwrite old `PS5Upload.exe` with new version
|
||||
4. **Done!** Your settings, favorites, and profiles are preserved
|
||||
|
||||
**Note:** Transfer history from v2.0.0 will NOT be migrated (new feature in v2.1.0).
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Bug Fixes
|
||||
|
||||
- Fixed potential race condition in parallel uploads (per-file mutexes)
|
||||
- Fixed memory leak in long-running transfers (proper resource disposal)
|
||||
- Fixed UI freezing during large folder uploads (async operations)
|
||||
- Fixed socket timeout issues (increased to 5 minutes with keepalive)
|
||||
|
||||
---
|
||||
|
||||
## 🔮 Known Limitations
|
||||
|
||||
1. **Upload Speed on WiFi:**
|
||||
- WiFi has ~40-60% overhead compared to Ethernet
|
||||
- Expected: 32-70 MB/s on WiFi 6 vs 88-110 MB/s on Ethernet
|
||||
- This is a WiFi protocol limitation, not a software issue
|
||||
|
||||
2. **PS5 Disk Performance:**
|
||||
- Sustained upload speed limited by PS5 internal disk write speed
|
||||
- Single-threaded writes: 12-35 MB/s
|
||||
- Parallel writes (8 connections): 88-110 MB/s aggregate
|
||||
|
||||
3. **Large File Transfers:**
|
||||
- Files >100MB are chunked and uploaded in parallel
|
||||
- Requires sufficient RAM on both PC and PS5
|
||||
|
||||
---
|
||||
|
||||
## 🙏 Credits
|
||||
|
||||
- **PS5 SDK** - For the development tools
|
||||
- **etaHEN** - For enabling homebrew on PS5
|
||||
- **PS5 Homebrew Community** - For testing and feedback
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
For issues, questions, or feature requests:
|
||||
- **GitHub Issues:** https://github.com/manos555555/PS5-Upload-Suite/issues
|
||||
- **Discussions:** https://github.com/manos555555/PS5-Upload-Suite/discussions
|
||||
|
||||
---
|
||||
|
||||
## 📝 Changelog
|
||||
|
||||
### v2.1.0 (2026-01-19)
|
||||
- ⚡ Massive upload speed boost (88-110 MB/s aggregate)
|
||||
- 📊 Transfer History with success/failed tracking
|
||||
- 🔄 Auto-clear history on startup option
|
||||
- 🖥️ Maximized window UI by default
|
||||
- 🔧 Direct write() syscalls for upload (server-side)
|
||||
- 🔧 16MB socket buffers (up from 4MB)
|
||||
- 🔧 Per-file mutex locking for parallel writes
|
||||
- 🔧 File pre-allocation for large files
|
||||
- 🐛 Fixed race conditions in parallel uploads
|
||||
- 🐛 Fixed memory leaks in long transfers
|
||||
|
||||
### v2.0.0 (Previous Release)
|
||||
- 📥 Download files from PS5 to PC
|
||||
- 🔍 File search with real-time filtering
|
||||
- ⭐ Favorites/Bookmarks system
|
||||
- 🎮 Multi-PS5 profile support
|
||||
|
||||
---
|
||||
|
||||
**Enjoy blazing-fast file transfers on your PS5!** 🚀
|
||||
|
||||
**- Manos**
|
||||
@@ -1,8 +0,0 @@
|
||||
<Application x:Class="PS5Upload.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -1,8 +0,0 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace PS5Upload
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
<Window x:Class="PS5Upload.DuplicateFileDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="File Already Exists"
|
||||
Height="320"
|
||||
Width="550"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ResizeMode="NoResize"
|
||||
Background="#1E1E1E">
|
||||
|
||||
<Window.Resources>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="#2D2D30"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#3F3F46"/>
|
||||
<Setter Property="Padding" Value="15,8"/>
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
<Setter Property="FontSize" Value="13"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#3E3E42"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Icon and Message -->
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,15">
|
||||
<TextBlock Text="⚠️" FontSize="32" Margin="0,0,15,0"/>
|
||||
<TextBlock x:Name="MessageTextBlock"
|
||||
Text="This file already exists on PS5:"
|
||||
Foreground="White"
|
||||
FontSize="14"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- File Name -->
|
||||
<TextBlock Grid.Row="1"
|
||||
x:Name="FileNameTextBlock"
|
||||
Foreground="#4EC9B0"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Margin="0,0,0,10"
|
||||
TextWrapping="Wrap"/>
|
||||
|
||||
<!-- File Info -->
|
||||
<StackPanel Grid.Row="2" Margin="0,0,0,20">
|
||||
<TextBlock x:Name="LocalSizeTextBlock"
|
||||
Foreground="#9CDCFE"
|
||||
FontSize="12"
|
||||
Margin="0,0,0,5"/>
|
||||
<TextBlock x:Name="RemoteSizeTextBlock"
|
||||
Foreground="#9CDCFE"
|
||||
FontSize="12"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Buttons -->
|
||||
<StackPanel Grid.Row="4" Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,0,0,10">
|
||||
<Button Content="Replace" Width="120" Click="Replace_Click"/>
|
||||
<Button Content="Skip" Width="120" Click="Skip_Click"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Content="Replace All" Width="120" Click="ReplaceAll_Click"/>
|
||||
<Button Content="Skip All" Width="120" Click="SkipAll_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,67 +0,0 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace PS5Upload
|
||||
{
|
||||
public partial class DuplicateFileDialog : Window
|
||||
{
|
||||
public enum FileAction
|
||||
{
|
||||
Replace,
|
||||
Skip,
|
||||
ReplaceAll,
|
||||
SkipAll
|
||||
}
|
||||
|
||||
public FileAction UserAction { get; private set; }
|
||||
|
||||
public DuplicateFileDialog(string fileName, long localSize, long remoteSize)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
FileNameTextBlock.Text = fileName;
|
||||
LocalSizeTextBlock.Text = $"Local file: {FormatFileSize(localSize)}";
|
||||
RemoteSizeTextBlock.Text = $"Remote file: {FormatFileSize(remoteSize)}";
|
||||
}
|
||||
|
||||
private void Replace_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UserAction = FileAction.Replace;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void Skip_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UserAction = FileAction.Skip;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void ReplaceAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UserAction = FileAction.ReplaceAll;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void SkipAll_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UserAction = FileAction.SkipAll;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private string FormatFileSize(long bytes)
|
||||
{
|
||||
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
|
||||
double len = bytes;
|
||||
int order = 0;
|
||||
while (len >= 1024 && order < sizes.Length - 1)
|
||||
{
|
||||
order++;
|
||||
len = len / 1024;
|
||||
}
|
||||
return $"{len:0.##} {sizes[order]}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,473 +0,0 @@
|
||||
<Window x:Class="PS5Upload.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="PS5 Upload - High-Speed File Transfer" Height="600" Width="1200"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#1E1E1E"
|
||||
Icon="ps5_logo.png">
|
||||
|
||||
<Window.Resources>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="#007ACC"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Padding" Value="15,8"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#1C97EA"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="#3E3E42"/>
|
||||
<Setter Property="Foreground" Value="#666666"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBox">
|
||||
<Setter Property="Background" Value="#2D2D30"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#3E3E42"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="8"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="ListBox">
|
||||
<Setter Property="Background" Value="#2D2D30"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#3E3E42"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,20" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Image Source="ps5_logo.png"
|
||||
Width="80"
|
||||
Height="80"
|
||||
Margin="0,0,15,0"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock Text="PS5 Upload - High-Speed File Transfer"
|
||||
FontSize="24"
|
||||
FontWeight="Bold"
|
||||
Foreground="#007ACC"/>
|
||||
<TextBlock Text="By Manos"
|
||||
FontSize="12"
|
||||
Foreground="#999999"
|
||||
Margin="0,5,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Connection Panel -->
|
||||
<Border Grid.Row="1"
|
||||
Background="#252526"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4"
|
||||
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"/>
|
||||
|
||||
<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"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Main Content -->
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="15"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="15"/>
|
||||
<ColumnDefinition Width="300"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Local Files -->
|
||||
<Border Grid.Column="0"
|
||||
Background="#252526"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#2D2D30"
|
||||
Padding="10"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="0,0,0,1">
|
||||
<TextBlock Text="📁 Local Files"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"/>
|
||||
</Border>
|
||||
|
||||
<ListBox Grid.Row="1"
|
||||
x:Name="LocalFilesListBox"
|
||||
BorderThickness="0"
|
||||
AllowDrop="True"
|
||||
Drop="LocalFilesListBox_Drop"
|
||||
DragEnter="LocalFilesListBox_DragEnter"
|
||||
MouseRightButtonUp="LocalFilesListBox_RightClick">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" Margin="5">
|
||||
<TextBlock Text="{Binding Icon}"
|
||||
FontSize="16"
|
||||
Margin="0,0,10,0"/>
|
||||
<TextBlock Text="{Binding Name}"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="🗑️ Remove" Click="RemoveLocalFile_Click"/>
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
</ListBox>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Orientation="Horizontal"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Center">
|
||||
<Button Content="Browse Files"
|
||||
Click="BrowseFilesButton_Click"
|
||||
Margin="0,0,5,0"/>
|
||||
<Button Content="Browse Folder"
|
||||
Click="BrowseFolderButton_Click"
|
||||
Margin="0,0,5,0"/>
|
||||
<Button Content="Clear All"
|
||||
Click="ClearLocalFiles_Click"
|
||||
Background="#DC3545"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- PS5 Files -->
|
||||
<Border Grid.Column="2"
|
||||
Background="#252526"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#2D2D30"
|
||||
Padding="10"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="0,0,0,1">
|
||||
<TextBlock Text="🎮 PS5 Files"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"/>
|
||||
</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>
|
||||
|
||||
<ListBox Grid.Row="2"
|
||||
x:Name="PS5FilesListBox"
|
||||
BorderThickness="0"
|
||||
MouseDoubleClick="PS5FilesListBox_MouseDoubleClick">
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<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"/>
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" Margin="5">
|
||||
<TextBlock Text="{Binding Icon}"
|
||||
FontSize="16"
|
||||
Margin="0,0,10,0"/>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontWeight="SemiBold"/>
|
||||
<TextBlock Text="{Binding SizeText}"
|
||||
FontSize="11"
|
||||
Foreground="#999999"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<StackPanel Grid.Row="3"
|
||||
Margin="10">
|
||||
<TextBlock x:Name="StorageInfoText"
|
||||
Text="Storage: --"
|
||||
FontSize="12"
|
||||
Foreground="#999999"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Log Panel -->
|
||||
<Border Grid.Column="4"
|
||||
Background="#252526"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#2D2D30"
|
||||
Padding="10"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="0,0,0,1">
|
||||
<TextBlock Text="📋 Debug Log"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"/>
|
||||
</Border>
|
||||
|
||||
<TextBox Grid.Row="1"
|
||||
x:Name="LogTextBox"
|
||||
Text=""
|
||||
FontFamily="Consolas"
|
||||
FontSize="11"
|
||||
Foreground="#CCCCCC"
|
||||
Background="#1E1E1E"
|
||||
BorderThickness="0"
|
||||
Padding="10"
|
||||
TextWrapping="Wrap"
|
||||
IsReadOnly="True"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Auto"/>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Orientation="Horizontal"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Center">
|
||||
<Button Content="📋 Copy Log"
|
||||
Click="CopyLogButton_Click"
|
||||
Margin="0,0,10,0"
|
||||
Background="#28A745"/>
|
||||
<Button Content="Clear Log"
|
||||
Click="ClearLogButton_Click"
|
||||
Background="#3E3E42"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Upload Progress -->
|
||||
<Border Grid.Row="3"
|
||||
Background="#252526"
|
||||
BorderBrush="#3E3E42"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4"
|
||||
Padding="15"
|
||||
Margin="0,15,0,0"
|
||||
x:Name="ProgressPanel"
|
||||
Visibility="Collapsed">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Files Remaining Counter -->
|
||||
<TextBlock Grid.Row="0"
|
||||
x:Name="FilesRemainingText"
|
||||
Text="Files: 0 / 0 (0 remaining)"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#FFC107"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<!-- Total Folder Progress -->
|
||||
<TextBlock Grid.Row="1"
|
||||
x:Name="TotalProgressText"
|
||||
Text="Total: 0 / 0 files"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#28A745"
|
||||
Margin="0,0,0,5"/>
|
||||
|
||||
<ProgressBar Grid.Row="2"
|
||||
x:Name="TotalProgressBar"
|
||||
Height="20"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
Value="0"
|
||||
Foreground="#17A2B8"
|
||||
Background="#2D2D30"
|
||||
BorderBrush="#3E3E42"
|
||||
Margin="0,0,0,10"/>
|
||||
|
||||
<!-- Current File -->
|
||||
<TextBlock Grid.Row="3"
|
||||
x:Name="UploadFileNameText"
|
||||
Text="Uploading: filename.bin"
|
||||
FontSize="13"
|
||||
Margin="0,0,0,5"/>
|
||||
|
||||
<ProgressBar Grid.Row="4"
|
||||
x:Name="UploadProgressBar"
|
||||
Height="20"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
Value="0"
|
||||
Foreground="#28A745"
|
||||
Background="#2D2D30"
|
||||
BorderBrush="#3E3E42"/>
|
||||
|
||||
<!-- Speed and Progress -->
|
||||
<Grid Grid.Row="5" Margin="0,8,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0"
|
||||
x:Name="UploadSpeedText"
|
||||
Text="Speed: 0 MB/s | Avg: 0 MB/s"
|
||||
FontSize="12"
|
||||
Foreground="#999999"/>
|
||||
|
||||
<TextBlock Grid.Column="1"
|
||||
x:Name="UploadProgressText"
|
||||
Text="0 / 0 MB (0%)"
|
||||
FontSize="12"
|
||||
Foreground="#999999"/>
|
||||
</Grid>
|
||||
|
||||
<!-- ETA -->
|
||||
<TextBlock Grid.Row="6"
|
||||
x:Name="UploadETAText"
|
||||
Text="ETA: Calculating..."
|
||||
FontSize="12"
|
||||
Foreground="#999999"
|
||||
Margin="0,5,0,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Upload Buttons -->
|
||||
<Grid Grid.Row="4" Margin="0,15,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="10"/>
|
||||
<ColumnDefinition Width="150"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="0"
|
||||
x:Name="UploadButton"
|
||||
Content="⬆️ Upload to PS5"
|
||||
Click="UploadButton_Click"
|
||||
Height="45"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
IsEnabled="False"/>
|
||||
|
||||
<Button Grid.Column="2"
|
||||
x:Name="CancelButton"
|
||||
Content="❌ Cancel"
|
||||
Click="CancelButton_Click"
|
||||
Height="45"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Background="#DC3545"
|
||||
IsEnabled="False"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,29 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AssemblyName>PS5Upload</AssemblyName>
|
||||
<RootNamespace>PS5Upload</RootNamespace>
|
||||
<Version>1.0.0</Version>
|
||||
<Authors>Manos</Authors>
|
||||
<Description>High-Speed File Upload Tool for PS5</Description>
|
||||
<Copyright>Copyright © 2026 Manos</Copyright>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<PublishReadyToRun>true</PublishReadyToRun>
|
||||
<ApplicationIcon>ps5_logo_fixed.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="ps5_logo.png" />
|
||||
<None Include="ps5_logo.ico">
|
||||
<Link>ps5_logo.ico</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,529 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PS5Upload
|
||||
{
|
||||
// Protocol commands
|
||||
public enum Command : byte
|
||||
{
|
||||
Ping = 0x01,
|
||||
ListStorage = 0x02,
|
||||
ListDir = 0x03,
|
||||
CreateDir = 0x04,
|
||||
DeleteFile = 0x05,
|
||||
DeleteDir = 0x06,
|
||||
Rename = 0x07,
|
||||
CopyFile = 0x08,
|
||||
MoveFile = 0x09,
|
||||
StartUpload = 0x10,
|
||||
UploadChunk = 0x11,
|
||||
EndUpload = 0x12,
|
||||
Shutdown = 0xFF
|
||||
}
|
||||
|
||||
// Protocol responses
|
||||
public enum Response : byte
|
||||
{
|
||||
Ok = 0x01,
|
||||
Error = 0x02,
|
||||
Data = 0x03,
|
||||
Ready = 0x04,
|
||||
Progress = 0x05
|
||||
}
|
||||
|
||||
public class PS5Protocol : IDisposable
|
||||
{
|
||||
private TcpClient? _client;
|
||||
private NetworkStream? _stream;
|
||||
private const int BufferSize = 32 * 1024 * 1024; // 32MB for maximum throughput
|
||||
|
||||
public bool IsConnected => _client?.Connected ?? false;
|
||||
|
||||
public async Task<bool> ConnectAsync(string ipAddress, int port = 9113)
|
||||
{
|
||||
try
|
||||
{
|
||||
_client = new TcpClient();
|
||||
_client.ReceiveBufferSize = 64 * 1024 * 1024; // 64MB for maximum TCP throughput
|
||||
_client.SendBufferSize = 64 * 1024 * 1024; // 64MB for maximum TCP throughput
|
||||
_client.NoDelay = true;
|
||||
_client.LingerState = new System.Net.Sockets.LingerOption(false, 0);
|
||||
|
||||
// BUG FIX #1: Add 5 second timeout for connection to fail fast on wrong IP
|
||||
var connectTask = _client.ConnectAsync(ipAddress, port);
|
||||
var timeoutTask = Task.Delay(5000); // 5 second timeout
|
||||
|
||||
var completedTask = await Task.WhenAny(connectTask, timeoutTask);
|
||||
|
||||
if (completedTask == timeoutTask)
|
||||
{
|
||||
// Timeout occurred
|
||||
_client?.Close();
|
||||
_client?.Dispose();
|
||||
_client = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if connection actually succeeded
|
||||
if (!_client.Connected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_stream = _client.GetStream();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_client?.Close();
|
||||
_client?.Dispose();
|
||||
_client = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
_stream?.Dispose();
|
||||
_client?.Dispose();
|
||||
_stream = null;
|
||||
_client = null;
|
||||
}
|
||||
|
||||
private async Task SendCommandAsync(Command cmd, byte[]? data = null)
|
||||
{
|
||||
if (_stream == null) throw new InvalidOperationException("Not connected");
|
||||
|
||||
byte[] header = new byte[5];
|
||||
header[0] = (byte)cmd;
|
||||
|
||||
uint dataLen = data != null ? (uint)data.Length : 0;
|
||||
BitConverter.GetBytes(dataLen).CopyTo(header, 1);
|
||||
|
||||
await _stream.WriteAsync(header, 0, 5);
|
||||
if (data != null && data.Length > 0)
|
||||
{
|
||||
await _stream.WriteAsync(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<(Response response, byte[] data)> ReceiveResponseAsync()
|
||||
{
|
||||
if (_stream == null) throw new InvalidOperationException("Not connected");
|
||||
|
||||
byte[] header = new byte[5];
|
||||
await ReadExactAsync(header, 5);
|
||||
|
||||
Response response = (Response)header[0];
|
||||
uint dataLen = BitConverter.ToUInt32(header, 1);
|
||||
|
||||
byte[] data = new byte[dataLen];
|
||||
if (dataLen > 0)
|
||||
{
|
||||
await ReadExactAsync(data, (int)dataLen);
|
||||
}
|
||||
|
||||
return (response, data);
|
||||
}
|
||||
|
||||
private async Task ReadExactAsync(byte[] buffer, int count, int timeoutMs = 30000)
|
||||
{
|
||||
if (_stream == null) throw new InvalidOperationException("Not connected");
|
||||
|
||||
int offset = 0;
|
||||
using var cts = new CancellationTokenSource(timeoutMs);
|
||||
|
||||
try
|
||||
{
|
||||
while (offset < count)
|
||||
{
|
||||
int read = await _stream.ReadAsync(buffer, offset, count - offset, cts.Token);
|
||||
if (read == 0) throw new IOException("Connection closed");
|
||||
offset += read;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw new TimeoutException("Read timeout");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> PingAsync()
|
||||
{
|
||||
await SendCommandAsync(Command.Ping);
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
return response == Response.Ok;
|
||||
}
|
||||
|
||||
public async Task<StorageInfo[]> ListStorageAsync()
|
||||
{
|
||||
await SendCommandAsync(Command.ListStorage);
|
||||
var (response, data) = await ReceiveResponseAsync();
|
||||
|
||||
if (response != Response.Data) return Array.Empty<StorageInfo>();
|
||||
|
||||
using var ms = new MemoryStream(data);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
int count = br.ReadInt32();
|
||||
var result = new StorageInfo[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
ushort pathLen = br.ReadUInt16();
|
||||
string path = Encoding.UTF8.GetString(br.ReadBytes(pathLen));
|
||||
long total = br.ReadInt64();
|
||||
long free = br.ReadInt64();
|
||||
|
||||
result[i] = new StorageInfo { Path = path, TotalBytes = total, FreeBytes = free };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<FileEntry[]> ListDirAsync(string path)
|
||||
{
|
||||
byte[] pathBytes = Encoding.UTF8.GetBytes(path + "\0");
|
||||
await SendCommandAsync(Command.ListDir, pathBytes);
|
||||
var (response, data) = await ReceiveResponseAsync();
|
||||
|
||||
if (response != Response.Data) return Array.Empty<FileEntry>();
|
||||
|
||||
using var ms = new MemoryStream(data);
|
||||
using var br = new BinaryReader(ms);
|
||||
|
||||
int count = br.ReadInt32();
|
||||
|
||||
// Handle empty directory
|
||||
if (count <= 0) return Array.Empty<FileEntry>();
|
||||
|
||||
var result = new FileEntry[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
byte type = br.ReadByte();
|
||||
ushort nameLen = br.ReadUInt16();
|
||||
string name = Encoding.UTF8.GetString(br.ReadBytes(nameLen));
|
||||
long size = br.ReadInt64();
|
||||
long timestamp = br.ReadInt64();
|
||||
|
||||
// Clamp timestamp to valid DateTimeOffset range
|
||||
DateTime dt;
|
||||
try
|
||||
{
|
||||
if (timestamp < -62135596800 || timestamp > 253402300799)
|
||||
{
|
||||
dt = DateTime.Now; // Use current time for invalid timestamps
|
||||
}
|
||||
else
|
||||
{
|
||||
dt = DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
dt = DateTime.Now;
|
||||
}
|
||||
|
||||
result[i] = new FileEntry
|
||||
{
|
||||
Name = name,
|
||||
IsDirectory = type == 1,
|
||||
Size = size,
|
||||
Timestamp = dt
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> CreateDirAsync(string path)
|
||||
{
|
||||
byte[] pathBytes = Encoding.UTF8.GetBytes(path + "\0");
|
||||
await SendCommandAsync(Command.CreateDir, pathBytes);
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
return response == Response.Ok;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteFileAsync(string path)
|
||||
{
|
||||
byte[] pathBytes = Encoding.UTF8.GetBytes(path + "\0");
|
||||
await SendCommandAsync(Command.DeleteFile, pathBytes);
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
return response == Response.Ok;
|
||||
}
|
||||
|
||||
public event Action<string> OnProgressMessage;
|
||||
|
||||
public async Task<bool> DeleteDirAsync(string path)
|
||||
{
|
||||
byte[] pathBytes = Encoding.UTF8.GetBytes(path + "\0");
|
||||
await SendCommandAsync(Command.DeleteDir, pathBytes);
|
||||
|
||||
// Receive initial OK response
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
if (response != Response.Ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now listen for progress messages synchronously
|
||||
// Keep reading until we get the final OK/ERROR response
|
||||
bool deletionComplete = false;
|
||||
|
||||
try
|
||||
{
|
||||
while (!deletionComplete)
|
||||
{
|
||||
var (progressResponse, progressData) = await ReceiveResponseAsync();
|
||||
|
||||
if (progressResponse == Response.Progress)
|
||||
{
|
||||
string message = Encoding.UTF8.GetString(progressData).TrimEnd('\0');
|
||||
OnProgressMessage?.Invoke(message);
|
||||
}
|
||||
else if (progressResponse == Response.Ok)
|
||||
{
|
||||
// Final OK response received - deletion complete
|
||||
OnProgressMessage?.Invoke("🔚 Received final OK - deletion complete");
|
||||
deletionComplete = true;
|
||||
}
|
||||
else if (progressResponse == Response.Error)
|
||||
{
|
||||
// Error response received
|
||||
OnProgressMessage?.Invoke("❌ Received error response");
|
||||
deletionComplete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unexpected response - log it
|
||||
OnProgressMessage?.Invoke($"⚠️ Unexpected response: {progressResponse}");
|
||||
deletionComplete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Connection closed - log it
|
||||
OnProgressMessage?.Invoke($"⚠️ Connection closed: {ex.Message}");
|
||||
}
|
||||
|
||||
// Give server a moment to fully close the deletion thread
|
||||
await Task.Delay(100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> RenameAsync(string oldPath, string newPath)
|
||||
{
|
||||
byte[] oldBytes = Encoding.UTF8.GetBytes(oldPath + "\0");
|
||||
byte[] newBytes = Encoding.UTF8.GetBytes(newPath + "\0");
|
||||
byte[] data = new byte[oldBytes.Length + newBytes.Length];
|
||||
Array.Copy(oldBytes, 0, data, 0, oldBytes.Length);
|
||||
Array.Copy(newBytes, 0, data, oldBytes.Length, newBytes.Length);
|
||||
|
||||
await SendCommandAsync(Command.Rename, data);
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
return response == Response.Ok;
|
||||
}
|
||||
|
||||
public async Task<bool> CopyFileAsync(string srcPath, string dstPath)
|
||||
{
|
||||
byte[] srcBytes = Encoding.UTF8.GetBytes(srcPath + "\0");
|
||||
byte[] dstBytes = Encoding.UTF8.GetBytes(dstPath + "\0");
|
||||
byte[] data = new byte[srcBytes.Length + dstBytes.Length];
|
||||
Array.Copy(srcBytes, 0, data, 0, srcBytes.Length);
|
||||
Array.Copy(dstBytes, 0, data, srcBytes.Length, dstBytes.Length);
|
||||
|
||||
await SendCommandAsync(Command.CopyFile, data);
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
return response == Response.Ok;
|
||||
}
|
||||
|
||||
public async Task<bool> MoveFileAsync(string srcPath, string dstPath)
|
||||
{
|
||||
byte[] srcBytes = Encoding.UTF8.GetBytes(srcPath + "\0");
|
||||
byte[] dstBytes = Encoding.UTF8.GetBytes(dstPath + "\0");
|
||||
byte[] data = new byte[srcBytes.Length + dstBytes.Length];
|
||||
Array.Copy(srcBytes, 0, data, 0, srcBytes.Length);
|
||||
Array.Copy(dstBytes, 0, data, srcBytes.Length, dstBytes.Length);
|
||||
|
||||
await SendCommandAsync(Command.MoveFile, data);
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
return response == Response.Ok;
|
||||
}
|
||||
|
||||
public async Task<bool> UploadFileAsync(string localPath, string remotePath, IProgress<UploadProgress>? progress = null, CancellationToken cancellationToken = default, long chunkOffset = 0, long chunkSize = 0)
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(localPath);
|
||||
if (!fileInfo.Exists) return false;
|
||||
|
||||
// Determine actual upload size
|
||||
long uploadSize = chunkSize > 0 ? chunkSize : fileInfo.Length;
|
||||
|
||||
// Send START_UPLOAD with optional chunk offset
|
||||
byte[] pathBytes = Encoding.UTF8.GetBytes(remotePath);
|
||||
byte[] startData = new byte[pathBytes.Length + 1 + 8 + 8]; // path + null + size + offset
|
||||
Array.Copy(pathBytes, 0, startData, 0, pathBytes.Length);
|
||||
BitConverter.GetBytes(fileInfo.Length).CopyTo(startData, pathBytes.Length + 1);
|
||||
BitConverter.GetBytes(chunkOffset).CopyTo(startData, pathBytes.Length + 9);
|
||||
|
||||
await SendCommandAsync(Command.StartUpload, startData);
|
||||
var (response, _) = await ReceiveResponseAsync();
|
||||
|
||||
if (response != Response.Ready) return false;
|
||||
|
||||
// Upload chunks - simple async approach
|
||||
long totalSent = 0;
|
||||
var startTime = DateTime.Now;
|
||||
double avgSpeed = 0;
|
||||
|
||||
byte[] sendBuffer = new byte[5 + BufferSize];
|
||||
sendBuffer[0] = (byte)Command.UploadChunk;
|
||||
|
||||
using (FileStream fs = new FileStream(localPath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, FileOptions.SequentialScan))
|
||||
{
|
||||
// Seek to chunk offset if specified
|
||||
if (chunkOffset > 0)
|
||||
{
|
||||
fs.Seek(chunkOffset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
int chunksSent = 0;
|
||||
int bytesRead;
|
||||
long bytesRemaining = uploadSize;
|
||||
|
||||
while (bytesRemaining > 0 && (bytesRead = await fs.ReadAsync(sendBuffer, 5, (int)Math.Min(BufferSize, bytesRemaining), cancellationToken)) > 0)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested) return false;
|
||||
|
||||
BitConverter.GetBytes((uint)bytesRead).CopyTo(sendBuffer, 1);
|
||||
|
||||
if (_stream == null) return false;
|
||||
|
||||
await _stream.WriteAsync(sendBuffer, 0, 5 + bytesRead, cancellationToken);
|
||||
|
||||
totalSent += bytesRead;
|
||||
bytesRemaining -= bytesRead;
|
||||
chunksSent++;
|
||||
|
||||
if (chunksSent % 5 == 0 || bytesRemaining == 0)
|
||||
{
|
||||
var elapsed = DateTime.Now - startTime;
|
||||
double currentSpeed = elapsed.TotalSeconds > 0 ? totalSent / elapsed.TotalSeconds : 0;
|
||||
avgSpeed = currentSpeed;
|
||||
|
||||
TimeSpan eta = currentSpeed > 0
|
||||
? TimeSpan.FromSeconds(bytesRemaining / currentSpeed)
|
||||
: TimeSpan.Zero;
|
||||
|
||||
progress?.Report(new UploadProgress
|
||||
{
|
||||
BytesSent = chunkOffset + totalSent,
|
||||
TotalBytes = fileInfo.Length,
|
||||
SpeedBytesPerSecond = currentSpeed,
|
||||
AverageSpeedBytesPerSecond = avgSpeed,
|
||||
ElapsedTime = elapsed,
|
||||
EstimatedTimeRemaining = eta,
|
||||
CurrentFileName = fileInfo.Name
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send END_UPLOAD - fire-and-forget for maximum speed
|
||||
// Don't wait for response to avoid PS5 payload bottleneck
|
||||
try
|
||||
{
|
||||
await SendCommandAsync(Command.EndUpload);
|
||||
// Immediately return success without waiting for response
|
||||
// This eliminates the PS5 response handling bottleneck
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true; // Assume success if connection issues
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public class StorageInfo
|
||||
{
|
||||
public string Path { get; set; } = "";
|
||||
public long TotalBytes { get; set; }
|
||||
public long FreeBytes { get; set; }
|
||||
}
|
||||
|
||||
public class FileEntry
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public bool IsDirectory { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
}
|
||||
|
||||
public class UploadProgress
|
||||
{
|
||||
public long BytesSent { get; set; }
|
||||
public long TotalBytes { get; set; }
|
||||
public double SpeedBytesPerSecond { get; set; }
|
||||
public double AverageSpeedBytesPerSecond { get; set; }
|
||||
public TimeSpan ElapsedTime { get; set; }
|
||||
public TimeSpan EstimatedTimeRemaining { get; set; }
|
||||
public string CurrentFileName { get; set; } = "";
|
||||
|
||||
// For folder progress
|
||||
public int CurrentFileIndex { get; set; }
|
||||
public int TotalFiles { get; set; }
|
||||
public long TotalFolderBytes { get; set; }
|
||||
public long TotalFolderBytesSent { get; set; }
|
||||
}
|
||||
|
||||
// High-speed parallel uploader using multiple connections
|
||||
public class ParallelUploader : IDisposable
|
||||
{
|
||||
private readonly string _ipAddress;
|
||||
private readonly int _port;
|
||||
private readonly int _connectionCount;
|
||||
private const int ChunkSize = 4 * 1024 * 1024; // 4MB chunks per connection
|
||||
|
||||
public ParallelUploader(string ipAddress, int port = 9113, int connectionCount = 4)
|
||||
{
|
||||
_ipAddress = ipAddress;
|
||||
_port = port;
|
||||
_connectionCount = connectionCount;
|
||||
}
|
||||
|
||||
public async Task<bool> UploadFileAsync(string localPath, string remotePath, IProgress<UploadProgress>? progress = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(localPath);
|
||||
if (!fileInfo.Exists) return false;
|
||||
|
||||
// For small files, use single connection
|
||||
if (fileInfo.Length < ChunkSize * 2)
|
||||
{
|
||||
using var protocol = new PS5Protocol();
|
||||
if (!await protocol.ConnectAsync(_ipAddress, _port)) return false;
|
||||
return await protocol.UploadFileAsync(localPath, remotePath, progress, cancellationToken);
|
||||
}
|
||||
|
||||
// For large files, use parallel connections
|
||||
// This requires server support for chunked/parallel uploads
|
||||
// For now, fall back to single connection
|
||||
using var proto = new PS5Protocol();
|
||||
if (!await proto.ConnectAsync(_ipAddress, _port)) return false;
|
||||
return await proto.UploadFileAsync(localPath, remotePath, progress, cancellationToken);
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
@echo off
|
||||
echo ================================================
|
||||
echo PS5 Upload Client - Building
|
||||
echo By Manos
|
||||
echo ================================================
|
||||
echo.
|
||||
|
||||
echo [+] Building Windows GUI Client...
|
||||
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
|
||||
|
||||
if exist "bin\Release\net6.0-windows\win-x64\publish\PS5Upload.exe" (
|
||||
echo.
|
||||
echo ================================================
|
||||
echo [+] SUCCESS! Built PS5Upload.exe
|
||||
echo ================================================
|
||||
echo.
|
||||
echo Location: bin\Release\net6.0-windows\win-x64\publish\PS5Upload.exe
|
||||
echo.
|
||||
echo Copy PS5Upload.exe to any location and run it!
|
||||
) else (
|
||||
echo.
|
||||
echo ================================================
|
||||
echo [-] BUILD FAILED
|
||||
echo ================================================
|
||||
echo.
|
||||
echo Make sure .NET 6.0 SDK is installed:
|
||||
echo https://dotnet.microsoft.com/download/dotnet/6.0
|
||||
exit /b 1
|
||||
)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 155 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB |
@@ -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")
|
||||
@@ -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"
|
||||
@@ -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 ""
|
||||
@@ -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,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "================================================"
|
||||
echo "PS5 Upload Server - Compilation"
|
||||
echo "By Manos"
|
||||
echo "================================================"
|
||||
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
|
||||
|
||||
if [ -f "ps5_upload_server.elf" ]; then
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "[+] SUCCESS! Compiled ps5_upload_server.elf"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
ls -lh ps5_upload_server.elf
|
||||
file ps5_upload_server.elf
|
||||
echo ""
|
||||
echo "Upload to PS5 and run with elfldr"
|
||||
echo "Server will listen on port 9113"
|
||||
else
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo "[-] COMPILATION FAILED"
|
||||
echo "================================================"
|
||||
exit 1
|
||||
fi
|
||||
-1187
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 311 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
@@ -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())
|
||||
Reference in new issue
Block a user