Compare commits
3 Commits
v1.1
...
dffa29705f
Author | SHA1 | Date | |
---|---|---|---|
dffa29705f | |||
6ee5c227c6 | |||
57d4d1ce5c |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -152,13 +152,3 @@ cython_debug/
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Project specific
|
||||
.vscode
|
||||
config.json
|
||||
|
||||
*.session
|
||||
*.session-journal
|
||||
|
||||
venv
|
||||
venv_linux
|
||||
venv_windows
|
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"python.analysis.typeCheckingMode": "basic"
|
||||
}
|
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"puppeteer": "~20.2.0",
|
||||
"user-agents": "~1.0.1260"
|
||||
"puppeteer": "^14.4.0"
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,13 @@
|
||||
// npm install https://github.com/GoogleChrome/puppeteer/
|
||||
|
||||
const puppeteer = require('puppeteer');
|
||||
const userAgent = require('user-agents');
|
||||
|
||||
(async () => {
|
||||
|
||||
const url = process.argv[2];
|
||||
const browser = await puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
await page.setUserAgent(userAgent.random().toString());
|
||||
|
||||
|
||||
await page.goto(url, {waitUntil: 'load'});
|
||||
|
||||
const html = await page.content();
|
||||
|
13
README.md
13
README.md
@@ -1,26 +1,22 @@
|
||||
# BWTAqua
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
Simple yet helpful bot to check BWT Aqua's card balance
|
||||
|
||||
## Requirements
|
||||
> ⚠️ Please note that this branch is made for testing only so it can sometimes work strange or do not work at all.
|
||||
|
||||
## Requirements
|
||||
* nodejs & npm
|
||||
* python3
|
||||
* git
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download package
|
||||
1. `git clone https://git.end-play.xyz/profitroll/BWTAqua.git`
|
||||
2. `cd BWTAqua`
|
||||
2. Install needed modules:
|
||||
* `python3 -m pip install -r requirements.txt`
|
||||
3. Install PageSaver:
|
||||
1. `cd PageSaver`
|
||||
2. `npm install`
|
||||
3. `chmod +x pageSaver` (If you want to use compiled page saver)
|
||||
3. Install and configure Selenium Server
|
||||
4. Configure the bot:
|
||||
1. `cd ..`
|
||||
2. `nano config.json` (You can use any other text editor actually, for example `vim`)
|
||||
@@ -28,6 +24,5 @@ Simple yet helpful bot to check BWT Aqua's card balance
|
||||
* `python3 bwtbot.py`
|
||||
|
||||
## Configuration
|
||||
|
||||
You can edit with vim, nano, whatever.
|
||||
If you don't know where to find bot_token and your id - here you can find some hints: [get bot token](https://www.siteguarding.com/en/how-to-get-telegram-bot-api-token), [get your id](https://www.alphr.com/telegram-find-user-id/), [get api_hash and api_id](https://core.telegram.org/api/obtaining_api_id).
|
||||
If you don't know where to find bot_token and your id - here you can find some hints: [get bot token](https://www.siteguarding.com/en/how-to-get-telegram-bot-api-token), [get your id](https://www.alphr.com/telegram-find-user-id/), [get api_hash and api_id](https://core.telegram.org/api/obtaining_api_id).
|
200
bwtbot.py
200
bwtbot.py
@@ -1,37 +1,181 @@
|
||||
import logging
|
||||
from os import getpid
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
from convopyro import Conversation
|
||||
import traceback
|
||||
from pyrogram import filters, idle
|
||||
from pyrogram.types import ForceReply, BotCommand, BotCommandScopeChat
|
||||
from pyrogram.enums.chat_action import ChatAction
|
||||
from functions import *
|
||||
from modules.colors import *
|
||||
from modules.bwt import *
|
||||
from modules.app import app
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
from modules.app import PyroClient
|
||||
config = jsonLoad("config.json")
|
||||
owner_id = config["owner_id"]
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(name)s.%(funcName)s | %(levelname)s | %(message)s",
|
||||
datefmt="[%X]",
|
||||
driver = webdriver.Remote(
|
||||
command_executor=config["selenium_address"],
|
||||
options=webdriver.FirefoxOptions()
|
||||
)
|
||||
wait = WebDriverWait(driver, 10)
|
||||
# driver.execute_script(f"window.open('about:blank', 'home');")
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import uvloop
|
||||
|
||||
uvloop.install()
|
||||
except ImportError:
|
||||
pass
|
||||
@app.on_message(~ filters.scheduled & filters.command(["setcard", "задать карту"], prefixes=["/", ""]))
|
||||
async def setcard(_, msg):
|
||||
if userGet(msg.from_user.id, "context") is None:
|
||||
userSet(msg.from_user.id, "context", "set")
|
||||
await msg.reply_text(string("send_number"), reply_markup=ForceReply(placeholder=string("enter_number")))
|
||||
else:
|
||||
await msg.reply_text(string("cancel_first"))
|
||||
|
||||
|
||||
def main():
|
||||
client = PyroClient()
|
||||
Conversation(client)
|
||||
|
||||
try:
|
||||
client.run()
|
||||
except KeyboardInterrupt:
|
||||
logger.warning(f"Forcefully shutting down with PID {getpid()}...")
|
||||
finally:
|
||||
exit()
|
||||
@app.on_message(~ filters.scheduled & filters.command(["cancel", "відміна"], prefixes=["/", ""]))
|
||||
async def cancel(_, msg):
|
||||
if userGet(msg.from_user.id, "context") is not None:
|
||||
userReset(msg.from_user.id, "context")
|
||||
await msg.reply_text(string("cancel"))
|
||||
else:
|
||||
await msg.reply_text(string("cancel_none"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@app.on_message(~ filters.scheduled & filters.command(["resetcard", "забути картку"], prefixes=["/", ""]))
|
||||
async def resetcard(_, msg):
|
||||
if userGet(msg.from_user.id, "context") is None:
|
||||
if "card" in jsonLoad("data/database.json")[str(msg.from_user.id)]:
|
||||
userReset(msg.from_user.id, "card")
|
||||
await msg.reply_text(string("card_unlinked"))
|
||||
appendLog(f"User {str(msg.from_user.id)} reseted his card")
|
||||
else:
|
||||
await msg.reply_text(string("card_not_linked").format(string("get_number")))
|
||||
appendLog(f"User {str(msg.from_user.id)} tried to reset non-existent card")
|
||||
else:
|
||||
await msg.reply_text(string("cancel_first"))
|
||||
|
||||
|
||||
@app.on_message(~ filters.scheduled & filters.command(["balance", "баланс"], prefixes=["/", ""]))
|
||||
async def balance(_, msg):
|
||||
if userGet(msg.from_user.id, "context") is None:
|
||||
try:
|
||||
if "card" in jsonLoad("data/database.json")[str(msg.from_user.id)]:
|
||||
await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING)
|
||||
water_left = await getWaterLeft(driver, wait, userGet(msg.from_user.id, "card"), msg.from_user.id)
|
||||
if water_left == "":
|
||||
raise EmptyCardException("Card information is empty")
|
||||
elif water_left == "Failure":
|
||||
await msg.reply_text(string("error_occured").format(string("get_number")))
|
||||
appendLog(f"User {str(msg.from_user.id)} could not get left water amount")
|
||||
else:
|
||||
await msg.reply_text(string("card_balance").format(water_left))
|
||||
appendLog(f"User {str(msg.from_user.id)} has {water_left} liters remaining")
|
||||
else:
|
||||
await msg.reply_text(string("card_not_linked").format(string("get_number")))
|
||||
appendLog(f"User {str(msg.from_user.id)} tried to get balance without card set")
|
||||
except Exception as exp:
|
||||
await msg.reply_text(string("error_occured").format(string("get_number")))
|
||||
await app.send_message(owner_id, f"Error occured by {str(msg.from_user.id)}:\nException: `{exp}`\nTraceback: `{traceback.format_exc()}`")
|
||||
appendLog(f"User {str(msg.from_user.id)} could not get left water amount")
|
||||
else:
|
||||
await msg.reply_text(string("cancel_first"))
|
||||
|
||||
|
||||
@app.on_message(~ filters.scheduled & filters.command(["topup", "refill", "поповнити"], prefixes=["/", ""]))
|
||||
async def topup_cmd(_, msg):
|
||||
if userGet(msg.from_user.id, "context") is None:
|
||||
try:
|
||||
if "card" in jsonLoad("data/database.json")[str(msg.from_user.id)]:
|
||||
await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING)
|
||||
await msg.reply_text(string("top_up").format(str(userGet(msg.from_user.id, "card"))))
|
||||
appendLog(f"User {str(msg.from_user.id)} requested top up")
|
||||
else:
|
||||
await msg.reply_text(string("card_not_linked").format(string("get_number")))
|
||||
appendLog(f"User {str(msg.from_user.id)} tried to request top up without card set")
|
||||
except Exception as exp:
|
||||
await msg.reply_text(exp)
|
||||
else:
|
||||
await msg.reply_text(string("cancel_first"))
|
||||
|
||||
|
||||
@app.on_message(~ filters.scheduled & filters.command(["start", "help", "допомога"], prefixes=["/", ""]))
|
||||
async def help(_, msg):
|
||||
if userGet(msg.from_user.id, "context") is None:
|
||||
await msg.reply_text(string("welcome").format(string("get_number")))
|
||||
if msg.from_user.language_code in jsonLoad("strings.json"):
|
||||
userSet(msg.from_user.id, "locale", msg.from_user.language_code)
|
||||
else:
|
||||
userSet(msg.from_user.id, "locale", "en")
|
||||
else:
|
||||
await msg.reply_text(string("cancel_first"))
|
||||
|
||||
pid = os.getpid()
|
||||
|
||||
@app.on_message(~ filters.scheduled & filters.command(["kill", "die", "shutdown"], prefixes="/"))
|
||||
async def kill(_, msg):
|
||||
if msg.from_user.id == owner_id:
|
||||
await msg.reply_text(f"Shutting down bot with pid **{pid}**")
|
||||
driver.quit()
|
||||
os.system(f"kill -9 {pid}")
|
||||
|
||||
|
||||
@app.on_message(~ filters.scheduled)
|
||||
async def any_message_handler(app, msg):
|
||||
if userGet(msg.from_user.id, "context") == "set":
|
||||
userSet(msg.from_user.id, "card", msg.text)
|
||||
userReset(msg.from_user.id, "context")
|
||||
appendLog(f"User {str(msg.from_user.id)} set card id to {msg.text}")
|
||||
await msg.reply_text(string("card_linked").format(msg.text))
|
||||
|
||||
print(f'{nowtime()} {WHITE}Starting with PID {YELLOW}{pid}{RESET}')
|
||||
|
||||
app.start()
|
||||
app.send_message(owner_id, f"Starting bot with pid **{pid}**")
|
||||
|
||||
app.set_bot_commands([
|
||||
BotCommand("help", "Меню допомоги"),
|
||||
BotCommand("balance", "Баланс картки"),
|
||||
BotCommand("topup", "Поповнити картку"),
|
||||
BotCommand("setcard", "Прив'язати картку"),
|
||||
BotCommand("resetcard", "Відв'язати картку"),
|
||||
BotCommand("cancel", "Відмінити операцію"),
|
||||
],
|
||||
language_code="uk")
|
||||
|
||||
app.set_bot_commands([
|
||||
BotCommand("help", "Меню допомоги"),
|
||||
BotCommand("balance", "Баланс картки"),
|
||||
BotCommand("topup", "Поповнити картку"),
|
||||
BotCommand("setcard", "Прив'язати картку"),
|
||||
BotCommand("resetcard", "Відв'язати картку"),
|
||||
BotCommand("cancel", "Відмінити операцію"),
|
||||
],
|
||||
language_code="ru")
|
||||
|
||||
app.set_bot_commands([
|
||||
BotCommand("help", "Help menu"),
|
||||
BotCommand("balance", "Card's balance"),
|
||||
BotCommand("topup", "Refill card"),
|
||||
BotCommand("setcard", "Link card"),
|
||||
BotCommand("resetcard", "Unlink card"),
|
||||
BotCommand("cancel", "Cancel operation"),
|
||||
])
|
||||
|
||||
app.set_bot_commands([
|
||||
BotCommand("help", "Help menu"),
|
||||
BotCommand("balance", "Card's balance"),
|
||||
BotCommand("topup", "Refill card"),
|
||||
BotCommand("setcard", "Link card"),
|
||||
BotCommand("resetcard", "Unlink card"),
|
||||
BotCommand("shutdown", "Turn off the bot"),
|
||||
BotCommand("cancel", "Cancel operation"),
|
||||
],
|
||||
scope=BotCommandScopeChat(chat_id=owner_id))
|
||||
|
||||
idle()
|
||||
|
||||
driver.quit()
|
||||
app.send_message(owner_id, f"Shutting down bot with pid **{pid}**")
|
||||
print(f'\n{nowtime()} {WHITE}Shutting down with PID {YELLOW}{pid}{RESET}')
|
||||
|
||||
subprocess.call(f'kill -9 {pid}', shell=True)
|
||||
|
13
config.json
13
config.json
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"owner_id": 0,
|
||||
"bot": {
|
||||
"api_id": 0,
|
||||
"api_hash": "",
|
||||
"bot_token": "",
|
||||
"workers": 1
|
||||
},
|
||||
"use_compiled_page_saver": false
|
||||
"log_size": 1024,
|
||||
"api_id": 0,
|
||||
"api_hash": "",
|
||||
"bot_token": "",
|
||||
"bot_name": "",
|
||||
"selenium_address": "http://localhost:4444"
|
||||
}
|
123
functions.py
Normal file
123
functions.py
Normal file
@@ -0,0 +1,123 @@
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import gzip
|
||||
import time
|
||||
from modules.colors import *
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
path = Path(__file__).resolve().parent
|
||||
|
||||
days_path = str(path)+"/assets/days/"
|
||||
users_path = str(path)+"/users/"
|
||||
logs_folder = str(path)+"/logs/"
|
||||
|
||||
|
||||
def jsonSave(filename, value):
|
||||
with open(filename, 'w', encoding="utf-8") as f:
|
||||
json.dump(value, f, indent=4, ensure_ascii=False)
|
||||
f.close()
|
||||
|
||||
def jsonLoad(filename):
|
||||
with open(filename, 'r', encoding="utf-8") as f:
|
||||
value = json.load(f)
|
||||
f.close()
|
||||
return value
|
||||
|
||||
|
||||
config = jsonLoad(f"{path}/config.json")
|
||||
|
||||
log_size = config["log_size"]
|
||||
owner_id = config["owner_id"]
|
||||
|
||||
|
||||
def nowtime():
|
||||
return f'{BBLACK}[{CYAN}{datetime.now().strftime("%H:%M:%S")}{BBLACK}]{RESET}'
|
||||
|
||||
def checkSize():
|
||||
global logs_folder, log_size
|
||||
|
||||
i = 0
|
||||
|
||||
while i < 2:
|
||||
try:
|
||||
log = os.stat(logs_folder + 'latest.log')
|
||||
|
||||
if (log.st_size / 1024) > log_size:
|
||||
with open(logs_folder + 'latest.log', 'rb') as f_in:
|
||||
with gzip.open(f'{logs_folder}{datetime.now().strftime("%d.%m.%Y_%H:%M:%S")}.zip', 'wb') as f_out:
|
||||
shutil.copyfileobj(f_in, f_out)
|
||||
|
||||
open(logs_folder + 'latest.log', 'w').close()
|
||||
|
||||
i = 2
|
||||
|
||||
except FileNotFoundError:
|
||||
|
||||
try:
|
||||
log = open(logs_folder + 'latest.log', 'a')
|
||||
open(logs_folder + 'latest.log', 'a').close()
|
||||
except:
|
||||
try:
|
||||
os.mkdir(logs_folder)
|
||||
log = open(logs_folder + 'latest.log', 'a')
|
||||
open(logs_folder + 'latest.log', 'a').close()
|
||||
except:
|
||||
pass
|
||||
|
||||
i += 1
|
||||
|
||||
def appendLog(message):
|
||||
global logs_folder
|
||||
|
||||
checkSize()
|
||||
|
||||
try:
|
||||
log = open(logs_folder + 'latest.log', 'a')
|
||||
open(logs_folder + 'latest.log', 'a').close()
|
||||
except:
|
||||
try:
|
||||
os.mkdir(logs_folder)
|
||||
log = open(logs_folder + 'latest.log', 'a')
|
||||
open(logs_folder + 'latest.log', 'a').close()
|
||||
except:
|
||||
time.sleep(2)
|
||||
print('Log file could not be created')
|
||||
return
|
||||
|
||||
log.write(f'[{datetime.now().strftime("%H:%M:%S | %d.%m.%Y")}] {message}\n')
|
||||
|
||||
log.close()
|
||||
|
||||
|
||||
def string(key: str, *args: str, userlocale="uk"):
|
||||
locales = jsonLoad("strings.json")
|
||||
strings = locales[userlocale]
|
||||
string = strings
|
||||
for dict_key in args:
|
||||
string = string[dict_key]
|
||||
return string[key]
|
||||
|
||||
|
||||
def userSet(userid, key: str, value):
|
||||
database = jsonLoad("data/database.json")
|
||||
if str(userid) not in database:
|
||||
database[str(userid)] = {}
|
||||
database[str(userid)][key] = value
|
||||
jsonSave("data/database.json", database)
|
||||
|
||||
def userReset(userid, key: str):
|
||||
database = jsonLoad("data/database.json")
|
||||
del database[str(userid)][key]
|
||||
jsonSave("data/database.json", database)
|
||||
|
||||
def userGet(userid, key: str):
|
||||
try:
|
||||
return jsonLoad("data/database.json")[str(userid)][key]
|
||||
except KeyError:
|
||||
return None
|
||||
except FileNotFoundError:
|
||||
return None
|
105
modules/app.py
105
modules/app.py
@@ -1,104 +1,7 @@
|
||||
import logging
|
||||
from os import getpid
|
||||
from time import time
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
import pyrogram
|
||||
from libbot import config_get
|
||||
from pyrogram.client import Client
|
||||
from pyrogram.errors import BadRequest
|
||||
from pyrogram.raw.all import layer
|
||||
from pyrogram.types import BotCommand, BotCommandScopeChat
|
||||
from ujson import loads
|
||||
from functions import jsonLoad
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PyroClient(Client):
|
||||
def __init__(self):
|
||||
with open("config.json", "r", encoding="utf-8") as f:
|
||||
config = loads(f.read())
|
||||
super().__init__(
|
||||
name="bwtbot",
|
||||
api_id=config["bot"]["api_id"],
|
||||
api_hash=config["bot"]["api_hash"],
|
||||
bot_token=config["bot"]["bot_token"],
|
||||
workers=config["bot"]["workers"],
|
||||
plugins=dict(root="plugins", exclude=config["disabled_plugins"]),
|
||||
sleep_threshold=120,
|
||||
)
|
||||
|
||||
async def start(self):
|
||||
await super().start()
|
||||
|
||||
self.start_time = time()
|
||||
|
||||
logger.info(
|
||||
"Bot is running with Pyrogram v%s (Layer %s) and has started as @%s on PID %s.",
|
||||
pyrogram.__version__,
|
||||
layer,
|
||||
self.me.username,
|
||||
getpid(),
|
||||
)
|
||||
|
||||
try:
|
||||
await self.send_message(
|
||||
chat_id=await config_get("chat_id", "reports"),
|
||||
text=f"Bot started PID `{getpid()}`",
|
||||
)
|
||||
except BadRequest:
|
||||
logger.warning("Unable to send message to report chat.")
|
||||
|
||||
await self.set_bot_commands(
|
||||
[
|
||||
BotCommand("help", "Меню допомоги"),
|
||||
BotCommand("balance", "Баланс картки"),
|
||||
BotCommand("topup", "Поповнити картку"),
|
||||
BotCommand("setcard", "Прив'язати картку"),
|
||||
BotCommand("resetcard", "Відв'язати картку"),
|
||||
],
|
||||
language_code="uk",
|
||||
)
|
||||
|
||||
await self.set_bot_commands(
|
||||
[
|
||||
BotCommand("help", "Меню допомоги"),
|
||||
BotCommand("balance", "Баланс картки"),
|
||||
BotCommand("topup", "Поповнити картку"),
|
||||
BotCommand("setcard", "Прив'язати картку"),
|
||||
BotCommand("resetcard", "Відв'язати картку"),
|
||||
],
|
||||
language_code="ru",
|
||||
)
|
||||
|
||||
await self.set_bot_commands(
|
||||
[
|
||||
BotCommand("help", "Help menu"),
|
||||
BotCommand("balance", "Card's balance"),
|
||||
BotCommand("topup", "Refill card"),
|
||||
BotCommand("setcard", "Link card"),
|
||||
BotCommand("resetcard", "Unlink card"),
|
||||
]
|
||||
)
|
||||
|
||||
await self.set_bot_commands(
|
||||
[
|
||||
BotCommand("help", "Help menu"),
|
||||
BotCommand("balance", "Card's balance"),
|
||||
BotCommand("topup", "Refill card"),
|
||||
BotCommand("setcard", "Link card"),
|
||||
BotCommand("resetcard", "Unlink card"),
|
||||
BotCommand("shutdown", "Turn off the bot"),
|
||||
],
|
||||
scope=BotCommandScopeChat(chat_id=await config_get("owner_id")),
|
||||
)
|
||||
|
||||
async def stop(self):
|
||||
try:
|
||||
await self.send_message(
|
||||
chat_id=await config_get("chat_id", "reports"),
|
||||
text=f"Bot stopped with PID `{getpid()}`",
|
||||
)
|
||||
except BadRequest:
|
||||
logger.warning("Unable to send message to report chat.")
|
||||
await super().stop()
|
||||
logger.warning(f"Bot stopped with PID {getpid()}.")
|
||||
config = jsonLoad("config.json")
|
||||
app = Client(config["bot_name"], api_id=config["api_id"], api_hash=config["api_hash"], bot_token=config["bot_token"])
|
116
modules/bwt.py
116
modules/bwt.py
@@ -1,101 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from os import makedirs, path
|
||||
from subprocess import check_output
|
||||
from traceback import format_exc
|
||||
from uuid import uuid4
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import traceback
|
||||
from typing import Union
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from functions import *
|
||||
from modules.app import app
|
||||
from bs4 import BeautifulSoup
|
||||
from libbot import config_get
|
||||
|
||||
from modules.utils import *
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
config = jsonLoad("config.json")
|
||||
|
||||
class EmptyCardException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
async def getWaterLeft(cardid, filename, app=None):
|
||||
async def getWaterLeft(driver: webdriver.Remote, wait: WebDriverWait, cardid: Union[str, int], filename: int):
|
||||
|
||||
url = f"https://bwtaqua.com.ua/card-topup/?id={cardid}"
|
||||
|
||||
|
||||
try:
|
||||
# if path.exists(f"data/pages/{str(filename)}.html") is False:
|
||||
# run(["touch", f"data/pages/{str(filename)}.html"])
|
||||
|
||||
logger.info(f"Trying to get liters for url '{url}'")
|
||||
# driver.execute_script(f"window.open('about:blank', '{filename}');")
|
||||
# driver.switch_to.window(f"{filename}")
|
||||
driver.get(f"https://bwtaqua.com.ua/card-topup/?id={cardid}")
|
||||
|
||||
if await config_get("use_compiled_page_saver") is True:
|
||||
proc = check_output(
|
||||
[
|
||||
"PageSaver/pageSaver",
|
||||
f"https://bwtaqua.com.ua/card-topup/?id={cardid}",
|
||||
]
|
||||
) # , ">", f"data/pages/{str(filename)}.html"])
|
||||
html_file = proc.decode("utf-8")
|
||||
else:
|
||||
proc = check_output(
|
||||
[
|
||||
"node",
|
||||
"./PageSaver/pageSaver.js",
|
||||
f"https://bwtaqua.com.ua/card-topup/?id={cardid}",
|
||||
]
|
||||
) # , ">", f"data/pages/{str(filename)}.html"])
|
||||
html_file = proc.decode("utf-8")
|
||||
wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'js-payment-balance')))
|
||||
|
||||
# with open(f'data/pages/{str(filename)}.html') as f:
|
||||
# html_file = f.read()
|
||||
# f.close()
|
||||
page_source = driver.page_source
|
||||
|
||||
soup = BeautifulSoup(html_file, "html.parser")
|
||||
driver.execute_script("window.stop();")
|
||||
|
||||
output = (
|
||||
(
|
||||
soup.find_all(
|
||||
"h3",
|
||||
class_="headline headline_center headline_pink js-payment-balance",
|
||||
)[0].getText()
|
||||
)
|
||||
.replace("Твій баланс ", "")
|
||||
.replace(" л", "")
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Parsed {output} liters of water remaining (user: {str(filename)}, cardid: {cardid})"
|
||||
)
|
||||
with open(f'data/pages/{filename}.html', "w", encoding="utf-8") as f:
|
||||
f.write(page_source)
|
||||
|
||||
output = driver.find_element(By.CLASS_NAME, "js-payment-balance").text.replace("Твій баланс ", "").replace(" л", "")
|
||||
|
||||
# soup = BeautifulSoup(page_source, 'html.parser')
|
||||
# output = (soup.find_all("h3", class_="headline headline_center headline_pink js-payment-balance")[0].getText()).replace("Твій баланс ", "").replace(" л", "")
|
||||
|
||||
appendLog(f"Parsed {output} liters of water remaining (user: {filename}, cardid: {cardid})")
|
||||
|
||||
except Exception as exp:
|
||||
logger.exception(
|
||||
f"Exception occured: {exp} (user: {str(filename)}, cardid: {cardid})", exp
|
||||
)
|
||||
|
||||
try:
|
||||
tmp_name = str(uuid4())
|
||||
makedirs("tmp", exist_ok=True)
|
||||
with open(path.join("tmp", tmp_name), "w", encoding="utf-8") as f:
|
||||
f.write(html_file)
|
||||
except NameError:
|
||||
tmp_name = "N/A"
|
||||
logger.warning(f"'html_file' is not defined so I won't gather any tmp data")
|
||||
|
||||
|
||||
appendLog(f"Exception occured: {exp} (user: {filename}, cardid: {cardid})")
|
||||
|
||||
if app != None:
|
||||
await app.send_message(
|
||||
await config_get("owner_id"),
|
||||
f"**Exception occured:**\n • User: `{str(filename)}`\n • Card: [{cardid}]({url})\n • Exception: `{exp}`\n • TMP UUID: `{tmp_name}`\n • Traceback: `{format_exc()}`",
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
await app.send_message(config["owner_id"], f"**Exception occured:**\n • User: `{filename}`\n • Card: [{cardid}]({url})\n • Exception: `{exp}`\n • Traceback: `{traceback.format_exc()}`", disable_web_page_preview=True)
|
||||
else:
|
||||
logger.warning(f"Exception occurred and could not send to user: {exp}")
|
||||
|
||||
print(f'Exception occured and could not send to user: {exp}')
|
||||
|
||||
output = "Failure"
|
||||
|
||||
|
||||
return output
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
cardid = input("Enter card number: ")
|
||||
userid = input("Enter Telegram ID (optional): ")
|
||||
|
||||
|
||||
print(f"Card has {str(getWaterLeft(cardid, userid, app=None))} l. left")
|
||||
|
22
modules/colors.py
Normal file
22
modules/colors.py
Normal file
@@ -0,0 +1,22 @@
|
||||
RESET = '\u001b[0m'
|
||||
|
||||
BLACK = '\u001b[30m'
|
||||
RED = '\u001b[31m'
|
||||
GREEN = '\u001b[32m'
|
||||
YELLOW = '\u001b[33m'
|
||||
BLUE = '\u001b[34m'
|
||||
MAGENTA = '\u001b[35m'
|
||||
CYAN = '\u001b[36m'
|
||||
WHITE = '\u001b[37m'
|
||||
|
||||
BBLACK = '\u001b[30;1m'
|
||||
BRED = '\u001b[31;1m'
|
||||
BGREEN = '\u001b[32;1m'
|
||||
BYELLOW = '\u001b[33;1m'
|
||||
BBLUE = '\u001b[34;1m'
|
||||
BMAGENTA = '\u001b[35;1m'
|
||||
BCYAN = '\u001b[36;1m'
|
||||
BWHITE = '\u001b[37;1m'
|
||||
|
||||
ULINE = '\u001b[4m'
|
||||
REVERSE = '\u001b[7m'
|
@@ -1,35 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from libbot import json_read, sync
|
||||
|
||||
|
||||
async def string(key: str, *args: str, userlocale="uk"):
|
||||
locales = await json_read("strings.json")
|
||||
strings = locales[userlocale]
|
||||
string = strings
|
||||
for dict_key in args:
|
||||
string = string[dict_key]
|
||||
return string[key]
|
||||
|
||||
|
||||
def userSet(userid, key: str, value):
|
||||
database = sync.json_read("data/database.json")
|
||||
if str(userid) not in database:
|
||||
database[str(userid)] = {}
|
||||
database[str(userid)][key] = value
|
||||
sync.json_write(database, "data/database.json")
|
||||
|
||||
|
||||
def userReset(userid, key: str):
|
||||
database = sync.json_read("data/database.json")
|
||||
del database[str(userid)][key]
|
||||
sync.json_write(database, "data/database.json")
|
||||
|
||||
|
||||
def userGet(userid, key: str):
|
||||
try:
|
||||
return sync.json_read("data/database.json")[str(userid)][key]
|
||||
except KeyError:
|
||||
return None
|
||||
except FileNotFoundError:
|
||||
return None
|
@@ -1,63 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from traceback import format_exc
|
||||
|
||||
from libbot import config_get, json_read
|
||||
from pyrogram import filters
|
||||
from pyrogram.client import Client
|
||||
from pyrogram.enums.chat_action import ChatAction
|
||||
from pyrogram.types import Message
|
||||
|
||||
from modules.utils import string, userGet
|
||||
from modules.bwt import getWaterLeft
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Client.on_message(
|
||||
~filters.scheduled & filters.command(["balance", "баланс"], prefixes=["/", ""]) # type: ignore
|
||||
)
|
||||
async def command_balance(app: Client, msg: Message):
|
||||
try:
|
||||
if "card" in (await json_read("data/database.json"))[str(msg.from_user.id)]:
|
||||
await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING)
|
||||
water_left = await getWaterLeft(
|
||||
userGet(msg.from_user.id, "card"), msg.from_user.id, app
|
||||
)
|
||||
if water_left == "":
|
||||
await msg.reply_text(
|
||||
(await string("error_new")).format(
|
||||
f'https://bwtaqua.com.ua/card-topup/?id={userGet(msg.from_user.id, "card")}'
|
||||
)
|
||||
)
|
||||
# raise EmptyCardException("Card information is empty")
|
||||
elif water_left == "Failure":
|
||||
await msg.reply_text(
|
||||
(await string("error_occured")).format(await string("get_number"))
|
||||
)
|
||||
logger.warning(
|
||||
f"User {str(msg.from_user.id)} could not get left water amount"
|
||||
)
|
||||
else:
|
||||
await msg.reply_text((await string("card_balance")).format(water_left))
|
||||
logger.info(
|
||||
f"User {str(msg.from_user.id)} has {water_left} liters remaining"
|
||||
)
|
||||
else:
|
||||
await msg.reply_text(
|
||||
(await string("card_not_linked")).format(await string("get_number"))
|
||||
)
|
||||
logger.info(
|
||||
f"User {str(msg.from_user.id)} tried to get balance without card set"
|
||||
)
|
||||
except Exception as exp:
|
||||
if msg.from_user.id != await config_get("owner_id"):
|
||||
await msg.reply_text(
|
||||
(await string("error_occured")).format(await string("get_number"))
|
||||
)
|
||||
await app.send_message(
|
||||
await config_get("owner_id"),
|
||||
f"Error occured by {str(msg.from_user.id)}:\nException: `{exp}`\nTraceback: `{format_exc()}`",
|
||||
)
|
||||
logger.warning(f"User {str(msg.from_user.id)} could not get left water amount")
|
@@ -1,24 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from libbot import json_read
|
||||
from pyrogram import filters
|
||||
from pyrogram.client import Client
|
||||
from pyrogram.types import Message
|
||||
|
||||
from modules.utils import string, userSet
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Client.on_message(
|
||||
~filters.scheduled
|
||||
& filters.command(["start", "help", "допомога"], prefixes=["/", ""]) # type: ignore
|
||||
)
|
||||
async def command_help(app: Client, msg: Message):
|
||||
await msg.reply_text((await string("welcome")).format(await string("get_number")))
|
||||
if msg.from_user.language_code in await json_read("strings.json"):
|
||||
userSet(msg.from_user.id, "locale", msg.from_user.language_code)
|
||||
else:
|
||||
userSet(msg.from_user.id, "locale", "en")
|
@@ -1,28 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from libbot import json_read
|
||||
from pyrogram import filters
|
||||
from pyrogram.client import Client
|
||||
from pyrogram.types import Message
|
||||
|
||||
from modules.utils import string, userReset
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Client.on_message(
|
||||
~filters.scheduled
|
||||
& filters.command(["resetcard", "забути картку"], prefixes=["/", ""]) # type: ignore
|
||||
)
|
||||
async def command_resetcard(app: Client, msg: Message):
|
||||
if "card" in (await json_read("data/database.json"))[str(msg.from_user.id)]:
|
||||
userReset(msg.from_user.id, "card")
|
||||
await msg.reply_text(await string("card_unlinked"))
|
||||
logger.info(f"User {str(msg.from_user.id)} reseted his card")
|
||||
else:
|
||||
await msg.reply_text(
|
||||
(await string("card_not_linked")).format(await string("get_number"))
|
||||
)
|
||||
logger.info(f"User {str(msg.from_user.id)} tried to reset non-existent card")
|
@@ -1,35 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from convopyro import listen_message
|
||||
from pyrogram import filters
|
||||
from pyrogram.client import Client
|
||||
from pyrogram.types import ForceReply, Message, ReplyKeyboardRemove
|
||||
|
||||
from modules.utils import string, userSet
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Client.on_message(
|
||||
~filters.scheduled
|
||||
& filters.command(["setcard", "задать карту"], prefixes=["/", ""]) # type: ignore
|
||||
)
|
||||
async def command_setcard(app: Client, msg: Message):
|
||||
await msg.reply_text(
|
||||
await string("send_number"),
|
||||
reply_markup=ForceReply(placeholder=await string("enter_number")),
|
||||
)
|
||||
answer = await listen_message(app, msg.chat.id, timeout=None)
|
||||
if answer is None:
|
||||
return
|
||||
elif answer.text.strip() in ["/cancel", "cancel", "/відміна", "відміна"]:
|
||||
await msg.reply_text(await string("cancel"), reply_markup=ReplyKeyboardRemove())
|
||||
return
|
||||
userSet(answer.from_user.id, "card", answer.text)
|
||||
logger.info(f"User {str(msg.from_user.id)} set card id to {answer.text}")
|
||||
await msg.reply_text(
|
||||
(await string("card_linked")).format(answer.text),
|
||||
reply_markup=ReplyKeyboardRemove(),
|
||||
)
|
@@ -1,21 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
from os import getpid
|
||||
|
||||
from libbot import config_get
|
||||
from pyrogram import filters
|
||||
from pyrogram.client import Client
|
||||
from pyrogram.types import Message
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Client.on_message(
|
||||
~filters.scheduled & filters.command(["kill", "die", "shutdown"], prefixes="/") # type: ignore
|
||||
)
|
||||
async def command_shutdown(app: Client, msg: Message):
|
||||
if msg.from_user.id == await config_get("owner_id"):
|
||||
await msg.reply_text(f"Shutting down bot with pid **{getpid()}**")
|
||||
logger.info(f"Shutting down as requested by {msg.from_user.id}")
|
||||
exit()
|
@@ -1,36 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
|
||||
from libbot import json_read
|
||||
from pyrogram import filters
|
||||
from pyrogram.client import Client
|
||||
from pyrogram.enums.chat_action import ChatAction
|
||||
from pyrogram.types import Message
|
||||
|
||||
from modules.utils import string, userGet
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Client.on_message(
|
||||
~filters.scheduled
|
||||
& filters.command(["topup", "refill", "поповнити"], prefixes=["/", ""]) # type: ignore
|
||||
)
|
||||
async def command_topup(app: Client, msg: Message):
|
||||
try:
|
||||
if "card" in (await json_read("data/database.json"))[str(msg.from_user.id)]:
|
||||
await app.send_chat_action(chat_id=msg.chat.id, action=ChatAction.TYPING)
|
||||
await msg.reply_text(
|
||||
(await string("top_up")).format(str(userGet(msg.from_user.id, "card")))
|
||||
)
|
||||
logger.info(f"User {str(msg.from_user.id)} requested top up")
|
||||
else:
|
||||
await msg.reply_text(
|
||||
(await string("card_not_linked")).format(await string("get_number"))
|
||||
)
|
||||
logger.info(
|
||||
f"User {str(msg.from_user.id)} tried to request top up without card set"
|
||||
)
|
||||
except Exception as exp:
|
||||
await msg.reply_text(str(exp))
|
@@ -1,9 +1,2 @@
|
||||
beautifulsoup4==4.12.2
|
||||
convopyro==0.5
|
||||
pathlib~=1.0.1
|
||||
pyrogram==2.0.106
|
||||
tgcrypto==1.2.5
|
||||
ujson==5.7.0
|
||||
uvloop==0.17.0
|
||||
--extra-index-url https://git.end-play.xyz/api/packages/profitroll/pypi/simple
|
||||
libbot[speed,pyrogram]==0.4
|
||||
beautifulsoup4==4.11.1
|
||||
selenium==4.7.2
|
14
strings.json
14
strings.json
@@ -4,14 +4,15 @@
|
||||
"get_number": "**Get card number (Var. 1):**\nOn the front bottom side of your card, number may be found\n\n**Get card number (Var. 2):**\n1. Scan QR on the card\n2. Open webpage from code\n3. Numer should be found in **Номер карти \"Здорова Вода\"** or **Номер карти BWT Aqua** fields",
|
||||
"card_linked": "Linked card: `{0}`\n\nPlease, make sure the number is correct before using the bot",
|
||||
"card_unlinked": "Card was unlinked from your Telegram",
|
||||
"card_not_linked": "You don't have any linked card.\n\nВYou can set it using /setcard\n\n{0}",
|
||||
"card_not_linked": "You don't have any linked card.\n\nВы можете задать её с помощью команды /setcard\n\n{0}",
|
||||
"error_occured": "An error occurred while getting the amount of remaining water on the card.\n\nPlease make sure the linked card number is correct. If you are sure that the bot is broken, please contact @profitroll.\n\nLink your card: /setcard\n\n{0}",
|
||||
"error_new": "An error occurred while getting the amount of remaining water on the card.\n\nLast a few weeks BWT seems to return empty string to balance request from our server. We assume that our server has been blacklisted.\n\nTo check your balance you can use official [BWT App](https://bwtaqua.com.ua/en/#app) or simply bookmark this page: {0}.",
|
||||
"card_balance": "Card's balance is {0} l. of water",
|
||||
"top_up": "[Click here to top up](https://bwtaqua.com.ua/card-topup/?id={0})",
|
||||
"cancel": "Operation cancelled",
|
||||
"cancel_none": "Nothing to cancel",
|
||||
"cancel_first": "Operation ongoing. Cancel the current one using /cancel to run this action",
|
||||
"enter_number": "Enter card number",
|
||||
"send_number": "Please, send your card number\nIf you want to abort this operation, use /cancel"
|
||||
"send_number": "Please, send your card number"
|
||||
},
|
||||
"uk": {
|
||||
"welcome": "Привіт-привіт!\n\nЦей бот дозволяє дізнатись скільки літрів залишилось на вашій карточці.\n\n**Команди:**\n • /balance – дізнатись баланс карти\n • /setcard – приав'язати карту\n • /resetcard – відв'язати карту\n\n{0}\n\nРозробник **не має жодного відношення до BWT Aqua**, а бот створений лише для особистого, некомерційного використання.",
|
||||
@@ -20,11 +21,12 @@
|
||||
"card_unlinked": "Картку відв'язано від вашого Telegram",
|
||||
"card_not_linked": "У вас немає прив'язаної картки.\n\nВи можете зробити це за допомогою команди /setcard\n\n{0}",
|
||||
"error_occured": "При отриманні води на карточці виникла помилка.\n\nБудь ласка, упевніться що номер карти правильний. Якщо ви впевнені, що номер картки правильний та бот зламався – зв'яжіться з @profitroll.\n\nПрив'язати карту: /setcard\n\n{0}",
|
||||
"error_new": "При отриманні води на карточці виникла помилка.\n\nОстанні тижні BWT повертає нашому серверу порожні строки замість балансу. Є підозри, що сервер потрапив у блеклист.\n\nДля перевірки балансу рекомендуємо користуватись офіційним [додатком BWT](https://bwtaqua.com.ua/#app) або просто додати цю сторінку у закладки: {0}.",
|
||||
"card_balance": "На карточці {0} л. води",
|
||||
"top_up": "[Натисніть для поповнення](https://bwtaqua.com.ua/card-topup/?id={0})",
|
||||
"cancel": "Операцію скасовано",
|
||||
"cancel": "Операція відмінена",
|
||||
"cancel_none": "Нема що відміняти",
|
||||
"cancel_first": "Триває інша операція. Відмініть триваючу операцію командою /cancel щоб запустити іншу дію",
|
||||
"enter_number": "Введіть номер картки",
|
||||
"send_number": "Будь ласка, надішліть номер вашої картки\nЯкщо ви хочете скасувати цю операцію, використовуйте /cancel"
|
||||
"send_number": "Будь ласка, надішліть номер вашої картки"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user