diff --git a/.env.example b/.env.example deleted file mode 100644 index 8381152..0000000 --- a/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -MISSKEY_TOKEN = YOUR_ACCESS_TOKEN_HERE -MISSKEY_ORIGIN = YOUR_MISSKEY_SERVER_HERE -MAX_DUPLICATE_COUNT = 3 -SPREADSHEET_URL = YOUR_WORKSHEET_URL_HERE diff --git a/.gitignore b/.gitignore index 95ba1df..0a1cc7e 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ share/python-wheels/ *.egg MANIFEST .DS_Store +config.json # PyInstaller # Usually these files are written by a python script from a template diff --git a/config.example.json b/config.example.json new file mode 100644 index 0000000..c0c39fc --- /dev/null +++ b/config.example.json @@ -0,0 +1,12 @@ +{ + "token": "YOUR_ACCESS_TOKEN_HERE", + "origin": "YOUR_MISSKEY_SERVER_HERE", + "max_duplicate": 3, + "rate": 60, + "visibility": "home", + "worksheet": "YOUR_WORKSHEET_URL_HERE", + "template": { + "auto": "{note}", + "mention": "{note}\n \nFrom {from} ({number})" + } +} \ No newline at end of file diff --git a/exts/post.py b/exts/post.py index dfd2af2..bb27e8f 100644 --- a/exts/post.py +++ b/exts/post.py @@ -7,9 +7,11 @@ from mipa.ext.commands.bot import Bot class Post(commands.Cog): def __init__(self, bot: Bot) -> None: self.bot = bot + self.max_count = bot.config.max or 3 + self.visibility = bot.config.visibility or "home" self.posted = [] - @tasks.loop(seconds=60) + @tasks.loop(seconds=1800) async def _postLine(self) -> None: now = datetime.now() if now.minute not in [30, 00]: # Only post in n:30 and n:00 @@ -17,14 +19,18 @@ class Post(commands.Cog): line = self.bot.get_random_line() while line in self.posted: - line = self.bot.get_line() - await self.bot.client.note.action.send(content=line, visibility="home") + line = self.bot.get_random_line() + template = self.bot.config.reply + result = template.replace("{text}", line.text).replace("{from}", line.where).replace("{number}", line.number) + await self.bot.client.note.action.send(content=result, visibility=self.visibility) self.posted.append(line) - if len(self.posted) > self.bot.max_count: + if len(self.posted) > self.max_count: self.posted.pop(0) async def setup(bot: Bot): cog = Post(bot) + if bot.config.rate is not None: + cog._postLine.seconds = bot.config.rate * 60 await cog._postLine.start() await bot.add_cog(cog) diff --git a/main.py b/main.py index cc9ebc4..4386b7b 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,5 @@ import asyncio +import json import os import random @@ -7,19 +8,50 @@ from aiohttp import ClientWebSocketResponse from gspread.worksheet import Worksheet from mipac.models.notification import NotificationNote from mipa.ext import commands -from dotenv import load_dotenv -load_dotenv() + +class Config: + def __init__(self, path: str) -> None: + raw = json.load(path) + self.token = raw.get("token") + self.origin = raw.get("origin") + self.max = raw.get("max_duplicate") + self.rate = raw.get("rate") + self.visibility = raw.get("visibility") + self.worksheet = raw.get("worksheet") + template = raw.get("template") + self.note = template.get("auto") + self.reply = template.get("mention") + if any([ + self.token is None, + self.origin is None, + self.worksheet is None, + self.note is None, + self.reply is None + ]): + raise ValueError("config.json 파일에 일부 필수 값이 누락되었습니다.") + + +class Line: + def __init__(self, row: int, bot: "Autoposter") -> None: + sheet = bot.get_worksheet() + self.location = row + res = sheet.get(f"D{row}") + self.text = res[0][0].strip() + res = sheet.get(f"C{row}") + self.where = res[0][0].strip() + res = sheet.get(f"B{row}") + self.number = res[0][0].strip() class Autoposter(commands.Bot): def __init__(self): super().__init__() - self.max_count = int(os.getenv("MAX_DUPLICATE_COUNT")) + self.config: Config = Config("./config.json") def get_worksheet(self) -> Worksheet: gc = gspread.service_account() - sh = gc.open_by_url(os.getenv("SPREADSHEET_URL")) + sh = gc.open_by_url(self.config["worksheet"]) worksheet = sh.get_worksheet(0) return worksheet @@ -31,17 +63,10 @@ class Autoposter(commands.Bot): count = int(response[0][0]) result = random.randint(1, count) number = result + 2 - res = sheet.get(f"D{number}") - text = res[0][0].strip() - return text + return Line(number, self) - def get_info(self, line: str) -> dict: - sheet = self.get_worksheet() - result = sheet.find(line, in_column=4) - number = result.row - 2 - where = sheet.get(f"C{result.row}") - where = where[0][0] - return {"number": number, "from": where} + def get_line(self, number: int) -> str: + return Line(number, self) async def _connect_channel(self): await self.router.connect_channel(['main', 'global']) @@ -56,17 +81,20 @@ class Autoposter(commands.Bot): await self.load_extension(extension) async def on_reconnect(self, ws: ClientWebSocketResponse): - print("Disconnected from server.") + print("Disconnected from server. Reconnecting...") await self._connect_channel() async def on_mention(self, notice: NotificationNote): - line = self.get_random_line() - info = self.get_info(line) - await notice.note.api.action.reply(content=f"{line}\n \n- {info['from']}에서 발췌됨. ({info['number']}번 대사)", reply_id=notice.note.id) + if notice.note.reply_id is not None: + return + + line: Line = self.get_random_line() + template = self.config.reply + result = template.replace("{text}", line.text).replace("{from}", line.where).replace("{number}", line.number) + await notice.note.api.action.reply(content=result, visibility=notice.note.visibility, reply_id=notice.note.id) if __name__ == '__main__': bot = Autoposter() loop = asyncio.get_event_loop() - origin = os.getenv("MISSKEY_ORIGIN") - loop.run_until_complete(bot.start(f"wss://{origin}/streaming", os.getenv("MISSKEY_TOKEN"))) + loop.run_until_complete(bot.start(f"wss://{bot.config.origin}/streaming", os.getenv("MISSKEY_TOKEN")))