mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 03:00:18 +02:00
Harden the APK reader and build downloads after review
- frame_apk: android: attributes win over same-named attributes in other namespaces; string attributes that keep only a typed value (no raw string) still resolve; a failed icon read leaves the icon out instead of failing the install. - The clipboard IPC origin check can't throw on odd frame URLs. - fetch-deps.js: 60 s download timeout, at most 5 redirects, a SystemRoot fallback for tar.exe, and prunes pydoc_data, venv and the static libpython. - Docs keep the clipboard-tool note for running the UI in a browser. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
770f26c703
commit
d145537d9a
5 files changed
+65
-25
No files matched your search
+22
-12
@@ -71,9 +71,14 @@ def manifest_elements(data):
|
||||
for i in range(count):
|
||||
a = off + hsize + astart + i * asize
|
||||
aname, raw, dtype, value = struct.unpack_from('<4xII3xBI', data, a)
|
||||
key = ATTR.get(resmap[aname]) if aname < len(resmap) else None
|
||||
key = key or (strings[aname] if aname < len(strings) else '')
|
||||
attrs[key] = (dtype, value, strings[raw] if raw < len(strings) else None)
|
||||
raw = strings[raw] if raw < len(strings) else None
|
||||
if raw is None and dtype == T_STRING and value < len(strings):
|
||||
raw = strings[value] # some repackers keep only the typed value
|
||||
android = ATTR.get(resmap[aname]) if aname < len(resmap) else None
|
||||
if android: # android: attributes win over same-named ones in other namespaces
|
||||
attrs[android] = (dtype, value, raw)
|
||||
else:
|
||||
attrs.setdefault(strings[aname] if aname < len(strings) else '', (dtype, value, raw))
|
||||
out.append((strings[name] if name < len(strings) else '', attrs))
|
||||
return out
|
||||
|
||||
@@ -197,18 +202,23 @@ def apk_info(path):
|
||||
'min_sdk': min_sdk[1] if min_sdk and min_sdk[0] in (T_INT_DEC, T_INT_HEX) else None,
|
||||
'icon_png': None,
|
||||
}
|
||||
for icon in _icons(app.get('icon'), res):
|
||||
if icon.endswith('.png') and icon in names:
|
||||
info['icon_png'] = z.read(icon)
|
||||
break
|
||||
else: # adaptive icons are XML; fall back to the largest launcher PNG
|
||||
pngs = sorted((n for n in names if n.endswith('.png') and 'ic_launcher' in n and 'foreground' not in n),
|
||||
key=lambda n: z.getinfo(n).file_size)
|
||||
if pngs:
|
||||
info['icon_png'] = z.read(pngs[-1])
|
||||
try:
|
||||
info['icon_png'] = _icon_png(z, names, _icons(app.get('icon'), res))
|
||||
except (zipfile.BadZipFile, RuntimeError, OSError):
|
||||
pass # a missing icon shouldn't stop the install
|
||||
return info
|
||||
|
||||
|
||||
def _icon_png(z, names, icons):
|
||||
for icon in icons:
|
||||
if icon.endswith('.png') and icon in names:
|
||||
return z.read(icon)
|
||||
# Adaptive icons are XML; fall back to the largest launcher PNG.
|
||||
pngs = sorted((n for n in names if n.endswith('.png') and 'ic_launcher' in n and 'foreground' not in n),
|
||||
key=lambda n: z.getinfo(n).file_size)
|
||||
return z.read(pngs[-1]) if pngs else None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
for p in sys.argv[1:]:
|
||||
|
||||
Reference in new issue
Block a user