99 lines
2.9 KiB
Python
99 lines
2.9 KiB
Python
|
#!/usr/bin/env python
|
||
|
#
|
||
|
# UnityPackage Extractor
|
||
|
#
|
||
|
# Extracts files/folders from a .unitypackage file, reading the 'pathname'
|
||
|
# files it contains to rebuild a "readable" file/folder structure.
|
||
|
#
|
||
|
# Usage: extractunitypackage.py input_file [output_path]
|
||
|
#
|
||
|
# "input_file" should be a .unitypackage file. The part of the filename
|
||
|
# before the extension will be used as the name of the directory that the
|
||
|
# packages contents will be extracted to.
|
||
|
#
|
||
|
# "output_path" is an optional path where the package's files will be
|
||
|
# extracted to. If omitted, the current working directory is used. If
|
||
|
# specified, the path should already exist.
|
||
|
|
||
|
import os
|
||
|
import shutil
|
||
|
import sys
|
||
|
import tarfile
|
||
|
|
||
|
if len(sys.argv) < 2:
|
||
|
print 'No input file specified.'
|
||
|
sys.exit()
|
||
|
|
||
|
name, extension = os.path.splitext(sys.argv[1])
|
||
|
|
||
|
outputDir = ''
|
||
|
if len(sys.argv) > 2:
|
||
|
outputDir = os.path.join(sys.argv[2], name)
|
||
|
else:
|
||
|
outputDir = './' + name
|
||
|
workingDir = './.working'
|
||
|
|
||
|
# can't proceed if the output dir exists already
|
||
|
# but if the temp working dir exists, we clean it out before extracting
|
||
|
if os.path.exists(outputDir):
|
||
|
print 'Output dir "' + outputDir + '" exists. Aborting.'
|
||
|
sys.exit();
|
||
|
if os.path.exists(workingDir):
|
||
|
shutil.rmtree(workingDir)
|
||
|
|
||
|
# extract .unitypackage contents to a temporary space
|
||
|
tar = tarfile.open(sys.argv[1], 'r:gz')
|
||
|
tar.extractall(workingDir);
|
||
|
tar.close()
|
||
|
|
||
|
# build association between the unitypackage's root directory names
|
||
|
# (which each have 1 asset in them) to the actual filename (stored in the 'pathname' file)
|
||
|
mapping = {}
|
||
|
for i in os.listdir(workingDir):
|
||
|
rootFile = os.path.join(workingDir, i)
|
||
|
asset = i
|
||
|
|
||
|
if os.path.isdir(rootFile):
|
||
|
realPath = ''
|
||
|
|
||
|
# we need to check if an 'asset' file exists (sometimes it won't be there
|
||
|
# such as when the 'pathname' file is just specifying a directory)
|
||
|
hasAsset = False
|
||
|
|
||
|
for j in os.listdir(rootFile):
|
||
|
# grab the real path
|
||
|
if j == 'pathname':
|
||
|
lines = [line.strip() for line in open(os.path.join(rootFile, j))]
|
||
|
realPath = lines[0] # should always be on the first line
|
||
|
elif j == 'asset':
|
||
|
hasAsset = True
|
||
|
|
||
|
# if an 'asset' file exists in this directory, then this directory
|
||
|
# contains a file that should be moved+renamed. otherwise we can
|
||
|
# ignore this directory altogether...
|
||
|
if hasAsset:
|
||
|
mapping[asset] = realPath
|
||
|
|
||
|
# mapping from unitypackage internal filenames to real filenames is now built
|
||
|
# walk through them all and move the 'asset' files out and rename, building
|
||
|
# the directory structure listed in the real filenames we found as we go
|
||
|
|
||
|
os.mkdir(outputDir)
|
||
|
|
||
|
for asset in mapping:
|
||
|
path, filename = os.path.split(mapping[asset])
|
||
|
|
||
|
destDir = os.path.join(outputDir, path)
|
||
|
destFile = os.path.join(destDir, filename)
|
||
|
source = os.path.join(workingDir, asset, 'asset');
|
||
|
|
||
|
if not os.path.exists(destDir):
|
||
|
os.makedirs(destDir)
|
||
|
|
||
|
shutil.move(source, destFile)
|
||
|
|
||
|
print asset, '=>', mapping[asset]
|
||
|
|
||
|
# done, cleanup any leftovers...
|
||
|
shutil.rmtree(workingDir)
|