barotrauma-sunken-tapes/deploy.py

294 lines
10 KiB
Python
Raw Normal View History

2021-09-24 12:00:38 +02:00
import jinja2 as j2
import yaml
import subprocess
import shutil
2021-11-14 14:52:53 +01:00
import requests
2021-09-24 12:00:38 +02:00
import os
import os.path
import sys
import time
import logging
2021-11-14 14:52:53 +01:00
import certifi
import math
2021-09-24 12:00:38 +02:00
from PIL import Image
from mutagen.oggvorbis import OggVorbis
from distutils.dir_util import copy_tree
from pathlib import Path
2021-11-14 14:52:53 +01:00
def download_via_requests(url_source, file_name):
response = requests.get(url_source, stream=True, verify=certifi.where())
with open(file_name, 'wb') as out_file:
shutil.copyfileobj(response.raw, out_file)
del response
2021-09-24 12:00:38 +02:00
def rmfulldir(dirpath):
try:
shutil.rmtree(dirpath)
except FileNotFoundError:
pass
def update():
logging.info(f"checking for updates via git pull.")
2021-09-24 12:00:38 +02:00
pull = ["utils/git/bin/git.exe", "pull"]
subprocess.call(pull)
def download_and_extract(url_source, out_archive):
logging.info(f"Downloading {url_source}, this may take a while.")
2021-11-14 14:52:53 +01:00
download_via_requests(url_source, out_archive)
2021-09-24 12:00:38 +02:00
time.sleep(0.7)
logging.info("Download complete.")
logging.info(f"Extracting {out_archive}")
extract = ["utils/7z/7za.exe", "x", out_archive, "-o" "./utils/"]
subprocess.call(extract)
time.sleep(0.7)
logging.info("Removing " + out_archive)
os.remove(out_archive)
def download_ffmpeg(clean=False):
if clean:
rmfulldir("./utils/ffmpeg-" + get_ffmpeg_version() + "-full_build")
url_ffmpeg_source = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z"
out_ffmpeg_archive = "./utils/ffmpeg-release-full.7z.exe"
download_and_extract(url_ffmpeg_source, out_ffmpeg_archive)
def download_git(clean=False):
if clean:
rmfulldir("./utils/PortableGit-2.33.0.2-64-bit")
url_git_source = "https://github.com/git-for-windows/git/releases/download/" + \
"v2.33.0.windows.2/PortableGit-2.33.0.2-64-bit.7z.exe"
out_git_archive = "./utils/PortableGit-2.33.0.2-64-bit.7z"
2021-11-14 14:52:53 +01:00
download_via_requests(url_git_source, out_git_archive)
2021-09-24 12:00:38 +02:00
time.sleep(0.7)
logging.info("Download complete.")
logging.info(f"Extracting {out_git_archive}")
extract = [out_git_archive, "-o" "./utils/git", "-y"]
subprocess.call(extract)
time.sleep(0.7)
logging.info("Removing " + out_git_archive)
os.remove(out_git_archive)
def get_ffmpeg_version():
url_ffmpeg_version = "https://www.gyan.dev/ffmpeg/builds/release-version"
2021-11-14 14:52:53 +01:00
fp = requests.get(url_ffmpeg_version, verify=certifi.where())
ffmpeg_version = fp.text
del fp
2021-09-24 12:00:38 +02:00
return ffmpeg_version
def fetch_and_cut_song(tape, ffmpeg_version):
2021-09-24 12:00:38 +02:00
python_executable = "./utils/python-3.9.7-embed-amd64/python.exe"
script = "./fetch_song.py"
if type(tape["source"]) == str:
shutil.copy(tape["source"], f"./build/music/{tape['identifier']}.ogg")
else:
fetch = [python_executable, script, tape["source"]["url"], "-x", "--audio-format", "vorbis",
"--audio-quality", "0", "-o", f"./build/tmp_music/{tape['identifier']}.ogg"]
# this is done in a separate python script because subprocess.call makes sure that the
# download process is finished before trying to cut the song
subprocess.call(fetch)
time.sleep(0.1)
cut = ["./utils/ffmpeg-" + ffmpeg_version + "-full_build/bin/ffmpeg.exe",
"-y", "-ss", f"{tape['source']['start']}",
"-i", f"./build/tmp_music/{tape['identifier']}.ogg", "-acodec", "libvorbis",
"-ac", "1", "-af", f"volume={tape['source']['volume']}dB",
f"./build/music/{tape['identifier']}.ogg"]
if tape["source"]["end"] != -1:
cut = cut[:-7] + ["-to", f"{tape['source']['end']}"] + cut[-7:]
try:
subprocess.call(cut)
except FileNotFoundError:
print("ffmpeg not in utils directory. Run python install_dependencies.py "
"or download the latest release version manually.")
sys.exit()
2021-11-28 00:45:25 +01:00
walkman = ["./utils/ffmpeg-" + ffmpeg_version + "-full_build/bin/ffmpeg.exe",
"-i", f"./build/music/{tape['identifier']}.ogg",
"-af", f"highpass=f=300,lowpass=f=12000",
f"./build/music/{tape['identifier']}-walkman.ogg"]
try:
subprocess.call(walkman)
except FileNotFoundError:
print("ffmpeg not in utils directory. Run python install_dependencies.py "
"or download the latest release version manually.")
sys.exit()
2021-09-24 12:00:38 +02:00
2021-12-17 17:13:02 +01:00
def assemble_png_images(tapes, outfile: str, resize=None):
img_names = [f"./source/images/{tape['identifier']}.png" for tape in tapes]
2021-09-24 12:00:38 +02:00
images = [Image.open(x) for x in img_names]
2021-12-17 17:13:02 +01:00
if resize is not None:
for i, (im, tape) in enumerate(zip(images, tapes)):
im.thumbnail((128, 82), Image.ANTIALIAS)
if resize == (64, 41) and tape["icon_resize"] == "blur":
im.thumbnail(resize, Image.ANTIALIAS)
else:
im.thumbnail(resize, Image.NEAREST)
images[i] = im
2021-09-24 12:00:38 +02:00
widths, heights = zip(*(i.size for i in images))
columns = int((len(images))**0.5)
rows = int(math.ceil(len(images) / columns))
total_width = max(widths) * columns
max_height = max(heights) * rows
2021-09-24 12:00:38 +02:00
new_im = Image.new('RGBA', (total_width, max_height))
for i, im in enumerate(images):
x_offset = max(widths) * (i % columns)
y_offset = max(heights) * math.floor(i / columns)
new_im.paste(im, (x_offset, y_offset))
2021-09-24 12:00:38 +02:00
2021-12-17 17:13:02 +01:00
new_im.save(f"./build/{outfile}.png")
2021-09-24 12:00:38 +02:00
def prepare_music(data):
2021-09-24 12:00:38 +02:00
try:
os.mkdir('./build/music/')
except FileExistsError:
pass
logging.info("reading ffmpeg version")
ffmpeg_version = get_ffmpeg_version()
logging.info(f"ffmpeg version is {ffmpeg_version}")
logging.info("downloading and cutting the songs")
2021-11-14 21:27:38 +01:00
for i, tape in enumerate(data):
2021-11-28 00:45:25 +01:00
if not (os.path.exists(f"./build/music/{tape['identifier']}.ogg") or os.path.exists(f"./build/music/{tape['identifier']}-walkman.ogg")):
2021-11-14 21:27:38 +01:00
logging.info(f"{i + 1}/{len(data)} Downloading: {tape['name']}")
fetch_and_cut_song(tape, ffmpeg_version)
2021-09-24 12:00:38 +02:00
else:
2021-11-14 21:27:38 +01:00
logging.info(f"{i + 1}/{len(data)} Already exists: {tape['name']}")
2021-09-24 12:00:38 +02:00
logging.info(f"removing temporary music folder")
rmfulldir('./build/tmp_music/')
logging.info(f"copying the sound effects to build")
copy_tree("./source/sound_effects", "./build/sound_effects")
def prepare_images(data, config):
logging.info(f"assembling covers and icons into png files")
2021-12-17 17:13:02 +01:00
assemble_png_images(data, "covers")
assemble_png_images(data, "icons", resize=(64, 41))
assemble_png_images(data, "sprites", resize=(33, 21))
2021-09-24 12:00:38 +02:00
logging.info(f"copying other images")
2021-12-17 17:13:02 +01:00
shutil.copy("./source/images/players_icons.png", "./build/players_icons.png")
shutil.copy("./source/images/players_sprites.png", "./build/players_sprites.png")
2021-10-11 01:14:38 +02:00
shutil.copy("./source/images/PreviewImage.png", "./build/PreviewImage.png")
2021-09-24 12:00:38 +02:00
def build_xml_code(data, config):
logging.info(f"calculate the value that lets you use the songs n-times")
song_lengths = [OggVorbis(f"./build/music/{tape['identifier']}.ogg").info.length
for tape in data]
use_lengths = [song_length * n for song_length, n in
zip(song_lengths, [tape["no_of_uses"] for tape in data])]
condition_delta = [f"{1 / use_length:0.5f}" for use_length in use_lengths]
affliction_delta = [100 / song_length for song_length in song_lengths]
columns = int((len(data))**0.5)
positions = [{"column": i % columns, "row": math.floor(i / columns)} for i in range(len(data))]
2021-09-24 12:00:38 +02:00
logging.info(f"creating jinja environment")
# create jinja2 environment
j2env = j2.Environment(loader=j2.FileSystemLoader(Path(".")))
j2env.globals.update(zip=zip)
# load the template file
template0 = j2env.get_template("./source/filelist_template.xml")
2021-09-24 12:00:38 +02:00
template1 = j2env.get_template("./source/sunken_tapes_template.xml")
if config["use_ita"]:
template2 = j2env.get_template("./source/sunken_tapes_style_ita_template.xml")
else:
template2 = j2env.get_template("./source/sunken_tapes_style_template.xml")
logging.info(f"rendering the xml files")
with open("./build/filelist.xml", "w+", encoding="utf8") as output_file:
# render the template
2021-11-14 21:20:03 +01:00
output_file.write(template0.render(config=config, tapes=data))
with open(f"./build/{config['slug']}.xml", "w+", encoding="utf8") as output_file:
2021-09-24 12:00:38 +02:00
# render the template
output_file.write(template1.render(tapes=data, config=config,
condition_delta=condition_delta,
affliction_delta=affliction_delta,
song_lengths=song_lengths,
positions=positions))
2021-09-24 12:00:38 +02:00
with open(f"./build/{config['slug']}_style.xml", "w+", encoding="utf8") as output_file:
2021-09-24 12:00:38 +02:00
# render the template
output_file.write(template2.render(tapes=data, config=config, positions=positions))
2021-09-24 12:00:38 +02:00
def deploy(config):
try:
os.mkdir('./build')
except FileExistsError:
logging.info(f"removing old XML files in ./build/:")
for f in Path('./build/').glob("*.xml"):
logging.info(f" {f}")
os.remove(f)
2021-09-24 12:00:38 +02:00
pass
logging.info("Reading tapes.yaml")
data_file = Path("./source/tapes.yaml")
# load yaml file
with data_file.open(encoding='utf-8') as fr:
data = yaml.load(fr, Loader=yaml.SafeLoader)
prepare_music(data)
2021-09-24 12:00:38 +02:00
prepare_images(data, config)
build_xml_code(data, config)
2021-10-28 12:03:58 +02:00
mod_directory = f"/Mods/{config['name']}/"
logging.info(f"removing the old installed mod directory {config['installdir'] + mod_directory}")
rmfulldir(config["installdir"] + mod_directory)
2021-09-24 12:00:38 +02:00
logging.info(f"copying the new build")
if Path(config["installdir"]).is_dir():
copy_tree("./build/", config["installdir"] + mod_directory)
2021-09-24 12:00:38 +02:00
else:
raise FileNotFoundError(
f"{config['installdir']} does not exist. Set up the correct Barotrauma installation directory")
logging.info(f"Done!")