显然,discord机器人可以拥有移动状态,而不是默认的桌面(在线)状态.
经过一点挖掘,我发现这样的状态是通过修改IDENTIFY packet
/discord.gateway.DiscordWebSocket.identify
来实现的,修改$browser
到Discord Android
或Discord iOS
的值理论上应该可以得到移动状态.
在修改了我在网上找到的代码片段后,我得到了以下结论:
def get_mobile():
"""
The Gateway's IDENTIFY packet contains a properties field, containing $os, $browser and $device fields.
Discord uses that information to know when your phone client and only your phone client has connected to Discord,
from there they send the extended presence object.
The exact field that is checked is the $browser field. If it's set to Discord Android on desktop,
the mobile indicator is is triggered by the desktop client. If it's set to Discord Client on mobile,
the mobile indicator is not triggered by the mobile client.
The specific values for the $os, $browser, and $device fields are can change from time to time.
"""
import ast
import inspect
import re
import discord
def source(o):
s = inspect.getsource(o).split("\n")
indent = len(s[0]) - len(s[0].lstrip())
return "\n".join(i[indent:] for i in s)
source_ = source(discord.gateway.DiscordWebSocket.identify)
patched = re.sub(
r'([\'"]\$browser[\'"]:\s?[\'"]).+([\'"])',
r"\1Discord Android\2",
source_,
)
loc = {}
exec(compile(ast.parse(patched), "<string>", "exec"), discord.gateway.__dict__, loc)
return loc["identify"]
现在只需在运行时在主文件中覆盖discord.gateway.DiscordWebSocket.identify
,如下所示:
import discord
import os
from discord.ext import commands
import mobile_status
discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
bot = commands.Bot(command_prefix="?")
@bot.event
async def on_ready():
print(f"Sucessfully logged in as {bot.user}")
bot.run(os.getenv("DISCORD_TOKEN"))
And we do get the mobile status successfully
But here's the problem,我想直接修改文件(保存函数),而不是在运行时对其进行修补.所以我在本地克隆了dpy库,并在我的机器上编辑了文件,结果是这样的:
async def identify(self):
"""Sends the IDENTIFY packet."""
payload = {
'op': self.IDENTIFY,
'd': {
'token': self.token,
'properties': {
'$os': sys.platform,
'$browser': 'Discord Android',
'$device': 'Discord Android',
'$referrer': '',
'$referring_domain': ''
},
'compress': True,
'large_threshold': 250,
'v': 3
}
}
# ...
(为了安全起见,编辑了$browser
和$device
至Discord Android
)
But this does not work and just gives me the regular desktop online icon.
So the next thing I did is to inspect the identify
function after it has been monkey-patched, so I could just look at the source code and see what went wrong earlier, but due to hard luck I got this error :
Traceback (most recent call last):
File "c:\Users\Achxy\Desktop\fresh\file.py", line 8, in <module>
print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1024, in getsource
lines, lnum = getsourcelines(object)
File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 1006, in getsourcelines
lines, lnum = findsource(object)
File "C:\Users\Achxy\AppData\Local\Programs\Python\Python39\lib\inspect.py", line 835, in findsource
raise OSError('could not get source code')
OSError: could not get source code
代码:
import discord
import os
from discord.ext import commands
import mobile_status
import inspect
discord.gateway.DiscordWebSocket.identify = mobile_status.get_mobile()
print(inspect.getsource(discord.gateway.DiscordWebSocket.identify))
bot = commands.Bot(command_prefix="?")
@bot.event
async def on_ready():
print(f"Sucessfully logged in as {bot.user}")
bot.run(os.getenv("DISCORD_TOKEN"))
由于每个补丁函数(前面提到的一个和loc["identify"]
个)都表现出了相同的行为,我不能再使用inspect.getsource(...)
,然后依赖dis.dis
,这导致了更令人失望的结果
分解后的数据看起来与猴子补丁的工作版本完全相同,因此直接修改的版本根本无法工作,尽管函数内容完全相同.(关于反汇编数据)
注意:直接使用Discord iOS
也不起作用,将$device
改为其他值,但保留$browser
不起作用,我try 了所有组合,但都不起作用.
TL;DR:如何在运行时不使用猴子补丁的情况下获取discord机器人的移动状态?