Skip to content

Instantly share code, notes, and snippets.

@Coolsonickirby
Last active October 11, 2023 08:22
Show Gist options
  • Save Coolsonickirby/a9894df9b938e0ab8851116f9ddb3594 to your computer and use it in GitHub Desktop.
Save Coolsonickirby/a9894df9b938e0ab8851116f9ddb3594 to your computer and use it in GitHub Desktop.
# ============================================================
# 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