Spaces:
Paused
Paused
File size: 14,628 Bytes
9dae746 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>APK Debug</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
<style>
#dropZone:hover {
background-color: #2d3748;
border-color: #d69e2e;
}
#progressBar {
transition: width 0.3s ease-in-out;
}
.loader {
border: 4px solid #f3f3f3;
border-top: 4px solid #d69e2e;
border-radius: 50%;
width: 48px;
height: 48px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.container {
max-width: 1200px;
width: 100%;
}
@media (max-width: 640px) {
.container {
padding-left: 1rem;
padding-right: 1rem;
}
#dropZone {
padding: 1.5rem;
}
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex flex-col">
<!-- Header -->
<header class="bg-gray-800 p-4 shadow-md">
<div class="container mx-auto flex justify-between items-center">
<h1 class="text-xl font-bold">APKDebug</h1>
<div class="text-sm bg-gray-700 px-3 py-1 rounded">VIP User</div>
</div>
</header>
<!-- Main Content -->
<main class="flex-1 container mx-auto p-4">
<!-- Tabs -->
<div class="flex space-x-2 mb-4">
<button id="uploadTab" class="flex-1 bg-yellow-600 text-white py-2 rounded-t-lg">Upload</button>
<button id="howItWorksTab" class="flex-1 bg-gray-700 text-white py-2 rounded-t-lg">How It Works</button>
</div>
<!-- Upload Section -->
<section id="uploadSection" class="bg-gray-800 p-6 rounded-b-lg rounded-tr-lg">
<div id="dropZone" class="border-2 border-dashed border-gray-500 p-6 text-center cursor-pointer">
<div class="flex justify-center mb-2">
<svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
</svg>
</div>
<p class="text-gray-400">Click to upload or drag and drop</p>
<p class="text-gray-500 text-sm">Supported file: .APK</p>
<input type="file" id="fileInput" class="hidden" accept=".apk">
</div>
<p id="fileNameDisplay" class="mt-2 text-sm text-gray-400 text-center"></p>
<button id="submitBtn" class="mt-4 w-full bg-yellow-600 text-white py-2 rounded flex items-center justify-center">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
</svg>
Debug APK
</button>
<div id="progressContainer" class="mt-4 hidden">
<div class="w-full bg-gray-600 rounded-full h-2.5">
<div id="progressBar" class="bg-yellow-600 h-2.5 rounded-full transition-all duration-300" style="width: 0%"></div>
</div>
<p id="progressText" class="text-sm text-gray-400 mt-1 text-center"></p>
</div>
</section>
<!-- Overlay for Processing -->
<div id="processingOverlay" class="fixed inset-0 bg-black bg-opacity-50 backdrop-blur-sm flex items-center justify-center hidden">
<div class="text-center">
<div class="loader border-t-4 border-yellow-600 rounded-full w-12 h-12 animate-spin mx-auto"></div>
<p class="mt-4 text-gray-300">Processing... Time remaining: <span id="timeLeft">2:00</span></p>
</div>
</div>
<!-- How It Works Section -->
<section id="howItWorksSection" class="bg-gray-800 p-6 rounded-b-lg rounded-tr-lg hidden">
<h3 class="text-lg font-semibold text-gray-300">How It Works</h3>
<p class="mt-2 text-gray-400">1. Upload your APK file by dragging it into the box or clicking to select.</p>
<p class="mt-1 text-gray-400">2. Click "Debug APK" and wait for the processing to complete.</p>
<p class="mt-1 text-gray-400">3. Download your debugged file from the Recent App Uploads section.</p>
</section>
<!-- Recent Uploads -->
<section class="mt-6">
<h3 class="text-lg font-semibold text-gray-300">Recent App Uploads</h3>
<div class="mt-2">
<input type="text" id="searchUploads" placeholder="Search uploads..." class="w-full bg-gray-700 text-gray-300 p-2 rounded">
</div>
<div id="recentUploads" class="mt-2 space-y-2">
<!-- Recent uploads will be populated by JavaScript -->
</div>
</section>
<!-- Error Alert -->
<div id="errorAlert" class="fixed bottom-4 left-1/2 transform -translate-x-1/2 bg-red-900 border border-red-700 text-red-300 px-4 py-3 rounded hidden">
<span id="errorMessage"></span>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const submitBtn = document.getElementById('submitBtn');
const progressContainer = document.getElementById('progressContainer');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
const processingOverlay = document.getElementById('processingOverlay');
const timeLeft = document.getElementById('timeLeft');
const errorAlert = document.getElementById('errorAlert');
const errorMessage = document.getElementById('errorMessage');
const fileNameDisplay = document.getElementById('fileNameDisplay');
const uploadTab = document.getElementById('uploadTab');
const howItWorksTab = document.getElementById('howItWorksTab');
const uploadSection = document.getElementById('uploadSection');
const howItWorksSection = document.getElementById('howItWorksSection');
const recentUploads = document.getElementById('recentUploads');
const searchUploads = document.getElementById('searchUploads');
// Tab Switching
uploadTab.addEventListener('click', () => {
uploadTab.classList.add('bg-yellow-600');
uploadTab.classList.remove('bg-gray-700');
howItWorksTab.classList.add('bg-gray-700');
howItWorksTab.classList.remove('bg-yellow-600');
uploadSection.classList.remove('hidden');
howItWorksSection.classList.add('hidden');
});
howItWorksTab.addEventListener('click', () => {
howItWorksTab.classList.add('bg-yellow-600');
howItWorksTab.classList.remove('bg-gray-700');
uploadTab.classList.add('bg-gray-700');
uploadTab.classList.remove('bg-yellow-600');
howItWorksSection.classList.remove('hidden');
uploadSection.classList.add('hidden');
});
// Drag and Drop
dropZone.addEventListener('click', () => fileInput.click());
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('border-yellow-600');
});
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('border-yellow-600'));
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('border-yellow-600');
fileInput.files = e.dataTransfer.files;
displayFileName();
});
fileInput.addEventListener('change', () => {
displayFileName();
});
// Submit Handler
submitBtn.addEventListener('click', () => {
if (!fileInput.files.length) {
showError('Please select a file');
return;
}
const file = fileInput.files[0];
if (file.size > 500 * 1024 * 1024) {
showError('File size exceeds 500MB limit');
return;
}
const formData = new FormData();
formData.append('file', file);
progressContainer.classList.remove('hidden');
progressText.textContent = 'Uploading...';
const xhr = new XMLHttpRequest();
xhr.open('POST', '/process/debug', true);
xhr.upload.onprogress = (event) => {
if (event.lengthComputable) {
const percent = Math.round((event.loaded * 100) / event.total);
progressBar.style.width = `${percent}%`;
progressText.textContent = `Uploading: ${percent}%`;
if (percent === 100) {
setTimeout(() => {
progressContainer.classList.add('hidden');
processingOverlay.classList.remove('hidden');
startTimer();
}, 500);
}
}
};
xhr.onload = () => {
if (xhr.status === 200) {
clearInterval(timerInterval);
processingOverlay.classList.add('hidden');
const blob = new Blob([xhr.response], { type: 'application/vnd.android.package-archive' });
const url = window.URL.createObjectURL(blob);
const filename = xhr.getResponseHeader('content-disposition')?.split('filename=')[1]?.replace(/"/g, '') || `${file.name}_debugged.apk`;
addRecentUpload(file.name, filename, url);
} else {
const error = JSON.parse(xhr.responseText || '{}');
showError(error.error || 'Failed to debug APK');
resetUI();
}
};
xhr.onerror = () => {
showError('An error occurred while uploading the file');
resetUI();
};
xhr.responseType = 'blob';
xhr.send(formData);
});
// Timer function
let timerInterval;
function startTimer() {
let time = 120; // 2 minutes
timerInterval = setInterval(() => {
const minutes = Math.floor(time / 60);
const seconds = time % 60;
timeLeft.textContent = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
time--;
if (time < 0) clearInterval(timerInterval);
}, 1000);
}
// Display file name
function displayFileName() {
if (fileInput.files.length > 0) {
fileNameDisplay.textContent = `Selected file: ${fileInput.files[0].name}`;
} else {
fileNameDisplay.textContent = '';
}
}
// Add to recent uploads
function addRecentUpload(originalName, processedName, downloadUrl) {
const uploadItem = document.createElement('div');
uploadItem.className = 'bg-gray-700 p-3 rounded flex justify-between items-center';
const date = new Date().toLocaleDateString('en-US', { month: 'numeric', day: 'numeric', year: 'numeric' });
uploadItem.innerHTML = `
<div class="flex items-center">
<img src="https://img.icons8.com/color/40/000000/android-os.png" alt="Android Icon" class="w-10 h-10 mr-3">
<div>
<p class="text-gray-300">${originalName}</p>
<p class="text-gray-500 text-sm">Uploaded on ${date}</p>
</div>
</div>
<a href="${downloadUrl}" download="${processedName}" class="bg-yellow-600 text-white px-3 py-1 rounded text-sm">
Download
</a>
`;
recentUploads.prepend(uploadItem);
if (recentUploads.children.length > 5) {
recentUploads.removeChild(recentUploads.children[recentUploads.children.length - 1]);
}
}
// Search uploads
searchUploads.addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase();
const items = recentUploads.children;
for (let item of items) {
const fileName = item.querySelector('p').textContent.toLowerCase();
item.style.display = fileName.includes(searchTerm) ? '' : 'none';
}
});
// UI Helpers
function showError(message) {
errorAlert.classList.remove('hidden');
errorMessage.textContent = message;
setTimeout(() => errorAlert.classList.add('hidden'), 5000);
}
function resetUI() {
progressContainer.classList.add('hidden');
processingOverlay.classList.add('hidden');
progressBar.style.width = '0%';
progressText.textContent = '';
fileNameDisplay.textContent = '';
}
});
</script>
</body>
</html> |