【问题标题】:Control custrom script through discord.py bot通过 discord.py bot 控制自定义脚本
【发布时间】:2021-03-07 04:20:35
【问题描述】:

正如标题所说,我有一个脚本,它正在执行(一些超级秘密)任务,它几乎不间断地运行。 我现在做的,就是时不时的检查一下,看它是否运行顺利。

我最近从 python2.7 切换到了 python 3.7,并开始使用 discord.py 机器人。现在,我想做的是让我的脚本几乎不间断地运行:

  1. 将它的日志打印到discord服务器,这样我就可以检查它是否运行顺利,而无需访问PC
  2. 能够通过 discord 命令控制脚本

所以,基本上,我想要实现两件事:

1.) 当脚本将一些日志打印到控制台时,也将其发送到 discord.py 机器人,后者会将其发送到给定的频道

2.) 让 discord.py 机器人读取给定的频道(不同于之前的频道),如果正确的命令来了,在脚本中采取行动(做一些事情,或者只是改变一些变量值)

这是我到目前为止的代码示例:

# Discord bot, to control bot over discord
try:
    import discord
    import disc_bot_con
    from discord.ext import commands
except Exception as x:
    print("Unable to import discord libraries [%s]" % x)


# Global methods *******************************************************************************************************
def print_log(msg, lvl=None):
    if lvl == 'i':
        print("[%s] INFO:       %s" % (datetime.datetime.now(), msg))
    elif lvl == 'w':
        print("[%s] WARNING:    %s" % (datetime.datetime.now(), msg))
    elif lvl == 'e':
        print("[%s] ERRROR:     %s" % (datetime.datetime.now(), msg))
    elif lvl == 'd':
        if DEBUG:
            print("[%s] DEBUG:      %s" % (datetime.datetime.now(), msg))
    else:
        print("[%s] %s" % (datetime.datetime.now(), msg))


# Classes **************************************************************************************************************
class Script:
    def __init__(self):
        # do soemthing

    def run(self):
        # repeatedly doing some stuff
        while True:
            if something:
                print_log('Soemthing')
            else:
                print_log('Taking action')
                self.take_action()


class ScriptDiscordBot(discord.Client):
    async def setup_guild(self):
        await self.login(disc_bot_con.TOKEN)
        self.guild = discord.utils.get(self.guilds, name=disc_bot_con.NAME_CZ_SK_RIVALS)
        self.channel = discord.utils.get(self.guild.channels, name='bot_trash')

    async def my_background_task(self):
        await self.wait_until_ready()
        counter = 0
        channel = discord.Object(id='channel_id_here')
        while not self.is_closed:
            counter += 1
            await self.send_message(channel, counter)
            await asyncio.sleep(60)  # task runs every 60 seconds

    async def on_connect(self):
        print_log("Connecting to discord!")

    async def on_ready(self):
        print('Logged on as {0}!'.format(self.user))
        guild = discord.utils.get(self.guilds, name=disc_bot_con.NAME_CZ_SK_RIVALS)
        print('Logged to: {0}!'.format(self.guild))

    async def send_log(self, message):
        #channel = discord.utils.get(self.guild.channels, name=chanel_name)
        channel_id = self.channel.id
        await self.send_message(channel_id, message)


# run the thing
if __name__ == '__main__':

    if not TEST_MODE:
        try:
            opts, extraparams = getopt.getopt(sys.argv[1:], 'ASFWsc:t:w:h', ['help'])
        except getopt.GetoptError as err:
            print(str(err))
            Script.print_help()
            sys.exit(2)

        discord_bot = ScriptDiscordBot()
        discord_bot.run(disc_bot_con.TOKEN)

        the_bot = Script()
        the_bot.run()

当我这样运行它时,它会启动 bot 并运行它,但显然不会启动 Script 类。

起初,我一直在尝试将ScriptDiscordBot 封装到单独的线程中..但它没有奏效。

# run the thing
if __name__ == '__main__':

    if not TEST_MODE:
        try:
            opts, extraparams = getopt.getopt(sys.argv[1:], 'ASFWsc:t:w:h', ['help'])
        except getopt.GetoptError as err:
            print(str(err))
            Script.print_help()
            sys.exit(2)

        discord_bot = ScriptDiscordBot()
        t = threading.Thread(target=discord_bot.run, args=disc_bot_con.TOKEN)
        t.start()

        the_bot = Script()
        the_bot.run()

正如github示例所说,我试图让discord bot在abckground中运行,但那里也没有运气。

# run the thing
if __name__ == '__main__':

    if not TEST_MODE:
        try:
            opts, extraparams = getopt.getopt(sys.argv[1:], 'ASFWsc:t:w:h', ['help'])
        except getopt.GetoptError as err:
            print(str(err))
            Script.print_help()
            sys.exit(2)

        discord_bot = ScriptDiscordBot()
        discord_bot.loop.create_task(my_background_task())
        discord_bot.login(disc_bot_con.TOKEN)

        the_bot = Script()
        the_bot.run()

我尝试的最后一件事是,根本不让 run discord bot 运行,而是从 Script 调用它的方法。

# run the thing
if __name__ == '__main__':

    if not TEST_MODE:
        try:
            opts, extraparams = getopt.getopt(sys.argv[1:], 'ASFWsc:t:w:h', ['help'])
        except getopt.GetoptError as err:
            print(str(err))
            Script.print_help()
            sys.exit(2)

        discord_bot = ScriptDiscordBot()
        discord_bot.setup_guild()
        discord_bot.send_log('Test')

        the_bot = Script()
        the_bot.run()

那里也没有运气。 :(

我熟悉 python2.7 中的 ThreadingMultiprocessing,但 asyncio 对我来说是全新的。我一直在尝试不同的方法,以使其发挥作用。我编写了许多同时运行多个进程的应用程序,但这对我来说似乎太多了。我认为这是非常简单的任务,但解决方案对我来说似乎是不可能的。

另外,我很确定我的想法是错误的,但我不知道我应该怎么想。所以我按照我的想法使用了一些更正,还有一些代码示例。 dicsord.py 文档和 github 中的示例非常简单,我让它们在单独的脚本中工作,但我无法让这两个脚本协作或同时运行。

【问题讨论】:

    标签: python-3.x discord.py python-asyncio


    【解决方案1】:

    您可以创建一个任务,使其更易于管理:

    from discord.ext import tasks
    
    @tasks.loop(seconds=5.0)
    async def my_background_task(*args, **kwargs):
        # do something, you can put your script here
    

    如何启动、取消、停止、重新启动任务?

    my_background_task.start()
    my_background_task.cancel()
    my_background_task.stop()
    my_background_task.restart(*args, **kwargs)
    

    这里有一些有用的方法/属性

    my_background_task.current_loop
    my_background_task.next_iteration
    my_background_task.is_running()
    my_background_task.is_being_cancelled()
    

    您也可以在任务开始之前/之后使用装饰器进行操作

    @my_background_task.before_loop
    async def before_my_background_task(*args, **kwargs):
        # do something before
    
    
    @my_background_task.after_loop
    async def after_my_background_task(*args, **kwargs):
        # do something
    

    这里有一个关于如何使用命令的小例子

    @bot.command()
    async def start(ctx):
        my_background_task.start(some_arguments_here)
        await ctx.send('Task started')
    
    
    @bot.command()
    async def edit_task(ctx, *some_parameters_id_to_change):
        my_background_task.restart(some_parameters_id_to_change)
        await ctx.send(f'Task restarted with the following arguments:\n`{some_parameters_id_to_change}`')
    

    下面是关于如何使用discord.ext.tasks 的简要说明 如果你需要什么,请在 cmets 中告诉我 ↓

    参考:

    【讨论】:

    • 好吧,我可能应该提一下,Script 是大约 1500 多行代码类,执行图像识别、观看计时器和根据结果做出决定 :) 所以它不是将其放入某种方法中确实很容易。
    猜你喜欢
    • 2018-09-21
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    相关资源
    最近更新 更多