From 8391ecf8b306e9af09bc63af4bc6d488074d01c2 Mon Sep 17 00:00:00 2001 From: OleSTEEP Date: Sat, 27 May 2023 20:01:04 +0300 Subject: [PATCH] Initial Commit --- FFMpeg-Compressor/README.md | 8 ++++ FFMpeg-Compressor/config.ini | 9 ++++ FFMpeg-Compressor/main.py | 24 +++++++++++ FFMpeg-Compressor/modules/compressor.py | 47 +++++++++++++++++++++ FFMpeg-Compressor/modules/printer.py | 21 ++++++++++ FFMpeg-Compressor/modules/utils.py | 21 ++++++++++ README.md | 6 +++ RenPy-Android-Unpack/README.md | 6 +++ RenPy-Android-Unpack/unpack.py | 55 +++++++++++++++++++++++++ 9 files changed, 197 insertions(+) create mode 100644 FFMpeg-Compressor/README.md create mode 100644 FFMpeg-Compressor/config.ini create mode 100755 FFMpeg-Compressor/main.py create mode 100644 FFMpeg-Compressor/modules/compressor.py create mode 100644 FFMpeg-Compressor/modules/printer.py create mode 100644 FFMpeg-Compressor/modules/utils.py create mode 100644 README.md create mode 100644 RenPy-Android-Unpack/README.md create mode 100755 RenPy-Android-Unpack/unpack.py diff --git a/FFMpeg-Compressor/README.md b/FFMpeg-Compressor/README.md new file mode 100644 index 0000000..a42a23c --- /dev/null +++ b/FFMpeg-Compressor/README.md @@ -0,0 +1,8 @@ +## FFMpeg-Compressor +Python utility uses ffmpeg to compress Visual Novel Resources + +### How to use +* Configure utitlity in `config.ini` +* `python main.py` +* Drag and drop folder you want to compress and press `Enter` +* In result you get `{folder-compressed}` near with original `{folder}` diff --git a/FFMpeg-Compressor/config.ini b/FFMpeg-Compressor/config.ini new file mode 100644 index 0000000..c5edcb1 --- /dev/null +++ b/FFMpeg-Compressor/config.ini @@ -0,0 +1,9 @@ +[FFMPEG] +AudioBitRate = 320k +AudioExt = mp3 +CompLevel = 20 +ImageExt = png +JpegComp = 3 +FFmpegParams = -hide_banner -loglevel error +VideoCodec = libvpx-vp9 +VideoExt = webm diff --git a/FFMpeg-Compressor/main.py b/FFMpeg-Compressor/main.py new file mode 100755 index 0000000..6b36d29 --- /dev/null +++ b/FFMpeg-Compressor/main.py @@ -0,0 +1,24 @@ +#!/bin/python3 + +from modules import compressor +from modules import printer +from modules import utils +import os + +orig_folder = input("Folder: ").replace("'", "") + +try: + os.mkdir(f"{orig_folder}_compressed") + printer.info(f"Created {orig_folder}_compressed folder") +except OSError: + pass + +printer.info("Compression started!") +compressor.compress(orig_folder) + +if len(os.listdir(path=orig_folder)) == len((os.listdir(path=f"{orig_folder}_compressed"))): + printer.info("Success!") + utils.get_compression(orig_folder, f"{orig_folder}_compressed") +else: + printer.warning("Some files failed to compress!") + utils.get_compression(orig_folder, f"{orig_folder}_compressed") diff --git a/FFMpeg-Compressor/modules/compressor.py b/FFMpeg-Compressor/modules/compressor.py new file mode 100644 index 0000000..dd1df4f --- /dev/null +++ b/FFMpeg-Compressor/modules/compressor.py @@ -0,0 +1,47 @@ +from modules import printer +import configparser +import os + +audio_exts = ['.aac', '.flac', '.m4a', '.mp3', '.ogg', '.opus', '.raw', '.wav', '.wma'] +image_exts = ['.apng', '.avif', '.jfif', '.pjpeg', '.pjp', '.svg', '.webp', '.jpg', '.jpeg', '.png', '.raw'] +video_exts = ['.3gp' '.amv', '.avi', '.gif', '.m4v', '.mkv', '.mov', '.mp4', '.m4v', '.mpeg', '.mpv', '.webm', '.ogv'] + +config = configparser.ConfigParser() +config.read("config.ini") + +ffmpeg_params = config['FFMPEG']['FFmpegParams'] +req_audio_ext = config['FFMPEG']['AudioExt'] +req_image_ext = config['FFMPEG']['ImageExt'] +req_video_ext = config['FFMPEG']['VideoExt'] + + +def compress(folder): + files = len(os.listdir(path=folder)) + progress = 0 + for file in os.listdir(path=folder): + if os.path.splitext(file)[1] in audio_exts: + bitrate = config['FFMPEG']['AudioBitRate'] + printer.files(int((progress / files) * 100), file, os.path.splitext(file)[0], req_audio_ext, f"{bitrate}bit/s") + os.system(f"ffmpeg -i '{folder}/{file}' {ffmpeg_params} '{folder}_compressed/{os.path.splitext(file)[0]}.{req_audio_ext}'") + + elif os.path.splitext(file)[1] in image_exts: + if req_image_ext == "jpg" or os.path.splitext(file)[1] == "jpeg": + jpg_comp = config['FFMPEG']['JpegComp'] + printer.files(int((progress / files) * 100), file, os.path.splitext(file)[0], req_image_ext,f"{jpg_comp}%") + os.system(f"ffmpeg -i '{folder}/{file}' {ffmpeg_params} -q {jpg_comp} '{folder}_compressed/{os.path.splitext(file)[0]}.{req_image_ext}'") + else: + comp_level = config['FFMPEG']['CompLevel'] + printer.files(int((progress / files) * 100), file, os.path.splitext(file)[0], req_image_ext, f"{comp_level}%") + os.system(f"ffmpeg -i '{folder}/{file}' {ffmpeg_params} -compression_level {comp_level} '{folder}_compressed/{os.path.splitext(file)[0]}.{req_image_ext}'") + + elif os.path.splitext(file)[1] in video_exts: + codec = config['FFMPEG']['VideoCodec'] + printer.files(int((progress / files) * 100), file, os.path.splitext(file)[0], req_video_ext, codec) + os.system(f"ffmpeg -i '{folder}/{file}' {ffmpeg_params} -vcodec {codec} '{folder}_compressed/{os.path.splitext(file)[0]}.{req_video_ext}'") + + else: + printer.warning("File extension not recognized. This may affect the quality of the compression.") + print(f"\r[{int((progress/files) * 100)}%] \033[0;33m{file}\033[0m") + os.system(f"ffmpeg -i '{folder}/{file}' {ffmpeg_params} '{folder}_compressed/{file}'") + + progress += 1 diff --git a/FFMpeg-Compressor/modules/printer.py b/FFMpeg-Compressor/modules/printer.py new file mode 100644 index 0000000..209f813 --- /dev/null +++ b/FFMpeg-Compressor/modules/printer.py @@ -0,0 +1,21 @@ +import os + + +def info(string): + print(f"[INFO] \033[0;32m{string}\033[0m") + + +def files(progress, source, dest, dest_ext, comment): + source_ext = os.path.splitext(source)[1] + source_name= os.path.splitext(source)[0] + + if progress < 10: + progress = f" {progress}" + elif progress < 100: + progress = f" {progress}" + + print(f"[{progress}%] \033[0;32m{source_name}\033[0m{source_ext}\033[0;32m -> {dest}\033[0m.{dest_ext}\033[0;32m ({comment})\033[0m") + + +def warning(string): + print(f"\033[0;33m[WARNING] {string}\033[0m") \ No newline at end of file diff --git a/FFMpeg-Compressor/modules/utils.py b/FFMpeg-Compressor/modules/utils.py new file mode 100644 index 0000000..a7c82e7 --- /dev/null +++ b/FFMpeg-Compressor/modules/utils.py @@ -0,0 +1,21 @@ +from modules import printer +import os + + +def get_dir_size(start_path): + total_size = 0 + for dirpath, dirnames, filenames in os.walk(start_path): + for f in filenames: + fp = os.path.join(dirpath, f) + if not os.path.islink(fp): + total_size += os.path.getsize(fp) + return total_size + + +def get_compression(orig, comp): + comp = 100 - int((get_dir_size(comp) / get_dir_size(orig)) * 100) + if comp < 0: + printer.warning(f'Compression: {comp}%') + printer.warning("The resulting files are larger than the original ones!") + else: + printer.info(f'Compression: {comp}%') diff --git a/README.md b/README.md new file mode 100644 index 0000000..abbf9c7 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +## VNTools +Collection of tools used by administrators from VN Telegram Channel + +### Tools +* FFMpeg-Compressor - Python utility uses ffmpeg to compress Visual Novel Resources +* A simple Python script for unpacking Ren'Py based .apk files for later rebuilding in the Ren'Py SDK diff --git a/RenPy-Android-Unpack/README.md b/RenPy-Android-Unpack/README.md new file mode 100644 index 0000000..95beb69 --- /dev/null +++ b/RenPy-Android-Unpack/README.md @@ -0,0 +1,6 @@ +## RenPy-Android-Unpack +A simple Python script for unpacking Ren'Py based .apk files for later rebuilding in the Ren'Py SDK + +### How to use +* Put some .apk files in folder +* `python3 unpack.py` diff --git a/RenPy-Android-Unpack/unpack.py b/RenPy-Android-Unpack/unpack.py new file mode 100755 index 0000000..6d826a8 --- /dev/null +++ b/RenPy-Android-Unpack/unpack.py @@ -0,0 +1,55 @@ +#!/bin/python3 +import zipfile +import os +import shutil + + +def extract_assets(file): + with zipfile.ZipFile(file, 'r') as zip_ref: + for content in zip_ref.namelist(): + if content.split('/')[0] == 'assets': + zip_ref.extract(content) + zip_ref.extract('res/mipmap-xxxhdpi-v4/icon_background.png', 'assets') + zip_ref.extract('res/mipmap-xxxhdpi-v4/icon_foreground.png', 'assets') + os.rename('assets/res/mipmap-xxxhdpi-v4/icon_background.png', 'assets/android-icon_background.png') + os.rename('assets/res/mipmap-xxxhdpi-v4/icon_foreground.png', 'assets/android-icon_foreground.png') + + +def rename_files(directory): + for dir_ in os.walk(directory): + for file in dir_[2]: + path = f'{dir_[0]}/{file}' + folder = '/'.join(path.split('/')[:len(path.split('/')) - 1]) + newname = f'{path.split("/").pop().replace("x-", "")}' + os.rename(path, f'{folder}/{newname}') + + +def rename_dirs(directory): + dirs = [] + for dir_ in os.walk(directory): + dirs.append(dir_[0]) + dirs.reverse() + dirs.pop() + for dir__ in dirs: + folder = '/'.join(dir__.split('/')[:len(dir__.split('/')) - 1]) + newname = f'{dir__.split("/").pop().replace("x-", "")}' + os.rename(dir__, f'{folder}/{newname}') + + +if __name__ == '__main__': + for filename in os.listdir(os.getcwd()): + if os.path.splitext(filename)[1] == '.apk': + print(f'[INFO] Extracting assets from {filename}... ', end='') + extract_assets(filename) + print('Done') + print('[INFO] Renaming game assets... ', end='') + rename_files('assets') + rename_dirs('assets') + print('Done') + print('[INFO] Removing unneeded files... ', end='') + shutil.rmtree('assets/renpy') + shutil.rmtree('assets/res') + print('Done') + print('[INFO] Renaming directory... ', end='') + os.rename('assets', f'{os.path.splitext(filename)[0]}') + print('Done')