77 Commits

Author SHA1 Message Date
AlberLC
a9a79b2705 Add minor changes 2023-05-06 05:36:29 +02:00
AlberLC
29ebfd5e26 Fix ScraperBot._search_medias (fake instagram ban) 2023-04-29 01:35:41 +02:00
AlberLC
cf6b39e262 Fix _on_reset_instagram_ban (private or mentioned) 2023-04-29 01:34:28 +02:00
AlberLC
225bad07cc Update requirements.txt 2023-04-27 07:28:09 +02:00
AlberLC
336d8f8b8a Fix connect_4 message data 2023-04-25 06:44:52 +02:00
AlberLC
ad98464446 Fix replied message date 2023-04-25 06:44:32 +02:00
AlberLC
94fe902d41 Update flanautils (do_later, do_every) 2023-04-16 09:59:41 +02:00
AlberLC
b86fc98377 Update ScraperBot.send_song_info 2023-04-16 09:58:11 +02:00
AlberLC
fa67733416 Update instagram scraper 2023-04-11 11:03:12 +02:00
AlberLC
63e972a774 Update instagram scraper 2023-04-11 10:52:46 +02:00
AlberLC
a1434e54d3 Update instagram scraper 2023-04-11 08:57:57 +02:00
AlberLC
88b61cd87f Update self.owner_chat initialization 2023-04-11 08:57:11 +02:00
AlberLC
4fc52128ec Update connect 4 background color 2023-04-07 06:22:22 +02:00
AlberLC
8788904d44 Update instagram scraper 2023-04-04 05:36:01 +02:00
AlberLC
fdb02e9d65 Update instagram scraper 2023-04-04 04:17:21 +02:00
AlberLC
8594351229 Update instagram scraper 2023-04-03 12:00:20 +02:00
AlberLC
ae7fb1b9b2 Update UberEatsBot._scrape_codes 2023-04-03 11:22:07 +02:00
AlberLC
d21978b2da Update FlanaBot._on_delete 2023-03-31 09:01:26 +02:00
AlberLC
35e8ec5090 Remove UberEatsBot pyperclip 2023-03-31 07:39:15 +02:00
AlberLC
8703eca5ff Update UberEatsBot._scrape_codes 2023-03-30 02:44:51 +02:00
AlberLC
6be120da17 Remove UberEatsBot pyperclip 2023-03-30 02:05:32 +02:00
AlberLC
aaf17c6877 Add FlanaBot._on_help antiflood 2023-03-24 05:07:48 +01:00
AlberLC
68a3fde4ed Update UberEatsBot.send_ubereats_code 2023-03-24 00:44:06 +01:00
AlberLC
edad87b683 Update self.owner_chat initialization 2023-03-23 07:13:40 +01:00
AlberLC
3be1cf5c47 Add FlanaBot._on_help 2023-03-23 07:13:03 +01:00
AlberLC
ff934325c5 Add FlanaBot._on_help 2023-03-23 06:33:48 +01:00
AlberLC
11ef06b1d3 Update flana_tele_bot whitelisted decorator 2023-03-23 06:33:26 +01:00
AlberLC
d5b51e3f44 Update FlanaBot._on_database_messages 2023-03-23 06:25:49 +01:00
AlberLC
a6b0e699ea Update FlanaBot._on_database_messages 2023-03-23 06:02:26 +01:00
AlberLC
e90e081b69 Update FlanaBot._on_database_messages 2023-03-23 06:01:40 +01:00
AlberLC
8a23baf626 Update FlanaBot send methods 2023-03-23 05:09:00 +01:00
AlberLC
7f795e0b73 Update setup.cfg 2023-03-23 03:43:30 +01:00
AlberLC
9fbc16df02 Update UberEatsBot.send_ubereats_code message spaces 2023-03-23 03:27:06 +01:00
AlberLC
9da95e5e1c Update ScraperBot._on_scraping 2023-03-18 06:21:07 +01:00
AlberLC
a27f86d1b9 Update FlanaBot._on_new_message_default 2023-03-15 01:17:07 +01:00
AlberLC
26b3d714d3 Add tunnel chats 2023-03-13 23:07:37 +01:00
AlberLC
afa96325fe Add tunnel chats 2023-03-13 09:35:00 +01:00
AlberLC
72a803daec Add tunnel chats 2023-03-13 09:30:15 +01:00
AlberLC
7ce6985fa9 Add tunnel chats 2023-03-13 09:24:43 +01:00
AlberLC
12d9dd6075 Add tunnel chats 2023-03-13 09:14:40 +01:00
AlberLC
cf8ec9182e Add tunnel chats 2023-03-13 08:29:37 +01:00
AlberLC
060484396e Update scraper_bot.py 2023-03-13 08:26:03 +01:00
AlberLC
94e8f72245 Add constants.KEYWORDS['tunnel'] 2023-03-13 07:07:45 +01:00
AlberLC
d359ccb39e Update song_info keywords 2023-03-12 23:26:51 +01:00
AlberLC
44dcb3d987 Improve UberEatsBot new code obtaining 2023-03-12 05:21:47 +01:00
AlberLC
4ebcade424 Improve UberEatsBot new code obtaining 2023-03-12 05:18:41 +01:00
AlberLC
52e981fc58 Improve UberEatsBot new code obtaining 2023-03-12 05:15:02 +01:00
AlberLC
722c2ffbac Fix UberEatsBot headless and new_context args 2023-03-08 23:49:49 +01:00
AlberLC
55e3fe53c2 Add user agent to UberEatsBot 2023-03-08 02:15:09 +01:00
AlberLC
34320079eb Update Chat.ubereats 2023-03-08 02:14:47 +01:00
AlberLC
61daaa387a Add ubereats_next_execution 2023-03-06 07:34:09 +01:00
AlberLC
7fee5f382c Add ubereats_next_execution 2023-03-06 07:28:37 +01:00
AlberLC
f8be4d3e5e Add ubereats_next_execution 2023-03-06 07:12:42 +01:00
AlberLC
89207de059 Fix concurrent ubereats 2023-03-06 07:12:08 +01:00
AlberLC
14793e5eb5 Fix scraping delete original in private 2023-03-05 20:45:57 +01:00
AlberLC
488db76710 Fix quick click buttons 2023-03-05 07:07:26 +01:00
AlberLC
a1cefe437d Add UberEatsBot support for multiple cookies 2023-03-05 06:41:45 +01:00
AlberLC
506af05ebb Add minor changes 2023-03-05 01:16:14 +01:00
AlberLC
c17ffe1010 Fix UberEats task stderr 2023-03-05 01:03:02 +01:00
AlberLC
81854375d1 Fix UberEats task stderr 2023-03-04 05:12:33 +01:00
AlberLC
154f02a1b6 Update requirements.txt 2023-03-03 23:03:58 +01:00
AlberLC
786bab4e04 Fix UberEats task cancellation 2023-03-03 22:07:53 +01:00
AlberLC
d045551db9 Fix UberEats task cancellation 2023-03-03 22:06:47 +01:00
AlberLC
5021bdd7ae Add UberEatsBot 2023-03-03 05:21:10 +01:00
AlberLC
e8742eca42 Add UberEatsBot 2023-03-03 05:20:20 +01:00
AlberLC
a24021c2bd Update FlanaBot.check_old_database_actions 2023-03-03 05:19:52 +01:00
AlberLC
d145f70a42 Update BotAction 2023-03-03 05:19:18 +01:00
AlberLC
73ad75e8b2 Update channel heating 2023-02-28 11:01:51 +01:00
AlberLC
1da383d5eb Update scraper_bot.py 2023-02-28 11:01:14 +01:00
AlberLC
a3893df34b Update requirements.txt 2023-02-20 23:34:13 +01:00
AlberLC
6645bef22f Update SCRAPING_TIMEOUT_SECONDS 2023-02-20 23:33:39 +01:00
AlberLC
d02d5d4df2 Update SCRAPING_TIMEOUT_SECONDS 2023-02-17 05:32:03 +01:00
AlberLC
85b181c598 Improve legibility 2023-02-01 07:15:19 +01:00
AlberLC
db5a1974b2 Fix FlanaDiscBot._changeable_roles 2023-02-01 02:30:13 +01:00
AlberLC
5e65b5a298 Update requirements.txt 2023-01-16 21:30:32 +01:00
AlberLC
4d60281a23 Add delay to FlanaBot._on_delete 2023-01-16 03:31:41 +01:00
AlberLC
0ede68d495 Add ScraperBot._on_no_scraping 2023-01-15 20:11:06 +01:00
15 changed files with 623 additions and 189 deletions

View File

@@ -4,4 +4,5 @@ from flanabot.bots.flana_tele_bot import *
from flanabot.bots.penalty_bot import *
from flanabot.bots.poll_bot import *
from flanabot.bots.scraper_bot import *
from flanabot.bots.ubereats_bot import *
from flanabot.bots.weather_bot import *

View File

@@ -284,8 +284,8 @@ class Connect4Bot(MultiBot, ABC):
return False
try:
message.data['is_active'] = False
except AttributeError:
message.data['connect_4']['is_active'] = False
except KeyError:
pass
await self.edit(
@@ -448,7 +448,7 @@ class Connect4Bot(MultiBot, ABC):
return winners
def _winning_positions(self, board: list[list[int | None]]) -> defaultdict[int, list[tuple[int, int]]]:
winning_positions = defaultdict(list)
winning_positions: defaultdict[int, list[tuple[int, int]]] = defaultdict(list)
for next_i, next_j in self._available_positions(board):
for player_number in self._check_winners(next_i, next_j, board):
winning_positions[player_number].append((next_i, next_j))

View File

@@ -1,7 +1,9 @@
__all__ = ['FlanaBot']
import asyncio
import datetime
import random
import time
from abc import ABC
from typing import Iterable
@@ -10,13 +12,14 @@ import pymongo
import pytz
from flanaapis import InstagramLoginError, MediaNotFoundError, PlaceNotFoundError
from flanautils import return_if_first_empty
from multibot import BadRoleError, MultiBot, Role, bot_mentioned, constants as multibot_constants, group, inline, owner
from multibot import BadRoleError, MultiBot, RegisteredCallback, Role, User, bot_mentioned, constants as multibot_constants, group, inline, owner
from flanabot import constants
from flanabot.bots.connect_4_bot import Connect4Bot
from flanabot.bots.penalty_bot import PenaltyBot
from flanabot.bots.poll_bot import PollBot
from flanabot.bots.scraper_bot import ScraperBot
from flanabot.bots.ubereats_bot import UberEatsBot
from flanabot.bots.weather_bot import WeatherBot
from flanabot.models import Action, BotAction, ButtonsGroup, Chat, Message
@@ -24,30 +27,40 @@ from flanabot.models import Action, BotAction, ButtonsGroup, Chat, Message
# ----------------------------------------------------------------------------------------------------- #
# --------------------------------------------- FLANA_BOT --------------------------------------------- #
# ----------------------------------------------------------------------------------------------------- #
class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBot, ABC):
class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, UberEatsBot, WeatherBot, MultiBot, ABC):
Chat = Chat
Message = Message
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tunnel_chat = None
self.help_calls = {}
# -------------------------------------------------------- #
# ------------------- PROTECTED METHODS ------------------ #
# -------------------------------------------------------- #
def _add_handlers(self):
super()._add_handlers()
self.register(self._on_activate_tunnel, (multibot_constants.KEYWORDS['activate'], constants.KEYWORDS['tunnel']))
self.register(self._on_bye, multibot_constants.KEYWORDS['bye'])
self.register(self._on_config, multibot_constants.KEYWORDS['config'])
self.register(self._on_config, (multibot_constants.KEYWORDS['show'], multibot_constants.KEYWORDS['config']))
self.register(self._on_database_messages, (multibot_constants.KEYWORDS['last'], multibot_constants.KEYWORDS['message']))
self.register(lambda message: self._on_database_messages(message, simple=True), (multibot_constants.KEYWORDS['last'], multibot_constants.KEYWORDS['message'], multibot_constants.KEYWORDS['simple']))
self.register(self._on_database_messages_simple, (multibot_constants.KEYWORDS['last'], multibot_constants.KEYWORDS['message'], multibot_constants.KEYWORDS['simple']))
self.register(self._on_deactivate_tunnel, (multibot_constants.KEYWORDS['deactivate'], constants.KEYWORDS['tunnel']))
self.register(self._on_delete, multibot_constants.KEYWORDS['delete'])
self.register(self._on_delete, (multibot_constants.KEYWORDS['delete'], multibot_constants.KEYWORDS['message']))
self.register(self._on_hello, multibot_constants.KEYWORDS['hello'])
self.register(self._on_help, multibot_constants.KEYWORDS['help'])
self.register(self._on_new_message_default, default=True)
self.register(self._on_recover_message, multibot_constants.KEYWORDS['reset'])
@@ -61,6 +74,8 @@ class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBo
self.register(self._on_roles, (multibot_constants.KEYWORDS['activate'], multibot_constants.KEYWORDS['role']))
self.register(self._on_roles, (multibot_constants.KEYWORDS['deactivate'], multibot_constants.KEYWORDS['role']))
self.register(self._on_tunnel_message, always=True)
self.register(self._on_users, multibot_constants.KEYWORDS['user'])
self.register_button(self._on_config_button_press, ButtonsGroup.CONFIG)
@@ -74,7 +89,7 @@ class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBo
async def _get_message(
self,
event: multibot_constants.MESSAGE_EVENT,
pull_overwrite_fields: Iterable[str] = ('_id', 'config')
pull_overwrite_fields: Iterable[str] = ('_id', 'config', 'date', 'ubereats')
) -> Message:
return await super()._get_message(event, pull_overwrite_fields)
@@ -120,29 +135,67 @@ class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBo
# ---------------------------------------------- #
# HANDLERS #
# ---------------------------------------------- #
async def _on_activate_tunnel(self, message: Message):
keywords = (*multibot_constants.KEYWORDS['activate'], *constants.KEYWORDS['tunnel'])
try:
chat_id_or_name = next(part for part in flanautils.remove_accents(message.text.lower()).split() if not flanautils.cartesian_product_string_matching(part, keywords, multibot_constants.PARSER_MIN_SCORE_DEFAULT))
except StopIteration:
return
chat_id_or_name = flanautils.cast_number(chat_id_or_name, raise_exception=False)
if (chat := await self.get_chat(chat_id_or_name)) or (chat := await self.get_chat(await self.get_user(chat_id_or_name))):
self.tunnel_chat = chat
await self.send(f"Túnel abierto con <b>{chat.name}{f' ({chat.group_name})' if chat.group_name else ''}</b>.", message)
else:
await self.send_error('Chat inválido.', message)
async def _on_bye(self, message: Message):
if message.chat.is_private or self.is_bot_mentioned(message):
await self.send_bye(message)
@group
@bot_mentioned
async def _on_config(self, message: Message):
if not message.chat.config:
if message.chat.is_private:
config_names = ('auto_insult', 'auto_scraping', 'scraping_delete_original', 'ubereats')
elif self.is_bot_mentioned(message):
config_names = (
'auto_insult',
'auto_scraping',
'auto_weather_chart',
'check_flood',
'punish',
'scraping_delete_original'
)
else:
return
buttons_texts = [(f"{'' if v else ''} {k}", v) for k, v in message.chat.config.items()]
buttons_texts = []
for k, v in message.chat.config.items():
if k not in config_names:
continue
if k == 'ubereats':
k = f"ubereats (cada {flanautils.TimeUnits(seconds=message.chat.ubereats['seconds']).to_words()})"
buttons_texts.append((f"{'' if v else ''} {k}", v))
await self.send('<b>Estos son los ajustes del chat:</b>\n\n', flanautils.chunks(buttons_texts, 3), message, buttons_key=ButtonsGroup.CONFIG)
await self.delete_message(message)
async def _on_config_button_press(self, message: Message):
await self.accept_button_event(message)
if message.buttons_info.presser_user.is_admin is False:
if message.buttons_info.presser_user.is_admin is False or not message.buttons_info.pressed_button:
return
config_name = message.buttons_info.pressed_text.split()[1]
message.chat.config[config_name] = not message.chat.config[config_name]
message.buttons_info.pressed_button.text = f"{'' if message.chat.config[config_name] else ''} {config_name}"
if config_name == 'ubereats':
if message.chat.config[config_name]:
await self.start_ubereats(message.chat)
else:
await self.stop_ubereats(message.chat)
button_text = f"ubereats (cada {flanautils.TimeUnits(seconds=message.chat.ubereats['seconds']).to_words()})"
else:
button_text = config_name
message.buttons_info.pressed_button.text = f"{'' if message.chat.config[config_name] else ''} {button_text}"
await self.edit(message.buttons_info.buttons, message)
@@ -163,23 +216,28 @@ class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBo
),
message
)
await self.delete_message(message)
async def _on_database_messages_simple(self, message: Message):
await self._on_database_messages(message, simple=True)
async def _on_deactivate_tunnel(self, message: Message):
self.tunnel_chat = None
await self.send('Túnel cerrado.', message)
@inline(False)
async def _on_delete(self, message: Message):
if message.replied_message:
if message.replied_message.author.id == self.id:
await self.delete_message(message.replied_message)
if message.chat.is_group:
await self.delete_message(message)
if (
self.is_bot_mentioned(message)
and
(message.author.is_admin or message.replied_message.author.id == self.id)
):
flanautils.do_later(flanautils.text_to_time(message.text).total_seconds(), self.delete_message, message.replied_message)
await self.delete_message(message)
elif message.chat.is_group and self.is_bot_mentioned(message):
await self.send_negative(message)
elif (
(message.chat.is_private or self.is_bot_mentioned(message))
and
(n_messages := flanautils.text_to_number(message.text))
(message.chat.is_private or self.is_bot_mentioned(message))
and
(n_messages := flanautils.text_to_number(message.text))
):
if message.author.is_admin is False:
await self.send_negative(message)
@@ -195,54 +253,109 @@ class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBo
if message.chat.is_private or self.is_bot_mentioned(message):
await self.send_hello(message)
async def _on_help(self, message: Message):
now = datetime.timedelta(seconds=time.time())
if (
message.chat.is_group
and
not self.is_bot_mentioned(message)
or
self.help_calls.get(message.chat.id)
and
now - self.help_calls[message.chat.id] <= datetime.timedelta(minutes=1)
):
return
self.help_calls[message.chat.id] = now
await self.send(
'<b>Necesita ayuda:</b>\n'
'<b>User:</b>\n'
f' <b>id:</b> <code>{message.author.id}</code>\n'
f' <b>name:</b> <code>{message.author.name}</code>\n'
f' <b>is_admin:<b> <code>{message.author.is_admin}</code>\n'
f' <b>is_bot:</b> <code>{message.author.is_bot}</code>\n'
'\n'
'<b>Chat:</b>\n'
f' <b>id:</b> <code>{message.chat.id}</code>\n'
f' <b>name:</b> <code>{message.chat.name}</code>\n'
f' <b>group_id:</b> <code>{message.chat.group_id}</code>\n'
f' <b>group_name:</b> <code>{message.chat.group_name}</code>',
await self.owner_chat
)
await self.send('Se ha notificado a Flanagan. Se pondrá en contacto contigo cuando pueda.', message)
async def _on_new_message_default(self, message: Message):
if message.is_inline:
await self._scrape_and_send(message)
await self._on_scraping(message)
elif (
(
message.chat.is_group
and
not self.is_bot_mentioned(message)
and
not message.chat.config['auto_scraping']
or
not await self._scrape_send_and_delete(message)
)
(
message.chat.is_group
and
(
message.author.id != self.owner_id
and
(
not message.replied_message
or
message.replied_message.author.id != self.id
or
not message.replied_message.medias
)
and
(
self.is_bot_mentioned(message)
or
(
message.chat.config['auto_insult']
and
random.random() < constants.INSULT_PROBABILITY
)
)
)
not self.is_bot_mentioned(message)
and
not message.chat.config['auto_scraping']
or
not await self._on_scraping(message, scrape_replied=False)
)
and
message.author.id != self.owner_id
and
(
not message.replied_message
or
message.replied_message.author.id != self.id
or
not message.replied_message.medias
)
and
(
self.is_bot_mentioned(message)
or
message.chat.config['auto_insult']
and
random.random() < constants.INSULT_PROBABILITY
)
and
(
not self.tunnel_chat
or
self.tunnel_chat != message.chat
)
):
await self.send_insult(message)
async def _on_ready(self):
await super()._on_ready()
await flanautils.do_every(multibot_constants.CHECK_OLD_DATABASE_MESSAGES_EVERY_SECONDS, self.check_old_database_actions)
flanautils.do_every(multibot_constants.CHECK_OLD_DATABASE_MESSAGES_EVERY_SECONDS, self.check_old_database_actions)
for chat in Chat.find({
'platform': self.platform.value,
'config.ubereats': {"$exists": True, "$eq": True},
'ubereats.cookies': {"$exists": True, "$ne": []}
}):
chat = await self.get_chat(chat.id)
chat.pull_from_database(overwrite_fields=('_id', 'config', 'ubereats'))
if (
chat.ubereats['next_execution']
and
(delta_time := chat.ubereats['next_execution'] - datetime.datetime.now(datetime.timezone.utc)) > datetime.timedelta()
):
flanautils.do_later(delta_time, self.start_ubereats, chat)
else:
await self.start_ubereats(chat)
@inline(False)
async def _on_recover_message(self, message: Message):
if message.replied_message and message.replied_message.author.id == self.id:
message_deleted_bot_action = BotAction.find_one({'action': Action.MESSAGE_DELETED.value, 'chat': message.chat.object_id, 'affected_objects': message.replied_message.object_id})
message_deleted_bot_action = BotAction.find_one({
'platform': self.platform.value,
'action': Action.MESSAGE_DELETED.value,
'chat': message.chat.object_id,
'affected_objects': message.replied_message.object_id
})
elif self.is_bot_mentioned(message):
message_deleted_bot_action = BotAction.find_one({
'platform': self.platform.value,
'action': Action.MESSAGE_DELETED.value,
'chat': message.chat.object_id,
'date': {'$gt': datetime.datetime.now(datetime.timezone.utc) - constants.RECOVERY_DELETED_MESSAGE_BEFORE}
@@ -298,6 +411,28 @@ class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBo
message.buttons_info.presser_user.save()
async def _on_tunnel_message(self, message: Message):
if (
not self.tunnel_chat
or
self._parse_callbacks(
message.text,
[
RegisteredCallback(..., (multibot_constants.KEYWORDS['activate'], constants.KEYWORDS['tunnel'])),
RegisteredCallback(..., (multibot_constants.KEYWORDS['deactivate'], constants.KEYWORDS['tunnel']))
]
)
):
return
if message.chat == self.tunnel_chat:
await self.send(f"<b>{message.author.name.split('#')[0]}:</b> {message.text}", await self.owner_chat)
elif message.author.id == self.owner_id and message.chat.is_private:
if message.text:
await self.send(message.text, self.tunnel_chat)
else:
await self.send('No puedo enviar un mensaje sin texto.', message)
@group
@bot_mentioned
async def _on_users(self, message: Message):
@@ -345,17 +480,20 @@ class FlanaBot(Connect4Bot, PenaltyBot, PollBot, ScraperBot, WeatherBot, MultiBo
# -------------------------------------------------------- #
# -------------------- PUBLIC METHODS -------------------- #
# -------------------------------------------------------- #
@staticmethod
def check_old_database_actions():
def check_old_database_actions(self):
before_date = datetime.datetime.now(datetime.timezone.utc) - multibot_constants.DATABASE_MESSAGE_EXPIRATION_TIME
BotAction.delete_many_raw({'date': {'$lte': before_date}})
BotAction.delete_many_raw({'platform': self.platform.value, 'date': {'$lte': before_date}})
async def send_bye(self, message: Message) -> multibot_constants.ORIGINAL_MESSAGE:
return await self.send(random.choice((*constants.BYE_PHRASES, flanautils.CommonWords.random_time_greeting())), message)
async def send_bye(self, chat: int | str | User | Chat | Message) -> multibot_constants.ORIGINAL_MESSAGE:
chat = await self.get_chat(chat)
return await self.send(random.choice((*constants.BYE_PHRASES, flanautils.CommonWords.random_time_greeting())), chat)
async def send_hello(self, message: Message) -> multibot_constants.ORIGINAL_MESSAGE:
return await self.send(random.choice((*constants.HELLO_PHRASES, flanautils.CommonWords.random_time_greeting())), message)
async def send_hello(self, chat: int | str | User | Chat | Message) -> multibot_constants.ORIGINAL_MESSAGE:
chat = await self.get_chat(chat)
return await self.send(random.choice((*constants.HELLO_PHRASES, flanautils.CommonWords.random_time_greeting())), chat)
async def send_insult(self, message: Message) -> multibot_constants.ORIGINAL_MESSAGE | None:
await self.typing_delay(message)
return await self.send(random.choice(constants.INSULTS), message)
async def send_insult(self, chat: int | str | User | Chat | Message) -> multibot_constants.ORIGINAL_MESSAGE | None:
chat = await self.get_chat(chat)
async with await self.typing(chat):
await asyncio.sleep(random.randint(1, 3))
return await self.send(random.choice(constants.INSULTS), chat)

View File

@@ -10,7 +10,7 @@ import discord
import flanautils
import pytz
from flanautils import Media, NotFoundError, OrderedSet
from multibot import BadRoleError, DiscordBot, Role, User, bot_mentioned, constants as multibot_constants, group
from multibot import BadRoleError, DiscordBot, Platform, Role, User, bot_mentioned, constants as multibot_constants, group
from flanabot import constants
from flanabot.bots.flana_bot import FlanaBot
@@ -39,7 +39,8 @@ class FlanaDiscBot(DiscordBot, FlanaBot):
async def _changeable_roles(self, group_: int | str | Chat | Message) -> list[Role]:
group_id = self.get_group_id(group_)
return [role for role in await self.get_group_roles(group_) if role.id in constants.CHANGEABLE_ROLES[group_id]]
r = await self.get_group_roles(group_)
return [role for role in r if role.id in constants.CHANGEABLE_ROLES[Platform.DISCORD][group_id]]
async def _heat_channel(self, channel: discord.VoiceChannel):
async def set_fire_to(channel_key: str, depends_on: str, firewall=0):
@@ -60,9 +61,9 @@ class FlanaDiscBot(DiscordBot, FlanaBot):
await channels[channel_key]['object'].edit(name=new_name_)
channels = {}
for key in constants.DISCORD_HOT_CHANNEL_IDS:
channel_ = flanautils.find(channel.guild.voice_channels, condition=lambda c: c.id == constants.DISCORD_HOT_CHANNEL_IDS[key])
channels[key] = {
for letter, channel_id in constants.DISCORD_HOT_CHANNEL_IDS.items():
channel_ = flanautils.find(channel.guild.voice_channels, condition=lambda c: c.id == channel_id)
channels[letter] = {
'object': channel_,
'original_name': channel_.name,
'n_fires': 0
@@ -84,7 +85,10 @@ class FlanaDiscBot(DiscordBot, FlanaBot):
continue
i = int(self.heat_level)
if i < len(constants.DISCORD_HEAT_NAMES):
if not i:
n_fires = 0
new_name = channels['C']['original_name']
elif i < len(constants.DISCORD_HEAT_NAMES):
n_fires = 0
new_name = constants.DISCORD_HEAT_NAMES[i]
else:
@@ -113,7 +117,7 @@ class FlanaDiscBot(DiscordBot, FlanaBot):
message: Message,
force=False,
audio_only=False,
timeout_for_media: int | float = 15
timeout_for_media: int | float = constants.SCRAPING_TIMEOUT_SECONDS
) -> OrderedSet[Media]:
return await super()._search_medias(message, force, audio_only, timeout_for_media)

View File

@@ -10,6 +10,7 @@ import telethon.tl.functions
from flanautils import Media, OrderedSet
from multibot import TelegramBot, find_message, user_client
from flanabot import constants
from flanabot.bots.flana_bot import FlanaBot
from flanabot.models import Message
@@ -20,11 +21,11 @@ from flanabot.models import Message
def whitelisted(func: Callable) -> Callable:
@functools.wraps(func)
@find_message
async def wrapper(self: FlanaTeleBot, message: Message):
async def wrapper(self: FlanaTeleBot, message: Message, *args, **kwargs):
if message.author.id not in self.whitelist_ids:
return
return await func(self, message)
return await func(self, message, *args, **kwargs)
return wrapper
@@ -57,7 +58,7 @@ class FlanaTeleBot(TelegramBot, FlanaBot):
message: Message,
force=False,
audio_only=False,
timeout_for_media: int | float = 15
timeout_for_media: int | float = constants.SCRAPING_TIMEOUT_SECONDS
) -> OrderedSet[Media]:
return await super()._search_medias(message, force, audio_only, timeout_for_media)

View File

@@ -118,7 +118,7 @@ class PenaltyBot(MultiBot, ABC):
async def _on_ready(self):
await super()._on_ready()
await flanautils.do_every(constants.CHECK_PUNISHMENTS_EVERY_SECONDS, self.check_old_punishments)
flanautils.do_every(constants.CHECK_PUNISHMENTS_EVERY_SECONDS, self.check_old_punishments)
@bot_mentioned
@group

View File

@@ -1,15 +1,16 @@
__all__ = ['ScraperBot']
import asyncio
import datetime
import random
from abc import ABC
from collections import defaultdict
from typing import Iterable
import flanautils
from flanaapis import RedditMediaNotFoundError, instagram, reddit, tiktok, twitter, yt_dlp_wrapper
from flanaapis import InstagramMediaNotFoundError, RedditMediaNotFoundError, instagram, reddit, tiktok, twitter, yt_dlp_wrapper
from flanautils import Media, MediaType, OrderedSet, return_if_first_empty
from multibot import MultiBot, RegisteredCallback, SendError, constants as multibot_constants, reply
from multibot import MultiBot, RegisteredCallback, SendError, constants as multibot_constants, owner, reply
from flanabot import constants
from flanabot.models import Action, BotAction, Message
@@ -19,27 +20,27 @@ from flanabot.models import Action, BotAction, Message
# --------------------------------------------- SCRAPER_BOT --------------------------------------------- #
# ------------------------------------------------------------------------------------------------------- #
class ScraperBot(MultiBot, ABC):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.instagram_ban_date = None
# -------------------------------------------------------- #
# ------------------- PROTECTED METHODS ------------------ #
# -------------------------------------------------------- #
def _add_handlers(self):
super()._add_handlers()
self.register(self._on_force_scraping, constants.KEYWORDS['force'])
self.register(self._on_force_scraping, (constants.KEYWORDS['force'], constants.KEYWORDS['scraping']))
self.register(self._on_no_scraping, (multibot_constants.KEYWORDS['negate'], constants.KEYWORDS['scraping']))
self.register(self._on_force_scraping_audio, (constants.KEYWORDS['force'], multibot_constants.KEYWORDS['audio']))
self.register(self._on_force_scraping_audio, (constants.KEYWORDS['force'], multibot_constants.KEYWORDS['audio'], constants.KEYWORDS['scraping']))
self.register(self._on_no_delete_original, (multibot_constants.KEYWORDS['negate'], multibot_constants.KEYWORDS['delete']))
self.register(self._on_no_delete_original, (multibot_constants.KEYWORDS['negate'], multibot_constants.KEYWORDS['message']))
self.register(self._on_no_delete_original, (multibot_constants.KEYWORDS['negate'], multibot_constants.KEYWORDS['delete'], multibot_constants.KEYWORDS['message']))
self.register(self._on_no_delete_original, (multibot_constants.KEYWORDS['deactivate'], multibot_constants.KEYWORDS['delete'], multibot_constants.KEYWORDS['message']))
self.register(self._on_reset_instagram_ban, (multibot_constants.KEYWORDS['delete'], 'instagram'))
self.register(self._on_reset_instagram_ban, (multibot_constants.KEYWORDS['reset'], 'instagram'))
self.register(self._on_scraping, constants.KEYWORDS['scraping'])
self.register(self._on_scraping_audio, multibot_constants.KEYWORDS['audio'])
self.register(self._on_scraping_audio, (multibot_constants.KEYWORDS['audio'], constants.KEYWORDS['scraping']))
self.register(self._on_scraping, constants.KEYWORDS['force'])
self.register(self._on_scraping, multibot_constants.KEYWORDS['audio'])
self.register(lambda message: self._on_scraping(message, delete=False), (multibot_constants.KEYWORDS['negate'], multibot_constants.KEYWORDS['delete']))
self.register(lambda message: self._on_scraping(message, delete=False), (multibot_constants.KEYWORDS['negate'], multibot_constants.KEYWORDS['message']))
self.register(lambda message: self._on_scraping(message, delete=False), (multibot_constants.KEYWORDS['negate'], multibot_constants.KEYWORDS['delete'], multibot_constants.KEYWORDS['message']))
self.register(self._on_song_info, constants.KEYWORDS['song_info'])
@@ -53,9 +54,32 @@ class ScraperBot(MultiBot, ABC):
tiktok.find_download_urls(text)
)
@staticmethod
def _get_keywords(delete=True, force=False, full=False, audio_only=False) -> list[str]:
keywords = list(constants.KEYWORDS['scraping'])
if not delete:
keywords += [
*multibot_constants.KEYWORDS['negate'],
*multibot_constants.KEYWORDS['deactivate'],
*multibot_constants.KEYWORDS['delete'],
*multibot_constants.KEYWORDS['message']
]
if force:
keywords += constants.KEYWORDS['force']
if full:
keywords += ['sin', 'timeout', 'limite', *multibot_constants.KEYWORDS['all']]
if audio_only:
keywords += multibot_constants.KEYWORDS['audio']
return keywords
@staticmethod
def _medias_sended_info(medias: Iterable[Media]) -> str:
medias_count = defaultdict(lambda: defaultdict(int))
medias_count: dict = defaultdict(lambda: defaultdict(int))
for media in medias:
if not media.source or isinstance(media.source, str):
medias_count[media.source][media.type_] += 1
@@ -89,21 +113,28 @@ class ScraperBot(MultiBot, ABC):
new_line = ' ' if len(medias_sended_info) == 1 else '\n'
return f'{new_line}{medias_sended_info_joined}:'
async def _scrape_and_send(self, message: Message, force=False, audio_only=False) -> OrderedSet[Media]:
kwargs = {}
if self._parse_callbacks(
message.text,
[
RegisteredCallback(..., [['sin'], ['timeout', 'limite']]),
RegisteredCallback(..., 'completo entero full todo')
]
):
kwargs['timeout_for_media'] = None
async def _scrape_and_send(
self,
message: Message,
force=False,
full=False,
audio_only=False,
send_user_context=True,
keywords: list[str] = None,
sended_media_messages: OrderedSet[Message] = None
) -> OrderedSet[Message]:
if not keywords:
keywords = []
if sended_media_messages is None:
sended_media_messages = OrderedSet()
kwargs = {'timeout_for_media': None} if full else {}
if not (medias := await self._search_medias(message, force, audio_only, **kwargs)):
return OrderedSet()
sended_media_messages, _ = await self.send_medias(medias, message)
sended_media_messages = OrderedSet(sended_media_messages)
new_sended_media_messages, _ = await self.send_medias(medias, message, send_user_context=send_user_context, keywords=keywords)
sended_media_messages |= new_sended_media_messages
await self.send_inline_results(message)
@@ -113,23 +144,22 @@ class ScraperBot(MultiBot, ABC):
self,
message: Message,
force=False,
full=False,
audio_only=False,
sended_media_messages: OrderedSet[Media] = None
) -> OrderedSet[Media]:
send_user_context=True,
keywords: list[str] = None,
sended_media_messages: OrderedSet[Message] = None
) -> OrderedSet[Message]:
if not keywords:
keywords = []
if sended_media_messages is None:
sended_media_messages = OrderedSet()
sended_media_messages += await self._scrape_and_send(message, force, audio_only)
sended_media_messages += await self._scrape_and_send(message, force, full, audio_only, send_user_context, keywords)
if (
sended_media_messages
and
message.chat.is_group
and
message.chat.config['scraping_delete_original']
):
if sended_media_messages and message.chat.config['scraping_delete_original']:
# noinspection PyTypeChecker
BotAction(Action.MESSAGE_DELETED, message, affected_objects=[message, *sended_media_messages]).save()
BotAction(self.platform.value, Action.MESSAGE_DELETED, message, affected_objects=[message, *sended_media_messages]).save()
await self.delete_message(message)
return sended_media_messages
@@ -155,9 +185,8 @@ class ScraperBot(MultiBot, ABC):
if not any(ids) and flanautils.find_urls(text_part):
if force:
media_urls.append(text_part)
else:
if not any(domain.lower() in text_part for domain in multibot_constants.GIF_DOMAINS):
media_urls.append(text_part)
elif not any(domain.lower() in text_part for domain in multibot_constants.GIF_DOMAINS):
media_urls.append(text_part)
if not any(ids) and not media_urls:
return medias
@@ -188,18 +217,36 @@ class ScraperBot(MultiBot, ABC):
else:
media_urls.append(reddit_url)
gather_result = asyncio.gather(
gather_future = asyncio.gather(
twitter.get_medias(tweet_ids, audio_only),
instagram.get_medias(instagram_ids, audio_only),
tiktok.get_medias(tiktok_users_and_ids, tiktok_download_urls, 'h264', 'mp4', force, audio_only, timeout_for_media),
yt_dlp_wrapper.get_medias(media_urls, 'h264', 'mp4', force, audio_only, timeout_for_media),
return_exceptions=True
)
await gather_result
instagram_results = []
if instagram_ids:
can_instagram_v1 = not self.instagram_ban_date or datetime.datetime.now(datetime.timezone.utc) - self.instagram_ban_date >= constants.INSTAGRAM_BAN_SLEEP
if can_instagram_v1:
try:
instagram_results = await instagram.get_medias(instagram_ids, audio_only)
except InstagramMediaNotFoundError:
pass
if not instagram_results:
try:
instagram_results = await instagram.get_medias_v2(instagram_ids, audio_only)
except InstagramMediaNotFoundError as e:
if not (instagram_results := await yt_dlp_wrapper.get_medias(instagram.make_urls(instagram_ids), 'h264', 'mp4', force, audio_only, timeout_for_media)):
exceptions.append(e)
if instagram_results and can_instagram_v1:
self.instagram_ban_date = datetime.datetime.now(datetime.timezone.utc)
await self.send('Límite de Instagram excedido.', await self.owner_chat)
gather_results = await gather_future
await self.delete_message(bot_state_message)
gather_medias, gather_exceptions = flanautils.filter_exceptions(gather_result.result())
gather_medias, gather_exceptions = flanautils.filter_exceptions(gather_results + instagram_results)
await self._manage_exceptions(exceptions + gather_exceptions, message, print_traceback=True)
return medias | gather_medias
@@ -207,31 +254,91 @@ class ScraperBot(MultiBot, ABC):
# ---------------------------------------------- #
# HANDLERS #
# ---------------------------------------------- #
async def _on_force_scraping(self, message: Message) -> OrderedSet[Media]:
return await self._on_scraping(message, force=True)
async def _on_force_scraping_audio(self, message: Message) -> OrderedSet[Media]:
return await self._on_scraping(message, force=True, audio_only=True)
async def _on_no_delete_original(self, message: Message):
if not await self._scrape_and_send(message):
await self._on_recover_message(message)
async def _on_no_scraping(self, message: Message):
pass
async def _on_recover_message(self, message: Message):
pass
async def _on_scraping(self, message: Message, force=False, audio_only=False) -> OrderedSet[Media]:
@owner
async def _on_reset_instagram_ban(self, message: Message):
if message.chat.is_group and not self.is_bot_mentioned(message):
return
self.instagram_ban_date = None
bot_message = await self.send('Ban de Instagram reseteado.', message)
await self.delete_message(message)
flanautils.do_later(multibot_constants.COMMAND_MESSAGE_DURATION, self.delete_message, bot_message)
async def _on_scraping(
self,
message: Message,
delete=True,
force: bool = None,
full: bool = None,
audio_only: bool = None,
scrape_replied=True,
) -> OrderedSet[Message]:
sended_media_messages = OrderedSet()
if not message.chat.config['auto_scraping'] and not self.is_bot_mentioned(message):
return sended_media_messages
if message.replied_message:
sended_media_messages += await self._scrape_and_send(message.replied_message, force, audio_only)
if force is None:
force = bool(
flanautils.cartesian_product_string_matching(
message.text,
constants.KEYWORDS['force'],
multibot_constants.PARSER_MIN_SCORE_DEFAULT
)
)
return await self._scrape_send_and_delete(message, force, audio_only, sended_media_messages)
if full is None:
full = bool(
self._parse_callbacks(
message.text,
[
RegisteredCallback(..., (('sin',), ('timeout', 'limite'))),
RegisteredCallback(..., multibot_constants.KEYWORDS['all'])
]
)
)
async def _on_scraping_audio(self, message: Message) -> OrderedSet[Media]:
return await self._on_scraping(message, audio_only=True)
if audio_only is None:
audio_only = bool(
flanautils.cartesian_product_string_matching(
message.text,
multibot_constants.KEYWORDS['audio'],
multibot_constants.PARSER_MIN_SCORE_DEFAULT
)
)
keywords = self._get_keywords(delete, force, full, audio_only)
if scrape_replied and message.replied_message:
sended_media_messages += await self._scrape_and_send(
message.replied_message,
force,
full,
audio_only,
send_user_context=False
)
kwargs = {
'message': message,
'force': force,
'full': full,
'audio_only': audio_only,
'keywords': keywords,
'sended_media_messages': sended_media_messages
}
if delete:
sended_media_messages |= await self._scrape_send_and_delete(**kwargs)
else:
sended_media_messages |= await self._scrape_and_send(**kwargs)
if not sended_media_messages:
await self._on_recover_message(message)
return sended_media_messages
@reply
async def _on_song_info(self, message: Message):
@@ -247,7 +354,17 @@ class ScraperBot(MultiBot, ABC):
# -------------------- PUBLIC METHODS -------------------- #
# -------------------------------------------------------- #
@return_if_first_empty(([], 0), exclude_self_types='ScraperBot', globals_=globals())
async def send_medias(self, medias: OrderedSet[Media], message: Message, send_song_info=False) -> tuple[list[Message], int]:
async def send_medias(
self,
medias: OrderedSet[Media],
message: Message,
send_song_info=False,
send_user_context=True,
keywords: list[str] = None
) -> tuple[list[Message], int]:
if not keywords:
keywords = []
sended_media_messages = []
fails = 0
bot_state_message: Message | None = None
@@ -259,29 +376,22 @@ class ScraperBot(MultiBot, ABC):
if message.chat.is_group:
sended_info_message = await self.send(f"{message.author.name.split('#')[0]} compartió{self._medias_sended_info(medias)}", message, reply_to=message.replied_message)
user_text = ' '.join(
[word for word in message.text.split()
if (
not any(await self._find_ids(word))
and
not flanautils.find_urls(word)
and
not flanautils.cartesian_product_string_matching(
word,
(
*multibot_constants.KEYWORDS['audio'],
*multibot_constants.KEYWORDS['delete'],
*constants.KEYWORDS['force'],
*multibot_constants.KEYWORDS['negate'],
*constants.KEYWORDS['scraping']
),
multibot_constants.PARSER_MIN_SCORE_DEFAULT
)
and
flanautils.remove_symbols(word).lower() not in (str(self.id), self.name.lower())
)]
)
if user_text:
if (
send_user_context
and
(user_text := ' '.join(
[word for word in message.text.split()
if (
not any(await self._find_ids(word))
and
not flanautils.find_urls(word)
and
not flanautils.cartesian_product_string_matching(word, keywords, multibot_constants.PARSER_MIN_SCORE_DEFAULT)
and
flanautils.remove_symbols(word).lower() not in (str(self.id), self.name.lower())
)]
))
):
user_text_bot_message = await self.send(user_text, message, reply_to=message.replied_message)
for media in medias:
@@ -318,10 +428,10 @@ class ScraperBot(MultiBot, ABC):
@return_if_first_empty(exclude_self_types='ScraperBot', globals_=globals())
async def send_song_info(self, song_info: Media, message: Message):
attributes = (
f'Título: {song_info.title}\n' if song_info.title else '',
f'Autor: {song_info.author}\n' if song_info.author else '',
f'Álbum: {song_info.album}\n' if song_info.album else '',
f'Previa:'
f'<b>Título:</b> {song_info.title}\n' if song_info.title else '',
f'<b>Autor:</b> {song_info.author}\n' if song_info.author else '',
f'<b>Álbum:</b> {song_info.album}\n' if song_info.album else '',
f'<b>Previa:</b>'
)
await self.send(''.join(attributes), message)
if song_info:

View File

@@ -0,0 +1,178 @@
__all__ = ['UberEatsBot']
import asyncio
import datetime
import random
from abc import ABC
from collections import defaultdict
import flanautils
import playwright.async_api
from multibot import MultiBot, group
import constants
from flanabot.models import Chat, Message
# ---------------------------------------------------------------------------------------------------- #
# --------------------------------------------- POLL_BOT --------------------------------------------- #
# ---------------------------------------------------------------------------------------------------- #
class UberEatsBot(MultiBot, ABC):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.playwright: playwright.async_api.Playwright | None = None
self.browser: playwright.async_api.Browser | None = None
self.task_contexts: dict[int, dict] = defaultdict(lambda: defaultdict(lambda: None))
# -------------------------------------------------------- #
# ------------------- PROTECTED METHODS ------------------ #
# -------------------------------------------------------- #
def _add_handlers(self):
super()._add_handlers()
self.register(self._on_ubereats, 'ubereats', priority=2)
async def _cancel_scraping_task(self, chat: Chat):
if not (task := self.task_contexts[chat.id]['task']) or task.done():
return
await self._close_playwright(chat)
task.cancel()
del self.task_contexts[chat.id]
async def _close_playwright(self, chat: Chat):
if browser := self.task_contexts[chat.id]['browser']:
await browser.close()
if playwright_ := self.task_contexts[chat.id]['playwright']:
await playwright_.stop()
async def _scrape_codes(self, chat: Chat) -> list[str | None]:
async def get_code() -> str:
return await page.input_value("input[class='code toCopy']")
codes: list[str | None] = [None] * len(chat.ubereats['cookies'])
async with playwright.async_api.async_playwright() as playwright_:
self.task_contexts[chat.id]['playwright'] = playwright_
for i, cookies in enumerate(chat.ubereats['cookies']):
for _ in range(3):
try:
async with await playwright_.chromium.launch() as browser:
self.task_contexts[chat.id]['browser'] = browser
context: playwright.async_api.BrowserContext = await browser.new_context(
storage_state={'cookies': cookies},
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.5615.49 Safari/537.36',
screen={
'width': 1920,
'height': 1080
},
viewport={
'width': 1280,
'height': 720
},
device_scale_factor=1,
is_mobile=False,
has_touch=False,
default_browser_type='chromium',
locale='es-ES'
)
context.set_default_timeout(3000)
page = await context.new_page()
await page.goto('https://www.myunidays.com/ES/es-ES/partners/ubereats/access/online', timeout=30000)
if button := await page.query_selector("button[class='button highlight']"):
await button.click()
else:
await page.click("'Revelar código'")
for _ in range(5):
if len(context.pages) == 2:
break
await asyncio.sleep(0.5)
else:
continue
page = context.pages[1]
await page.wait_for_load_state()
code = await get_code()
if not (new_code_button := await page.query_selector("button[class='getNewCode button secondary']")):
new_code_button = page.locator("'Obtener nuevo código'")
if await new_code_button.is_enabled():
await new_code_button.click()
for _ in range(5):
if (new_code := await get_code()) != code:
code = new_code
break
await asyncio.sleep(0.5)
codes[i] = code
chat.ubereats['cookies'][i] = await context.cookies('https://www.myunidays.com')
except playwright.async_api.Error:
await asyncio.sleep(1)
else:
break
return codes
# ---------------------------------------------- #
# HANDLERS #
# ---------------------------------------------- #
@group(False)
async def _on_ubereats(self, message: Message):
if not message.chat.ubereats['cookies']:
return
time = flanautils.text_to_time(message.text)
if not time:
bot_state_message = await self.send(random.choice(constants.SCRAPING_PHRASES), message)
await self.send_ubereats_code(message.chat, update_next_execution=False)
await self.delete_message(bot_state_message)
return
if time < datetime.timedelta(days=1, minutes=5):
await self.send('El mínimo es 1 día y 5 minutos.', message)
return
seconds = int(time.total_seconds())
message.chat.ubereats['seconds'] = seconds
message.save()
period = flanautils.TimeUnits(seconds=seconds)
await self.send(f'A partir de ahora te enviaré un código de UberEats cada <b>{period.to_words()}</b>.', message)
await self.start_ubereats(message.chat)
# -------------------------------------------------------- #
# -------------------- PUBLIC METHODS -------------------- #
# -------------------------------------------------------- #
async def send_ubereats_code(self, chat: Chat, update_next_execution=True):
chat.pull_from_database(overwrite_fields=('ubereats',))
codes = await self._scrape_codes(chat)
for i, code in enumerate(codes):
if code:
if code in chat.ubereats['last_codes']:
warning_text = '<i>Código ya enviado anteriormente:</i> '
else:
warning_text = ''
await self.send(f'{warning_text}<code>{code}</code>', chat, silent=True)
else:
try:
codes[i] = chat.ubereats['last_codes'][i]
except IndexError:
codes[i] = None
chat.ubereats['last_codes'] = codes
if update_next_execution:
chat.ubereats['next_execution'] = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=chat.ubereats['seconds'])
chat.save()
async def start_ubereats(self, chat: Chat, send_code_now=True):
await self._cancel_scraping_task(chat)
chat.config['ubereats'] = True
chat.save(pull_overwrite_fields=('ubereats',))
self.task_contexts[chat.id]['task'] = flanautils.do_every(chat.ubereats['seconds'], self.send_ubereats_code, chat, do_first_now=send_code_now)
async def stop_ubereats(self, chat: Chat):
await self._cancel_scraping_task(chat)
chat.config['ubereats'] = False
chat.save(pull_overwrite_fields=('ubereats',))

View File

@@ -40,7 +40,7 @@ class WeatherBot(MultiBot, ABC):
show_progress_state = False
elif message.chat.is_group and not self.is_bot_mentioned(message):
if message.chat.config['auto_weather_chart']:
if BotAction.find_one({'action': Action.AUTO_WEATHER_CHART.value, 'chat': message.chat.object_id, 'date': {'$gt': datetime.datetime.now(datetime.timezone.utc) - constants.AUTO_WEATHER_EVERY}}):
if BotAction.find_one({'platform': self.platform.value, 'action': Action.AUTO_WEATHER_CHART.value, 'chat': message.chat.object_id, 'date': {'$gt': datetime.datetime.now(datetime.timezone.utc) - constants.AUTO_WEATHER_EVERY}}):
return
show_progress_state = False
else:
@@ -161,7 +161,7 @@ class WeatherBot(MultiBot, ABC):
if bot_message and not self.is_bot_mentioned(message):
# noinspection PyTypeChecker
BotAction(Action.AUTO_WEATHER_CHART, message, affected_objects=[bot_message]).save()
BotAction(self.platform.value, Action.AUTO_WEATHER_CHART, message, affected_objects=[bot_message]).save()
async def _on_weather_button_press(self, message: Message):
await self.accept_button_event(message)

View File

@@ -26,7 +26,7 @@ FONT_SIZE = 32 * SIZE_MULTIPLIER
TABLE_LINE_WIDTH = 4 * SIZE_MULTIPLIER
BLUE = (66 / 255, 135 / 255, 245 / 255)
BACKGROUND_COLOR = (54 / 255, 57 / 255, 63 / 255)
BACKGROUND_COLOR = (49 / 255, 51 / 255, 56 / 255)
GRAY = (200 / 255, 200 / 255, 200 / 255)
HIGHLIGHT_COLOR = (104 / 255, 107 / 255, 113 / 255)
RED = (255 / 255, 70 / 255, 70 / 255)

View File

@@ -11,15 +11,17 @@ CONNECT_4_AI_DELAY_SECONDS = 1
CONNECT_4_CENTER_COLUMN_POINTS = 2
CONNECT_4_N_COLUMNS = 7
CONNECT_4_N_ROWS = 6
FLOOD_2s_LIMIT = 2
FLOOD_7s_LIMIT = 4
HEAT_PERIOD_SECONDS = datetime.timedelta(minutes=15).total_seconds()
HELP_MINUTES_LIMIT = 1
INSTAGRAM_BAN_SLEEP = datetime.timedelta(days=1)
INSULT_PROBABILITY = 0.00166666667
MAX_PLACE_QUERY_LENGTH = 50
PUNISHMENT_INCREMENT_EXPONENT = 6
PUNISHMENTS_RESET_TIME = datetime.timedelta(weeks=2)
RECOVERY_DELETED_MESSAGE_BEFORE = datetime.timedelta(hours=1)
SCRAPING_TIMEOUT_SECONDS = 10
BYE_PHRASES = ('Adiós.', 'adio', 'adioh', 'adios', 'adió', 'adiós', 'agur', 'bye', 'byyeeee', 'chao', 'hasta la vista',
'hasta luego', 'hasta nunca', ' hasta pronto', 'hasta la próxima', 'nos vemos', 'taluego')
@@ -38,7 +40,6 @@ CHANGEABLE_ROLES = defaultdict(
)
DISCORD_HEAT_NAMES = [
'Canal Congelado',
'Canal Fresquito',
'Canal Templaillo',
'Canal Calentito',
@@ -96,12 +97,12 @@ KEYWORDS = {
'fusila', 'hell', 'humos', 'infierno', 'jefe', 'jode', 'learn', 'leccion', 'lesson', 'manda', 'paliza',
'purgatorio', 'purgatory', 'sancion', 'shoot', 'teach', 'whip'),
'random': ('aleatorio', 'azar', 'random'),
'scraping': ('api', 'aqui', 'busca', 'contenido', 'content', 'descarga', 'descargar', 'download', 'envia', 'habia',
'media', 'redes', 'scrap', 'scraping', 'search', 'send', 'social', 'sociales', 'tenia', 'video',
'videos'),
'scraping': ('busca', 'contenido', 'content', 'descarga', 'descargar', 'descargues', 'download', 'envia', 'scrap',
'scrapea', 'scrapees', 'scraping', 'search', 'send'),
'self': (('contigo', 'contra', 'ti'), ('mismo', 'ti')),
'song_info': ('aqui', 'cancion', 'data', 'datos', 'info', 'informacion', 'information', 'llama', 'media', 'name',
'nombre', 'sonaba', 'sonando', 'song', 'sono', 'sound', 'suena', 'title', 'titulo', 'video'),
'song_info': ('cancion', 'data', 'datos', 'info', 'informacion', 'information', 'sonaba', 'sonando', 'song', 'sono',
'sound', 'suena'),
'tunnel': ('canal', 'channel', 'tunel', 'tunnel'),
'unpunish': ('absolve', 'forgive', 'innocent', 'inocente', 'perdona', 'spare'),
'vote': ('votacion', 'votar', 'vote', 'voting', 'voto'),
'weather': ('atmosfera', 'atmosferico', 'calle', 'calor', 'caloret', 'clima', 'climatologia', 'cloud', 'cloudless',

View File

@@ -4,7 +4,7 @@ import datetime
from dataclasses import dataclass, field
from flanautils import DCMongoBase, FlanaBase
from multibot.models.user import User
from multibot import Platform, User
from flanabot.models.chat import Chat
from flanabot.models.enums import Action
@@ -17,6 +17,7 @@ class BotAction(DCMongoBase, FlanaBase):
unique_keys = 'message'
nullable_unique_keys = 'message'
platform: Platform = None
action: Action = None
message: Message = None
author: User = None

View File

@@ -7,17 +7,18 @@ from multibot import Chat as MultiBotChat
@dataclass(eq=False)
class Chat(MultiBotChat):
DEFAULT_CONFIG = {
config: dict = field(default_factory=lambda: {
'auto_insult': True,
'auto_scraping': True,
'auto_weather_chart': False,
'check_flood': False,
'punish': False,
'scraping_delete_original': True
}
config: dict[str, bool] = field(default_factory=dict)
def __post_init__(self):
super().__post_init__()
self.config = self.DEFAULT_CONFIG | self.config
'scraping_delete_original': True,
'ubereats': False
})
ubereats: dict = field(default_factory=lambda: {
'cookies': [],
'last_codes': [],
'seconds': 86700,
'next_execution': None
})

View File

@@ -10,7 +10,7 @@ charset-normalizer==2.1.1
click==8.1.3
colorama==0.4.6
cryptg==0.4.0
discord.py==2.1.0
discord.py==2.2.2
dnspython==2.2.1
fastapi==0.89.1
flanaapis
@@ -28,7 +28,7 @@ multibot
multidict==6.0.4
mutagen==1.46.0
Pillow==9.4.0
playwright==1.29.1
playwright==1.17.2
plotly==5.11.0
pyaes==1.6.1
pyasn1==0.4.8
@@ -45,7 +45,7 @@ sniffio==1.3.0
soupsieve==2.3.2.post1
starlette==0.22.0
sympy==1.11.1
Telethon==1.26.1
Telethon==1.27.0
tenacity==8.1.0
twitchio==2.5.0
typing_extensions==4.4.0
@@ -54,4 +54,4 @@ urllib3==1.26.13
uvicorn==0.20.0
websockets==10.4
yarl==1.8.2
yt-dlp==2023.1.6
yt-dlp==2023.3.4

View File

@@ -2,7 +2,6 @@
name = {project_name}
version = {project_version}
author = {author}
author_email = alberlc@outlook.com
description = {description}
long_description = file: README.rst
url = https://github.com/{author}/{project_name}