Python 批量刷新Unity项目资源MD5 支持音效,视频,图片纹理,模型,meta,预制体,场景,脚本,json

Python 批量刷新Unity项目资源MD5 支持音效,视频,图片纹理,模型,meta,预制体,场景,脚本,json

上代码!

代码目录和启动入口

Python 批量刷新Unity项目资源MD5 支持音效,视频,图片纹理,模型,meta,预制体,场景,脚本,json_第1张图片



def main( ):

    import confuse_audio
    confuse_audio.run(work_directory)
    
    import confuse_picture
    confuse_picture.run(work_directory)

    import confuse_meta
    confuse_meta.run(work_directory)

    import confuse_anim
    confuse_anim.run(work_directory)

    import confuse_video
    confuse_video.run(work_directory)

    import confuse_text
    confuse_text.run(work_directory)

    import confuse_bytes
    confuse_bytes.run(work_directory)





    # 植入垃圾代码 稀释马甲代码
    

# domain

if __name__ == "__main__":

    work_directory = input('input work directory:\n')
    work_directory = work_directory.replace('\\','/')

    import unittestutls
    howlong_benrunning =  unittestutls.get_func_time(func=main,log=False)

    input(f'appliction complete: running time {round(howlong_benrunning,2)} seconds')




基础混淆类

以二进制的方式读入后覆盖源文件


from os.path import isfile


class confuse_base( ):

    def __init__(self, filepath:str) -> None:
        if not isfile(filepath):
            raise ValueError(f"not a file type: {filepath}")
        self.filepath = filepath
    
    def confuse( self ):
        with open( self.filepath,'rb+') as fp:
            content = fp.read()
            fp.seek(0)
            fp.write(content)

图片

使用PIL修改像素矩阵 确保图片像素变动的同时 表现上无明显差异

from findutils import find_img_files

def run(pro_dir:str):
    pro_dir = pro_dir.replace('\\','/')
    img_urls = find_img_files( pro_dir )
    num_imgs = len(img_urls)
    if num_imgs == 0:
        print(f'not found image in directory: {pro_dir}')
        return

    from imgfileutils import auto_modify_img_pixels
    

    import time
    s = time.time()
    
    executor = None

    # 使用进程池
    if num_imgs >= 1e+5:
        import concurrent.futures
        executor = concurrent.futures.ProcessPoolExecutor()
    # 使用线程池
    elif num_imgs >= 1e+3:
        import concurrent.futures
        executor = concurrent.futures.ThreadPoolExecutor()

    if executor != None:
        # 提交图像处理任务
        futures = [executor.submit(auto_modify_img_pixels, arg) for arg in img_urls]
        # 等待所有任务完成
        concurrent.futures.wait(futures)
    else:
        #使用协程池
        import gevent
        from gevent import monkey; monkey.patch_all()
        tasks = [gevent.spawn(auto_modify_img_pixels, arg) for arg in img_urls]
        gevent.joinall(tasks)

    e = time.time()

    print(f'处理图片完毕: ({len(img_urls)})|{round(e-s,2)}s')

from PIL import Image,ImageFile
import numpy as np
import random
import os
ImageFile.LOAD_TRUNCATED_IMAGES = True


 # 支持的图像文件头信息
supported_headers = {
    b'\xFF\xD8\xFF': 'JPEG',
    b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A': 'PNG',
    b'\x42\x4D\xe6\x04\x00\x00\x00\x00\x00\x00\x36\x00\x00\x00':'BMP',
    b'II*\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00':'TIFF'
    # 添加其他支持的图像格式的文件头信息
}

def is_valid_image_bytes(image_bytes):
    if len(image_bytes) == 0:
        return False
    
    for header, format in supported_headers.items():
        if image_bytes.startswith(header):
            return True
    return False

def modify_pixel(image_path, output_path, x, y, color):
    
    if not os.path.isfile( image_path ):
        print(f'{image_path} not a file')
        return 
    
    if not is_valid_image_bytes(open(image_path,'rb').read()):
        print(f'{image_path} is invalid image')
        return
    
    # 打开图像
    image = Image.open(image_path)

    # 将图像转换为 NumPy 数组
    img_array = np.array(image)

    # 修改指定位置的像素
    img_array[y, x] = color  # 这里注意纵坐标在前,横坐标在后

    # 将 NumPy 数组转换回图像
    modified_image = Image.fromarray(img_array)

    # 保存修改后的图像
    modified_image.save(output_path)

def auto_modify_img_pixels( img_url:str ):
    
    if not os.path.isfile( img_url ):
        print(f'无效文件: {img_url}')
        return 
    
    if not is_valid_image_bytes(open(img_url,'rb').read()):
        print(f'无效图片: {img_url}')
        return
    
    img = Image.open(img_url)
    img = np.asarray(img).copy()
    dest = random.randint(0,255-2)
    img[img==dest] =dest+1
    img = Image.fromarray(img)
    img.save(img_url)
    print(f'混淆完毕: {img_url}')
    # try:
    #     img = Image.open(img_url)
    #     img = np.asarray(img).copy()
    #     dest = random.randint(0,255-2)
    #     img[img==dest] =dest+1
    #     img = Image.fromarray(img)
    #     img.save(img_url)
    # except Exception as e:
    #     print(img_url)
    #     print(e)


# from unittestutls import get_func_time
# get_func_time( auto_modify_img_pixels,"4.jpg")

音效

使用ffmpeg来进行抽帧

import os
import subprocess
import re

ffmpeg = 'bin/ffmpeg.exe'
cwd = os.getcwd()

def get_audio_duration(file_path):
    # 构建 FFmpeg 命令
    command = [
        ffmpeg,
        "-i", file_path,
    ]

    # 执行命令并捕获输出
    result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

    # 从输出中提取时长信息
    duration_match = re.search(r"Duration: (\d{2}:\d{2}:\d{2}\.\d+)", result.stderr)
    
    if duration_match:
        duration_str = duration_match.group(1)
        # 将时长字符串转换为秒
        hours, minutes, seconds = map(float, duration_str.split(":"))
        duration_in_seconds = hours * 3600 + minutes * 60 + seconds
        return duration_in_seconds
    else:
        print("Failed to extract duration information.")
        return 0

def set_audio_speed( file:str, speed:float ):
    cmd = f'{ffmpeg} -y -i {file} -filter_complex "[0:a]atempo={speed}[out]" -map "[out]" {file}'
    subprocess.run(cmd)

def set_audio_volume( inputfile:str, volume:float,outfile:str ):
    cmd = f'{ffmpeg} -y -i {inputfile} -af "volume={volume}" {outfile}'
    subprocess.run(cmd)

cache_audio_path = {}
def proc_one( file_path:str ):
    if file_path not in cache_audio_path.keys():
        return
    set_audio_volume(file_path,1.01,cache_audio_path[file_path])
    print(f'修改: {file_path} -> {cache_audio_path[file_path]}')

def proc_all( files:list[str]):
    if not os.path.exists('bin/.temp'):
        os.mkdir('bin/.temp')
    
    cache_audio_path.clear()
    import shutil
    for file in files:
        tempath = os.path.join( cwd , 'bin\\.temp\\' + file.replace('\\','_').replace('/','_').replace(':','@') )
        shutil.move(file,tempath)
        cache_audio_path[tempath] = file
        print(f'暂存: {file} -> {tempath}')
    
    import time
    s = time.time()
    import gevent
    from gevent import monkey; monkey.patch_all()
    tasks = [gevent.spawn(proc_one, arg) for arg in cache_audio_path.keys()]
    gevent.joinall(tasks)
    e = time.time()
    print(f'处理音效完成: {len(files)}|{round(e-s,2)}s')

def run( root_dir: str ):
    from findutils import find_audio_files
    proc_all( find_audio_files(root_dir) )

视频

from confusebase import confuse_base
import os,shutil,subprocess

cwd = os.getcwd()
ffmpeg = 'bin/ffmpeg.exe'

def delete_frame(input_file, output_file):
    # 构建 FFmpeg 命令
    command = [
        ffmpeg,
        '-i', input_file,
        '-vf', "select='not(eq(n,1))'",
        '-c:v', 'libx264',
        '-c:a', 'aac',
        '-strict', 'experimental',
        output_file
    ]

    # 调用命令
    subprocess.run(command)

class confuse_video( confuse_base ):

    def __init__(self, filepath: str) -> None:
        super().__init__(filepath)
        self.temppath = os.path.join( cwd , 'bin\\.temp\\' + filepath.replace('\\','_').replace('/','_').replace(':','@') )
        shutil.move(filepath,self.temppath)

    def confuse( self ):
        delete_frame(self.temppath,self.filepath)

def proc_one( confuse_cls:confuse_base )->None:

    confuse_cls.confuse()

def run( root_dir ):
    from findutils import find_files
    confuse_meta_clss =[ confuse_video(f) for f in find_files(root_dir,'.mp4') ]

    import concurrentutils
    def foo():
        concurrentutils.run(proc_one,*confuse_meta_clss)
    from unittestutls import get_func_time
    running_time = get_func_time(foo,log=False)
    print(f'处理视频完毕: ({len(confuse_meta_clss)})|{running_time}s')

文本类

‘.txt’,‘.json’,‘.unity’,‘.prefab’ 这类做文本处理 当然你也可以加些其它的筛选

from confusebase import confuse_base

class confuse_text(confuse_base):

    def confuse(self):
        with open( self.filepath,'r+') as fp:
            fp.seek(0,2)
            fp.write("\n")

def proc_one( confuse_cls:confuse_base )->None:

    confuse_cls.confuse()

def run( root_dir ):
    from findutils import find_files
    confuse_meta_clss =[ confuse_text(f) for f in find_files(root_dir,['.txt','.json','.unity','.prefab']) ]

    import concurrentutils
    def foo():
        concurrentutils.run(proc_one,*confuse_meta_clss)
    from unittestutls import get_func_time
    running_time = get_func_time(foo,log=False)
    print(f'处理meta完成: {len(confuse_meta_clss)}|{running_time}s')

Bytes

from confusebase import confuse_base

def proc_one( confuse_cls:confuse_base )->None:

    confuse_cls.confuse()

def run( root_dir ):
    from findutils import find_files
    confuse_meta_clss =[ confuse_base(f) for f in find_files(root_dir,['.bytes','.fbx','.TTF','.ttf','.asset','.mat','.shader']) ]

    import concurrentutils
    def foo():
        concurrentutils.run(proc_one,*confuse_meta_clss)
    from unittestutls import get_func_time
    running_time = get_func_time(foo,log=False)
    print(f'处理meta完成: {len(confuse_meta_clss)}|{running_time}s')

智能多任务管理类 < 进程,线程,协程 > 自动根据任务量动态调度



def run( func, *args):

    executor = None
    num_reqs = len(args)

    # 使用进程池
    if num_reqs >= 2e+3+48:
        import concurrent.futures
        executor = concurrent.futures.ProcessPoolExecutor()
    # 使用线程池
    elif num_reqs >= 1e+3+24:
        import concurrent.futures
        executor = concurrent.futures.ThreadPoolExecutor()

    if executor != None:
        # 提交图像处理任务
        futures = [executor.submit(func, arg) for arg in args]
        # 等待所有任务完成
        concurrent.futures.wait(futures)
    else:
        #使用协程池
        import gevent
        from gevent import monkey; monkey.patch_all()
        tasks = [gevent.spawn(func, arg) for arg in args]
        gevent.joinall(tasks)

任务计时统计

def get_func_time( func,*args,log = True ):
    import time

    s = time.time()
    func(*args)
    e = time.time()

    elapsedTime = round(e-s,2)
    
    if log:
        print(f'elapsed time: {elapsedTime}s')
    
    return elapsedTime

你可能感兴趣的:(Python,Unity,python,unity,音视频)