Last active
October 11, 2023 08:22
-
-
Save Coolsonickirby/a9894df9b938e0ab8851116f9ddb3594 to your computer and use it in GitHub Desktop.
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
# ============================================================ | |
# Written by Coolsonickirby | |
# Use Python 3.9 or higher | |
# | |
# You shouldn't need to install any modules for this script | |
# However, you do need sys-ftpd(-light) set up on your switch | |
# This also won't work on emulators (for now) since irdc about that | |
# | |
# Make sure you update the following variables for your specific setup: | |
# - server | |
# - port | |
# - username | |
# - password | |
# - title_id (optional, default is 01006A800016E000 (Super Smash Bros. Ultimate)) | |
# | |
# Usage: python skyline-plugin-manager.py [title_id] | |
# (apparently `[]` is used to denote that an argument is optional lol) | |
# ============================================================ | |
import ftplib, sys, os | |
def get_input(prompt): | |
return input(prompt) | |
def get_friendly_name(plugin_filename): | |
name = plugin_filename[:-4] | |
name = name[3:] if name.startswith("lib") else name | |
name = name.replace("_", " ").title() | |
return name | |
def get_number(prompt, min, max): | |
try: | |
res = int(get_input(prompt)) | |
if not(res >= min and res <= max): | |
raise | |
return res | |
except KeyboardInterrupt: | |
exit() | |
except: | |
print("Invalid number!") | |
return get_number(prompt, min, max) | |
def select_from_array(prompt, arr, allow_all, allow_none=False): | |
print(prompt) | |
for i in range(len(arr)): | |
print("%s - %s" % (i, arr[i])) | |
if allow_all: | |
print("%s - All" % len(arr)) | |
if allow_none: | |
print("-1 - None") | |
selected_number = get_number("Select a number: ", -1 if allow_none else 0, len(arr) if allow_all else len(arr) - 1) | |
if selected_number == len(arr): | |
return arr | |
else: | |
return [] if selected_number == -1 else [arr[selected_number]] | |
def folder_exists(folder_path): | |
current_path = ftp.pwd() | |
try: | |
ftp.cwd(folder_path) | |
ftp.cwd(current_path) | |
return True | |
except: | |
ftp.cwd(current_path) | |
return False | |
def make_folder(folder_path): | |
folder_path = folder_path.replace("\\", "/") | |
for x in folder_path.split('/'): | |
ftp.mkd(x) | |
ftp.cwd(x) | |
def get_folder_contents(path): | |
ftp.cwd(path) | |
return ftp.nlst() | |
def get_folders(path): | |
entries = get_folder_contents(path) | |
folders = [] | |
for entry in entries: | |
try: | |
ftp.cwd(entry) | |
ftp.cwd('..') | |
folders.append(entry) | |
except: | |
pass | |
return folders | |
def get_files(path): | |
entries = get_folder_contents(path) | |
files = [] | |
for entry in entries: | |
try: | |
ftp.cwd(entry) | |
ftp.cwd('..') | |
except: | |
files.append(entry) | |
return files | |
def rename_filepath(source, dest): | |
ftp.cwd('/') | |
parent_folder = os.path.dirname(dest) | |
if folder_exists(parent_folder) == False: | |
make_folder(parent_folder) | |
ftp.rename(source, dest) | |
def get_plugins() -> [(str, bool)]: | |
os.system("cls") | |
enabled = [os.path.basename(x) for x in get_files(skyline_path + enabled_plugins_path)] if folder_exists(skyline_path + enabled_plugins_path) else [] | |
disabled = [os.path.basename(x) for x in get_files(skyline_path + disabled_plugins_path)] if folder_exists(skyline_path + disabled_plugins_path) else [] | |
both = list(set(enabled).intersection(disabled)) | |
if len(both) > 0: | |
print("Found a plugin that's both enabled and disabled! Select which one you want to keep: ") | |
for x in range(len(both)): | |
choices = ["Enabled", "Disabled"] | |
print("- %s" % both[x]) | |
res = select_from_array("Select:", choices, False)[0] | |
target = "" | |
if res == "Enabled": | |
target = disabled_plugins_path | |
disabled.remove(both[x]) | |
elif res == "Disabled": | |
target = enabled_plugins_path | |
enabled.remove(both[x]) | |
ftp.delete(skyline_path + target + both[x]) | |
enabled = [(x, True) for x in enabled] | |
disabled = [(x, False) for x in disabled] | |
return enabled + disabled | |
def toggle_plugin(plugin_name, current_state, target_state=None): | |
source_path = skyline_path + enabled_plugins_path if current_state else skyline_path + disabled_plugins_path | |
dest_path = skyline_path + disabled_plugins_path if current_state else skyline_path + enabled_plugins_path | |
if target_state != None: | |
if current_state == target_state: | |
return | |
dest_path = skyline_path + enabled_plugins_path if target_state else skyline_path + disabled_plugins_path | |
source_path = source_path + plugin_name | |
dest_path = dest_path + plugin_name | |
rename_filepath(source_path, dest_path) | |
def plugins_menu(): | |
plugins = get_plugins() | |
plugins.sort(key=lambda a: a[0].lstrip('lib')) | |
print("%-15s%-50s\t%-20s" % ("ID", "Plugin Name", "Status")) | |
possible_options = [] | |
print("---------------------------------------------------------------------------------") | |
for x in range(len(plugins)): | |
possible_options.append(str(x + 1)) | |
print("%-15d%-50s\t%-20s" % (x + 1, get_friendly_name(plugins[x][0]), "Enabled" if plugins[x][1] else "Disabled")) | |
print("---------------------------------------------------------------------------------") | |
print("Options:") | |
print("<id> - Toggle Plugin") | |
print("r - Refresh List") | |
print("0 - Enable All") | |
print("-1 - Disabled All") | |
print("q - Quit") | |
possible_options = possible_options + ['r', '0', '-1', 'q'] | |
res = get_input("Enter: ") | |
while res not in possible_options: | |
print("Invalid option!") | |
res = get_input("Enter: ") | |
if res == 'q': | |
return False | |
elif res == 'r': | |
return True | |
elif res == '0': | |
for x in plugins: | |
toggle_plugin(x[0], x[1], True) | |
return True | |
elif res == '-1': | |
for x in plugins: | |
toggle_plugin(x[0], x[1], False) | |
return True | |
else: | |
id = int(res) - 1 | |
if id < 0: | |
id = 0 | |
toggle_plugin(plugins[id][0], plugins[id][1]) | |
return True | |
title_id = sys.argv[1] if len(sys.argv) > 1 else "01006A800016E000" | |
skyline_path = "/atmosphere/contents/%s/romfs/skyline/" % title_id | |
enabled_plugins_path = "plugins/" | |
disabled_plugins_path = "disabled/" | |
server = "10.0.0.143" | |
port = 5000 | |
username = "anonymous" | |
password = "" | |
ftp = ftplib.FTP() | |
ftp.connect(server, port) | |
ftp.login(username, password) | |
ftp.cwd('/') | |
state = True | |
while state: | |
state = plugins_menu() | |
ftp.quit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment