diff --git a/.gitmodules b/.gitmodules index b0dec20e..794ebe66 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "mods/hotbar_switching"] path = mods/hotbar_switching url = https://github.com/TheEt1234/hotbar_switching -[submodule "luanti_lsp_definitions"] - path = luanti_lsp_definitions - url = https://github.com/corpserot/luanti_lsp_definitions/ [submodule "mods/unified_inventory_plus"] path = mods/unified_inventory_plus url = https://github.com/mt-mods/unified_inventory_plus diff --git a/devtools/optimize_audio.py b/devtools/optimize_audio.py new file mode 100644 index 00000000..481bd771 --- /dev/null +++ b/devtools/optimize_audio.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +"""Optimizes audio files involved between commits using FFmpeg.""" + +# Copyright (C) 2026 corpserot. MIT license. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import subprocess +import sys +import argparse +import json +from pathlib import Path + +# Thresholds for audio file candidates to optimize +MIN_BITRATE = 128000 # 128 kbps +MIN_SAMPLERATE = 44100 # 44.1 kHz + +# Audio files to keep unoptimized +KEEP = [ + 'digistuff_*.ogg' +] + +def get_audio_paths(commit_range: str): + """Get list of audio files changed in the given commit range or single commit""" + try: + audio_paths = set[Path]() + if '..' in commit_range: + result = subprocess.run( + ['git', 'diff', '--name-only', '--diff-filter=d', commit_range, '--', '*.ogg'], + capture_output=True, + text=True, + check=True + ) + audio_paths.update([Path(p) for p in result.stdout.strip().split('\n')]) + result = subprocess.run( + ['git', 'show', '--name-only', '--format=', commit_range[:commit_range.find('..')], '--', '*.ogg'], + capture_output=True, + text=True, + check=True + ) + audio_paths.update([Path(p) for p in result.stdout.strip().split('\n')]) + else: + result = subprocess.run( + ['git', 'show', '--name-only', '--format=', commit_range, '--', '*.ogg'], + capture_output=True, + text=True, + check=True + ) + audio_paths.update([Path(p) for p in result.stdout.strip().split('\n')]) + return list(audio_paths) + except subprocess.CalledProcessError as e: + print(f"Error getting audio files: {e}") + sys.exit(1) + +def get_audio_info(file_path: Path): + """Check bitrate and sample rate using ffprobe.""" + try: + result = subprocess.run( + ['ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_streams', '-show_format', str(file_path)], + capture_output=True, + text=True, + check=True) + data = json.loads(result.stdout) + + # Get stream data (usually index 0 for audio files) + stream = next((s for s in data['streams'] if s['codec_type'] == 'audio'), None) + if not stream: + return None, None + + sample_rate = int(stream.get('sample_rate', 0)) + # Bitrate can be in format or stream depending on container + bitrate = int(stream.get('bit_rate') or data['format'].get('bit_rate') or 0) + + return sample_rate, bitrate + except (subprocess.CalledProcessError, ValueError, KeyError): + return None, None + +def process_audio(file_path: Path): + """Downsample audio if it meets the optimization threshold.""" + sample_rate, bitrate = get_audio_info(file_path) + + if sample_rate is None or bitrate is None: + print(f"Skipping {file_path}: Could not probe metadata.") + return + + if sample_rate < MIN_SAMPLERATE or bitrate < MIN_BITRATE: + print(f"Skipping {file_path}: Already below optimization thresholds.") + return + + print(f"Processing {file_path} ({sample_rate}Hz, {bitrate//1000}kbps)...") + + # Temporary output to avoid file corruption during overwrite + temp_file = file_path.with_suffix('.tmp.ogg') + try: + subprocess.run([ + 'ffmpeg', '-y', '-i', str(file_path), + '-aq', '1', # audio quality 1 + # sample rate 32KHz instead of 22KHz so probably nobody can hear it + '-ar', '32000', + str(temp_file) + ], check=True, capture_output=True) + + temp_file.replace(file_path.with_suffix('.ogg')) + if file_path.suffix.lower() != '.ogg': + file_path.unlink() # Delete old non-ogg file + except subprocess.CalledProcessError as e: + print(f"FFmpeg error on {file_path}: {e.stderr.decode()}") + if temp_file.exists(): + temp_file.unlink() + +def main(): + parser = argparse.ArgumentParser(description='Optimize audio files between git commit ranges down to ~22kHz, FFmpeg quality 1') + parser.add_argument('commit_ranges', nargs='+', help='Git commit ranges (e.g., HEAD~5..HEAD or HEAD)') + args = parser.parse_args() + + audio_paths = set[Path]() + for commit_range in args.commit_ranges: + audio_paths.update(get_audio_paths(commit_range)) + + if not audio_paths: + print("No audio files found in the specified range.") + return + + for p in audio_paths: + if p.exists() and all(not p.match(keep) for keep in KEEP): + process_audio(p) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/devtools/optimize_pngs.py b/devtools/optimize_pngs.py index 608967ed..ec222496 100644 --- a/devtools/optimize_pngs.py +++ b/devtools/optimize_pngs.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Optimizes PNGs involved between commits.""" +"""Optimizes PNGs involved between commits using optipng.""" # Copyright (C) 2026 corpserot. MIT license. # @@ -29,28 +29,30 @@ def get_images_paths(commit_range: str): """Get list of PNG files changed in the given commit range or single commit""" try: + image_paths = set[Path]() if '..' in commit_range: result = subprocess.run( - ['git', 'rev-list', '--reverse', commit_range], + ['git', 'diff', '--name-only', '--diff-filter=d', commit_range, '--', '*.png'], + capture_output=True, + text=True, + check=True + ) + image_paths.update([Path(p) for p in result.stdout.strip().split('\n')]) + result = subprocess.run( + ['git', 'show', '--name-only', '--format=', commit_range[:commit_range.find('..')], '--', '*.png'], capture_output=True, text=True, check=True ) - commits = result.stdout.strip().split('\n') + image_paths.update([Path(p) for p in result.stdout.strip().split('\n')]) else: - commits = [commit_range] - - image_paths = set[Path]() - for commit in commits: - # Get files changed in each commit result = subprocess.run( - ['git', 'show', '--name-only', '--pretty=format:', commit, '--', '*.png'], + ['git', 'show', '--name-only', '--format=', commit_range, '--', '*.png'], capture_output=True, text=True, check=True ) - image_paths.update([Path(p) for p in result.stdout.strip().split('\n') if p.endswith('.png')]) - + image_paths.update([Path(p) for p in result.stdout.strip().split('\n')]) return list(image_paths) except subprocess.CalledProcessError as e: print(f"Error getting PNG files: {e}") @@ -69,15 +71,14 @@ def optimize_png(file_path): def main(): parser = argparse.ArgumentParser(description='Optimize PNG files between git commit ranges') - parser.add_argument('commit_ranges', nargs='+', help='Git commit ranges or single commits (e.g., aaaaaaaa~1..bbbbbbbb or cccccccc)') + parser.add_argument('commit_ranges', nargs='+', help='Git commit ranges or single commits (e.g., HEAD~1..HEAD or HEAD)') args = parser.parse_args() - commit_ranges = args.commit_ranges - image_paths = set[Path]() - for commit_range in commit_ranges: + for commit_range in args.commit_ranges: image_paths.update(get_images_paths(commit_range)) image_paths = list(image_paths) + if not image_paths: print("No PNG files found in the specified commit range.") return diff --git a/luanti_lsp_definitions b/luanti_lsp_definitions deleted file mode 160000 index d2c647a0..00000000 --- a/luanti_lsp_definitions +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d2c647a0c06295351dfba49846576c9967ec87a6 diff --git a/mods/sbz_resources/sounds/whirr.wav b/mods/sbz_resources/sounds/whirr.wav deleted file mode 100644 index bf784f49..00000000 Binary files a/mods/sbz_resources/sounds/whirr.wav and /dev/null differ diff --git a/mods/unified_inventory/sounds/electricity.ogg b/mods/unified_inventory/sounds/electricity.ogg index 4cd7c846..19627810 100644 Binary files a/mods/unified_inventory/sounds/electricity.ogg and b/mods/unified_inventory/sounds/electricity.ogg differ diff --git a/mods/unified_inventory/sounds/paperflip1.ogg b/mods/unified_inventory/sounds/paperflip1.ogg index eaed13f8..fccab99f 100644 Binary files a/mods/unified_inventory/sounds/paperflip1.ogg and b/mods/unified_inventory/sounds/paperflip1.ogg differ diff --git a/mods/unified_inventory/sounds/paperflip2.ogg b/mods/unified_inventory/sounds/paperflip2.ogg index 321bc487..44ec50a2 100644 Binary files a/mods/unified_inventory/sounds/paperflip2.ogg and b/mods/unified_inventory/sounds/paperflip2.ogg differ