finished Skin UGC
This commit is contained in:
@@ -7,6 +7,7 @@ adopted file (under MEDIA_ROOT) and return plain dicts/values.
|
||||
|
||||
import json
|
||||
import os
|
||||
import struct
|
||||
import zipfile
|
||||
|
||||
INJECTOR_NAMES = {'V': 'Vaginal', 'M': 'Mouth', 'A': 'Anal'}
|
||||
@@ -16,6 +17,48 @@ PROBLEM_TAGS = {'broken', 'bugged', 'borked'}
|
||||
MODEL_FILE_EXTENSIONS = ('.bbmodel', '.geo.json', '.jem', '.gltf', '.glb')
|
||||
|
||||
|
||||
def _png_size(head):
|
||||
"""(width, height) from a PNG IHDR header, or None when not a PNG."""
|
||||
if len(head) < 24 or head[:8] != b'\x89PNG\r\n\x1a\n':
|
||||
return None
|
||||
return (struct.unpack('>I', head[16:20])[0], struct.unpack('>I', head[20:24])[0])
|
||||
|
||||
|
||||
SKIN_SIZES = {(64, 32), (64, 64), (128, 128)}
|
||||
|
||||
|
||||
def read_skins_manifest(path):
|
||||
"""Scan the archive for Minecraft skin PNGs (64x32, 64x64 or 128x128).
|
||||
|
||||
Returns None when no skins are found; otherwise {skins: [{name, member,
|
||||
width, height}]} where ``member`` is the zip member served via pack_asset.
|
||||
"""
|
||||
zf = _open_zip(path)
|
||||
if zf is None:
|
||||
return None
|
||||
try:
|
||||
skins = []
|
||||
for name in sorted(n for n in set(zf.namelist()) if n.lower().endswith('.png')):
|
||||
try:
|
||||
with zf.open(name) as fh:
|
||||
head = fh.read(24)
|
||||
except (KeyError, OSError, zipfile.BadZipFile):
|
||||
continue
|
||||
size = _png_size(head)
|
||||
if size and size in SKIN_SIZES:
|
||||
skins.append({
|
||||
'name': name.rsplit('/', 1)[-1],
|
||||
'member': name,
|
||||
'width': size[0],
|
||||
'height': size[1],
|
||||
})
|
||||
if not skins:
|
||||
return None
|
||||
return {'skins': skins}
|
||||
finally:
|
||||
zf.close()
|
||||
|
||||
|
||||
def _in_plugins_dir(name):
|
||||
"""True when a member lives inside a plugins/ folder (any nesting)."""
|
||||
parts = name.split('/')
|
||||
|
||||
Reference in New Issue
Block a user