Compare commits

..

1 Commits
main ... backup

Author SHA1 Message Date
Justuser bcc61603a7 Revert "Remove except block and put replace ping"
2 years ago

@ -1,25 +1 @@
## Что это? Just ping server and get stats.
Это проект, который предоставялет: простого онлайн ТГ бота ; аналитику сервера по типу пинг сервера, количество игроков.
<img src="https://gitea.404.mn/justuser/minestatsping/raw/branch/main/preview/2024-03-09_12-20.png" alt="drawing" width="400"/>
## Как использовать?
### Использование ТГ бота
1. Получить токен в https://t.me/BotFather
2. Запустить: `python online.py`
3. Вставить токен в `config.json`, где написано "token"
4. Запустить: `python online.py`
5. Проверить команду бота: `/online`
### Использование аналитики
1. Указать данные сервера в `ping.py`
- адрес - host
- порт - port
- протокол - prot ( https://minecraft.fandom.com/wiki/Protocol_version#Java_Edition )
2. Запустить сбор статистики: `python ping.py`
3. Запустить сайт: `python site_stat.py`
4. Зайти на сайт: `127.0.0.1:8050` (браузер)

26
db.py

@ -1,26 +0,0 @@
import os
import json
if not os.path.exists('config.json'):
db = {}
js = json.dumps(db, indent=2)
with open("config.json", "w") as outfile:
outfile.write(js)
print('Created new config.json')
exit()
def read(file = 'config.json'):
if not os.path.exists(file):
with open(file, "w") as f:
f.write("{}")
f.close()
with open(file, "r", encoding="utf-8") as openfile:
db = json.load(openfile)
return db
def write(db, file = 'config.json'):
js = json.dumps(db, indent=2, ensure_ascii=False)
with open(file, "w", encoding="utf-8") as outfile:
outfile.write(js)

@ -0,0 +1,38 @@
#Json
import json
def read():
global db
with open('db.json', 'r') as openfile:
db = json.load(openfile)
def dump():
read()
tmes = ''
for i in db:
ttime = db[i]
hours = ttime//60//60 ; ttime = ttime - hours*60*60
minutes = ttime//60 ; ttime = ttime - minutes*60
seconds = ttime
tmes = tmes + f'{i[:i.find("[")]} >> {hours}:{minutes}:{seconds}'+'<br>'
return tmes
#Simple server
import tornado.httpserver, tornado.ioloop, tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write(dump())
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()

@ -1,20 +0,0 @@
from db import *
import json
import os
def stat_exist(date):
if not os.path.exists(f'data/{date}.json'):
db = {}
js = json.dumps(db, indent=2)
with open(f'data/{date}.json', "w") as outfile:
outfile.write(js)
# Заполняем БД, если она пустая
# Пинг
# "ping": {"time": ["14:30:36", "14:30:41"], "ms": [42, 39]}
db["ping"] = {"time": [], "ms": []}
# Онлайн
# "online": {"time": ["14:30:36", "14:30:41"], "count": [1, 0]}
db["online"] = {"time": [], "count":[]}
write(db, f'data/{date}.json')

@ -1,63 +0,0 @@
from mctools import PINGClient
import telebot
from db import *
API_TOKEN = read()['token']
bot = telebot.TeleBot(API_TOKEN)
host = 'CoolFunZone.aternos.me'
port = 36413
# 764 - 1.20.2
prot = 764
global c
c = PINGClient(host, port, proto_num = prot)
@bot.message_handler(commands=['online'])
def check_online(message):
global c
try:
stats = c.get_stats()
ms = c.ping()
except:
bot.reply_to(message, "🔴 Сервер оффлайн")
c.stop()
c = PINGClient(host, port, proto_num = prot)
return 0
maxp = stats['players']['max']
onp = stats['players']['online']
# Фикс для aternos
if maxp == 0:
bot.reply_to(message, "🔴 Сервер оффлайн")
return 0
try:
first = True
for i in stats['players']['sample']:
if first == True:
pp = i[0][:i[0].find('[')]
first = False
else:
pp = pp+ ' ; ' +i[0][:i[0].find('[')]
except:
pp = ''
bot.reply_to(message, f"""🟢 Игроки онлайн >> {onp}/{maxp}
{pp}
📡 {round(ms)} ms""")
while True:
try:
bot.infinity_polling()
except KeyboardInterrupt:
exit()
except:
pass

@ -1,87 +1,48 @@
from mctools import PINGClient from mctools import PINGClient
from time import sleep, time ping = PINGClient('play.dmcraft.online')
#stats = ping.get_stats()
from datetime import datetime
now = datetime.now #Work with JSON
import json
host = 'CoolFunZone.aternos.me' def read():
port = 36413 global db
# 764 - 1.20.2 with open('db.json', 'r') as openfile:
prot = 764 db = json.load(openfile)
global c def write():
c = PINGClient(host, port, proto_num = prot) global db
js = json.dumps(db, indent=4)
from db import * with open("db.json", "w") as outfile:
from func import * outfile.write(js)
date = now().strftime("%Y-%m-%d") #My libraries
# Проверяем существует ли from time import sleep
stat_exist(date)
db = read(f'data/{date}.json') #Read
read()
# КАК ЧАСТО ОБНОВЛЯЕМ (секунды)
update = 60 ttime = 0
while True: while True:
try: sleep(1)
raw = c.get_stats()
ms = round( c.ping() ) # Пинг
except:
c.stop()
c = PINGClient(host, port, proto_num = prot)
continue
if "sample" in raw["players"]: try:
# Список игроков #if True:
players_raw = raw["players"]["sample"] stats = ping.get_stats()
# Оставляем только ники (без айди) if stats['players']['online'] != 0:
players = [] for i in stats['players']['sample']:
for i in players_raw: #Add in db if not in db
players.append(i[0][:i[0].find('[')]) if i[0] not in db:
# Онлайн db[i[0]] = 1 + ttime
online = raw["players"]["online"] write()
else: else:
players = [] db[i[0]] = db[i[0]] + 1 + ttime
online = 0 write()
ttime = 0
# Фикс атерноса
max = raw["players"]["max"] except Exception as e:
if max == 0: if e == '[Errno 32] Broken pipe':
ms = 0 sleep(60)
ttime = 59
# Открываем БД. print("CATCHED")
# Дата
date = now().strftime("%Y-%m-%d")
# Проверяем существует ли
stat_exist(date)
db = read(f'data/{date}.json')
# Заполняем БД
# Пинг
db["ping"]["time"].append( now().strftime('%H:%M') )
db["ping"]["ms"].append( ms )
# Онлайн
db["online"]["time"].append( now().strftime('%H:%M') )
db["online"]["count"].append( online )
# Топ игроков по времени и последнее время захода
stat = read('data/stat.json')
# Перебираем игроков
for i in players:
# Если игрок уже в базе
if i in stat["players"]["time"]:
stat["players"]["time"][i] += update
else: else:
stat["players"]["time"][i] = update print(e)
# Время захода
stat["players"]["last"][i] = time()
# Записываем изменения
write(db, f'data/{date}.json')
write(stat, 'data/stat.json')
# Задержка
sleep(update)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

@ -1,176 +0,0 @@
from dash import Dash, html, dcc, Input, Output, callback
import plotly.graph_objs as go
from time import strftime, localtime
from db import *
from func import stat_exist
from datetime import datetime
now = datetime.now
app = Dash(__name__)
app.layout = html.Div([
html.Div([
dcc.Dropdown(["Сервер", "Игроки"], "Сервер", id = "select", clearable=False, searchable=False, style = {"flex": 70}),
dcc.Dropdown(id = "date", clearable=True, searchable=False, style = {"flex": 30}, placeholder="Дата"),
], style = {"display": "flex", "flexDirection": "row"}),
html.Div([], id = "out")
])
def server(date = None):
if not date:
date = now().strftime("%Y-%m-%d")
stat_exist(date)
db = read(f'data/{date}.json')
# Настройка для графика без рамок
layout = go.Layout( margin=go.layout.Margin(l=0, r=0, b=0, t=0,), height = 300 )
ping = db["ping"]
ping_fig = go.Figure(data=[go.Scatter(x = ping["time"], y = ping["ms"] )], layout = layout )
#ping_fig.update_xaxes(visible=False)
ping_fig.update_traces(hoverinfo='y')
#ping_fig.update_layout(yaxis=dict(dtick=1))
online = db["online"]
online_fig = go.Figure(data=[go.Scatter(x = online["time"], y = online["count"] )], layout = layout)
#online_fig.update_xaxes(visible=False)
online_fig.update_traces(hoverinfo='y')
online_fig.update_layout(yaxis=dict(dtick=1))
gr_conf = {"displayModeBar": False, "showAxisDragHandles": False, "showAxisRangeEntryBoxes": False, "fillFrame": False}
return html.Div([
html.H2("Пинг"),
dcc.Graph(
id = 'ping',
figure = ping_fig,
config = gr_conf
),
html.H2("Онлайн"),
dcc.Graph(
id = 'online',
figure = online_fig,
config = gr_conf
)
])
def players():
db = read('data/stat.json')
layout = go.Layout( margin=go.layout.Margin(l=0, r=0, b=0, t=0,), height = 300 )
time = db["players"]["time"]
# Конвертируем в вид ["hythe", "freedom"] и [1764, 6532]
time_nick = list(time.keys())
time_time = list(time.values())
# Сортируем по времени (3, 2, 1)
sorted = False
while not sorted:
sorted = True
for i in range(len(time_time) - 1):
# Если [5, 7] => [7, 5]
if time_time[i + 1] > time_time[i]:
sorted = False
# Меняем местами
time_time[i], time_time[i + 1] = time_time[i + 1], time_time[i]
time_nick[i], time_nick[i + 1] = time_nick[i + 1], time_nick[i]
# Конвертируем 12960 => 3:36
conv_time = []
for i in range(len(time_time)):
seconds = time_time[i]
hours = seconds // 3600
minutes = (seconds-hours*3600) // 60
conv_time.append(f"Время: {hours} час. {minutes} мин.")
time_fig = go.Figure(data=[go.Bar(x = time_nick, y = time_time, hovertemplate=conv_time, name="",
text=conv_time, textposition='inside', insidetextfont=dict(size=16, color='white')
)], layout = layout )
time_fig.update_yaxes(visible=False)
#time_fig.update_xaxes(visible=False)
time_fig.update_xaxes({"tickfont": {"size": 18} })
time_fig.update_traces(hoverinfo='y')
last = db["players"]["last"]
# Конвертируем в вид ["hythe"] и [1434657.567523]
last_nick = list(last.keys())
last_time = list(last.values())
# Сортируем по времени (3, 2, 1)
# Сортируем по времени
sorted = False
while not sorted:
sorted = True
for i in range(len(last_time) - 1):
# Если [5, 7] => [7, 5]
if float(last_time[i + 1]) > float(last_time[i]):
sorted = False
# Меняем местами
last_time[i], last_time[i + 1] = last_time[i + 1], last_time[i]
last_nick[i], last_nick[i + 1] = last_nick[i + 1], last_nick[i]
# Конвертируем 1709475944.625857 => '2012-09-13 02:22:50'
for i in range(len(last_time)):
last_time[i] = strftime('%Y-%m-%d %H:%M:%S', localtime( float(last_time[i]) ))
last_fig = go.Figure(data= [go.Table(header={"values": ["Игрок","Время захода"], "font": {"size": 18}, "height": 40},
cells={"values": [last_nick, last_time], "font_size": 18, "height": 30},
) ], layout = layout )
# Подгоняем высоту таблицы: 40 пикселей заголовка + кол.элементов * 30
last_fig.layout.update({'height': 40 + len(last_nick)*30 })
gr_conf = {"displayModeBar": False, "showAxisDragHandles": False, "showAxisRangeEntryBoxes": False, "fillFrame": False}
return html.Div([
html.H2("Топ по времени"),
dcc.Graph(
id = 'ping',
figure = time_fig,
config = gr_conf
),
html.H2("Последний заход"),
dcc.Graph(
id = 'ping',
figure = last_fig,
config = gr_conf
)
])
def av_stats():
raw = sorted( next(os.walk('data/'), (None, None, []))[2] )
# Убираем .json
dates = []
for i in raw:
if i != "stat.json":
dates.append(i[:i.find(".json")])
return dates
@callback(
Output('out', 'children'),
Output('date', 'options'),
Input('date', 'value'),
Input('select', 'value'),
)
def main(date, select):
if select == "Сервер":
return server(date), av_stats()
elif select == "Игроки":
return players(), av_stats()
while True:
try:
app.run(debug=False)
except KeyboardInterrupt:
exit()
except:
pass
Loading…
Cancel
Save