commit 84055d431aa4a0f763088d0b728dd7bb70d409f7 Author: gsd Date: Wed Feb 8 12:51:59 2023 +0000 rewrited on v1 bot diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b1c70ae --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +auth_data/ +.env \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b1c70ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +auth_data/ +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fb487f5 --- /dev/null +++ b/Dockerfile @@ -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"] \ No newline at end of file diff --git a/colors.py b/colors.py new file mode 100644 index 0000000..b7deb0f --- /dev/null +++ b/colors.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)) \ No newline at end of file diff --git a/db_driver.py b/db_driver.py new file mode 100644 index 0000000..3519e6e --- /dev/null +++ b/db_driver.py @@ -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 \ No newline at end of file diff --git a/discord_alarm.py b/discord_alarm.py new file mode 100644 index 0000000..16c7768 --- /dev/null +++ b/discord_alarm.py @@ -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) \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..224b8b5 Binary files /dev/null and b/docker-compose.yaml differ diff --git a/tradebot.facti13.py b/tradebot.facti13.py new file mode 100644 index 0000000..440a16a --- /dev/null +++ b/tradebot.facti13.py @@ -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"], + ) \ No newline at end of file