diff --git a/nonpacks/library/zips.py b/nonpacks/library/zips.py index 6273792..cf5c5a1 100644 --- a/nonpacks/library/zips.py +++ b/nonpacks/library/zips.py @@ -869,6 +869,39 @@ def _modpack_totals(files): } +def _loader_from_filename(filename): + """Best-effort loader from a mod filename ('x_FABRIC_1.0.jar' → 'fabric').""" + low = str(filename).lower() + for token in ('fabricloader', 'fabric', 'neoforge', 'forge', 'quilt', 'rift', 'liteloader'): + if token in low: + return _normalize_modloader(token) + return '' + + +def _modpack_loaders(zf, members, limit=12): + """Unique modloaders inferred for a modpack. + + Folder/instance archives embed their jars, so we parse the first few for + their metadata. Modrinth .mrpack files only carry config overrides, so we + fall back to the loader encoded in the mod filenames. A sample is enough + because a modpack almost always targets a single loader. + """ + loaders = [] + for member in members[:limit]: + loader = '' + if str(member).lower().endswith('.jar'): + try: + meta = read_mod_manifest(zf.read(member)) + except Exception: + meta = None + loader = (meta or {}).get('modloader') or '' + if not loader: + loader = _loader_from_filename(member) + if loader and loader not in loaders: + loaders.append(loader) + return loaders + + def parse_mods_manifest(path, filename=''): """Inspect a modpack archive and build a manifest for the Mods tab. @@ -899,7 +932,8 @@ def parse_mods_manifest(path, filename=''): 'file_name': path_name, 'env': _mod_env(entry.get('env')), }) - return _modpack_result('modrinth', '', [], files) + modloaders = _modpack_loaders(zf, [f['file_name'] for f in files]) + return _modpack_result('modrinth', '', modloaders, files) if 'manifest.json' in names: try: @@ -951,7 +985,8 @@ def parse_mods_manifest(path, filename=''): seen.add(fname) mods.append({'name': fname, 'file_name': name}) if mods: - return _modpack_result('instance' if is_instance else 'folder', '', [], mods) + modloaders = _modpack_loaders(zf, [m['file_name'] for m in mods]) + return _modpack_result('instance' if is_instance else 'folder', '', modloaders, mods) return _modpack_result('unknown', '', [], []) finally: