Reaperxxxx commited on
Commit
95015d3
Β·
verified Β·
1 Parent(s): ecbd587

Update index.js

Browse files
Files changed (1) hide show
  1. index.js +37 -13
index.js CHANGED
@@ -9,7 +9,7 @@ const axios = require('axios');
9
  const crypto = require('crypto');
10
 
11
  const app = express();
12
- const PORT = 7860;
13
 
14
  // ── DOWNLOAD HASH ─────────────────────────────────────────────────────────────
15
  // A stable hash generated once at startup. Share this URL to download the APK.
@@ -230,18 +230,42 @@ app.post('/patch', express.json({ limit: '10mb' }), (req, res) => {
230
  ensureKeystore();
231
  const tools = checkTools();
232
 
233
- // 1. Open APK as zip, replace assets/characters.txt
234
- const zip = new AdmZip(originalApk);
235
- zip.updateFile('assets/characters.txt', Buffer.from(characters, 'utf8'));
236
-
237
- // 2. Delete META-INF (old signature) so re-sign works cleanly
238
- const toDelete = [];
239
- zip.getEntries().forEach(e => {
240
- if (e.entryName.startsWith('META-INF/')) toDelete.push(e.entryName);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  });
242
- toDelete.forEach(name => zip.deleteFile(name));
243
-
244
- zip.writeZip(patchedApk);
 
245
 
246
  // 3. zipalign (align before signing for v2/v3; v1 is fine either way)
247
  let toSign = patchedApk;
@@ -299,7 +323,7 @@ app.get('/', (req, res) => {
299
  });
300
 
301
  // ── START ─────────────────────────────────────────────────────────────────────
302
- app.listen(PORT, () => {
303
  console.log(`\n🦸 Super City Editor backend running at http://localhost:${PORT}`);
304
  console.log(`\n⬇ Direct APK download: http://localhost:${PORT}/download/${DOWNLOAD_HASH}\n`);
305
  try { ensureKeystore(); } catch (e) { console.warn('Keystore not ready yet:', e.message); }
 
9
  const crypto = require('crypto');
10
 
11
  const app = express();
12
+ const PORT = 3000;
13
 
14
  // ── DOWNLOAD HASH ─────────────────────────────────────────────────────────────
15
  // A stable hash generated once at startup. Share this URL to download the APK.
 
230
  ensureKeystore();
231
  const tools = checkTools();
232
 
233
+ // 1. Repack APK using system unzip/zip to preserve per-entry compression.
234
+ // AdmZip re-deflates ALL entries including files Android requires to be
235
+ // STORED (resources.arsc, .so libs, etc.) β€” causing "App not installed".
236
+ const workDir = path.join(sessionDir, 'apk_work');
237
+ if (fs.existsSync(workDir)) fs.rmSync(workDir, { recursive: true, force: true });
238
+ fs.mkdirSync(workDir, { recursive: true });
239
+
240
+ // Extract APK
241
+ const unzipResult = spawnSync('unzip', ['-q', '-o', originalApk, '-d', workDir], { encoding: 'utf8' });
242
+ if (unzipResult.status !== 0) throw new Error('unzip failed: ' + unzipResult.stderr);
243
+
244
+ // Remove META-INF so apksigner can add a fresh signature
245
+ const metaInfDir = path.join(workDir, 'META-INF');
246
+ if (fs.existsSync(metaInfDir)) fs.rmSync(metaInfDir, { recursive: true, force: true });
247
+
248
+ // Overwrite characters.txt with edited content
249
+ const charsDest = path.join(workDir, 'assets', 'characters.txt');
250
+ fs.mkdirSync(path.dirname(charsDest), { recursive: true });
251
+ fs.writeFileSync(charsDest, Buffer.from(characters, 'utf8'));
252
+
253
+ // Repack: compress most files, but re-add known STORED types uncompressed.
254
+ // Step A β€” pack everything with compression
255
+ const zipResult = spawnSync('zip', ['-r', '-9', patchedApk, '.'], { cwd: workDir, encoding: 'utf8' });
256
+ if (zipResult.status !== 0) throw new Error('zip failed: ' + zipResult.stderr);
257
+
258
+ // Step B β€” find files that must stay STORED and re-add them uncompressed
259
+ const storedPatterns = ['*.so', '*.arsc', '*.png', '*.gif', '*.jpg', '*.jpeg',
260
+ '*.webp', '*.wav', '*.mp3', '*.ogg', '*.aac', '*.ttf', '*.otf'];
261
+ const storedFiles = storedPatterns.flatMap(pat => {
262
+ const r = spawnSync('find', ['.', '-name', pat], { cwd: workDir, encoding: 'utf8' });
263
+ return r.stdout.trim().split('\n').filter(Boolean);
264
  });
265
+ if (storedFiles.length > 0) {
266
+ const sr = spawnSync('zip', ['-0', '-u', patchedApk, ...storedFiles], { cwd: workDir, encoding: 'utf8' });
267
+ if (sr.status !== 0 && sr.status !== 12) console.warn('zip -0 warning:', sr.stderr);
268
+ }
269
 
270
  // 3. zipalign (align before signing for v2/v3; v1 is fine either way)
271
  let toSign = patchedApk;
 
323
  });
324
 
325
  // ── START ─────────────────────────────────────────────────────────────────────
326
+ app.listen(7860, () => {
327
  console.log(`\n🦸 Super City Editor backend running at http://localhost:${PORT}`);
328
  console.log(`\n⬇ Direct APK download: http://localhost:${PORT}/download/${DOWNLOAD_HASH}\n`);
329
  try { ensureKeystore(); } catch (e) { console.warn('Keystore not ready yet:', e.message); }