diff --git a/.env.example b/.env.example index 822bc9f52b..6a1065c5db 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,7 @@ DATABASE_URL=postgres://postgres:password@postgres:5432/ DISCORD_API_TOKEN= +MISSKEY_API_TOKEN= +MISSKEY_DOMAIN= MODE= OPENAI_API_KEY= SLACK_API_TOKEN= diff --git a/Pipfile b/Pipfile index 78cb281eb2..fe090575b2 100644 --- a/Pipfile +++ b/Pipfile @@ -33,3 +33,5 @@ pandas = "==1.5.3" matplotlib = "==3.7.1" openai = "==0.27.0" discord = "==2.2.2" +"misskey.py" = "==4.1.0" +websockets = "==10.4" diff --git a/Pipfile.lock b/Pipfile.lock index 943516f378..0bccc95b31 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "97af50d7742a680247e44b67f9d68c0981d7ae7aaa088e095a17ccb2268d924d" + "sha256": "a1773407fdf86dc32120c18a8ac1624037014f7aa9358bd588c9e850aa65517a" }, "pipfile-spec": 6, "requires": { @@ -628,6 +628,13 @@ "index": "pypi", "version": "==3.7.1" }, + "misskey.py": { + "hashes": [ + "sha256:d118891d0cd59d7e8942870ab2145c78221ec9ea0c9a79e309a473f0a8db96fe" + ], + "index": "pypi", + "version": "==4.1.0" + }, "multidict": { "hashes": [ "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9", @@ -1077,6 +1084,81 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==1.26.14" }, + "websockets": { + "hashes": [ + "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41", + "sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96", + "sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4", + "sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72", + "sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576", + "sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63", + "sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b", + "sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d", + "sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032", + "sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393", + "sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50", + "sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631", + "sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f", + "sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c", + "sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6", + "sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4", + "sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6", + "sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0", + "sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8", + "sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112", + "sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94", + "sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4", + "sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb", + "sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331", + "sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c", + "sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c", + "sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193", + "sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b", + "sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b", + "sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038", + "sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089", + "sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa", + "sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9", + "sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56", + "sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4", + "sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179", + "sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c", + "sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882", + "sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28", + "sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1", + "sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a", + "sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033", + "sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1", + "sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13", + "sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8", + "sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c", + "sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74", + "sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab", + "sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3", + "sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588", + "sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485", + "sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342", + "sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48", + "sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf", + "sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0", + "sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a", + "sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea", + "sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf", + "sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8", + "sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df", + "sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc", + "sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f", + "sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269", + "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3", + "sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c", + "sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46", + "sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f", + "sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106", + "sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f" + ], + "index": "pypi", + "version": "==10.4" + }, "werkzeug": { "hashes": [ "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe", diff --git a/README.md b/README.md index 1f1d691285..14f0ce0aaf 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,12 @@ DISCORD_API_TOKENには `Read Messages/View Channels` と、 `Send Messages` の権限が必要です。 + MODEに `misskey` を指定すると、自分のサーバーからのメンションに限って反応するMisskeyのBotとして動作します。 + + MISSKEY_URLにBotのいるMisskeyサーバーのドメインを指定します。 + + MISSKEY_API_TOKENにMisskeyのBotのアクセストークンを指定します。 + 6. docker composeで鳩botとPostgreSQLを起動します。 ```sh diff --git a/README.template.md b/README.template.md index 77230c3a82..b5dbb0c5b6 100644 --- a/README.template.md +++ b/README.template.md @@ -58,6 +58,12 @@ DISCORD_API_TOKENには `Read Messages/View Channels` と、 `Send Messages` の権限が必要です。 + MODEに `misskey` を指定すると、自分のサーバーからのメンションに限って反応するMisskeyのBotとして動作します。 + + MISSKEY_URLにBotのいるMisskeyサーバーのドメインを指定します。 + + MISSKEY_API_TOKENにMisskeyのBotのアクセストークンを指定します。 + 6. docker composeで鳩botとPostgreSQLを起動します。 ```sh diff --git a/library/clientclass.py b/library/clientclass.py index cbed687687..1c52b8c931 100644 --- a/library/clientclass.py +++ b/library/clientclass.py @@ -142,3 +142,40 @@ def get_send_user_name(self): def get_type(): """discord""" return "discord" + + +class MisskeyClient(BaseClient): + """ + Misskeyを操作するClient + """ + + def __init__(self, misskey_client, message): + self.client = misskey_client + self.message = message + + def post(self, text): + """Discordにポストする""" + self._post(text=text) + + def upload(self, file, filename=None): + """ファイルを投稿する""" + with open(file, "rb") as f: + drive_file = self.client.drive_files_create(file=f) + self._post(file_ids=[drive_file["id"]]) + + def _post(self, text=None, file_ids=None): + self.client.notes_create( + text=text, reply_id=self.message["id"], file_ids=file_ids + ) + + def get_send_user(self): + """botを呼び出したユーザーを返す""" + return self.message["user"]["username"] + + def get_send_user_name(self): + return self.message["user"]["name"] + + @staticmethod + def get_type(): + """misskey""" + return "misskey" diff --git a/run.py b/run.py index 4722ffd86c..81ed60c3fc 100644 --- a/run.py +++ b/run.py @@ -3,6 +3,8 @@ """ BotのMain関数 """ +import asyncio +import json import logging import logging.config import sys @@ -10,11 +12,18 @@ from typing import Callable, List import discord +import websockets from flask import Flask, escape, jsonify, request +from misskey import Misskey from slackeventsapi import SlackEventAdapter import slackbot_settings as conf -from library.clientclass import ApiClient, DiscordClient, SlackClient +from library.clientclass import ( + ApiClient, + DiscordClient, + MisskeyClient, + SlackClient, +) from library.database import Database from plugins import analyze @@ -172,6 +181,39 @@ def main(): if conf.MODE == "discord": discordClient.run(token=conf.DISCORD_API_TOKEN) + elif conf.MODE == "misskey": + misskey_client = Misskey(conf.MISSKEY_DOMAIN, i=conf.MISSKEY_API_TOKEN) + + async def discord_runner(): + # pylint: disable=E1101 + async with websockets.connect( + "wss://" + + misskey_client.address + + "/streaming" + + "?i=" + + misskey_client.token + ) as ws: + await ws.send( + json.dumps( + {"type": "connect", "body": {"channel": "main", "id": "main"}} + ) + ) + while True: + data = json.loads(await ws.recv()) + if data["type"] == "channel" and data["body"]["type"] == "mention": + note = data["body"]["body"] + host = note["user"].get("host") + mentions = note.get("mentions") + if ( + (host is None or host == conf.MISSKEY_DOMAIN) + and mentions + and misskey_client.i()["id"] in mentions + ): + analyze.analyze_message( + note["text"].replace("\xa0", " ").split(" ", 1)[1] + )(MisskeyClient(misskey_client, note)) + + asyncio.get_event_loop().run_until_complete(discord_runner()) else: app.run(host="0.0.0.0", port=conf.PORT) diff --git a/slackbot_settings.py b/slackbot_settings.py index 7c543b08ae..3bea3ce924 100644 --- a/slackbot_settings.py +++ b/slackbot_settings.py @@ -40,6 +40,10 @@ # Discord用の設定 DISCORD_API_TOKEN = str(os.environ["DISCORD_API_TOKEN"]) +# Misskey用の設定 +MISSKEY_DOMAIN = str(os.environ["MISSKEY_DOMAIN"]) +MISSKEY_API_TOKEN = str(os.environ["MISSKEY_API_TOKEN"]) + MODE = str(os.environ["MODE"]) GIT_COMMIT_HASH = os.environ.get("GIT_COMMIT_HASH")