Ero-Lab部分游戏资源下载脚本

很久沒更新的遊戲了 tps://nidg.bhjsj8.com/new_patch/files/index.txt.852550fed47ae553edf7e3b66c935678

ttps://nidg.bhjsj8.com/new_patch/files/assets_resources_honly_baseassets_uiprefabs_simpleprefab_img_hcg_e001_01_hcg1_2.7fa8c079dd7

ttps://www.sbkjl.com/game_list.html

ttps://www.sbkjl.com/game.html?id=1

櫻境和這款除了加密其實差不多 (紳士冒險沒有加密)

nutaku版叫 Lusty Odyssey 已經收了

绅士冒险半个月前抓的。具体资源清单hash的逻辑没仔细看。

下载清单
import os
import requests
import urllib3
from concurrent.futures import ThreadPoolExecutor
import time

# 忽略 InsecureRequestWarning 警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# 下载单个文件的函数
def download_file(link, download_dir):
    # 从链接中提取文件名(保留原始文件名)
    path_part = link.split("?")[0].split("/")
    file_name = path_part[-1] if path_part[-1] else f"file_{hash(link) % 1000000}.bin"
    
    file_path = os.path.join(download_dir, file_name)

    headers = {
        "Accept": "*/*",
        "Accept-Encoding": "deflate, gzip",
        "User-Agent": "UnityPlayer/2020.3.41f1 (UnityWebRequest/1.0, libcurl/7.84.0-DEV)",
        "X-Unity-Version": "2020.3.41f1",
        "Host": "nidg.bhjsj8.com"
    }

    try:
        # 禁用 SSL 证书验证
        response = requests.get(link, headers=headers, verify=False)
        response.raise_for_status()

        # 确定响应内容类型
        content_type = response.headers.get('Content-Type', '')
        
        # 根据内容类型选择写入模式
        if 'json' in content_type or 'text' in content_type:
            # 文本内容
            with open(file_path, 'w', encoding='utf-8') as file:
                file.write(response.text)
            print(f"下载完成: {file_name} (文本模式)")
        else:
            # 二进制内容
            with open(file_path, 'wb') as file:
                file.write(response.content)
            print(f"下载完成: {file_name} (二进制模式)")
            
        # 打印文件信息
        file_size = os.path.getsize(file_path)
        print(f"文件大小: {file_size} 字节")
        print(f"保存路径: {os.path.abspath(file_path)}")

    except requests.RequestException as e:
        print(f"请求过程中出现错误: {e}")
    except Exception as e:
        print(f"下载过程中出现未知错误: {e}")

# 主下载函数
def main_download():
    # 生成时间戳
    ts = int(time.time())
    # 下载链接
    base_link = "https://nidg.bhjsj8.com/new_patch/files/index.txt.c47c53a61a6b650788724579ebab4da9"
    download_link = [f"{base_link}?ts={ts}"]
    
    # 确保下载目录存在
    download_dir = os.getcwd()
    os.makedirs(download_dir, exist_ok=True)
    
    print(f"下载目录: {os.path.abspath(download_dir)}")
    
    # 使用线程池进行下载
    with ThreadPoolExecutor(max_workers=2) as executor:
        print(f"开始下载: {download_link}")
        executor.map(lambda link: download_file(link, download_dir), download_link)

    print("\n🎉 文件下载完成!")

if __name__ == "__main__":
    # 执行下载操作
    main_download()
    
    # 等待用户查看结果
    input("按 Enter 键退出...")
提取url
import os
import json

def process_index_file():
    # 读取同目录下的 index.txt 文件
    input_file_path = os.path.join(os.getcwd(), 'index.txt')
    output_file_path = os.path.join(os.getcwd(), 'output.txt')
    
    try:
        with open(input_file_path, 'r', encoding='utf-8') as f:
            content = f.read()
            data = json.loads(content)
    except FileNotFoundError:
        print(f"错误: 找不到 {input_file_path} 文件")
        return
    except json.JSONDecodeError:
        print(f"错误: {input_file_path} 文件不是有效的 JSON 格式")
        return
    except Exception as e:
        print(f"错误: 读取文件时发生未知错误: {e}")
        return
    
    # 基础 URL
    base_url = "https://nidg.bhjsj8.com/new_patch/files/"
    
    # 用于存储结果的列表
    result_urls = []
    
    # 遍历 JSON 数据中的每个键值对
    for key, value in data.items():
        # 确保值是列表且至少有两个元素
        if isinstance(value, list) and len(value) >= 2:
            # 拼接文件名和哈希值(直接使用键名,不做前缀过滤)
            filename = f"{key}.{value[1]}"
            # 拼接完整 URL
            full_url = f"{base_url}{filename}"
            result_urls.append(full_url)
    
    # 将结果写入 output.txt 文件
    try:
        with open(output_file_path, 'w', encoding='utf-8') as f:
            # 每行写入一个 URL
            for url in result_urls:
                f.write(url + '\n')
        print(f"成功生成 {output_file_path} 文件,共写入 {len(result_urls)} 个 URL")
    except Exception as e:
        print(f"错误: 写入文件时发生未知错误: {e}")

if __name__ == "__main__":
    process_index_file()
    input("按 Enter 键退出...")
下载
import requests
import os
import time
from concurrent.futures import ThreadPoolExecutor
import urllib3
from datetime import datetime

# 禁用 InsecureRequestWarning 警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def get_simplified_timestamp():
    now = datetime.now()
    return now.strftime("%y%m%d%H%M%S")

def download_file(link, download_dir, total_files, index, digit_count, success_files, failed_files):
    # 提取文件名和路径
    path_parts = link.split("/")
    file_name = path_parts[-1].split("?")[0]
    relative_path = "/".join(path_parts[3:-1])  # 假设前三个部分是协议和域名,可根据实际情况调整
    local_dir = os.path.join(download_dir, relative_path)
    local_path = os.path.join(local_dir, file_name)

    max_retries = 3  # 最大重试次数
    retry_delay = 5  # 重试延迟时间(秒)

    # 创建本地目录
    os.makedirs(local_dir, exist_ok=True)

    for attempt in range(max_retries):
        try:
            # 检查本地文件是否存在且大小相同(忽略证书验证)
            if os.path.exists(local_path):
                local_size = os.path.getsize(local_path)
                headers = requests.head(link, allow_redirects=True, timeout=10, verify=False).headers
                remote_size = int(headers.get('Content-Length', 0))
                if local_size == remote_size and remote_size != 0:
                    print(f"[跳过] {total_files}/{index:0{digit_count}d} 已存在且大小一致: {local_path}")
                    success_files.append(file_name)
                    return

            response = requests.get(link, stream=True, timeout=10, verify=False)
            response.raise_for_status()

            with open(local_path, 'wb') as file:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        file.write(chunk)

            if os.path.exists(local_path):
                final_size = os.path.getsize(local_path)
                if final_size > 0:
                    print(f"[成功] {total_files}/{index:0{digit_count}d} 下载完成: {local_path}")
                    success_files.append(file_name)
                    return
                else:
                    raise Exception("下载后文件大小为0")
        except (requests.RequestException, Exception) as e:
            if attempt < max_retries - 1:
                print(f"[尝试 {attempt + 1}/{max_retries}] {total_files}/{index:0{digit_count}d} 下载失败: {str(e)}, 重试中...")
                time.sleep(retry_delay)
            else:
                print(f"[失败] {total_files}/{index:0{digit_count}d} 下载失败: {str(e)}")
                failed_files.append(file_name)


def count_files_in_directory(directory):
    file_count = 0
    for root, dirs, files in os.walk(directory):
        file_count += len(files)
    return file_count

def main_download():
    file_path = "output.txt"
    download_dir = os.path.join(os.getcwd(), "com.superhgame.rpg.emma")

    if not os.path.exists(file_path):
        print("❌ 未找到下载列表文件")
        return

    with open(file_path, "r", encoding="utf-8") as f:
        download_links = [line.strip() for line in f if line.strip()]

    if not download_links:
        print("❌ 下载列表中没有有效链接")
        return

    total_files = len(download_links)
    digit_count = len(str(total_files))
    os.makedirs(download_dir, exist_ok=True)

    success_files = []
    failed_files = []

    print(f"✅ 准备下载 {total_files} 个文件,保存到 {download_dir}")
    print("-" * 60)

    with ThreadPoolExecutor(max_workers=32) as executor:
        futures = []
        for index, link in enumerate(download_links, start=1):
            futures.append(executor.submit(
                download_file,
                link, download_dir, total_files, index, digit_count,
                success_files, failed_files
            ))

        for future in futures:
            future.result()

    print("\n" + "=" * 60)
    print(f"📦 下载完成 | 成功: {len(success_files)} | 失败: {len(failed_files)}")
    if failed_files:
        print("\n❌ 以下文件下载失败(请手动检查):")
        for fname in failed_files:
            print(f" - {fname}")
    else:
        print("\n🎉 所有文件均下载成功!")

    # 计算目标文件夹中的实际文件数
    actual_file_count = count_files_in_directory(download_dir)
    print(f"\n📁 目标文件夹中的实际文件数: {actual_file_count}")
    print(f"📋 下载列表中的文件数: {total_files}")

    if actual_file_count == total_files:
        print("✅ 实际文件数与下载数相同。")
    else:
        print("❌ 实际文件数与下载数不同,请检查。")

    # 等待用户输入,阻止程序立即退出
    input("按回车键退出...")


if __name__ == "__main__":
    try:
        import requests
    except ImportError:
        print("❌ 缺少requests库,请先安装:pip install requests")
        exit(1)

    main_download()
1 个赞

感谢
不过我的意思是我需要游戏本体的安装包,不仅是为了研究逻辑还有一点就是这种游戏一般都有离线(APK自带)资源,比如星陨的H060(使徒),最近在验证已有资源的完整性发现了一些APK里有但是没收集到的资源

工口.R18 成人遊戲免費線上玩

感谢大佬

这个是绅士冒险游戏本体的安装包https://resfile.lixincsb.com/apk/1697525935357.apk

import os

import requests
import json


def test():
    index_url = "https://nidg.bhjsj8.com/new_patch/files/index.txt.623f677d60bab9e181b00a26f8bf2d77"

    try:
        response = requests.get(index_url, timeout=10)
        response.raise_for_status()
        data = json.loads(response.text)
        base_url = "https://nidg.bhjsj8.com/new_patch/files/{filename}.{hash}"
        with open("ssmx.txt", "w", encoding="utf-8") as outfile:
            for filename, values in data.items():
                if isinstance(values, list) and len(values) >= 2:
                    file_hash = values[1]
                    download_url = base_url.format(filename=filename, hash=file_hash)
                    outfile.write(f"{download_url}\n   out={filename}\n")
        print(f"共处理 {len(data)} 个资源条目。")
    except requests.exceptions.RequestException as e:
        print(f"下载资源清单失败: {e}")
    except json.JSONDecodeError as e:
        print(f"解析JSON数据失败: {e}")
    except Exception as e:
        print(f"发生未知错误: {e}")


if __name__ == "__main__":
    test()
    os.system("aria2c -i ssmx.txt -j 32 --check-certificate=false --dir=resdownload/绅士冒险")

试试看行不行

1 个赞

这也是NS做的游戏应该风格太像了logo也是
怪了
没有找到
b004_01.png这个资源

1 个赞

我自己猜 這款是NS主要員工的前東家的遊戲

(這個前東家有很多CG互用 水球社 桃色旅團等等 CG都很多一樣的 水球社最近也收了)

2025 07 02 23:00(UTC +8)
V1.29更新加入 禁域战姬 支持
加入清除生成的所有url txt
感谢 yjzyl9008 & Airtnp的支持

本来想直接等E服新游的算了估计还要一段时间先更吧。。。

3 个赞

關於 [童話邊境] 檔案名稱這部分,我還是很懶得改
叫GPT寫了一份
同時可以修改所有檔案名稱補0
又可以修正ATLAS內的PNG名稱補0

:white_check_mark: 功能總覽:

  1. 遞迴處理所有子資料夾
  2. .png, .json, .atlas 三種檔案:
  • Hero3.pngHero03.png
  • Walk.pngWalk01.png
  • Jump15.png → 不修改
  1. 修改 .atlas 檔案 第二行檔名 也套用同樣補零規則!
import os
import re

def fix_filename(name, ext):
    match = re.match(r'^(.*?)(\d+)?$', name)
    if not match:
        return None

    base = match.group(1)
    digits = match.group(2)

    if digits is None:
        return f"{base}01{ext}"
    elif len(digits) == 1:
        return f"{base}0{digits}{ext}"
    else:
        return None  # 兩位數以上不動

def rename_files_and_fix_atlas(root_dir):
    for dirpath, _, filenames in os.walk(root_dir):
        for filename in filenames:
            name, ext = os.path.splitext(filename)
            if ext.lower() not in ['.png', '.json', '.atlas']:
                continue

            old_path = os.path.join(dirpath, filename)
            new_filename = fix_filename(name, ext)

            # 改檔名
            if new_filename and new_filename != filename:
                new_path = os.path.join(dirpath, new_filename)
                if not os.path.exists(new_path):
                    os.rename(old_path, new_path)
                    print(f"✅ 檔名修正:{filename} ➜ {new_filename}")
                    # 若是 atlas 被改名,也要順便改內容(第二行)
                    if ext.lower() == '.atlas':
                        fix_atlas_second_line(new_path)
                else:
                    print(f"⚠ 目標檔案已存在:{new_filename},略過")
            else:
                # 如果是 atlas 而檔名沒改,也要檢查第二行
                if ext.lower() == '.atlas':
                    fix_atlas_second_line(old_path)

def fix_atlas_second_line(file_path):
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()

        if len(lines) < 2:
            print(f"⏩ {os.path.basename(file_path)} 少於兩行,略過第二行處理")
            return

        line2 = lines[1].strip()
        name, ext = os.path.splitext(line2)
        if ext.lower() != '.png':
            print(f"⏩ {file_path} 第二行不是 PNG 檔名,略過")
            return

        new_line2 = fix_filename(name, ext)
        if new_line2 and new_line2 != line2:
            lines[1] = new_line2 + '\n'
            with open(file_path, 'w', encoding='utf-8') as f:
                f.writelines(lines)
            print(f"📝 {os.path.basename(file_path)} 第二行修正為:{new_line2}")
        else:
            print(f"⏩ {os.path.basename(file_path)} 第二行無需更改")
    except Exception as e:
        print(f"❌ 錯誤處理 atlas 第二行:{file_path},錯誤:{e}")

# ▶ 請修改這個資料夾路徑為你的目標資料夾
rename_files_and_fix_atlas("Spine-merge")