summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/helpers.py2
-rw-r--r--backend/locales/en-US.json32
-rw-r--r--backend/locales/it-IT.json30
-rw-r--r--backend/utilities.py111
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