This repository has been archived on 2024-07-30. You can view files and clone it, but cannot push or open issues or pull requests.
python-aternos/python_aternos/atfm.py

195 lines
5.1 KiB
Python
Raw Normal View History

2022-07-01 13:28:39 +03:00
"""Exploring files in your server directory"""
from typing import Union, Optional, Any, List
2021-10-15 18:31:47 +03:00
from typing import TYPE_CHECKING
import lxml.html
2023-05-24 16:41:33 +03:00
from .atconnect import BASE_URL, AJAX_URL
2022-03-18 17:38:36 +03:00
from .atfile import AternosFile, FileType
2023-05-24 16:41:33 +03:00
2021-10-15 18:31:47 +03:00
if TYPE_CHECKING:
2022-06-23 14:13:56 +03:00
from .atserver import AternosServer
2021-10-15 18:31:47 +03:00
2022-03-18 17:38:36 +03:00
class FileManager:
"""Aternos file manager class
for viewing files structure"""
2022-06-23 14:13:56 +03:00
def __init__(self, atserv: 'AternosServer') -> None:
"""Aternos file manager class
for viewing files structure
Args:
atserv (python_aternos.atserver.AternosServer):
atserver.AternosServer instance
"""
2022-06-23 14:13:56 +03:00
self.atserv = atserv
def list_dir(self, path: str = '') -> List[AternosFile]:
2022-06-23 14:13:56 +03:00
"""Requests a list of files
in the specified directory
Args:
path (str, optional):
Directory (an empty string means root)
Returns:
List of atfile.AternosFile objects
2022-06-23 14:13:56 +03:00
"""
path = path.lstrip('/')
2022-07-01 13:28:39 +03:00
2022-06-23 14:13:56 +03:00
filesreq = self.atserv.atserver_request(
2023-05-24 16:41:33 +03:00
f'{BASE_URL}/files/{path}', 'GET'
2022-06-23 14:13:56 +03:00
)
filestree = lxml.html.fromstring(filesreq.content)
2022-07-01 13:28:39 +03:00
2022-06-23 14:13:56 +03:00
fileslist = filestree.xpath(
'//div[@class="file" or @class="file clickable"]'
2022-06-23 14:13:56 +03:00
)
files = []
for f in fileslist:
ftype_raw = f.xpath('@data-type')[0]
2022-07-01 13:28:39 +03:00
fsize = self.extract_size(
f.xpath('./div[@class="filesize"]')
)
2022-06-23 14:13:56 +03:00
rm_btn = f.xpath('./div[contains(@class,"js-delete-file")]')
dl_btn = f.xpath('./div[contains(@class,"js-download-file")]')
clickable = 'clickable' in f.classes
is_config = ('server.properties' in path) or ('level.dat' in path)
2022-06-23 14:13:56 +03:00
files.append(
AternosFile(
atserv=self.atserv,
path=f.xpath('@data-path')[0],
rmable=(len(rm_btn) > 0),
dlable=(len(dl_btn) > 0),
editable=(clickable and not is_config),
ftype={'file': FileType.file}.get(
ftype_raw, FileType.dir
),
size=fsize
2022-06-23 14:13:56 +03:00
)
)
return files
2022-07-01 13:28:39 +03:00
def extract_size(self, fsize_raw: List[Any]) -> float:
"""Parses file size from the LXML tree
Args:
fsize_raw (List[Any]): XPath parsing result
Returns:
File size in bytes
2022-07-01 13:28:39 +03:00
"""
if len(fsize_raw) > 0:
fsize_text = fsize_raw[0].text.strip()
fsize_num = fsize_text[:fsize_text.rfind(' ')]
fsize_msr = fsize_text[fsize_text.rfind(' ') + 1:]
try:
return self.convert_size(
float(fsize_num),
fsize_msr
)
2022-07-01 13:28:39 +03:00
except ValueError:
return -1.0
return 0.0
def convert_size(
self,
num: Union[int, float],
measure: str) -> float:
2022-06-23 14:13:56 +03:00
"""Converts "human" file size to size in bytes
Args:
num (Union[int,float]): Size
measure (str): Units (B, kB, MB, GB)
Returns:
Size in bytes
2022-06-23 14:13:56 +03:00
"""
measure_match = {
'B': 1,
'kB': 1000,
'MB': 1000000,
'GB': 1000000000
}
2022-07-01 13:28:39 +03:00
return measure_match.get(measure, -1) * num
2022-06-23 14:13:56 +03:00
def get_file(self, path: str) -> Optional[AternosFile]:
"""Returns :class:`python_aternos.atfile.AternosFile`
instance by its path
Args:
path (str): Path to the file including its filename
Returns:
atfile.AternosFile object
if file has been found,
otherwise None
2022-06-23 14:13:56 +03:00
"""
filedir = path[:path.rfind('/')]
2022-06-23 14:13:56 +03:00
filename = path[path.rfind('/'):]
files = self.list_dir(filedir)
2022-06-23 14:13:56 +03:00
return {
'file': f
for f in files
if f.name == filename
}.get('file', None)
2022-06-23 14:13:56 +03:00
def dl_file(self, path: str) -> bytes:
"""Returns the file content in bytes (downloads it)
Args:
path (str): Path to file including its filename
Returns:
File content
2022-06-23 14:13:56 +03:00
"""
2022-07-01 13:28:39 +03:00
file = self.atserv.atserver_request( # type: ignore
2023-05-24 16:41:33 +03:00
f'{AJAX_URL}/files/download.php'
2022-06-23 14:13:56 +03:00
'GET', params={
'file': path.replace('/', '%2F')
}
)
return file.content
def dl_world(self, world: str = 'world') -> bytes:
"""Returns the world zip file content
by its name (downloads it)
Args:
world (str, optional): Name of world
Returns:
ZIP file content
2022-06-23 14:13:56 +03:00
"""
2022-07-01 13:28:39 +03:00
resp = self.atserv.atserver_request( # type: ignore
2023-05-24 16:41:33 +03:00
f'{AJAX_URL}/worlds/download.php'
2022-06-23 14:13:56 +03:00
'GET', params={
'world': world.replace('/', '%2F')
}
)
2022-07-01 13:28:39 +03:00
return resp.content