Added plugin downloader capabilities

Added plugin downloader capabilities and added full console argument support.
Fixed #46 and added error handling for it
This commit is contained in:
Neocky 2022-06-12 20:03:36 +02:00
parent ac139ed048
commit 3943357569
5 changed files with 204 additions and 32 deletions

View File

@ -27,21 +27,14 @@ if __name__ == "__main__":
#parser.add_argument("-a", "--archive", action="store_true", help="archive mode")
#parser.add_argument("--exclude", help="files to exclude")
parser.add_argument("mode", help="Mode (install/update)", nargs='?', default=None)
parser.add_argument("plugin", help="Plugin Name", nargs='?', default=None)
parser.add_argument("object", help="Object/Plugin Name", nargs='?', default=None)
parser.add_argument("version", help="Version", nargs='?', default=None)
args = vars(parser.parse_args())
if args["mode"] is not None and args["plugin"] is not None:
print("arguments")
if args["mode"] is not None and args["object"] is not None:
# arguments were give and call the handle_input function to get the right function call
handle_input(args["mode"], args["object"], args["version"], arguments_from_console=True)
else:
print("no arguments")
# no arguments were given so start pluGET console
clear_console()
print_logo()
rich_print_error("test")
rich_print_error("test2")
handle_input()
config = config_value()
print(config.connection)
print(config.path_to_plugin_folder)
print(config.sftp_port)
print(config.local_seperate_download_path)

View File

@ -19,7 +19,7 @@ class config_value():
yaml = ruamel.yaml.YAML()
with open("pluGET_config.yaml", "r") as config_file:
data = yaml.load(config_file)
self.connection = data["Connection"]
self.connection = str(data["Connection"]).lower()
self.path_to_plugin_folder = Path(data["Local"]["PathToPluginFolder"])
self.local_seperate_download_path = True if data["Local"]["SeperateDownloadPath"] == True else False
self.local_path_to_seperate_download_path = Path(data["Local"]["PathToSeperateDownloadPath"])
@ -100,7 +100,7 @@ def validate_config() -> None:
config = config_value()
# rich console for nice colors
console = Console()
if (config.connection).lower() not in accepted_values[0]:
if config.connection not in accepted_values[0]:
console.print(f"Error in Config! Accepted values for key 'Connection' are {accepted_values[0]}",
style="bright_red")
exit_afterwards = True

View File

@ -1,8 +1,9 @@
""""
Handles the input through the pluGET command line
Handles the input through the pluGET command line
"""
from src.utils.utilities import rich_print_error
from src.plugin.plugin_downloader import get_specific_plugin
# check
@ -16,23 +17,24 @@ from src.utils.utilities import rich_print_error
# search ???
def handle_input() -> None:
def handle_input(input_command=None, input_selected_object=None, input_parameter=None, arguments_from_console=False) -> None:
"""
Manages the correct function calling from the given input
Manages the correct function calling from the given input
"""
while True:
try:
input_command, input_selected_object, input_parameter = get_input()
except TypeError:
# KeyboardInterrupt was triggered and None was returned so exit
return
# when arguemnts were not passed from console
if arguments_from_console is False:
try:
input_command, input_selected_object, input_parameter = get_input()
except TypeError:
# KeyboardInterrupt was triggered and None was returned so exit
return
match input_command:
case "get":
match input_selected_object.isdigit():
case True:
print("get specific package")
#getSpecificPackage(inputSelectedObject, pluginPath, inputParams)
get_specific_plugin(input_selected_object, input_parameter)
case _:
print("get search specific package")
#searchPackage(inputSelectedObject)
@ -67,16 +69,23 @@ def handle_input() -> None:
# download papermc
print("download papermc")
#papermc_downloader(inputSelectedObject, inputParams)
case "exit":
return
case _:
rich_print_error("Error: Command not found. Please try again. :(")
rich_print_error("Use: 'help command' to get all available commands")
# return to break out of while loop
if arguments_from_console:
return None
def get_input() -> None:
"""
Gets command line input and calls the handle input function
"""
input_command = None
print("'STRG + C' to exit")
while True:
try:
input_command, input_selected_object, *input_parameter = input("pluGET >> ").split()

View File

@ -0,0 +1,161 @@
"""
File and functions which handle the download of the specific plugins
"""
import re
import urllib.request
from urllib.error import HTTPError
from pathlib import Path
import rich
from src.utils.utilities import rich_print_error, convert_file_size_down, remove_temp_plugin_folder, create_temp_plugin_folder
from src.utils.utilities import api_do_request
from src.handlers.handle_config import config_value
def handle_regex_package_name(full_plugin_name) -> str:
"""
Return the plugin name after trimming clutter from name with regex operations
"""
# trims the part of the package that has for example "[1.1 Off]" in it
unwanted_plugin_name = re.search(r'(^\[+[a-zA-Z0-9\s\W*\.*\-*\+*\%*\,]*\]+)', full_plugin_name)
if bool(unwanted_plugin_name):
unwanted_plugin_name_string = unwanted_plugin_name.group()
full_plugin_name = full_plugin_name.replace(unwanted_plugin_name_string, '')
# gets the real plugin_name "word1 & word2" is not supported only gets word1
plugin_name = re.search(r'([a-zA-Z]\d*)+(\s?\-*\_*[a-zA-Z]\d*\+*\-*\'*)+', full_plugin_name)
try:
plugin_name_full_string = plugin_name.group()
found_plugin_name = plugin_name_full_string.replace(' ', '')
except AttributeError:
found_plugin_name = unwanted_plugin_name_string
return found_plugin_name
def get_version_id(plugin_id, plugin_version) -> str:
"""
Returns the version id of the plugin
"""
if plugin_version == None or plugin_version == 'latest':
url = f"https://api.spiget.org/v2/resources/{plugin_id}/versions/latest"
response = api_do_request(url)
version_id = response["id"]
return version_id
url = f"https://api.spiget.org/v2/resources/{plugin_id}/versions?size=100&sort=-name"
version_list = api_do_request(url)
for plugins in version_list:
plugin_update = plugins["name"]
version_id = plugins["id"]
if plugin_update == plugin_version:
return version_id
return version_list[0]["id"]
def getVersionName(plugin_id, plugin_version_id) -> str:
"""
Returns the name of a specific version
"""
url = f"https://api.spiget.org/v2/resources/{plugin_id}/versions/{plugin_version_id}"
response = api_do_request(url)
version_name = response["name"]
return version_name
def get_download_path() -> str:
"""
Reads the config and gets the path of the plugin folder
"""
config_values = config_value()
if config_values.connection == "local":
if config_values.local_seperate_download_path is True:
return config_values.local_path_to_seperate_download_path
else:
return config_values.path_to_plugin_folder
else:
if config_values.remote_seperate_download_path is True:
return config_values.remote_path_to_seperate_download_path
else:
return config_values.remote_plugin_folder_on_server
def download_specific_plugin_version(plugin_id, download_path, version_id="latest") -> None:
"""
Download a specific plugin
"""
#config_values = config_value()
if version_id != "latest" and version_id != None:
#url = f"https://spigotmc.org/resources/{plugin_id}/download?version={versionID}"
rich_print_error("Sorry but specific version downloads aren't supported because of cloudflare protection. :(")
rich_print_error("Reverting to latest version.")
#url = f"https://api.spiget.org/v2/resources/{plugin_id}/versions/latest/download" #throws 403 forbidden error...cloudflare :(
url = f"https://api.spiget.org/v2/resources/{plugin_id}/download"
urrlib_opener = urllib.request.build_opener()
urrlib_opener.addheaders = [('User-agent', 'pluGET/1.0')]
urllib.request.install_opener(urrlib_opener)
remote_file = urllib.request.urlopen(url)
try:
file_size = int(remote_file.info()['Content-Length'])
except TypeError:
# if api won't return file size set it to 0 to avoid throwing an error
file_size = 0
urllib.request.urlretrieve(url, download_path)
print(" ", end='')
if file_size >= 1000000 and file_size != 0:
file_size_data = convert_file_size_down(convert_file_size_down(file_size))
print("Downloaded " + (str(file_size_data)).rjust(9) + f" MB here {download_path}")
elif file_size != 0:
file_size_data = convert_file_size_down(file_size)
print("Downloaded " + (str(file_size_data)).rjust(9) + f" KB here {download_path}")
else:
print(f"Downloaded file here {download_path}")
# TODO add sftp and ftp support
#if config_values.connection == "sftp":
# sftp_session = createSFTPConnection()
# sftp_upload_file(sftp_session, download_path)
#elif config_values.connection == "ftp":
# ftp_session = createFTPConnection()
# ftp_upload_file(ftp_session, download_path)
return None
def get_specific_plugin(plugin_id, plugin_version="latest") -> None:
"""
Gets the specific plugin and calls the download function
"""
config_values = config_value()
# use a temporary folder to store plugins until they are uploaded
if config_values.connection != "local":
download_path = create_temp_plugin_folder()
else:
download_path = get_download_path()
url = f"https://api.spiget.org/v2/resources/{plugin_id}"
plugin_details = api_do_request(url)
try:
plugin_name = plugin_details["name"]
except KeyError:
# exit if plugin id coudn't be found
rich_print_error("Error: Plugin ID couldn't be found")
return None
plugin_name = handle_regex_package_name(plugin_name)
plugin_version_id = get_version_id(plugin_id, plugin_version)
plugin_version_name = getVersionName(plugin_id, plugin_version_id)
plugin_download_name = f"{plugin_name}-{plugin_version_name}.jar"
download_plugin_path = Path(f"{download_path}/{plugin_download_name}")
# set the plugin_version_id to None if a specific version wasn't given as parameter
if plugin_version == "latest" or plugin_version is None:
plugin_version_id = None
download_specific_plugin_version(plugin_id, download_plugin_path, plugin_version_id)
if config_values.connection != "local":
remove_temp_plugin_folder()
return None

View File

@ -1,5 +1,5 @@
"""
Holds all the utilitie code for pluGET and the webrequests function
Holds all the utilitie code for pluGET and the webrequests function
"""
import os
@ -12,7 +12,7 @@ from rich.console import Console
def api_do_request(url) -> list:
"""
Handles the webrequest and returns a json list
Handles the webrequest and returns a json list
"""
webrequest_header = {'user-agent': 'pluGET/1.0'}
try:
@ -26,7 +26,7 @@ def api_do_request(url) -> list:
def api_test_spiget() -> None:
"""
Test if the Spiget api sends a 200 status code back
Test if the Spiget api sends a 200 status code back
"""
try:
r = requests.get('https://api.spiget.org/v2/status')
@ -43,7 +43,7 @@ def api_test_spiget() -> None:
def rich_print_error(error_message) -> None:
"""
Prints a formatted error message from rich
Prints a formatted error message from rich
"""
console = Console()
console.print(error_message, style="bright_red")
@ -52,8 +52,8 @@ def rich_print_error(error_message) -> None:
def create_temp_plugin_folder() -> Path:
"""
Creates a temporary folder to store plugins inside
Returns full path of temporary folder
Creates a temporary folder to store plugins inside
Returns full path of temporary folder
"""
path_temp_plugin_folder = Path("./TempSFTPFolder")
if os.path.isdir(path_temp_plugin_folder):
@ -71,10 +71,19 @@ def create_temp_plugin_folder() -> Path:
def remove_temp_plugin_folder() -> None:
"""
Removes the temporary plugin folder and all content inside it
Removes the temporary plugin folder and all content inside it
"""
try:
shutil.rmtree(Path("./TempSFTPFolder"))
except OSError as e:
rich_print_error(f"Error: {e.filename} - {e.strerror}")
return
def convert_file_size_down(file_size) -> float:
"""
Convert the size of the number one down. E.g. MB -> KB through division with 1024
"""
converted_file_size = (int(file_size)) / 1024
converted_file_size = round(converted_file_size, 2)
return converted_file_size