幻能边境解包求助

E服就是换个url…
json的hash都是一样的…

import os
import requests
import json

BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
BASE64_VALUES = [0] * 128
for idx, char in enumerate(BASE64_CHARS):
    BASE64_VALUES[ord(char)] = idx

HEX_CHARS = list('0123456789abcdef')
_t = ['', '', '', '']
UUID_TEMPLATE = _t + _t + ['-'] + _t + ['-'] + _t + ['-'] + _t + ['-'] + _t + _t + _t
INDICES = [i for i, x in enumerate(UUID_TEMPLATE) if x != '-']

def decode_uuid(base64_str):
    if len(base64_str) != 22:
        return base64_str
    result = UUID_TEMPLATE.copy()
    result[0] = base64_str[0]
    result[1] = base64_str[1]

    j = 2
    for i in range(2, 22, 2):
        lhs = BASE64_VALUES[ord(base64_str[i])]
        rhs = BASE64_VALUES[ord(base64_str[i + 1])]

        result[INDICES[j]] = HEX_CHARS[lhs >> 2]
        j += 1
        result[INDICES[j]] = HEX_CHARS[((lhs & 3) << 2) | (rhs >> 4)]
        j += 1
        result[INDICES[j]] = HEX_CHARS[rhs & 0xF]
        j += 1

    return ''.join(result)

def has_sp_skeleton_data(obj):
    if isinstance(obj, list):
        if len(obj) > 0 and obj[0] == "sp.SkeletonData":
            return obj
        for item in obj:
            found = has_sp_skeleton_data(item)
            if found:
                return found
    elif isinstance(obj, dict):
        for value in obj.values():
            found = has_sp_skeleton_data(value)
            if found:
                return found
    return None

def getspresjson(bundle):
    url1 = "https://cpev.fhaqlbp.com/eow-jp-game/proj.confg.json"
    response1 = requests.get(url1)
    response1.raise_for_status()

    data1 = response1.json()

    special_value = data1.get("Config", {}).get(bundle)
    if not special_value:
        raise ValueError(f"无法获取 Config -> {bundle} 的值")

    print(f"{bundle} = {special_value}")

    url2 = f"https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/{bundle}/config.{special_value}.json"

    response2 = requests.get(url2)
    response2.raise_for_status()

    return response2.json()

def getresjson(bundle):
    url1 = "https://cpev.fhaqlbp.com/eow-jp-game/bundle/version.json"
    response1 = requests.get(url1)
    response1.raise_for_status()

    data1 = response1.json()

    anima_entry = next((item for item in data1 if item.get("abName") == bundle), None)
    if not anima_entry:
        raise ValueError(f"未找到 abName 为 '{bundle}' 的数据")

    anima_version = anima_entry.get("version")
    if not anima_version:
        raise ValueError(f"{bundle} 的 version 字段为空")

    print(f"anima version = {anima_version}")
    url2 = f"https://cpev.fhaqlbp.com/eow-jp-game/bundle/{bundle}/cc.config.{anima_version}.json"
    response2 = requests.get(url2)
    response2.raise_for_status()

    return response2.json()


def resdownloader(BASE, data,output_dir):
    uuids = data["uuids"]
    vers_imp = data["versions"]["import"]
    vers_nat = data["versions"]["native"]
    paths = data["paths"]
    types = data["types"]

    if "sp.SkeletonData" not in types:
        print(f"[!] 未找到 sp.SkeletonData 数据")
        return

    SpriteFrameint = types.index("sp.SkeletonData")

    vimp = {vers_imp[i]: vers_imp[i + 1] for i in range(0, len(vers_imp), 2)}
    vnat = {vers_nat[i]: vers_nat[i + 1] for i in range(0, len(vers_nat), 2)}
    os.makedirs(output_dir, exist_ok=True)

    for idx, sid in enumerate(uuids):
        if paths.get(str(idx)) and paths.get(str(idx))[1] == SpriteFrameint:
            if '@' in sid:
                uuid_base64, ext = sid.split('@', 1)
            else:
                uuid_base64, ext = sid, None
            uuid = decode_uuid(uuid_base64)
            full_uuid = f"{uuid}@{ext}" if ext else uuid
            imp_ver = f".{vimp.get(idx, '')}"
            nat_ver = f".{vnat.get(idx, '')}"

            json_url = f"{BASE}/import/{uuid[:2]}/{full_uuid}{imp_ver}.json"
            skel_url = f"{BASE}/native/{uuid[:2]}/{full_uuid}{nat_ver}.bin"

            base_name = os.path.basename(paths[str(idx)][0])
            print(f'json - {base_name}.json -> {json_url} | skel - {base_name}.skel -> {skel_url}')

            try:
                response = requests.get(json_url)
                response.raise_for_status()
                json_data = response.json()
            except Exception as e:
                print(f"[!] 下载失败: {json_url} ({e})")
                continue

            if not has_sp_skeleton_data(json_data):
                continue

            res_path = paths[str(idx)][0]
            folder = os.path.join(output_dir, *res_path.split("/"))
            os.makedirs(folder, exist_ok=True)

            try:
                sp_type_block = next(item for item in json_data[3] if item[0] == "sp.SkeletonData")
                field_names = sp_type_block[1]
            except Exception as e:
                print(f"[!] 无法解析字段名: {e}")
                continue

            try:
                obj_data = json_data[5][0]
                field_values = obj_data[1:]
                sp_dict = dict(zip(field_names, field_values))

                _name = sp_dict.get("_name", base_name)
                _atlasText = sp_dict.get("_atlasText", "")
                _skeletonJson = sp_dict.get("_skeletonJson", None)

                atlas_path = os.path.join(folder, f"{_name}.atlas")
                if os.path.exists(atlas_path): #and not overwrite:
                    print(f"[!] 已存在 atlas,跳过:{_name}.atlas")
                    continue
                with open(atlas_path, "w", encoding="utf-8") as f:
                    f.write(_atlasText)
                print(f"[+] 写入 atlas 成功:{_name}.atlas")

                if _skeletonJson:
                    json_path = os.path.join(folder, f"{_name}.json")
                    with open(json_path, "w", encoding="utf-8") as f:
                        json.dump(_skeletonJson, f, ensure_ascii=False, indent=2)
                    print(f"[+] 写入 skeletonJson 成功:{_name}.json")
                else:
                    skel_path = os.path.join(folder, f"{_name}.skel")
                    with open("eroeowurl.txt", "a", encoding="utf-8") as f:
                        f.write(f"{skel_url}\n  out={skel_path}\n")

                pngdata = json_data[1]
                for i, pngsid in enumerate(pngdata):
                    pnguuid = decode_uuid(pngsid[:22])
                    try:
                        idxpng = uuids.index(pngsid[:22])
                        nat_verpng = vnat[idxpng]
                        pngurl = f"{BASE}/native/{pnguuid[:2]}/{pnguuid}.{nat_verpng}.png"
                        png_tempname = f"{_name}_{i + 1}" if i >= 1 else f"{_name}"
                        png_path = os.path.join(folder, png_tempname + ".png")
                        print(f'{png_tempname}.png -> {pngurl}')
                        with open("eroeowurl.txt", "a", encoding="utf-8") as f:
                            f.write(f"{pngurl}\n  out={png_path}\n")
                    except Exception as e:
                        print(f"[!] PNG处理失败: {e}")
            except Exception as e:
                print(f"[!] 解包 sp.SkeletonData 数据失败: {e}")

if os.path.exists("eroeowurl.txt"):
    os.remove("eroeowurl.txt")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/normal",getspresjson('normal'),"resdownload\\EroLab幻能边境\\bundle_sp\\normal")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/spdata",getspresjson('spdata'),"resdownload\\EroLab幻能边境\\bundle_sp\\spdata")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/special",getspresjson('special'),"resdownload\\EroLab幻能边境\\bundle_sp\\special")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle_sp/special2",getspresjson('special2'),"resdownload\\EroLab幻能边境\\bundle_sp\\special2")

resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/anima",getresjson('anima'),"resdownload\\EroLab幻能边境\\bundle\\anima")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/activity",getresjson('activity'),"resdownload\\EroLab幻能边境\\bundle\\activity")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/barner",getresjson('barner'),"resdownload\\EroLab幻能边境\\bundle\\barner")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/battle",getresjson('battle'),"resdownload\\EroLab幻能边境\\bundle\\battle")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/bgs",getresjson('bgs'),"resdownload\\EroLab幻能边境\\bundle\\bgs")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/career",getresjson('career'),"resdownload\\EroLab幻能边境\\bundle\\career")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/cat",getresjson('cat'),"resdownload\\EroLab幻能边境\\bundle\\cat")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/dictionary",getresjson('dictionary'),"resdownload\\EroLab幻能边境\\bundle\\dictionary")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/mp4",getresjson('mp4'),"resdownload\\EroLab幻能边境\\bundle\\mp4")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/ornament",getresjson('ornament'),"resdownload\\EroLab幻能边境\\bundle\\ornament")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/sd",getresjson('sd'),"resdownload\\EroLab幻能边境\\bundle\\sd")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/sound",getresjson('sound'),"resdownload\\EroLab幻能边境\\bundle\\sound")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/texture",getresjson('texture'),"resdownload\\EroLab幻能边境\\bundle\\texture")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/vd",getresjson('vd'),"resdownload\\EroLab幻能边境\\bundle\\vd")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/icon",getresjson('icon'),"resdownload\\EroLab幻能边境\\bundle\\icon")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/maps",getresjson('maps'),"resdownload\\EroLab幻能边境\\bundle\\maps")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/normal",getresjson('normal'),"resdownload\\EroLab幻能边境\\bundle\\normal")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/special",getresjson('special'),"resdownload\\EroLab幻能边境\\bundle\\special")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/spdata",getresjson('spdata'),"resdownload\\EroLab幻能边境\\bundle\\spdata")
resdownloader("https://cpev.fhaqlbp.com/eow-jp-game/bundle/special2",getresjson('special2'),"resdownload\\EroLab幻能边境\\bundle\\special2")
os.system("aria2c -i eroeowurl.txt -j 32 -s 16 -x 16 --check-certificate=false")