commit
84055d431a
8 changed files with 347 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||
|
auth_data/ |
||||
|
.env |
@ -0,0 +1,2 @@ |
|||||
|
auth_data/ |
||||
|
.env |
@ -0,0 +1,23 @@ |
|||||
|
FROM python:3.7 |
||||
|
|
||||
|
RUN groupadd -g 1000 service && useradd -g 1000 -u 1000 service |
||||
|
|
||||
|
ENV TZ=Europe/Moscow |
||||
|
|
||||
|
RUN python -m pip install aiomysql aiohttp steamio |
||||
|
|
||||
|
RUN mkdir /home/service && \ |
||||
|
cp /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ |
||||
|
dpkg-reconfigure -f noninteractive tzdata |
||||
|
|
||||
|
ENV PYTHONUNBUFFERED 1 |
||||
|
|
||||
|
WORKDIR /home/service |
||||
|
|
||||
|
COPY ./ ./ |
||||
|
|
||||
|
RUN chown service:service -R /home/service && chmod 775 -R /home/service |
||||
|
|
||||
|
USER service |
||||
|
|
||||
|
ENTRYPOINT ["python", "tradebot.facti13.py"] |
@ -0,0 +1,29 @@ |
|||||
|
from time import strftime |
||||
|
|
||||
|
class colors: |
||||
|
HEADER = u'\033[95m' |
||||
|
OKBLUE = u'\033[94m' |
||||
|
OKGREEN = u'\033[92m' |
||||
|
WARNING = u'\033[93m' |
||||
|
FAIL = u'\033[91m' |
||||
|
ENDC = u'\033[0m' |
||||
|
BOLD = u'\033[1m' |
||||
|
UNDERLINE = u'\033[4m' |
||||
|
|
||||
|
HEADER = u"[{:^7}] ({:^17}) {}" |
||||
|
|
||||
|
def ok(text): |
||||
|
HEAD = colors.OKGREEN + u"OK" + colors.ENDC |
||||
|
return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) |
||||
|
|
||||
|
def error(text): |
||||
|
HEAD = colors.FAIL + u"FAIL" + colors.ENDC |
||||
|
return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) |
||||
|
|
||||
|
def warning(text): |
||||
|
HEAD = colors.WARNING + u"WARNING" + colors.ENDC |
||||
|
return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) |
||||
|
|
||||
|
def info(text): |
||||
|
HEAD = colors.HEADER + u"INFO" + colors.ENDC |
||||
|
return print(HEADER.format(HEAD, strftime(u"%H:%M:%S %d.%m.%y"), text)) |
@ -0,0 +1,72 @@ |
|||||
|
import asyncio |
||||
|
from cmath import inf |
||||
|
import aiomysql |
||||
|
from steam import SteamID |
||||
|
from colors import * |
||||
|
|
||||
|
class Database: |
||||
|
database = None |
||||
|
permitions = {"VIP":("20:oa",2592000)} |
||||
|
|
||||
|
def __init__(self, host, user, password, db): |
||||
|
self.host = host |
||||
|
self.user = user |
||||
|
self.password = password |
||||
|
self.db = db |
||||
|
|
||||
|
async def connect(self): |
||||
|
info("Create database pool") |
||||
|
self.database = await aiomysql.create_pool( |
||||
|
host = self.host, |
||||
|
user = self.user, |
||||
|
password = self.password, |
||||
|
db=self.db |
||||
|
) |
||||
|
|
||||
|
async def disconnect(self): |
||||
|
ok("Disconnect from database") |
||||
|
await self.database.wait_closed() |
||||
|
|
||||
|
async def processing_vip(self, steamid: SteamID, amount, status = "VIP", who = "Donate.User"): |
||||
|
check_status = await self.check_update_VIP(steamid) |
||||
|
if check_status: |
||||
|
if check_status > 1: |
||||
|
info(f"Append more time to {steamid.community_url}") |
||||
|
return await self.update_user(steamid, amount) |
||||
|
else: |
||||
|
info(f"Create new vip user {steamid.community_url}") |
||||
|
return await self.add_new_user(steamid, amount, status, who) |
||||
|
else: |
||||
|
warning(f"{steamid.community_url} currently have ADMIN/MOD permitions") |
||||
|
return False |
||||
|
|
||||
|
async def check_update_VIP(self, steamid: SteamID): |
||||
|
# 0 = mod/admin | -1 = not found | 1 = need update |
||||
|
query = f"SELECT * FROM `sm_admins` WHERE `identity` LIKE '{steamid.id2_zero}' ORDER BY `reg_date` DESC" |
||||
|
async with self.database.acquire() as connection: |
||||
|
async with connection.cursor(aiomysql.DictCursor) as cursor: |
||||
|
await cursor.execute(query) |
||||
|
for row in await cursor.fetchall(): |
||||
|
if row["status"] == "VIP" and row["amount"] > 0: |
||||
|
return 1 |
||||
|
else: |
||||
|
return 0 |
||||
|
return -1 |
||||
|
|
||||
|
async def update_user(self, steamid: SteamID, amount): |
||||
|
query = f"UPDATE `sm_admins` SET `amount`=`amount`+{amount}, `reg_date`=`reg_date` WHERE `identity` LIKE '{steamid.id2_zero}'" |
||||
|
async with self.database.acquire() as connection: |
||||
|
async with connection.cursor(aiomysql.DictCursor) as cursor: |
||||
|
await cursor.execute(query) |
||||
|
await cursor.commit() |
||||
|
return 101 |
||||
|
|
||||
|
async def add_new_user(self, steamid: SteamID, amount, status, who): |
||||
|
settings = self.permitions.get(status) |
||||
|
level, flags = settings[0].split(":") |
||||
|
query = f"INSERT INTO `sm_admins` (`id`, `authtype`, `identity`, `password`, `flags`, `name`, `immunity`, `comment`, `status`, `reg_date`, `amount`) VALUES (NULL, 'steam', '{steamid.id2_zero}', NULL, '{flags}', '', '{level}', '{who}', '{status}', CURRENT_TIMESTAMP,'{amount}')" |
||||
|
async with self.database.acquire() as connection: |
||||
|
async with connection.cursor(aiomysql.DictCursor) as cursor: |
||||
|
await cursor.execute(query) |
||||
|
await cursor.commit() |
||||
|
return 100 |
@ -0,0 +1,43 @@ |
|||||
|
import aiohttp |
||||
|
from random import choice |
||||
|
from steam import SteamID |
||||
|
|
||||
|
class DiscordAlarm: |
||||
|
def __init__(self, webhook_url): |
||||
|
self.url = webhook_url |
||||
|
|
||||
|
async def alert(self, steamid: SteamID, amount): |
||||
|
try: |
||||
|
await self.send(self.prepare_payload(steamid, amount)) |
||||
|
except: |
||||
|
pass |
||||
|
|
||||
|
def prepare_payload(self, steamid: SteamID, amount): |
||||
|
phrare = [ |
||||
|
"Поздравим очередного игрока с покупкой випа!", |
||||
|
"Очередной игрок приобрел вип.", |
||||
|
"Ура кто-то украл деньги у мамки и принес их нам!!!", |
||||
|
"Делать деньги, делать деньги блять вот так..." |
||||
|
] |
||||
|
payload = {"embeds":[{"fields":[]}]} |
||||
|
payload.update({"content":choice(phrare)}) |
||||
|
payload["embeds"][0]["fields"].append({ |
||||
|
"name": "Ссылка на игрока:", |
||||
|
"value": steamid.community_url, |
||||
|
"inline": True |
||||
|
}) |
||||
|
payload["embeds"][0]["fields"].append({ |
||||
|
"name": "Количество дней:", |
||||
|
"value": "{}".format(round(amount / 60 / 60 / 24)), |
||||
|
"inline": True |
||||
|
}) |
||||
|
payload["embeds"][0]["fields"].append({ |
||||
|
"name": "Оплата:", |
||||
|
"value": "{}".format("Steam"), |
||||
|
"inline": True |
||||
|
}) |
||||
|
return payload |
||||
|
|
||||
|
async def send(self, payload): |
||||
|
async with aiohttp.ClientSession() as session: |
||||
|
await session.post(self.url, json = payload) |
Binary file not shown.
@ -0,0 +1,176 @@ |
|||||
|
from cmath import inf |
||||
|
from pydoc import cli |
||||
|
import steam as SteamPy |
||||
|
import argparse, os, sys |
||||
|
from colors import * |
||||
|
from db_driver import Database |
||||
|
from json import load |
||||
|
from discord_alarm import DiscordAlarm |
||||
|
|
||||
|
class TradeChecker: |
||||
|
APP_ID = 440 |
||||
|
MONTH = 2678400 |
||||
|
WEEK = 604800 |
||||
|
DAY = 86400 |
||||
|
|
||||
|
def mannco_key(self, items): |
||||
|
class_id = 101785959 |
||||
|
instance_id = 11040578 |
||||
|
count = 0 |
||||
|
for item in items: |
||||
|
#print(f"{item._app_id} {item.class_id} {item.instance_id}") |
||||
|
if int(item._app_id) == self.APP_ID and int(item.class_id) == class_id and int(item.instance_id) == instance_id: |
||||
|
count += 1 |
||||
|
return count |
||||
|
|
||||
|
def pure_metal(self, items): |
||||
|
class_id = 2674 |
||||
|
instance_id = 11040547 |
||||
|
count = 0 |
||||
|
for item in items: |
||||
|
#print(f"{item._app_id} {item.class_id} {item.instance_id}") |
||||
|
if int(item._app_id) == self.APP_ID and int(item.class_id) == class_id and int(item.instance_id) == instance_id: |
||||
|
count += 1 |
||||
|
return count |
||||
|
|
||||
|
def Items2Seconds(self, items): |
||||
|
key_count = self.mannco_key(items) |
||||
|
metal_count = self.pure_metal(items) |
||||
|
final_amount = 0 |
||||
|
#print(key_count, ",", metal_count) |
||||
|
final_amount += key_count * self.MONTH |
||||
|
if(metal_count >= 20): |
||||
|
final_amount += (metal_count / 20) * self.WEEK |
||||
|
elif(metal_count >= 5): |
||||
|
final_amount += (metal_count / 5) * self.DAY |
||||
|
|
||||
|
return final_amount |
||||
|
|
||||
|
|
||||
|
async def send_msg(trade: SteamPy.TradeOffer, message: str): |
||||
|
try: |
||||
|
await trade.partner.send(message) |
||||
|
except: |
||||
|
error(f"[{trade.id}] Cannot send message") |
||||
|
|
||||
|
class SteamClient(SteamPy.Client): |
||||
|
db = None |
||||
|
items = TradeChecker() |
||||
|
discord_alarm = None |
||||
|
|
||||
|
async def on_ready(self): |
||||
|
info(f"Logged in as: {self.user}") |
||||
|
|
||||
|
async def on_connect(self): |
||||
|
ok("Success connect to steam") |
||||
|
await self.db.connect() |
||||
|
|
||||
|
async def on_disconnect(self): |
||||
|
ok("Disconnect from steam") |
||||
|
await self.db.disconnect() |
||||
|
|
||||
|
#Проверка шмота на леквид |
||||
|
async def on_trade_receive(self, trade: SteamPy.TradeOffer): |
||||
|
info(f"[{trade.id}] Incoming trade from [{trade.partner.id}] {trade.partner.name}") |
||||
|
|
||||
|
if trade.state != SteamPy.enums.TradeOfferState.Active: |
||||
|
error(f"[{trade.id}] trade have not active stats") |
||||
|
await send_msg(trade, "Бот не сможет принять трейд от тебя по причине удержания вещей с твоей стороны") |
||||
|
await trade.decline() |
||||
|
return |
||||
|
|
||||
|
if not trade.is_gift(): |
||||
|
warning(f"[{trade.id}] partner wanna get bot items, decine trade") |
||||
|
await send_msg(trade, "Не пытайся спиздить вещи у бота") |
||||
|
await trade.decline() |
||||
|
return |
||||
|
|
||||
|
if len(trade.items_to_receive) > 25: |
||||
|
warning(f"[{trade.id}] cannot accept trade with more 25 items") |
||||
|
await send_msg(trade, "За один раз можно отправить неболее 25 вещей") |
||||
|
await trade.decline() |
||||
|
return |
||||
|
|
||||
|
seconds = self.items.Items2Seconds(trade.items_to_receive) |
||||
|
if seconds == 0: |
||||
|
error(f"[{trade.id}] cannot accept trade not valid items") |
||||
|
await send_msg(trade, "Ты отправил неправльные вещи! Проверь что это:\n- Ключ МаннКо (уникальный)\n- Очищенный метал (уникальный)") |
||||
|
await trade.decline() |
||||
|
return |
||||
|
|
||||
|
info(f"[{trade.id}] Try accept trade") |
||||
|
await send_msg(trade, "Попытка принять трейд...") |
||||
|
await trade.accept() |
||||
|
return |
||||
|
|
||||
|
#Принятый трейд |
||||
|
async def on_trade_accept(self, trade: SteamPy.TradeOffer): |
||||
|
if not trade.is_gift(): |
||||
|
return |
||||
|
|
||||
|
info(f"[{trade.id}] Final stage accepted trade [{trade.partner.id}] {trade.partner.name}") |
||||
|
await send_msg(trade, "Успешно, сейчас посчитаем сколько ты надонатил") |
||||
|
|
||||
|
seconds = self.items.Items2Seconds(trade.items_to_receive) |
||||
|
result = await self.db.processing_vip(trade.partner, seconds) |
||||
|
if result == False: |
||||
|
await send_msg(trade, "Спасибо за вещи, но у тебя уже есть КРУТЫЕ права на фактах") |
||||
|
elif result == 100: |
||||
|
await send_msg(trade, f"Мои поздавления! Ты получил випку на {seconds / 60 / 60 / 24} дней") |
||||
|
elif result == 101: |
||||
|
await send_msg(trade, f"Круто! Ты продлил випку на {seconds / 60 / 60 / 24} дней") |
||||
|
await self.discord_alarm.alert(trade.partner, seconds) |
||||
|
return |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
parser = argparse.ArgumentParser() |
||||
|
parser.add_argument("--auth-file", type=str, default=os.environ.get("AUTH_FILE", "")) |
||||
|
parser.add_argument("--steam-secret", type=str, default=os.environ.get("STEAM_SECRET", "")) |
||||
|
parser.add_argument("--db-host", type=str, default=os.environ.get("DB_HOST", "")) |
||||
|
parser.add_argument("--db-username", type=str, default=os.environ.get("DB_USERNAME", "")) |
||||
|
parser.add_argument("--db-password", type=str, default=os.environ.get("DB_PASSWORD", "")) |
||||
|
parser.add_argument("--db-name", type=str, default=os.environ.get("DB_NAME", "")) |
||||
|
parser.add_argument("--discord-url", type=str, default=os.environ.get("DISCORD_WEBHOOK_URL", "")) |
||||
|
args = parser.parse_args() |
||||
|
|
||||
|
client = SteamClient(game = SteamPy.Game(id=440)) |
||||
|
|
||||
|
if args.db_host and args.db_username and args.db_password and args.db_name: |
||||
|
client.db = Database(args.db_host, args.db_username, args.db_password, args.db_name) |
||||
|
else: |
||||
|
error("DB data not be setted") |
||||
|
sys.exit(1) |
||||
|
|
||||
|
if args.auth_file and args.steam_secret: |
||||
|
try: |
||||
|
with open(args.auth_file, "r") as auth_file: |
||||
|
login = auth_file.readline()[:-1] |
||||
|
password = auth_file.readline() |
||||
|
except: |
||||
|
error("steam auth data is not correct") |
||||
|
sys.exit(3) |
||||
|
|
||||
|
try: |
||||
|
with open(args.steam_secret, "r") as steam_file: |
||||
|
secrets = load(steam_file) |
||||
|
#shared_secret |
||||
|
#identity_secret |
||||
|
except: |
||||
|
error("steam secret is not correct") |
||||
|
sys.exit(4) |
||||
|
else: |
||||
|
error("steam auth data or steam secret not be setted") |
||||
|
sys.exit(2) |
||||
|
|
||||
|
if args.discord_url: |
||||
|
client.discord_alarm = DiscordAlarm(args.discord_url) |
||||
|
else: |
||||
|
error("need discord webhook") |
||||
|
sys.exit(5) |
||||
|
|
||||
|
client.run( |
||||
|
username=login, |
||||
|
password = password, |
||||
|
shared_secret=secrets["shared_secret"], |
||||
|
identity_secret=secrets["identity_secret"], |
||||
|
) |
Loading…
Reference in new issue