diff options
Diffstat (limited to 'backend')
| -rw-r--r-- | backend/helpers.py | 2 | ||||
| -rw-r--r-- | backend/locales/en-US.json | 32 | ||||
| -rw-r--r-- | backend/locales/it-IT.json | 30 | ||||
| -rw-r--r-- | backend/utilities.py | 111 |
4 files changed, 147 insertions, 28 deletions
diff --git a/backend/helpers.py b/backend/helpers.py index b2464e8b..a1877fb8 100644 --- a/backend/helpers.py +++ b/backend/helpers.py @@ -159,4 +159,4 @@ async def stop_systemd_unit(unit_name: str) -> bool: return await localplatform.service_stop(unit_name) async def start_systemd_unit(unit_name: str) -> bool: - return await localplatform.service_start(unit_name)
\ No newline at end of file + return await localplatform.service_start(unit_name) diff --git a/backend/locales/en-US.json b/backend/locales/en-US.json index b5c32957..34bde6bd 100644 --- a/backend/locales/en-US.json +++ b/backend/locales/en-US.json @@ -12,9 +12,37 @@ "disabling": "Disabling React DevTools", "enabling": "Enabling React DevTools" }, + "DropdownMultiselect": { + "button": { + "back": "Back" + } + }, + "FilePickerError": { + "errors": { + "file_not_found": "The path specified is not valid. Please check it and reenter it correctly.", + "unknown": "An unknown error occurred. The raw error is: {{raw_error}}" + } + }, "FilePickerIndex": { - "folder": { - "select": "Use this folder" + "files": { + "all_files": "All Files", + "file_type": "File Type", + "show_hidden": "Show Hidden Files" + }, + "filter": { + "created_asce": "Created (Oldest)", + "created_desc": "Created (Newest)", + "modified_asce": "Modified (Oldest)", + "modified_desc": "Modified (Newest)", + "name_asce": "Z-A", + "name_desc": "A-Z", + "size_asce": "Size (Smallest)", + "size_desc": "Size (Largest)" + }, + "folder": { + "label": "Folder", + "select": "Use this folder", + "show_more": "Show more files" } }, "PluginView": { diff --git a/backend/locales/it-IT.json b/backend/locales/it-IT.json index d0a526c6..bff63fba 100644 --- a/backend/locales/it-IT.json +++ b/backend/locales/it-IT.json @@ -12,9 +12,37 @@ "disabling": "Disabilito i tools di React", "enabling": "Abilito i tools di React" }, + "DropdownMultiselect": { + "button": { + "back": "Indietro" + } + }, + "FilePickerError": { + "errors": { + "file_not_found": "Il percorso specificato non è valido. Controllalo e prova a reinserirlo di nuovo.", + "unknown": "È avvenuto un'errore sconosciuto. L'errore segnalato è {{raw_error}}" + } + }, "FilePickerIndex": { + "files": { + "all_files": "Tutti i file", + "file_type": "Tipo di file", + "show_hidden": "Mostra nascosti" + }, + "filter": { + "created_asce": "Creazione (meno recente)", + "created_desc": "Creazione (più recente)", + "modified_asce": "Modifica (meno recente)", + "modified_desc": "Modifica (più recente)", + "name_asce": "Z-A", + "name_desc": "A-Z", + "size_asce": "Dimensione (più piccolo)", + "size_desc": "Dimensione (più grande)" + }, "folder": { - "select": "Usa questa cartella" + "label": "Cartella", + "select": "Usa questa cartella", + "show_more": "Mostra più file" } }, "PluginCard": { diff --git a/backend/utilities.py b/backend/utilities.py index 45a32d3e..1057ac9d 100644 --- a/backend/utilities.py +++ b/backend/utilities.py @@ -1,16 +1,21 @@ import uuid import os from json.decoder import JSONDecodeError +from os.path import splitext +import re from traceback import format_exc +from stat import FILE_ATTRIBUTE_HIDDEN from asyncio import sleep, start_server, gather, open_connection from aiohttp import ClientSession, web from logging import getLogger from injector import inject_to_tab, get_gamepadui_tab, close_old_tabs, get_tab +from pathlib import Path +from localplatform import ON_WINDOWS import helpers import subprocess -from localplatform import service_stop, service_start +from localplatform import service_stop, service_start, get_home_path, get_username class Utilities: def __init__(self, context) -> None: @@ -33,7 +38,8 @@ class Utilities: "filepicker_ls": self.filepicker_ls, "disable_rdt": self.disable_rdt, "enable_rdt": self.enable_rdt, - "get_tab_id": self.get_tab_id + "get_tab_id": self.get_tab_id, + "get_user_info": self.get_user_info, } self.logger = getLogger("Utilities") @@ -189,31 +195,82 @@ class Utilities: await service_stop(helpers.REMOTE_DEBUGGER_UNIT) return True - async def filepicker_ls(self, path, include_files=True): - # def sorter(file): # Modification time - # if os.path.isdir(os.path.join(path, file)) or os.path.isfile(os.path.join(path, file)): - # return os.path.getmtime(os.path.join(path, file)) - # return 0 - # file_names = sorted(os.listdir(path), key=sorter, reverse=True) # TODO provide more sort options - file_names = sorted(os.listdir(path)) # Alphabetical - - files = [] - - for file in file_names: - full_path = os.path.join(path, file) - is_dir = os.path.isdir(full_path) - - if is_dir or include_files: - files.append({ - "isdir": is_dir, - "name": file, - "realpath": os.path.realpath(full_path) - }) + async def filepicker_ls(self, + path : str | None = None, + include_files: bool = True, + include_folders: bool = True, + include_ext: list[str] = [], + include_hidden: bool = False, + order_by: str = "name_asc", + filter_for: str | None = None, + page: int = 1, + max: int = 1000): + + if path == None: + path = get_home_path() + + path = Path(path).resolve() + + files, folders = [], [] + + #Resolving all files/folders in the requested directory + for file in path.iterdir(): + if file.exists(): + filest = file.stat() + is_hidden = file.name.startswith('.') + if ON_WINDOWS and not is_hidden: + is_hidden = bool(filest.st_file_attributes & FILE_ATTRIBUTE_HIDDEN) + if include_folders and file.is_dir(): + if (is_hidden and include_hidden) or not is_hidden: + folders.append({"file": file, "filest": filest, "is_dir": True}) + elif include_files: + # Handle requested extensions if present + if 'all_files' in include_ext or splitext(file.name)[1].lstrip('.') in include_ext: + if (is_hidden and include_hidden) or not is_hidden: + files.append({"file": file, "filest": filest, "is_dir": False}) + # Filter logic + if filter_for is not None: + try: + if re.compile(filter_for): + files = filter(lambda file: re.search(filter_for, file.name) != None, files) + except re.error: + files = filter(lambda file: file.name.find(filter_for) != -1, files) + + # Ordering logic + ord_arg = order_by.split("_") + ord = ord_arg[0] + rev = True if ord_arg[1] == "asc" else False + match ord: + case 'name': + files.sort(key=lambda x: x['file'].name.casefold(), reverse = rev) + folders.sort(key=lambda x: x['file'].name.casefold(), reverse = rev) + case 'modified': + files.sort(key=lambda x: x['filest'].st_mtime, reverse = not rev) + folders.sort(key=lambda x: x['filest'].st_mtime, reverse = not rev) + case 'created': + files.sort(key=lambda x: x['filest'].st_ctime, reverse = not rev) + folders.sort(key=lambda x: x['filest'].st_ctime, reverse = not rev) + case 'size': + files.sort(key=lambda x: x['filest'].st_size, reverse = not rev) + # Folders has no file size, order by name instead + folders.sort(key=lambda x: x['file'].name.casefold()) + + #Constructing the final file list, folders first + all = [{ + "isdir": x['is_dir'], + "name": str(x['file'].name), + "realpath": str(x['file']), + "size": x['filest'].st_size, + "modified": x['filest'].st_mtime, + "created": x['filest'].st_ctime, + } for x in folders + files ] return { - "realpath": os.path.realpath(path), - "files": files + "realpath": str(path), + "files": all[(page-1)*max:(page)*max], + "total": len(all), } + # Based on https://stackoverflow.com/a/46422554/13174603 def start_rdt_proxy(self, ip, port): @@ -289,5 +346,11 @@ class Utilities: await tab.evaluate_js("location.reload();", False, True, False) self.logger.info("React DevTools disabled") + async def get_user_info(self) -> dict: + return { + "username": get_username(), + "path": get_home_path() + } + async def get_tab_id(self, name): return (await get_tab(name)).id |
