Finally fixed 400 by updating URLs, improved logging
This commit is contained in:
parent
8ae655a34e
commit
4baf4ea1a7
17 changed files with 174 additions and 267 deletions
74
aternos.txt
74
aternos.txt
|
@ -1,74 +0,0 @@
|
|||
aternos.org/software/v/**TYPE**/**MCVER**-latest|recommended|**SOFTVER**
|
||||
(AternosSoftware) //div[@class="version-title"]
|
||||
(software_name) /h1[@class="version-title-name"]
|
||||
(software_id) /div[@id="install-software"]/@data-software
|
||||
|
||||
GET software/install.php
|
||||
software: rLyATopqZP79WHHR
|
||||
reinstall: 0 OR 1
|
||||
|
||||
GET confirm.php
|
||||
|
||||
GET config.php
|
||||
file: /server.properties OR /world/level.dat
|
||||
option: max-players OR resource-pack OR Data:hardcore OR Data:GameRules:commandBlockOutput
|
||||
value: 20
|
||||
|
||||
GET timezone.php
|
||||
timezone: Europe/Ulyanovsk
|
||||
|
||||
GET image.php
|
||||
image: openjdk:8
|
||||
|
||||
GET mclogs.php
|
||||
(save log to mclo.gs)
|
||||
response.json().id
|
||||
https://api.mclo.gs/1/raw/**ID**
|
||||
|
||||
POST create.php
|
||||
file: /config/hello
|
||||
type: directory OR file
|
||||
|
||||
POST delete.php
|
||||
file: /config/123.txt
|
||||
|
||||
POST save.php
|
||||
file: /config/123.txt
|
||||
content: ... (x-www-form-urlencoded; charset=UTF-8)
|
||||
|
||||
GET files/download.php?file=**FILENAME_ABSOLUTE**
|
||||
(ex. file=/world will download in ZIP all directory)
|
||||
|
||||
GET worlds/download.php?world=**WORLD_NAME**
|
||||
|
||||
GET players/add.php,remove.php
|
||||
list: whitelist,ops,banned-players,banned-ips
|
||||
name: CodePicker13 *OR* 1.2.3.4(in case of IP)
|
||||
(list players) //div[@class="page-content page-players"]/div[@class="player-list"]/div[@class="list-item-container"]
|
||||
(players[...]) ./div[@class="list-item"]/div[@class="list-name"] (and class="list-avatar")
|
||||
|
||||
POST friends/create.php
|
||||
username: t3test
|
||||
(LISTUSERIDs) //div[@class="friends-share-list list-players"]/div[@class="list-item-container"]/@data-id
|
||||
|
||||
POST friends/delete.php
|
||||
id: **LISTUSERID**
|
||||
|
||||
POST friends/update.php
|
||||
id: **LISTUSERID**
|
||||
permissions: json(permissions)
|
||||
|
||||
GET driveBackup/autoBackups.php?enabled=**0or1**&amount=**AUTOBACKUPS_COUNT_LIMIT**
|
||||
(list backups) //div[@class="backups"]/div[@class="file"]
|
||||
(backups[...]) ./@id, re.search(r'backup-(\w+)', _)[1]
|
||||
(backups[...]) ./div[@class="filename"] (/span[@class="backup-time js-date-time"], then /@data-date or content)
|
||||
(backups[...]) ./div[@class="backup-user,filesize"]
|
||||
|
||||
POST driveBackup/create.php
|
||||
name: MyBackup2
|
||||
|
||||
POST driveBackup/restore.php,delete.php
|
||||
backupID: 5
|
||||
|
||||
GET /panel/img/skin.php?name=**NICKNAME**
|
||||
(get player's head in png)
|
|
@ -1,7 +1,5 @@
|
|||
from getpass import getpass
|
||||
from typing import Optional
|
||||
from python_aternos import Client
|
||||
from python_aternos.atfile import AternosFile
|
||||
|
||||
user = input('Username: ')
|
||||
pswd = getpass('Password: ')
|
||||
|
|
|
@ -11,7 +11,10 @@ atclient.login(user, pswd)
|
|||
srvs = aternos.list_servers()
|
||||
|
||||
for srv in srvs:
|
||||
print('***', srv.domain, '***')
|
||||
print()
|
||||
print('***', srv.servid, '***')
|
||||
srv.fetch()
|
||||
print(srv.domain)
|
||||
print(srv.motd)
|
||||
print('*** Status:', srv.status)
|
||||
print('*** Full address:', srv.address)
|
||||
|
@ -20,3 +23,5 @@ for srv in srvs:
|
|||
print('*** Minecraft:', srv.software, srv.version)
|
||||
print('*** IsBedrock:', srv.edition == atserver.Edition.bedrock)
|
||||
print('*** IsJava:', srv.edition == atserver.Edition.java)
|
||||
|
||||
print()
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
import asyncio
|
||||
import logging
|
||||
from getpass import getpass
|
||||
|
||||
from typing import Tuple, Dict, Any
|
||||
|
||||
from python_aternos import Client, Streams
|
||||
|
||||
|
||||
# Request credentials
|
||||
user = input('Username: ')
|
||||
pswd = getpass('Password: ')
|
||||
|
||||
# Debug logging
|
||||
logs = input('Show detailed logs? (y/n) ').strip().lower() == 'y'
|
||||
if logs:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
# Authentication
|
||||
# Instantiate Client
|
||||
atclient = Client()
|
||||
aternos = atclient.account
|
||||
|
||||
# Enable debug logging
|
||||
logs = input('Show detailed logs? (y/n) ').strip().lower() == 'y'
|
||||
if logs:
|
||||
atclient.debug = True
|
||||
|
||||
# Authenticate
|
||||
atclient.login(user, pswd)
|
||||
|
||||
server = aternos.list_servers()[0]
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
import asyncio
|
||||
import logging
|
||||
from getpass import getpass
|
||||
|
||||
from typing import Tuple, Dict, Any
|
||||
|
||||
from python_aternos import Client, Streams
|
||||
|
||||
|
||||
# Request credentials
|
||||
user = input('Username: ')
|
||||
pswd = getpass('Password: ')
|
||||
|
||||
# Debug logging
|
||||
logs = input('Show detailed logs? (y/n) ').strip().lower() == 'y'
|
||||
if logs:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
# Authentication
|
||||
# Instantiate Client
|
||||
atclient = Client()
|
||||
aternos = atclient.account
|
||||
|
||||
# Enable debug logging
|
||||
logs = input('Show detailed logs? (y/n) ').strip().lower() == 'y'
|
||||
if logs:
|
||||
atclient.debug = True
|
||||
|
||||
# Authenticate
|
||||
atclient.login(user, pswd)
|
||||
|
||||
server = aternos.list_servers()[0]
|
||||
|
|
4
pylintrc
4
pylintrc
|
@ -74,9 +74,9 @@ max-args=10
|
|||
max-attributes=10
|
||||
max-bool-expr=5
|
||||
max-branches=12
|
||||
max-locals=16
|
||||
max-locals=20
|
||||
max-parents=7
|
||||
max-public-methods=30
|
||||
max-public-methods=31
|
||||
max-returns=6
|
||||
max-statements=50
|
||||
min-public-methods=2
|
||||
|
|
|
@ -1,52 +1,11 @@
|
|||
"""
|
||||
Unofficial Aternos API module written in Python.
|
||||
It uses Aternos' private API and html parsing"""
|
||||
"""Init"""
|
||||
|
||||
from .atclient import Client
|
||||
from .atserver import AternosServer
|
||||
from .atserver import Edition
|
||||
from .atserver import Status
|
||||
from .atconnect import AternosConnect
|
||||
from .atplayers import PlayersList
|
||||
from .atplayers import Lists
|
||||
from .atconf import AternosConfig
|
||||
from .atconf import ServerOpts
|
||||
from .atconf import WorldOpts
|
||||
from .atconf import WorldRules
|
||||
from .atconf import Gamemode
|
||||
from .atconf import Difficulty
|
||||
from .atwss import AternosWss
|
||||
from .atwss import Streams
|
||||
from .atfm import FileManager
|
||||
from .atfile import AternosFile
|
||||
from .atfile import FileType
|
||||
from .aterrors import AternosError
|
||||
from .aterrors import CloudflareError
|
||||
from .aterrors import CredentialsError
|
||||
from .aterrors import TokenError
|
||||
from .aterrors import ServerError
|
||||
from .aterrors import ServerStartError
|
||||
from .aterrors import FileError
|
||||
from .aterrors import AternosPermissionError
|
||||
from .atjsparse import Js2PyInterpreter
|
||||
from .atjsparse import NodeInterpreter
|
||||
|
||||
__all__ = [
|
||||
|
||||
'atclient', 'atserver', 'atconnect',
|
||||
'atplayers', 'atconf', 'atwss',
|
||||
'atfm', 'atfile',
|
||||
'aterrors', 'atjsparse',
|
||||
|
||||
'Client', 'AternosServer', 'AternosConnect',
|
||||
'PlayersList', 'AternosConfig', 'AternosWss',
|
||||
'FileManager', 'AternosFile', 'AternosError',
|
||||
'CloudflareError', 'CredentialsError', 'TokenError',
|
||||
'ServerError', 'ServerStartError', 'FileError',
|
||||
'AternosPermissionError',
|
||||
'Js2PyInterpreter', 'NodeInterpreter',
|
||||
|
||||
'Edition', 'Status', 'Lists',
|
||||
'ServerOpts', 'WorldOpts', 'WorldRules',
|
||||
'Gamemode', 'Difficulty', 'Streams', 'FileType',
|
||||
]
|
||||
|
|
|
@ -21,6 +21,7 @@ if TYPE_CHECKING:
|
|||
from .atclient import Client
|
||||
|
||||
|
||||
ACCOUNT_URL = f'{AJAX_URL}/account'
|
||||
email_re = re.compile(
|
||||
r'^[A-Za-z0-9\-_+.]+@[A-Za-z0-9\-_+.]+\.[A-Za-z0-9\-]+$|^$'
|
||||
)
|
||||
|
@ -116,7 +117,7 @@ class AternosAccount:
|
|||
"""
|
||||
|
||||
self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/username.php',
|
||||
f'{ACCOUNT_URL}/username',
|
||||
'POST', data={'username': value},
|
||||
sendtoken=True,
|
||||
)
|
||||
|
@ -136,7 +137,7 @@ class AternosAccount:
|
|||
raise ValueError('Invalid e-mail')
|
||||
|
||||
self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/email.php',
|
||||
f'{ACCOUNT_URL}/email',
|
||||
'POST', data={'email': value},
|
||||
sendtoken=True,
|
||||
)
|
||||
|
@ -165,7 +166,7 @@ class AternosAccount:
|
|||
"""
|
||||
|
||||
self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/password.php',
|
||||
f'{ACCOUNT_URL}/password',
|
||||
'POST', data={
|
||||
'oldpassword': old,
|
||||
'newpassword': new,
|
||||
|
@ -178,7 +179,7 @@ class AternosAccount:
|
|||
a QR code for enabling 2FA"""
|
||||
|
||||
return self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/secret.php',
|
||||
f'{ACCOUNT_URL}/secret',
|
||||
'GET', sendtoken=True,
|
||||
).json()
|
||||
|
||||
|
@ -205,7 +206,7 @@ class AternosAccount:
|
|||
"""
|
||||
|
||||
self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/twofactor.php',
|
||||
f'{ACCOUNT_URL}/twofactor',
|
||||
'POST', data={'code': code},
|
||||
sendtoken=True,
|
||||
)
|
||||
|
@ -218,7 +219,7 @@ class AternosAccount:
|
|||
"""
|
||||
|
||||
self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/disbaleTwofactor.php',
|
||||
f'{ACCOUNT_URL}/disbaleTwofactor',
|
||||
'POST', data={'code': code},
|
||||
sendtoken=True,
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@ import os
|
|||
import re
|
||||
from typing import Optional, Type
|
||||
|
||||
from .atlog import log
|
||||
from .atlog import log, is_debug, set_debug
|
||||
from .atmd5 import md5encode
|
||||
|
||||
from .ataccount import AternosAccount
|
||||
|
@ -28,12 +28,11 @@ class Client:
|
|||
def __init__(self) -> None:
|
||||
|
||||
# Config
|
||||
self.debug = False
|
||||
self.sessions_dir = '~'
|
||||
self.js: Type[Interpreter] = Js2PyInterpreter
|
||||
# ###
|
||||
|
||||
self.saved_session = ''
|
||||
self.saved_session = '~/.aternos' # will be rewritten by login()
|
||||
self.atconn = AternosConnect()
|
||||
self.account = AternosAccount(self)
|
||||
|
||||
|
@ -101,7 +100,7 @@ class Client:
|
|||
credentials['code'] = str(code)
|
||||
|
||||
loginreq = self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/login.php',
|
||||
f'{AJAX_URL}/account/login',
|
||||
'POST', data=credentials, sendtoken=True,
|
||||
)
|
||||
|
||||
|
@ -123,18 +122,18 @@ class Client:
|
|||
"""Log out from the Aternos account"""
|
||||
|
||||
self.atconn.request_cloudflare(
|
||||
f'{AJAX_URL}/account/logout.php',
|
||||
f'{AJAX_URL}/account/logout',
|
||||
'GET', sendtoken=True,
|
||||
)
|
||||
|
||||
self.remove_session(self.saved_session)
|
||||
|
||||
def restore_session(self, filename: str = '~/.aternos') -> None:
|
||||
def restore_session(self, file: str = '~/.aternos') -> None:
|
||||
"""Restores ATERNOS_SESSION cookie and,
|
||||
if included, servers list, from a session file
|
||||
|
||||
Args:
|
||||
filename (str, optional): Filename
|
||||
file (str, optional): Filename
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If the file cannot be found
|
||||
|
@ -142,13 +141,13 @@ class Client:
|
|||
(or the file at all) has incorrect format
|
||||
"""
|
||||
|
||||
filename = os.path.expanduser(filename)
|
||||
log.debug('Restoring session from %s', filename)
|
||||
file = os.path.expanduser(file)
|
||||
log.debug('Restoring session from %s', file)
|
||||
|
||||
if not os.path.exists(filename):
|
||||
if not os.path.exists(file):
|
||||
raise FileNotFoundError()
|
||||
|
||||
with open(filename, 'rt', encoding='utf-8') as f:
|
||||
with open(file, 'rt', encoding='utf-8') as f:
|
||||
saved = f.read() \
|
||||
.strip() \
|
||||
.replace('\r\n', '\n') \
|
||||
|
@ -164,7 +163,7 @@ class Client:
|
|||
self.account.refresh_servers(saved[1:])
|
||||
|
||||
self.atconn.session.cookies['ATERNOS_SESSION'] = session
|
||||
self.saved_session = filename
|
||||
self.saved_session = file
|
||||
|
||||
def save_session(
|
||||
self,
|
||||
|
@ -231,3 +230,11 @@ class Client:
|
|||
)
|
||||
|
||||
return f'{sessions_dir}/.at_{secure}'
|
||||
|
||||
@property
|
||||
def debug(self) -> bool:
|
||||
return is_debug()
|
||||
|
||||
@debug.setter
|
||||
def debug(self, state: bool) -> None:
|
||||
return set_debug(state)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""Stores API session and sends requests"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
|
||||
|
@ -16,7 +15,7 @@ import requests
|
|||
|
||||
from cloudscraper import CloudScraper
|
||||
|
||||
from .atlog import log
|
||||
from .atlog import log, is_debug
|
||||
|
||||
from . import atjsparse
|
||||
from .aterrors import TokenError
|
||||
|
@ -163,7 +162,8 @@ class AternosConnect:
|
|||
headers: Optional[Dict[Any, Any]] = None,
|
||||
reqcookies: Optional[Dict[Any, Any]] = None,
|
||||
sendtoken: bool = False,
|
||||
retry: int = 5) -> requests.Response:
|
||||
retries: int = 5,
|
||||
timeout: int = 4) -> requests.Response:
|
||||
"""Sends a request to Aternos API bypass Cloudflare
|
||||
|
||||
Args:
|
||||
|
@ -177,8 +177,9 @@ class AternosConnect:
|
|||
Cookies only for this request
|
||||
sendtoken (bool, optional): If the ajax and SEC token
|
||||
should be sent
|
||||
retry (int, optional): How many times parser must retry
|
||||
retries (int, optional): How many times parser must retry
|
||||
connection to API bypass Cloudflare
|
||||
timeout (int, optional): Request timeout in seconds
|
||||
|
||||
Raises:
|
||||
CloudflareError: When the parser has exceeded retries count
|
||||
|
@ -188,7 +189,7 @@ class AternosConnect:
|
|||
API response
|
||||
"""
|
||||
|
||||
if retry <= 0:
|
||||
if retries <= 0:
|
||||
raise CloudflareError('Unable to bypass Cloudflare protection')
|
||||
|
||||
try:
|
||||
|
@ -217,7 +218,7 @@ class AternosConnect:
|
|||
reqcookies['ATERNOS_SESSION'] = self.atcookie
|
||||
del self.session.cookies['ATERNOS_SESSION']
|
||||
|
||||
if log.level == logging.DEBUG:
|
||||
if is_debug():
|
||||
|
||||
reqcookies_dbg = {
|
||||
k: str(v or '')[:3]
|
||||
|
@ -240,18 +241,19 @@ class AternosConnect:
|
|||
sendreq = partial(
|
||||
self.session.post,
|
||||
params=params,
|
||||
data=data
|
||||
data=data,
|
||||
)
|
||||
else:
|
||||
sendreq = partial(
|
||||
self.session.get,
|
||||
params={**params, **data}
|
||||
params={**params, **data},
|
||||
)
|
||||
|
||||
req = sendreq(
|
||||
url,
|
||||
headers=headers,
|
||||
cookies=reqcookies
|
||||
cookies=reqcookies,
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
resp_type = req.headers.get('content-type', '')
|
||||
|
@ -265,7 +267,7 @@ class AternosConnect:
|
|||
url, method,
|
||||
params, data,
|
||||
headers, reqcookies,
|
||||
sendtoken, retry - 1
|
||||
sendtoken, retries - 1
|
||||
)
|
||||
|
||||
log.debug('AternosConnect received: %s', req.text[:65])
|
||||
|
|
|
@ -84,6 +84,7 @@ class NodeInterpreter(Interpreter):
|
|||
server_js = file_dir / 'data' / 'server.js'
|
||||
|
||||
self.url = f'http://{host}:{port}'
|
||||
self.timeout = 2
|
||||
|
||||
# pylint: disable=consider-using-with
|
||||
self.proc = subprocess.Popen(
|
||||
|
@ -100,11 +101,11 @@ class NodeInterpreter(Interpreter):
|
|||
log.debug('Received from server.js: %s', ok_msg)
|
||||
|
||||
def exec_js(self, func: str) -> None:
|
||||
resp = requests.post(self.url, data=func)
|
||||
resp = requests.post(self.url, data=func, timeout=self.timeout)
|
||||
resp.raise_for_status()
|
||||
|
||||
def get_var(self, name: str) -> Any:
|
||||
resp = requests.post(self.url, data=name)
|
||||
resp = requests.post(self.url, data=name, timeout=self.timeout)
|
||||
resp.raise_for_status()
|
||||
log.debug('NodeJS response: %s', resp.content)
|
||||
return json.loads(resp.content)
|
||||
|
|
|
@ -1,4 +1,31 @@
|
|||
"""Creates a logger"""
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
log = logging.getLogger('aternos')
|
||||
handler = logging.StreamHandler()
|
||||
fmt = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
||||
|
||||
handler.setFormatter(fmt)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
def is_debug() -> bool:
|
||||
"""Is debug logging enabled"""
|
||||
|
||||
return log.level == logging.DEBUG
|
||||
|
||||
|
||||
def set_debug(state: bool) -> None:
|
||||
"""Enable debug logging"""
|
||||
|
||||
if state:
|
||||
set_level(logging.DEBUG)
|
||||
else:
|
||||
set_level(logging.WARNING)
|
||||
|
||||
|
||||
def set_level(level: int) -> None:
|
||||
log.setLevel(level)
|
||||
handler.setLevel(level)
|
||||
|
|
|
@ -4,11 +4,8 @@ import re
|
|||
import json
|
||||
|
||||
import enum
|
||||
|
||||
from typing import Optional
|
||||
from typing import List, Dict, Any
|
||||
|
||||
import requests
|
||||
from typing import List
|
||||
from functools import partial
|
||||
|
||||
from .atconnect import BASE_URL, AJAX_URL
|
||||
from .atconnect import AternosConnect
|
||||
|
@ -24,6 +21,7 @@ from .aterrors import AternosError
|
|||
from .aterrors import ServerStartError
|
||||
|
||||
|
||||
SERVER_URL = f'{AJAX_URL}/server'
|
||||
status_re = re.compile(
|
||||
r'<script>\s*var lastStatus\s*?=\s*?(\{.+?\});?\s*<\/script>'
|
||||
)
|
||||
|
@ -58,27 +56,35 @@ class Status(enum.IntEnum):
|
|||
|
||||
|
||||
class AternosServer:
|
||||
|
||||
"""Class for controlling your Aternos Minecraft server"""
|
||||
|
||||
def __init__(
|
||||
self, servid: str,
|
||||
atconn: AternosConnect,
|
||||
reqinfo: bool = False) -> None:
|
||||
autofetch: bool = False) -> None:
|
||||
"""Class for controlling your Aternos Minecraft server
|
||||
|
||||
Args:
|
||||
servid (str): Unique server IDentifier
|
||||
atconn (AternosConnect):
|
||||
AternosConnect instance with initialized Aternos session
|
||||
reqinfo (bool, optional): Automatically call
|
||||
autofetch (bool, optional): Automatically call
|
||||
`fetch()` to get all info
|
||||
"""
|
||||
|
||||
self.servid = servid
|
||||
self.atconn = atconn
|
||||
|
||||
if reqinfo:
|
||||
self._info = {}
|
||||
|
||||
self.atserver_request = partial(
|
||||
self.atconn.request_cloudflare,
|
||||
reqcookies={
|
||||
'ATERNOS_SERVER': self.servid,
|
||||
}
|
||||
)
|
||||
|
||||
if autofetch:
|
||||
self.fetch()
|
||||
|
||||
def fetch(self) -> None:
|
||||
|
@ -113,6 +119,7 @@ class AternosServer:
|
|||
def start(
|
||||
self,
|
||||
headstart: bool = False,
|
||||
access_credits: bool = False,
|
||||
accepteula: bool = True) -> None:
|
||||
"""Starts a server
|
||||
|
||||
|
@ -120,6 +127,9 @@ class AternosServer:
|
|||
headstart (bool, optional): Start a server in
|
||||
the headstart mode which allows
|
||||
you to skip all queue
|
||||
access_credits (bool, optional):
|
||||
Some new parameter in Aternos API,
|
||||
I don't know what it is
|
||||
accepteula (bool, optional):
|
||||
Automatically accept the Mojang EULA
|
||||
|
||||
|
@ -129,9 +139,12 @@ class AternosServer:
|
|||
"""
|
||||
|
||||
startreq = self.atserver_request(
|
||||
f'{AJAX_URL}/start.php',
|
||||
'GET', params={'headstart': int(headstart)},
|
||||
sendtoken=True
|
||||
f'{SERVER_URL}/start',
|
||||
'GET', params={
|
||||
'headstart': int(headstart),
|
||||
'access-credits': int(access_credits),
|
||||
},
|
||||
sendtoken=True,
|
||||
)
|
||||
startresult = startreq.json()
|
||||
|
||||
|
@ -151,40 +164,40 @@ class AternosServer:
|
|||
"""Confirms server launching"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{AJAX_URL}/confirm.php',
|
||||
'GET', sendtoken=True
|
||||
f'{SERVER_URL}/confirm',
|
||||
'GET', sendtoken=True,
|
||||
)
|
||||
|
||||
def stop(self) -> None:
|
||||
"""Stops the server"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{AJAX_URL}/stop.php',
|
||||
'GET', sendtoken=True
|
||||
f'{SERVER_URL}/stop',
|
||||
'GET', sendtoken=True,
|
||||
)
|
||||
|
||||
def cancel(self) -> None:
|
||||
"""Cancels server launching"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{AJAX_URL}/cancel.php',
|
||||
'GET', sendtoken=True
|
||||
f'{SERVER_URL}/cancel',
|
||||
'GET', sendtoken=True,
|
||||
)
|
||||
|
||||
def restart(self) -> None:
|
||||
"""Restarts the server"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{AJAX_URL}/restart.php',
|
||||
'GET', sendtoken=True
|
||||
f'{SERVER_URL}/restart',
|
||||
'GET', sendtoken=True,
|
||||
)
|
||||
|
||||
def eula(self) -> None:
|
||||
"""Accepts the Mojang EULA"""
|
||||
"""Sends a request to accept the Mojang EULA"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{AJAX_URL}/eula.php',
|
||||
'GET', sendtoken=True
|
||||
f'{SERVER_URL}/accept-eula',
|
||||
'GET', sendtoken=True,
|
||||
)
|
||||
|
||||
def files(self) -> FileManager:
|
||||
|
@ -222,43 +235,40 @@ class AternosServer:
|
|||
|
||||
return PlayersList(lst, self)
|
||||
|
||||
def atserver_request(
|
||||
self, url: str, method: str,
|
||||
params: Optional[Dict[Any, Any]] = None,
|
||||
data: Optional[Dict[Any, Any]] = None,
|
||||
headers: Optional[Dict[Any, Any]] = None,
|
||||
sendtoken: bool = False) -> requests.Response:
|
||||
"""Sends a request to Aternos API
|
||||
with server IDenitfier parameter
|
||||
def set_subdomain(self, value: str) -> None:
|
||||
"""Set a new subdomain for your server
|
||||
(the part before `.aternos.me`)
|
||||
|
||||
Args:
|
||||
url (str): Request URL
|
||||
method (str): Request method, must be GET or POST
|
||||
params (Optional[Dict[Any, Any]], optional): URL parameters
|
||||
data (Optional[Dict[Any, Any]], optional): POST request data,
|
||||
if the method is GET, this dict
|
||||
will be combined with params
|
||||
headers (Optional[Dict[Any, Any]], optional): Custom headers
|
||||
sendtoken (bool, optional): If the ajax and SEC token should be sent
|
||||
|
||||
Returns:
|
||||
API response
|
||||
value (str): Subdomain
|
||||
"""
|
||||
|
||||
return self.atconn.request_cloudflare(
|
||||
url=url, method=method,
|
||||
params=params, data=data,
|
||||
headers=headers,
|
||||
reqcookies={
|
||||
'ATERNOS_SERVER': self.servid
|
||||
},
|
||||
sendtoken=sendtoken
|
||||
self.atserver_request(
|
||||
f'{SERVER_URL}/options/set-subdomain',
|
||||
'GET', params={'subdomain': value},
|
||||
sendtoken=True,
|
||||
)
|
||||
|
||||
def set_motd(self, value: str) -> None:
|
||||
"""Set new Message of the Day
|
||||
(shown below the name in the Minecraft servers list).
|
||||
Formatting with "paragraph sign + code" is supported,
|
||||
see https://minecraft.tools/color-code.php
|
||||
|
||||
Args:
|
||||
value (str): MOTD
|
||||
"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{SERVER_URL}/options/set-motd',
|
||||
'POST', data={'motd': value},
|
||||
sendtoken=True,
|
||||
)
|
||||
|
||||
@property
|
||||
def subdomain(self) -> str:
|
||||
"""Server subdomain
|
||||
(the part of domain before `.aternos.me`)
|
||||
"""Get the server subdomain
|
||||
(the part before `.aternos.me`)
|
||||
|
||||
Returns:
|
||||
Subdomain
|
||||
|
@ -267,25 +277,10 @@ class AternosServer:
|
|||
atdomain = self.domain
|
||||
return atdomain[:atdomain.find('.')]
|
||||
|
||||
@subdomain.setter
|
||||
def subdomain(self, value: str) -> None:
|
||||
"""Set a new subdomain for your server
|
||||
|
||||
Args:
|
||||
value (str): Subdomain
|
||||
"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{AJAX_URL}/options/subdomain.php',
|
||||
'GET', params={'subdomain': value},
|
||||
sendtoken=True
|
||||
)
|
||||
|
||||
@property
|
||||
def motd(self) -> str:
|
||||
"""Server message of the day
|
||||
which is shown below its name
|
||||
in the Minecraft servers list
|
||||
"""Get the server message of the day
|
||||
(shown below its name in Minecraft servers list)
|
||||
|
||||
Returns:
|
||||
MOTD
|
||||
|
@ -293,20 +288,6 @@ class AternosServer:
|
|||
|
||||
return self._info['motd']
|
||||
|
||||
@motd.setter
|
||||
def motd(self, value: str) -> None:
|
||||
"""Set a new message of the day
|
||||
|
||||
Args:
|
||||
value (str): New MOTD
|
||||
"""
|
||||
|
||||
self.atserver_request(
|
||||
f'{AJAX_URL}/options/motd.php',
|
||||
'POST', data={'motd': value},
|
||||
sendtoken=True
|
||||
)
|
||||
|
||||
@property
|
||||
def address(self) -> str:
|
||||
"""Full server address
|
||||
|
@ -392,11 +373,11 @@ class AternosServer:
|
|||
|
||||
@property
|
||||
def css_class(self) -> str:
|
||||
"""CSS class for
|
||||
server status block
|
||||
on official web site
|
||||
(offline, loading,
|
||||
loading starting, queueing)
|
||||
"""CSS class for the server status element
|
||||
on official web site: offline, online, loading, etc.
|
||||
See https://aternos.dc09.ru/howto/server/#server-info
|
||||
|
||||
In most cases you need `AternosServer.status` instead of this
|
||||
|
||||
Returns:
|
||||
CSS class
|
||||
|
|
13
python_aternos/data/package-lock.json
generated
13
python_aternos/data/package-lock.json
generated
|
@ -4,6 +4,7 @@
|
|||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "data",
|
||||
"dependencies": {
|
||||
"vm2": "^3.9.13"
|
||||
}
|
||||
|
@ -28,9 +29,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vm2": {
|
||||
"version": "3.9.13",
|
||||
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.13.tgz",
|
||||
"integrity": "sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==",
|
||||
"version": "3.9.19",
|
||||
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz",
|
||||
"integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==",
|
||||
"dependencies": {
|
||||
"acorn": "^8.7.0",
|
||||
"acorn-walk": "^8.2.0"
|
||||
|
@ -55,9 +56,9 @@
|
|||
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA=="
|
||||
},
|
||||
"vm2": {
|
||||
"version": "3.9.13",
|
||||
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.13.tgz",
|
||||
"integrity": "sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==",
|
||||
"version": "3.9.19",
|
||||
"resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.19.tgz",
|
||||
"integrity": "sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==",
|
||||
"requires": {
|
||||
"acorn": "^8.7.0",
|
||||
"acorn-walk": "^8.2.0"
|
||||
|
|
|
@ -18,17 +18,12 @@ with mock:
|
|||
)
|
||||
|
||||
mock.get(
|
||||
f'{BASE_URL}/server/',
|
||||
f'{BASE_URL}/server',
|
||||
content=files.read_html('aternos_server1'),
|
||||
)
|
||||
|
||||
mock.get(
|
||||
f'{AJAX_URL}/status.php',
|
||||
content=files.read_html('aternos_status'),
|
||||
)
|
||||
|
||||
mock.post(
|
||||
f'{AJAX_URL}/account/login.php',
|
||||
f'{AJAX_URL}/account/login',
|
||||
json={
|
||||
'success': True,
|
||||
'error': None,
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"brand":"aternos","status":0,"change":1667483582,"slots":20,"problems":0,"players":0,"playerlist":[],"message":{"text":"","class":"blue"},"dynip":null,"bedrock":false,"host":"","port":18713,"headstarts":null,"ram":0,"lang":"offline","label":"Offline","class":"offline","countdown":null,"queue":null,"id":"S0m3DGvTlbv8FfIM","name":"world35v","software":"Vanilla","softwareId":"NJcwtD9vj2X7udfa","type":"vanilla","version":"1.19.3","deprecated":false,"ip":"world35v.aternos.me","displayAddress":"world35v.aternos.me","motd":"\u00a77\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438\u0433\u0440\u043e\u043a\u0430 \u00a79world35v\u00a77!","onlineMode":true,"icon":"fa-stop-circle","dns":{"type":"DEFAULT","domains":["world35v.aternos.me"],"host":null,"port":null}}
|
|
@ -25,6 +25,7 @@ class TestHttp(unittest.TestCase):
|
|||
at = Client()
|
||||
at.login('test', '')
|
||||
srv = at.account.list_servers(cache=False)[0]
|
||||
srv.fetch()
|
||||
self.assertEqual(
|
||||
srv.subdomain,
|
||||
'world35v',
|
||||
|
|
Reference in a new issue