Created
January 5, 2022 14:06
-
-
Save MinekPo1/d929f0ed1a3436054c2d62c33cf987a1 to your computer and use it in GitHub Desktop.
Script converting meteor waypoints to xaeros or the other way if you want for some reason.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Callable, NewType, TypeAlias, TypedDict, overload | |
import pynbt as nbt | |
from glob import glob | |
import os.path | |
from os import mkdir, name as os_name, chdir | |
import re | |
XAEROS_HEADER = """ | |
# | |
#waypoint:name:initials:x:y:z:color:disabled:type:set:rotate_on_tp:tp_yaw:global | |
# | |
""".strip() | |
XAEROS_SETTINGS = """ | |
//waypoints config options | |
usingMultiworldDetection:false | |
ignoreServerLevelId:false | |
defaultMultiworldId:mw1,1,-3 | |
teleportationEnabled:true | |
usingDefaultTeleportCommand:true | |
sortType:NONE | |
sortReversed:false | |
//other config options | |
ignoreHeightmaps:false | |
""".strip() | |
Dimension = NewType("Dimension",int) | |
class Dimensions: | |
NONE = Dimension(0) | |
OVERWORLD = Dimension(1) | |
NETHER = Dimension(2) | |
END = Dimension(4) | |
DIM_NAMES = { | |
Dimension(0): "", | |
Dimension(1): "overworld", | |
Dimension(2): "nether", | |
Dimension(4): "end", | |
} | |
XColors = [ | |
(255, 255, 255), | |
(255, 128, 0), | |
(255, 0, 255), | |
(128, 128, 255), | |
(255, 255, 0), | |
(128, 255, 0), | |
(255, 128, 255), | |
(128, 128, 128), | |
(192, 192, 192), | |
(0, 255, 255), | |
(255, 0, 255), | |
(0, 0, 255), | |
(128, 128, 0), | |
(0, 255, 0), | |
(255, 0, 0), | |
(0, 0, 0) | |
] # I have no idea if this is accurate | |
color_tuple: TypeAlias = tuple[int,int,int,bool] | tuple[int,int,int,int] | tuple[int,int,int] # noqa: E501 | |
def color_tuple_to_XColor(c: color_tuple) -> int: | |
if len(c) != 3: | |
c = c[:3] | |
min_d = float("inf") | |
min_x = -1 | |
for x,t in enumerate(XColors): | |
d = sum((t[i]-c[i])**2 for i in range(3)) | |
if d < min_d: | |
min_d = d | |
min_x = x | |
return min_x | |
class MeteorColor(TypedDict): | |
r: nbt.TAG_Int | |
g: nbt.TAG_Int | |
b: nbt.TAG_Int | |
a: nbt.TAG_Int | |
rainbow: nbt.TAG_Byte | |
class MeteorWaypoint(TypedDict): | |
name: nbt.TAG_String | |
x: nbt.TAG_Int | |
y: nbt.TAG_Int | |
z: nbt.TAG_Int | |
color: MeteorColor | |
icon: nbt.TAG_String | |
maxVisibleDistance: nbt.TAG_Int | |
dimension: nbt.TAG_String | |
visible: nbt.TAG_Byte | |
scale: nbt.TAG_Double | |
overworld: nbt.TAG_Byte | |
nether: nbt.TAG_Byte | |
end: nbt.TAG_Byte | |
class RB: | |
ipv4 = re.compile(r"([12]*\d{1,2}\.){3}[12]*\d{1,2}") | |
ipv6 = re.compile(r"((([0-9A-Fa-f]{1,4}):){7}[0-9A-Fa-f]{1,4}|(([0-9A-Fa-f]{1,4}):){,7}:(([0-9A-Fa-f]{1,4}):){,7}[0-9A-Fa-f]{1,4})") # noqa: E501 | |
address = re.compile(r"([a-zA-Z]+\.)?[a-zA-Z]+\.[a-zA-Z]+") | |
port = re.compile(r"\d{1,5}") | |
ipv4_port = re.compile(r"([12]*\d{1,2}\.){3}[12]*\d{1,2}:\d{1,5}") | |
ipv6_port = re.compile(r"((([0-9A-Fa-f]{1,4}):){7}[0-9A-Fa-f]{1,4}|(([0-9A-Fa-f]{1,4}):){,7}:(([0-9A-Fa-f]{1,4}):){,7}[0-9A-Fa-f]{1,4}):\d{1,5}") # noqa: E501 | |
ipv4_port_= re.compile(r"([12]*\d{1,2}\.){3}[12]*\d{1,2}_\d{1,5}") | |
ipv6_port_= re.compile(r"((([0-9A-Fa-f]{1,4}):){7}[0-9A-Fa-f]{1,4}|(([0-9A-Fa-f]{1,4}):){,7}:(([0-9A-Fa-f]{1,4}):){,7}[0-9A-Fa-f]{1,4})_\d{1,5}") # noqa: E501 | |
class Waypoint(object): | |
color: color_tuple | None | |
dimension: Dimension | |
visible_dim: Dimension | |
icon: str | |
max_distance: int | |
initials: str | |
active: bool | |
set: str | |
tp_yaw: float | None | |
is_global: bool | None | |
world: str | |
is_server: bool | |
@overload | |
def __init__(self, x: int, y: int, z: int, name:str, *, | |
color: tuple[int,int,int] = ..., icon: str = ..., max_distance: int = ..., | |
initials: str = ..., active: bool = ..., set: str = ..., tp_yaw: float = ..., | |
is_global: bool = ..., world: str = ..., is_server: bool = ..., | |
visible_dim: Dimension | int = ..., scale: float = ..., | |
dimension: Dimension | int = ...,): | |
... | |
@overload | |
def __init__(self,x:int,y:int,z:int,name:str): | |
... | |
def __init__(self,x,y,z,name,**kwds): | |
self.x = x | |
self.y = y | |
self.z = z | |
self.name = name | |
self.color = kwds.get('color',None) | |
self.dimension = kwds.get('dimension',Dimensions.OVERWORLD) | |
self.visible_dim = kwds.get('visible_dim',self.dimension) | |
self.icon = kwds.get('icon','square') | |
self.max_distance = kwds.get('max_distance',1000) | |
self.initials = kwds.get('initials',name[0]) | |
self.active = kwds.get('active',True) | |
self.set = kwds.get('set',"0") | |
self.tp_yaw = kwds.get('tp_yaw',None) | |
self.is_global = kwds.get('is_global',None) | |
self.world = kwds.get('world',None) | |
self.is_server = kwds.get('is_server',False) | |
self.scale = kwds.get('scale',1) | |
def __repr__(self) -> str: | |
return f"<Waypoint {self.name} ({self.x},{self.y},{self.z})>" | |
def load_meteor(path:str) -> list[Waypoint]: | |
out: list[Waypoint] = [] | |
if not(os.path.exists(os.path.join(path,"meteor-client/waypoints"))): | |
raise Exception("Folder is not valid. " | |
"Make sure you are in the instances root folder.") | |
for i in glob(os.path.join(path,"meteor-client/waypoints/*.nbt")): | |
name = os.path.basename(i).replace(".nbt","") | |
server = False | |
if RB.ipv4_port_.fullmatch(name) or RB.ipv6_port_.fullmatch(name): | |
name = name.replace("_",":") | |
server = True | |
elif RB.ipv4.fullmatch(name) or RB.ipv6.fullmatch(name)\ | |
or RB.address.fullmatch(name): | |
server = True | |
with open(i,"rb") as f: | |
data = nbt.NBTFile(f) | |
w: MeteorWaypoint | |
for w in data['waypoints']: | |
kwargs = { | |
'name': w['name'].value, | |
'x': w['x'].value, | |
'y': w['y'].value, | |
'z': w['z'].value, | |
'color': ( | |
w['color']["r"].value, | |
w['color']["g"].value, | |
w['color']["b"].value, | |
w['color']["a"].value, | |
w['color']["rainbow"].value | |
), | |
'dimension': getattr(Dimensions,w['dimension'].value.upper()), | |
'icon': w['icon'].value, | |
'max_distance': w['maxVisibleDistance'].value, | |
'active': w['visible'].value, | |
'scale': w['scale'].value, | |
'set': "Meteor WPs" | |
} | |
dims = Dimensions.NONE | |
if w['overworld'].value: | |
dims |= Dimensions.OVERWORLD | |
if w['nether'].value: | |
dims |= Dimensions.NETHER | |
if w['end'].value: | |
dims |= Dimensions.END | |
out.append(Waypoint(world=name,is_server=server,visible_dim=dims,**kwargs)) | |
return out | |
def load_xaeros(path:str) -> list[Waypoint]: | |
out: list[Waypoint] = [] | |
if not(os.path.exists(os.path.join(path,"XaeroWaypoints"))): | |
raise Exception("Folder is not valid. " | |
"Make sure you are in the instances root folder.") | |
for i in glob(os.path.join(path,"XaeroWaypoints/*")): | |
if i == "backup": | |
continue | |
for j in glob(os.path.join(i,"*.txt")): | |
with open(j) as f: | |
data = f.read() | |
for ii in data.split("\n"): | |
if ii.startswith("#") or not(ii): | |
continue | |
ii = ii.split(":") | |
if ii[0] == "waypoint": | |
kwargs = { | |
'name': ii[1], | |
'initials': ii[2], | |
'x': int(ii[3]), | |
'y': int(ii[4]), | |
'z': int(ii[5]), | |
'color': XColors[int(ii[6])] if ii[6] != "false" else None, | |
'enabled': ii[7] == "false", | |
'set': ii[9], | |
'tp_yaw': float(ii[11]) if ii[10] != "false" else None, | |
'global': ii[12] == "true", | |
} | |
out.append(Waypoint(world=os.path.basename(i),**kwargs)) | |
return out | |
def dump_meteor(path:str,waypoints:list[Waypoint]) -> None: | |
if not(os.path.exists(os.path.join(path,"meteor-client/waypoints"))): | |
raise Exception("Folder is not valid. " | |
"Make sure you are in the instances root folder.") | |
worlds: dict[str,list[Waypoint]] = {} | |
for i in waypoints: | |
w_name = i.world | |
if RB.ipv4_port.fullmatch(w_name) or RB.ipv6_port.fullmatch(w_name): | |
w_name = w_name.replace(":","_") | |
if w_name not in worlds: | |
worlds[w_name] = [] | |
worlds[w_name].append(i) | |
for i, value in worlds.items(): | |
with open(os.path.join(path,"meteor-client/waypoints",i+".nbt"),"wb") as f: | |
root = nbt.TAG_List(nbt.TAG_Compound) | |
data = nbt.NBTFile(name="Waypoints",value=root) | |
for j in value: | |
wp: MeteorWaypoint = nbt.TAG_Compound() # type:ignore | |
wp['name'] = nbt.TAG_String(j.name) | |
wp['x'] = nbt.TAG_Int(j.x) | |
wp['y'] = nbt.TAG_Int(j.y) | |
wp['z'] = nbt.TAG_Int(j.z) | |
if j.color is None: | |
wp['color'] = nbt.TAG_Compound( # type:ignore | |
{ | |
"a": nbt.TAG_Int(255), | |
"r": nbt.TAG_Int(255), | |
"g": nbt.TAG_Int(0), | |
"b": nbt.TAG_Int(0), | |
"rainbow": nbt.TAG_Byte(0), | |
} | |
) | |
elif len(j.color) == 3: | |
wp['color'] = nbt.TAG_Compound( # type:ignore | |
{ | |
"a": nbt.TAG_Int(255), | |
"r": nbt.TAG_Int(j.color[0]), | |
"g": nbt.TAG_Int(j.color[1]), | |
"b": nbt.TAG_Int(j.color[2]), | |
"rainbow": nbt.TAG_Byte(0), | |
} | |
) | |
elif len(j.color) == 4: | |
wp['color'] = nbt.TAG_Compound( # type:ignore | |
{ | |
"a": nbt.TAG_Int(j.color[3]), | |
"r": nbt.TAG_Int(j.color[0]), | |
"g": nbt.TAG_Int(j.color[1]), | |
"b": nbt.TAG_Int(j.color[2]), | |
"rainbow": nbt.TAG_Byte(0), | |
} | |
) | |
else: | |
wp['color'] = nbt.TAG_Compound( # type:ignore | |
{ | |
"a": nbt.TAG_Int(j.color[3]), | |
"r": nbt.TAG_Int(j.color[0]), | |
"g": nbt.TAG_Int(j.color[1]), | |
"b": nbt.TAG_Int(j.color[2]), | |
"rainbow": nbt.TAG_Byte(j.color[4]), | |
} | |
) | |
wp['dimension'] = nbt.TAG_String(DIM_NAMES[j.dimension].capitalize()) | |
wp['overworld'] = nbt.TAG_Byte(j.visible_dim & Dimensions.OVERWORLD) | |
wp['nether'] = nbt.TAG_Byte(j.visible_dim & Dimensions.NETHER) | |
wp['end'] = nbt.TAG_Byte(j.visible_dim & Dimensions.END) | |
wp['icon'] = nbt.TAG_String(j.icon) | |
wp['visible'] = nbt.TAG_Byte(1 if j.active else 0) | |
wp['scale'] = nbt.TAG_Double(j.scale) | |
wp['maxVisibleDistance'] = nbt.TAG_Int(j.max_distance) | |
root.append(wp) | |
data.write(f) | |
def dump_xaeros(path:str,waypoints:list[Waypoint],only_main_dim: bool = False)\ | |
-> None: | |
if not(os.path.exists(os.path.join(path,"XaeroWaypoints"))): | |
raise Exception("Folder is not valid. " | |
"Make sure you are in the instances root folder.") | |
worlds: dict[str,list[list[Waypoint]]] = {} | |
for i in waypoints: | |
w_name = i.world | |
if RB.ipv4_port.fullmatch(w_name) or RB.ipv6_port.fullmatch(w_name): | |
w_name = w_name[:w_name.find(":")] | |
if i.is_server: | |
w_name = f"Multiplayer_{w_name}" | |
if w_name not in worlds: | |
worlds[w_name] = [ | |
[],[],[] | |
] | |
if only_main_dim: | |
match i.dimension: | |
case Dimensions.OVERWORLD: | |
worlds[w_name][0].append(i) | |
case Dimensions.NETHER: | |
worlds[w_name][1].append(i) | |
case Dimensions.END: | |
worlds[w_name][2].append(i) | |
else: | |
dims = [] | |
if i.visible_dim & Dimensions.OVERWORLD: | |
dims.append(0) | |
if i.visible_dim & Dimensions.NETHER: | |
dims.append(1) | |
if i.visible_dim & Dimensions.END: | |
dims.append(2) | |
for j in dims: | |
worlds[w_name][j].append(i) | |
for i,j in worlds.items(): | |
if not(os.path.exists(os.path.join(path,"XaeroWaypoints",i))): | |
mkdir(os.path.join(path,"XaeroWaypoints",i)) | |
with open(os.path.join(path,"XaeroWaypoints",i,"config.txt"),'w') as f: | |
f.write(f"{XAEROS_SETTINGS}\n") | |
w_path = os.path.join(path,"XaeroWaypoints",i) | |
for i2,j2 in enumerate(j): | |
sets = "sets:gui.xaero_default:" | |
main = "" | |
di = [0,-1,1][i2] | |
if os.path.exists(os.path.join(w_path,f"dim%{di}","mw$default_1.txt")): | |
with open(os.path.join(w_path,f"dim%{di}","mw$default_1.txt"),'r') as f: | |
for line in f.readlines(): | |
if line.startswith("sets:"): | |
for s in line.split(":")[1:]: | |
if s.endswith("\n"): | |
s = s[:-1] | |
if s == "gui.xaero_default": | |
continue | |
if f":{s}:" not in sets: | |
sets += f"{s}:" | |
if line.startswith("waypoints:"): | |
main += line | |
if not(os.path.exists(os.path.join(w_path,f"dim%{di}"))): | |
mkdir(os.path.join(w_path,f"dim%{di}")) | |
for wp in j2: | |
if f":{wp.set}:" not in sets: | |
sets += f"{wp.set}:" | |
color = wp.color | |
if color is None: | |
color = "false" | |
else: | |
color = color_tuple_to_XColor(color) | |
disabled = "false" if wp.active else "true" | |
do_rot = "true" if wp.tp_yaw is not None else "false" | |
rot = wp.tp_yaw if wp.tp_yaw is not None else 0 | |
gl = "true" if wp.is_global is not None else "false" | |
main += f"waypoint:{wp.name}:{wp.x}:{wp.y}:{wp.z}:{color}:{disabled}:0:"\ | |
f"{wp.set}:{do_rot}:{rot}:{gl}\n" | |
with open(os.path.join(w_path,f"dim%{di}","mw$default_1.txt"),'w') as f: | |
f.write("\n".join([sets,XAEROS_HEADER,main])) | |
LAUNCHERS = [ | |
# (name, win_path, linux path) | |
("Official Minecraft Launcher",None,None), | |
("GDLauncher","%appdata%/gdlauncher_next/instances",None), | |
("Cristall launcher","%appdata%/Crystal-Launcher/instances",None), | |
("MultiMC","%appdata%/MultiMC/instances",None), | |
] | |
SEEKED_FOLDERS: dict[str,tuple[str,Callable[[str],list[Waypoint]],Callable[[str,list[Waypoint]],None]]] = { # noqa: E501 | |
# folder: (name, loader, dumper) | |
"meteor-client": ("meteor",load_meteor,dump_meteor), | |
"XaeroWaypoints": ("xaeros",load_xaeros,dump_xaeros), | |
} | |
def interface(): # sourcery no-metrics | |
from prompt_toolkit import prompt | |
from prompt_toolkit.completion import Completer, Completion, PathCompleter | |
from prompt_toolkit.validation import ValidationError, Validator | |
from prompt_toolkit.document import Document | |
class IsContained(Validator): | |
def __init__(self,elements: list[str], strict: bool = False) -> None: | |
super().__init__() | |
self.elems = elements | |
self.strict = strict | |
def validate(self, document: Document) -> None: | |
text = document.text | |
if text in self.elems: | |
return | |
if self.strict or text == "": | |
raise ValidationError(message="Invalid choice.",cursor_position=len(text)) | |
for i in self.elems: | |
if i.startswith(text): | |
return | |
raise ValidationError(message="Invalid choice.",cursor_position=len(text)) | |
class ListCompleter(Completer): | |
def __init__(self,elements: list[str]) -> None: | |
super().__init__() | |
self.elems = elements | |
def get_completions(self,document: Document,complete_event): | |
text = document.text.lower() | |
for i in self.elems: | |
if i.lower().startswith(text): | |
yield Completion(i,start_position=-len(document.text)) | |
def check_directory(path: str) -> bool: | |
if not(os.path.exists(path) and os.path.isdir(path)): | |
return False | |
found = sum( | |
1 for i in SEEKED_FOLDERS.keys() if os.path.exists(os.path.join(path, i)) | |
) | |
return found >= 2 | |
CheckDirectoryValidator = Validator.from_callable(check_directory) | |
chdir(os.path.expanduser('~')) | |
print(os.path.abspath(".")) | |
print(os.path.expanduser("~")) | |
print(""" | |
Welcome to the interface. | |
Select your launcher:""") | |
for i,j in enumerate(LAUNCHERS): | |
print(f"\t{i+1}: {j[0]}") | |
print(f"\t{len(LAUNCHERS) + 1}: Custom path") | |
launcher = "" | |
while not( | |
launcher.isdigit() and int(launcher)-1 in range(len(LAUNCHERS) + 1)): | |
launcher = input(">: ") | |
launcher = int(launcher)-1 | |
if launcher == 0: | |
r = "" | |
while r.lower() not in ["y","n","yes","no","1","0"]: | |
r = input("use default directory? (y/n):") | |
if os_name == "nt": | |
ins_dir = os.path.join(os.path.expandvars("%appdata%"),'.minecraft') | |
else: | |
ins_dir = os.path.join(os.path.expandvars("$HOME"),'.minecraft') | |
if r.lower() in ["n","no","0"]: | |
try: | |
ins_dir = prompt("Enter the path to the instance: ", | |
completer=PathCompleter(only_directories=True,expanduser=True), | |
validator=CheckDirectoryValidator, | |
validate_while_typing=False, | |
default=ins_dir, | |
) | |
except KeyboardInterrupt: | |
return | |
else: | |
if launcher == len(LAUNCHERS): | |
try: | |
launch_dir = prompt("Enter the path to the directory containing " | |
"instances: ", | |
completer=PathCompleter(only_directories=True,expanduser=True), | |
validator=CheckDirectoryValidator, | |
validate_while_typing=False, | |
) | |
except KeyboardInterrupt: | |
return | |
else: | |
launch_dir = LAUNCHERS[launcher][1 + (os_name != "nt")] | |
launch_dir = os.path.expandvars(launch_dir) | |
if os_name == "nt": | |
launch_dir = os.path.expanduser(launch_dir) | |
if launch_dir is None or not(os.path.exists(launch_dir)): | |
print("\tCould not find instance directory.") | |
print("\tPlease select another launcher or use Custom path.") | |
return | |
found_one = [] | |
found_two = [] | |
for i in SEEKED_FOLDERS: | |
for j in glob(os.path.join(launch_dir,"*",i)): | |
j = os.path.split(j)[0] | |
j = os.path.split(j)[1] | |
if j in found_one: | |
found_one.remove(j) | |
found_two.append(j) | |
continue | |
if j not in found_two: | |
found_one.append(j) | |
if len(found_two) == 0: | |
print("\tCould not find any instances.") | |
print("\tPlease select another launcher or use Custom path.") | |
return | |
elif len(found_two) < 10: | |
print("\tFound the following instances:") | |
for i in found_two: | |
print(f"\t{i}") | |
else: | |
print(f"found {len(found_two)} valid instances") | |
try: | |
p = prompt( | |
"Instance:",completer=ListCompleter(found_two), | |
validator=IsContained(found_two), | |
validate_while_typing=False,complete_while_typing=True | |
) | |
except KeyboardInterrupt: | |
return | |
if p in found_two: | |
ins_dir = os.path.join(launch_dir,p) | |
else: | |
for i in found_two: | |
if p.startswith(i): | |
ins_dir = i | |
break | |
else: | |
print("\tCould not find instance directory.") | |
print("\tPlease select another launcher or use Custom path.") | |
return | |
available: dict[str,tuple[Callable[[str],list[Waypoint]],Callable[[str,list[Waypoint]],None]]] = {} # noqa: E501 | |
names = [] | |
for i,e in SEEKED_FOLDERS.items(): | |
if os.path.exists(os.path.join(ins_dir,i)): | |
available[e[0]] = (e[1:]) | |
names.append(e[0]) | |
try: | |
start = prompt( | |
"Convert from: ",completer=ListCompleter(names), | |
validator=IsContained(names), | |
validate_while_typing=False,complete_while_typing=True | |
) | |
names.remove(start) | |
end = prompt( | |
"Convert to: ",completer=ListCompleter(names), | |
validator=IsContained(names), | |
validate_while_typing=False,complete_while_typing=True | |
) | |
except KeyboardInterrupt: | |
return | |
available[end][1](ins_dir,available[start][0](ins_dir)) | |
print("done!") | |
# add a slash to the end to avoid being piceked up by wildcards | |
HELP_TEXT: dict[tuple[()] | tuple[str,...],str] = { | |
(): "Use the help command for usage", | |
("help",): "Commands:\n$(help,*)", | |
("help","help"): " help | Shows help for a command", | |
("help","interface"): " interface | Launches the interface. alias: i", | |
("help","convert"): " convert | Converts a minecraft instance. alias: c", | |
("help","i","/"): "$(help,interface)", | |
("help","c","/"): "$(help,convert)", | |
("convert",): "Converts a minecraft instance.\n$(convert,usage)", | |
("convert","usage"): "Usage: convert <instance path> <intake format> <output format>", # noqa: E501 | |
("c",): "$(convert,)", | |
("c","usage"): "$(convert,usage)", | |
} | |
def get_help_text(args: list[str]): | |
if "*" not in args: | |
while True: | |
if tuple(args) in HELP_TEXT: | |
break | |
if tuple(args)+("/",) in HELP_TEXT: | |
args.append("/") | |
break | |
args.pop() | |
return HELP_TEXT[tuple(args)] | |
else: | |
matches = [] | |
for i in HELP_TEXT: | |
if len(args) != len(i): | |
continue | |
for a,h in zip(args,i): | |
if a == "*": | |
continue | |
if a != h: | |
break | |
else: | |
matches.append(HELP_TEXT[i]) | |
return "\n".join(matches) | |
if __name__ == "__main__": | |
import sys | |
match sys.argv[1:]: | |
case ["i" | "interface"]: | |
interface() | |
case ['convert' | 'c',str(path),str(start),str(to)]: | |
if not(os.path.exists(path)): | |
print("Directory not found.") | |
sys.exit(1) | |
wps = None | |
dump = None | |
for k,i in SEEKED_FOLDERS.items(): | |
if i[0] == start: | |
if not(os.path.exists(os.path.join(path,i[0]))): | |
print(f"Invalid folder ({k} not found).") | |
sys.exit(1) | |
wps = i[1](path) | |
if i[0] == to: | |
if not(os.path.exists(os.path.join(path,i[0]))): | |
print(f"Invalid folder ({k} not found).") | |
sys.exit(1) | |
dump = i[2] | |
if wps is None: | |
print(f"Invalid format: {start!r}") | |
sys.exit(1) | |
if dump is None: | |
print(f"Invalid format: {to!r}") | |
sys.exit(1) | |
dump(path,wps) | |
print("done!") | |
case _: | |
text = get_help_text(sys.argv[1:]) | |
while m:=re.search(r"\$\((.+)\)",text): | |
if m[1].isnumeric(): | |
text = text.replace(m[0],sys.argv[int(m[1])+1]) | |
else: | |
text = text.replace(m[0],get_help_text(m[1].split(","))) | |
print(text) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment