def calculate_tax(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: USAGE = localized_string(lang, "taxUsage") if not data: return USAGE parts = data.split() if len(parts) < 2: return localized_string(lang, "taxUsage") amount = safe_int(parts[0], 0) if amount == 0: return USAGE query = " ".join(parts[1:]) tax_amount = EFT.check_tax(lang, amount, query) if not tax_amount: return USAGE (tax, model) = tax_amount profit = amount - tax return localized_string( lang, "twitch_tax", model.name, format(int(amount), ","), format(int(tax), ","), format(int(profit), ","), maya.MayaDT.from_datetime(model.updated).slang_time(), ) except Exception as e: print(e) return localized_string( lang, "searchFailed", )
def bot_astat(self, ctx: CommandContext, data: str) -> Union[str, discord.Embed]: log.info("%s - searching for %s (new)\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: astat = EFT.check_astat(lang, data) embed = discord.Embed( title=astat.name, url=astat.wikiLink, description=astat.description, color=0x780A81, ) embed.set_thumbnail( url="https://static.tarkov-database.com/image/icon/1-1/{0}.png" .format(astat.bsgID)) embed.add_field( name=localized_string(lang, "ammoFlesh"), value=astat.damage, inline=True, ) embed.add_field( name=localized_string(lang, "ammoPen"), value=astat.penetration, inline=True, ) embed.add_field( name=localized_string(lang, "ammoArmor"), value=astat.armorDamage, inline=True, ) embed.add_field( name=localized_string(lang, "ammoAccuracy"), value=astat.accuracy, inline=True, ) embed.add_field( name=localized_string(lang, "ammoRecoil"), value=astat.recoil, inline=True, ) embed.add_field( name=localized_string(lang, "ammoFrag"), value=astat.fragmentation, inline=True, ) return embed except: embed = discord.Embed( title="LogicEFTBot - Error", color=0x780A81, ) embed.set_thumbnail(url="https://illogical.network/api/error.png") embed.add_field( name="Invalid Item Search", value= "You've entered in an invalid ammo item ; please try again.", inline=True, ) return embed
def bot_price(self, ctx: CommandContext, data: str) -> Union[str, discord.Embed]: log.info("%s - searching for %s (new)\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: price = EFT.check_price(lang, data) embed = discord.Embed( title=price.name, url=price.wikiLink, color=0x780A81, ) embed.set_thumbnail(url=price.img) embed.add_field( name=localized_string(lang, "marketPrice"), value=format(int(price.price), ","), inline=True, ) embed.add_field( name=localized_string(lang, "marketTrader"), value=price.traderName, inline=True, ) embed.add_field( name=localized_string(lang, "marketTraderPrice"), value=format(int(price.traderPrice), ","), inline=True, ) embed.add_field( name=localized_string(lang, "marketSlot"), value=format(round((price.price / price.slots)), ","), inline=True, ) embed.add_field( name=localized_string(lang, "market7dAvg"), value=format(int(price.avg7daysPrice), ","), inline=True, ) embed.add_field( name=localized_string(lang, "market24hAvg"), value=format(int(price.avg24hPrice), ","), inline=True, ) embed.set_footer( text=localized_string(lang, "marketUpdated") + maya.MayaDT.from_datetime(price.updated).slang_time()) return embed except: embed = discord.Embed( title="LogicEFTBot - Error", color=0x780A81, ) embed.set_thumbnail(url="https://illogical.network/api/error.png") embed.add_field( name="Invalid Item Search", value="You've entered in an invalid item ; please try again.", inline=True, ) return embed
def calculate_tax(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: USAGE = localized_string(lang, "taxUsage") if not data: return USAGE parts = data.split() if len(parts) < 2: return localized_string(lang, "taxUsage") amount = safe_int(parts[0], 0) if amount == 0: return USAGE query = " ".join(parts[1:]) tax_amount = EFT.check_tax(lang, amount, query) if not tax_amount: return USAGE (tax, model) = tax_amount profit = amount - tax embed = discord.Embed( title=model.name, url=model.wikiLink, color=0x780A81, ) embed.set_thumbnail(url=model.img) embed.add_field( name=localized_string(lang, "taxBasePrice"), value=format(int(model.basePrice), ",") + " ₽", inline=True, ) embed.add_field( name=localized_string(lang, "taxBaseTax"), value=format(int(tax), ",") + " ₽", inline=True, ) embed.add_field( name=localized_string(lang, "taxProfit"), value=format(int(profit), ",") + " ₽", inline=True, ) embed.set_footer( text=localized_string(lang, "marketUpdated") + maya.MayaDT.from_datetime(model.updated).slang_time()) return embed except: embed = discord.Embed( title="LogicEFTBot - Error", color=0x780A81, ) embed.set_thumbnail(url="https://illogical.network/api/error.png") embed.add_field( name="Invalid Item Search", value= "You've entered in an invalid map name ; please try again.", inline=True, ) return embed
def bot_wiki(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) wiki = EFT.check_price(lang, data) try: return localized_string(lang, "twitch_wiki", wiki.name, wiki.wikiLink) except: return localized_string( lang, "searchFailed", )
def bot_profit(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: return localized_string( lang, "twitch_profit", ) except: return localized_string( lang, "searchFailed", )
def __init__(self) -> None: log.info("Connecting to MySQL...") db = mysql.connect( host=settings["database_config"]["host"], user=settings["database_config"]["user"], passwd=settings["database_config"]["passwd"], database=settings["database_config"]["database"], ) log.info("Connected.") sql = db.cursor(buffered=True) db.commit() self.db = db self.sql = sql
def on_welcome(self, connection, event): # Request specific capabilities before you can use them connection.cap("REQ", ":twitch.tv/membership") connection.cap("REQ", ":twitch.tv/tags") connection.cap("REQ", ":twitch.tv/commands") self.is_welcome = True # we've received welcome. self.message = "Running" if self.enqueued_channels: log.info("Joining %d channels", len(self.enqueued_channels)) for chan in self.enqueued_channels: self.do_join(chan) self.enqueued_channels = []
def bot_kappaquest(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: kappa = EFT.check_kappaquests(lang, data) return localized_string( lang, "twitch_kappaQuests", kappa.isReq, kappa.name, ) except: return localized_string( lang, "searchFailed", )
def bot_avg24h(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: avg24h = EFT.check_price(lang, data) return localized_string( lang, "twitch_avg24h", avg24h.name, format(int(avg24h.avg24hPrice), ","), maya.MayaDT.from_datetime(avg24h.updated).slang_time(), ) except: return localized_string( lang, "searchFailed", )
def bot_astat(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: astat = EFT.check_astat(lang, data) return localized_string( lang, "twitch_astat", astat.name, astat.damage, astat.penetration, ) except: return localized_string( lang, "searchFailed", )
def bot_medical(self, ctx: CommandContext, data: str) -> Union[str, discord.Embed]: log.info("%s - searching for %s (new)\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: medical = EFT.check_medical(lang, data) embed = discord.Embed( title=medical.name, url=medical.wikiLink, description=medical.description, color=0x780A81, ) embed.set_thumbnail( url="https://static.tarkov-database.com/image/icon/1-1/{0}.png" .format(medical.bsgID)) embed.add_field( name=localized_string(lang, "medUseTime"), value=medical.useTime, inline=True, ) embed.add_field( name=localized_string(lang, "maxItemHP"), value=medical.resources, inline=True, ) embed.add_field( name=localized_string(lang, "maxHealPerUse"), value=medical.resourceRate, inline=True, ) return embed except: embed = discord.Embed( title="LogicEFTBot - Error", color=0x780A81, ) embed.set_thumbnail(url="https://illogical.network/api/error.png") embed.add_field( name="Invalid Item Search", value= "You've entered in an invalid medical item ; please try again.", inline=True, ) return embed
def bot_trader(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) trader = EFT.check_price(lang, data) try: return localized_string( lang, "twitch_trader", trader.name, trader.traderName, format(int(trader.traderPrice), ","), maya.MayaDT.from_datetime(trader.updated).slang_time(), ) except: return localized_string( lang, "searchFailed", )
def bot_armor(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: armor = EFT.check_armor(lang, data) return localized_string( lang, "twitch_armor", armor.armorName, armor.armorClass, armor.armorDurability, armor.armorZones, ) except: return localized_string( lang, "searchFailed", )
def bot_maps(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: maps = EFT.check_maps(lang, data) return localized_string( lang, "twitch_maps", maps.name, maps.duration, maps.players, maps.enemies, ) except: return localized_string( lang, "searchFailed", )
def bot_slot(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: slot = EFT.check_price(lang, data) return localized_string( lang, "twitch_slot", slot.name, format(int((slot.price / slot.slots)), ","), maya.MayaDT.from_datetime(slot.updated).slang_time(), ) except Exception as e: print(e) return localized_string( lang, "searchFailed", )
def bot_medical(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: medical = EFT.check_medical(lang, data) return localized_string( lang, "twitch_medical", medical.name, medical.useTime, medical.resources, medical.resourceRate, ) except: return localized_string( lang, "searchFailed", )
def bot_helmet(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: helmet = EFT.check_helmets(lang, data) return localized_string( lang, "twitch_helmet", helmet.name, helmet.armorClass, helmet.armorDurability, helmet.armorRico, helmet.armorZones, ) except: return localized_string( lang, "searchFailed", )
def bot_maps(self, ctx: CommandContext, data: str) -> Union[str, discord.Embed]: log.info("%s - searching for %s (new)\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: maps = EFT.check_maps(lang, data) embed = discord.Embed( title=maps.name, url=maps.wikiLink, description=maps.features, color=0x780A81, ) embed.set_thumbnail(url="https://eft.bot/images/wiki/{0}.png". format(maps.shortName)) embed.add_field( name=localized_string(lang, "mapPlayers"), value=maps.players, inline=True, ) embed.add_field( name=localized_string(lang, "mapDuration"), value=maps.duration, inline=True, ) embed.add_field( name=localized_string(lang, "mapEnemies"), value=maps.enemies, inline=True, ) return embed except: embed = discord.Embed( title="LogicEFTBot - Error", color=0x780A81, ) embed.set_thumbnail(url="https://illogical.network/api/error.png") embed.add_field( name="Invalid Item Search", value= "You've entered in an invalid map name ; please try again.", inline=True, ) return embed
def observe_db(): joined_channels = set() """ A watchdog thread that checks for new channels being added to the DB. If new channels are added, this thread one of the twitch bot subprocesses to join the channel and listen for messages. The db observer thread runs on the MAIN PROCESS. It's """ global ALL_SHARDS_INFO global SHUTDOWN_INITIATED while not SHUTDOWN_INITIATED.isSet(): time.sleep(4) # wait a few seconds. ALL_SHARDS_INFO["db"] = ShardUpdate(status="Refreshing", message="Loading Channels From DB") all_channels = DB.get_channels() ALL_SHARDS_INFO["db"] = ShardUpdate( status="Refreshing", message=f"Refreshing {len(all_channels)} Channels") for i, channel in enumerate(all_channels): # TODO: We should use the tracked channels by the IRC bot. if channel not in joined_channels: target_shards = get_unsaturated_shards() target_shard = target_shards[i % len(target_shards)] target_shard.join_channel(channel) joined_channels.add(channel) if (i % int(settings["init_pack_size"])) == 0 and i > 0: # take a break! sleep_time = int(settings["init_pack_wait_s"]) ALL_SHARDS_INFO["db"] = ShardUpdate( status="Refreshing", message=f"Sleeping for {sleep_time} seconds") SHUTDOWN_INITIATED.wait(sleep_time) if SHUTDOWN_INITIATED.isSet(): continue if SHUTDOWN_INITIATED.isSet(): continue ALL_SHARDS_INFO["db"] = ShardUpdate(status="Sleeping", message="") SHUTDOWN_INITIATED.wait(int(settings["db_observe_frequency"])) ALL_SHARDS_INFO["db"] = ShardUpdate(status="Exited", message=f"Shutdown complete.") log.info("Stopped DB observer.")
def bot_armorstats(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: armor = EFT.check_armor(lang, data) return localized_string( lang, "twitch_armorstats", armor.armorName, armor.armorEffectiveDurability, armor.armorMoveSpeed, armor.armorTurnSpeed, armor.armorErgo, ) except Exception as e: print(e) return localized_string( lang, "searchFailed", )
def bot_helmetstats(self, ctx: CommandContext, data: str) -> str: log.info("%s - searching for %s\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: helmet = EFT.check_helmets(lang, data) return localized_string( lang, "twitch_helmetstats", helmet.name, helmet.armorMoveSpeed, helmet.armorTurnSpeed, helmet.armorErgo, helmet.helmetSoundReduc, helmet.helmetBlocksHeadset, ) except: return localized_string( lang, "searchFailed", )
def observe_db(): """ A watchdog thread that checks for new channels being added to the DB. If new channels are added, this thread asks the twitch bot to join the channel and listen for messages. """ while DB_OBSERVER_THREAD_LIVE: time.sleep(4) # wait a few seconds. #log.info("[observe_db] Scanning for new channels in DB.\n") # load all channels from db. all_channels = db.get_channels() for channel in all_channels: if channel not in channels: # join the channel + add to tracked channels. # TODO: We should use the tracked channels by the IRC bot, # and not the 'channels' list. TWITCH_BOT.do_join(channel) channels.append(channel) # wait until next time. time.sleep(int(settings["db_observe_frequency"])) log.info("Stopped DB observer.")
def do_join(self, channel: str) -> None: if channel in self.joined_channels: # already joined return if not self.connection.connected: # save this for later, when we actually connect if self.is_welcome: log.info( "ERROR: We've been rate limited. ------------------------------------" ) return self.enqueued_channels.append(channel) else: # join immediately log.info("Joining '#%s'", channel) self.status = ":rocket: Joining" self.message = f"#{channel}" self.connection.join("#" + channel) self.joined_channels.add(channel) self.status = ":white_heavy_check_mark: Healthy" self.message = "Connected"
def signal_handler(sig, frame): # Stop the DB Observer. global SHUTDOWN_INITIATED global DB_OBSERVER_THREAD global ABORT_STARTUP global SHUTDOWN_COMPLETE log.info("Stopping DB observer...") SHUTDOWN_INITIATED.set() ABORT_STARTUP = True if DB_OBSERVER_THREAD: DB_OBSERVER_THREAD.join() log.info("Stopping shards...") for i, shard in enumerate(ALL_SHARDS): shard.queue.put(END_OF_LIFE) # end-of-life signal. shard.process.join() log.info("Goodbye.") SHUTDOWN_COMPLETE = True
def on_welcome(self, connection, event): log.info('Received welcome.') log.info('Joining (%s) channels.', len(channels)) # Request specific capabilities before you can use them connection.cap('REQ', ':twitch.tv/membership') connection.cap('REQ', ':twitch.tv/tags') connection.cap('REQ', ':twitch.tv/commands') # Rejoin all the channels this bot should be in. for i, channel in enumerate(channels): self.do_join(channel) log.info('Joining `#%s`', channel) if (i > 0) and (i % int(settings["init_pack_size"]) == 0): # wait a bit before connecting more. # twitch rate-limits bots from the amount of JOIN commands # they can issue. time.sleep(int(settings["init_pack_wait_s"]))
def signal_handler(sig, frame): log.info("Received request to kill bot.") os._exit(0)
def bot_helmet(self, ctx: CommandContext, data: str) -> Union[str, discord.Embed]: log.info("%s - searching for %s (new)\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: helmet = EFT.check_helmets(lang, data) embed = discord.Embed( title=helmet.name, url=helmet.wikiLink, description=helmet.description, color=0x780A81, ) embed.set_thumbnail( url="https://static.tarkov-database.com/image/icon/1-1/{0}.png" .format(helmet.bsgID)) embed.add_field( name=localized_string(lang, "helmetZones"), value=helmet.armorZones, inline=True, ) embed.add_field( name=localized_string(lang, "helmetClass"), value=helmet.armorClass, inline=True, ) embed.add_field( name=localized_string(lang, "helmetDurability"), value=helmet.armorDurability, inline=True, ) embed.add_field( name=localized_string(lang, "helmetRicochet"), value=helmet.armorRico, inline=True, ) embed.add_field( name=localized_string(lang, "helmetMoveSpeed"), value=helmet.armorMoveSpeed, inline=True, ) embed.add_field( name=localized_string(lang, "helmetTurnSpeed"), value=helmet.armorTurnSpeed, inline=True, ) embed.add_field( name=localized_string(lang, "helmetErgo"), value=helmet.armorErgo, inline=True, ) embed.add_field( name=localized_string(lang, "helmetSoundReduc"), value=helmet.helmetSoundReduc, inline=True, ) embed.add_field( name=localized_string(lang, "helmetBlocksHeadset"), value=helmet.helmetBlocksHeadset, inline=True, ) return embed except: embed = discord.Embed( title="LogicEFTBot - Error", color=0x780A81, ) embed.set_thumbnail(url="https://illogical.network/api/error.png") embed.add_field( name="Invalid Item Search", value= "You've entered in an invalid helmet item ; please try again.", inline=True, ) return embed
def bot_armor(self, ctx: CommandContext, data: str) -> Union[str, discord.Embed]: log.info("%s - searching for %s (new)\n", ctx.channel, data) lang = self.db.get_lang(ctx.channel) try: armor = EFT.check_armor(lang, data) embed = discord.Embed( title=armor.armorName, url=armor.wikiLink, description=localized_string(lang, "armorZones") + armor.armorZones, color=0x780A81, ) embed.set_thumbnail( url="https://static.tarkov-database.com/image/icon/1-1/{0}.png" .format(armor.bsgID)) embed.add_field( name=localized_string(lang, "armorClass"), value=armor.armorClass, inline=True, ) embed.add_field( name=localized_string(lang, "armorMaterial"), value=armor.armorMaterial, inline=True, ) embed.add_field( name=localized_string(lang, "armorDurability"), value=armor.armorDurability, inline=True, ) embed.add_field( name=localized_string(lang, "armorMoveSpeed"), value=armor.armorMoveSpeed, inline=True, ) embed.add_field( name=localized_string(lang, "armorTurnSpeed"), value=armor.armorTurnSpeed, inline=True, ) embed.add_field( name=localized_string(lang, "armorErgo"), value=armor.armorErgo, inline=True, ) embed.set_footer( text=localized_string(lang, "armorEffectiveDurability") + armor.armorEffectiveDurability) return embed except Exception as e: embed = discord.Embed( title="LogicEFTBot - Error", color=0x780A81, ) embed.set_thumbnail(url="https://illogical.network/api/error.png") embed.add_field( name="Invalid Item Search", value= "You've entered in an invalid armor item ; please try again.", inline=True, ) print(e) return embed
def on_error(self, connection, event): log.info("Got error: %s", str(event)) self.status = "Exception" self.message = str(event)