temporal upload. parcial Phase 2 implementation

This commit is contained in:
JakeBreath
2026-08-03 23:49:19 -05:00
parent f09acedbcf
commit a81e31bf1a
11 changed files with 555 additions and 8 deletions
+100
View File
@@ -0,0 +1,100 @@
"""Zip introspection helpers for category-specific version metadata.
Parsed once at upload time and stored on the Version row, so the detail page
never re-reads large archives. All functions take the on-disk path of an
adopted file (under MEDIA_ROOT) and return plain dicts/values.
"""
import json
import zipfile
def _open_zip(path):
"""Return a ZipFile for the path (None when it's not a zip)."""
try:
return zipfile.ZipFile(path)
except (zipfile.BadZipFile, OSError):
return None
def read_pack_mcmeta(path):
"""Extract the NoN-relevant data from a datapack's pack.mcmeta.
Returns (pack_format, description) or (None, '').
"""
zf = _open_zip(path)
if zf is None:
return None, ''
try:
try:
data = json.loads(zf.read('pack.mcmeta').decode('utf-8', 'replace'))
except (KeyError, json.JSONDecodeError):
return None, ''
pack = data.get('pack') or {}
try:
pack_format = int(pack.get('pack_format'))
except (TypeError, ValueError):
pack_format = None
description = pack.get('description', '') or ''
if isinstance(description, (dict, list)):
description = json.dumps(description)
return pack_format, str(description)
finally:
zf.close()
def parse_mods_manifest(path, filename=''):
"""Inspect a modpack archive and build a manifest for the Mods tab.
- Modrinth .mrpack: modrinth.index.json → dependencies
- Curseforge modpack: manifest.json → files array
- Classic folder layout: minecraft/mods/*.jar
Returns a dict: {source, files: [...]}.
"""
zf = _open_zip(path)
if zf is None:
return {'source': 'unknown', 'files': []}
try:
names = set(zf.namelist())
if filename.lower().endswith('.mrpack') or 'modrinth.index.json' in names:
try:
index = json.loads(zf.read('modrinth.index.json').decode('utf-8', 'replace'))
except (KeyError, json.JSONDecodeError):
index = {}
deps = []
for dep in index.get('dependencies') or []:
deps.append({
'name': dep.get('file_name') or dep.get('project_id', 'unknown'),
'version_id': dep.get('version_id'),
'type': dep.get('dependency_type', ''),
})
return {'source': 'modrinth', 'files': deps}
if 'manifest.json' in names:
try:
manifest = json.loads(zf.read('manifest.json').decode('utf-8', 'replace'))
except (KeyError, json.JSONDecodeError):
manifest = {}
files = []
for entry in manifest.get('files') or []:
files.append({
'name': entry.get('fileName', entry.get('projectID', 'unknown')),
'project_id': entry.get('projectID'),
'file_id': entry.get('fileID'),
})
if files:
return {'source': 'curseforge', 'files': files}
mods = []
prefix = 'minecraft/mods/'
for name in sorted(names):
if name.startswith(prefix) and not name.endswith('/'):
mods.append({'name': name[len(prefix):]})
if mods:
return {'source': 'folder', 'files': mods}
return {'source': 'unknown', 'files': []}
finally:
zf.close()