Skip to content

Instantly share code, notes, and snippets.

@mkpoli
Last active February 16, 2020 13:37
Show Gist options
  • Select an option

  • Save mkpoli/79a95c399c47049e19ad6dc1d780e49b to your computer and use it in GitHub Desktop.

Select an option

Save mkpoli/79a95c399c47049e19ad6dc1d780e49b to your computer and use it in GitHub Desktop.
Minecraft Mod Jar Filename Renamer
from collections import defaultdict
# accept(1) -> A[c]cept
def format_option(option):
x = option.text.capitalize()
return "{}[{}]{}".format(x[0:option.key_pos], x[option.key_pos], x[option.key_pos + 1:])
class Option:
def __init__(self, text: str, key_pos: int=0):
self.text = text
self.key_pos = key_pos
def key_letter(self):
return self.text[self.key_pos]
def to_next(self):
self.key_pos += 1
def formatted(self):
return format_option(self)
def available_inputs(self):
return [self.key_letter().upper(), self.key_letter().lower(), self.text.upper(), self.text.lower()]
def __len__(self):
return len(self.text)
def ask(question, *options):
return_bool = False
if len(options) == 0:
options = ["Yes", "No"]
return_bool = True
if len(options) < 2:
raise IndexError
if not all(isinstance(x, str) for x in options):
raise TypeError
if len(options) != len(set(options)):
raise ValueError("duplicated options")
# Find key
option_objs = [Option(option) for option in options]
checked_keys = []
for option in option_objs:
while True:
key_letter = option.key_letter()
if key_letter.upper() not in checked_keys:
checked_keys.append(key_letter.upper())
break
elif option.key_pos + 1 >= len(option):
raise IndexError("Cannot find enough characters to fallback")
else:
option.to_next()
while True:
formatted_options = [ x.formatted() for x in option_objs ]
answer = input("{} ({} or {}) ".format(question, ", ".join(formatted_options[:-1]), formatted_options[-1]))
for option in option_objs:
if answer in option.available_inputs():
if return_bool:
return option.text == "Yes"
else:
return option.text
# Python 3.7.4+
# Format all mod jars to [<mcver>]<mod_name>-<mod_version+>.jar
import os
import sys
from pathlib import Path
import regex
from ask import ask
from os import pipe
SUBPATTERN_NAME = r"(?<name>.*)"
SUBPATTERN_NAME_N = r"(?<name>.*?)"
SUBPATTERN_MCV = r"(?:for-)?(?:mc)?(?<mcv>1.\d\d+(\.[x\d]+)?)"
SUBPATTERN_V = r"(?:v)?(?<v>.*?)(?:-universal|-dist)?"
PATTERN_FINAL = regex.compile(r"\[" + SUBPATTERN_MCV + r"\]" + SUBPATTERN_NAME_N + r"-" + SUBPATTERN_V + r"\.jar", regex.IGNORECASE)
PATTERN_NAME_MCV_V = regex.compile(SUBPATTERN_NAME + "-" + SUBPATTERN_MCV + r"-" + SUBPATTERN_V + r"\.jar", regex.IGNORECASE)
PATTERN_NAME_V_MCV = regex.compile(SUBPATTERN_NAME + "-" + SUBPATTERN_V + r"-" + SUBPATTERN_MCV + r"\.jar", regex.IGNORECASE)
PATTERN_NAME_V = regex.compile(SUBPATTERN_NAME + "-" + SUBPATTERN_V + r"\.jar")
def input_default(question: str = None, default: str = None):
if default:
try:
from pyautogui import typewrite
print(question, end='')
typewrite(default)
return input()
except ModuleNotFoundError:
pass
return input(question) if question else input()
def capitalize(string):
return string[0].upper() + string[1:]
def camelcase(string):
return "".join(capitalize(x) if x else "-" for x in string.split("-"))
def minecraft_default_dir():
if sys.platform.startswith("darwin"):
return Path.home() / "Library/Application Support/minecraft"
if sys.platform.startswith("linux"):
return Path.home() / ".minecraft"
elif sys.platform.startswith("win32"):
return Path(os.environ["APPDATA"]) / ".minecraft"
def normalize(original_filename: str):
original_filename = original_filename.replace("_", "-")
gd = {}
matched = PATTERN_FINAL.match(original_filename)
if matched:
gd = matched.groupdict()
else:
matched = PATTERN_NAME_V.match(original_filename)
if matched:
gd = matched.groupdict()
matched = PATTERN_NAME_MCV_V.match(original_filename)
if matched:
gd = matched.groupdict()
else:
matched = PATTERN_NAME_V_MCV.match(original_filename)
if matched:
gd = matched.groupdict()
else:
return original_filename
gd["name"] = camelcase(capitalize(gd['name']))
if "mcv" in gd:
return f"[{ gd['mcv'] }]{ capitalize(gd['name']) }-{ gd['v'] }.jar"
else:
return f"{ camelcase(capitalize(gd['name'])) }-{ gd['v'] }.jar"
def print_sep_line():
import shutil
print("-" * (shutil.get_terminal_size((80, 20))[0] - 1))
def main():
minecraft_folder = minecraft_default_dir()
if minecraft_folder.exists() and not ask(f"Minecraft in \"{ minecraft_folder }\"?"):
minecraft_folder = Path(input("Please input path to \".minecraft\": "))
if not minecraft_folder.exists():
minecraft_folder = Path(minecraft_default_dir().parent / minecraft_folder)
if minecraft_folder.exists() and minecraft_folder.name == "mods":
minecraft_folder = Path(minecraft_folder.parent)
if not minecraft_folder.exists():
print("Error: Cannot find Minecraft folder.")
return
print_sep_line()
mod_folder = minecraft_folder / "mods"
print("Minecraft Mods Directory: ", mod_folder)
print_sep_line()
all_mod_jars = sorted(mod_folder.glob("*.jar"))
max_index_width = len(str(len(all_mod_jars)))
normalized_jars = {}
change_count = 0
print("[n] will be changed, (n) will not be changed.")
print()
for index, mod_jar in enumerate(all_mod_jars):
normalized_jars[mod_jar] = mod_folder / normalize(mod_jar.name)
if normalized_jars[mod_jar] != mod_jar:
change_count += 1
header = f"[{ index + 1 }]".rjust(max_index_width + 2)
print(f"{ header } { mod_jar.name }")
else:
header = f"({ index + 1 })".rjust(max_index_width + 2)
print(f"{ header } { mod_jar.name } )")
if change_count == 0:
print()
print(f"None of { len(all_mod_jars) } jar files will be changed.")
return
print_sep_line()
print("The following WILL BE changed as:")
print()
for index, mod_jar in enumerate(all_mod_jars):
if normalized_jars[mod_jar] == mod_jar:
continue
header = f"[{ index + 1 }]".rjust(max_index_width + 2)
print(f"{ header } { mod_jar.name }\n{ ' ' * max_index_width }-> { normalized_jars[mod_jar].name }")
print()
if not ask(f"Are you sure you want to rename jar files above as such ({ change_count } of { len(all_mod_jars) } files will be changed) ?"):
answer = ask("Do you want to change or exit?", "Change", "Exit")
answer == "Change"
if answer == "change":
change_indices = input("- Which ones do you want to change? (seperate with \", \") ").split(", ")
for index_str in change_indices:
current_mod_jar_name = all_mod_jars[int(index_str)].name
changed = input_default(current_mod_jar_name)
if ask("Are you sure? "):
normalized_jars[current_mod_jar_name] = mod_folder / changed
else:
return
print_sep_line()
print("Renaming...")
succeeded_count = 0
changed_count = 0
for original, normalized in normalized_jars.items():
if original == normalized:
continue
changed_count += 1
os.rename(original, normalized)
if normalized.exists():
succeeded_count += 1
print_sep_line()
print(f"Finished ({ succeeded_count } succeeded / { changed_count } changes). ")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment