Compare commits

..

6 Commits
master ... niho

Author SHA1 Message Date
nihonium 063972ac9a
main fix 2 years ago
nihonium 31cb538e1a Finyally working websocket version 3 years ago
nihonium 8730dcd7f1 websockets 3 years ago
nihonium 298ea853b7 Global rewrite, shit cleaning 3 years ago
nihonium 27c2296db3 Основной функционал готов 3 years ago
nihonium dc517c4555 Nya 3 years ago

@ -1,54 +1,9 @@
# Misskey Bot # Misskey Bot
Какой функционал планируется у бота: Ранняя стадия разработки, авось что получится съедобное
* Бот-группа (репостер упоминаний)
* Бот-ретранслятор с Twitter
* Автопостер картинок из заданного каталога (готово на 80%) (отменено)
## 1. Как заставить бота работать?
## 1.1. Технические моменты
* Python 3.8+
* Готовый misskey инстанс (не обязательно свой)
## 1.2. Административные моменты
* Свободных 200 мб RAM памяти
* Свободного времени на поиск и устранение проблем, в случае чего
* Тематика вашего бота
## 2. Настройка бота
### 2.1. Достаём API
В первую очередь нужно зайти в аккаунт бота на вашем инстансе (создайте, если еще не сделали этого.). Дальше перейдите в
`Настройки (шестерёнка) -> API -> Создать токен `
Выберите необходимые расширения (я выбираю все) и нажмите галочку, после чего появится всплывающие окно с токеном вашего бота.
!ВНИМАНИЕ!
Создав токен один раз вы больше не сможете его посмотреть (неизвестно, баг это misskey или фича, но что есть то есть).
### 2.2. Настраиваем config.json
Дальше переходим в config.json и заполняем его под ваш инстанс, где
`"name"` - название вашего инстанса,
`"url"` - веб-адрес вашего инстанса (!не бота!),
`"token"` - ваш токен, который вы получили в пункте 1.1,
`"visibility" - "public"` (обязательно)
### 2.3. Запускаем бота
Запускаем скрипт `python main.py`. По сути, бот сейчас должен работать.
### 2.4. Проверка бота
Проверяем работоспособность бота:
* Подпишитесь на бота
* Отправьте что-нибудь с его упоминанием (главное, чтобы пост был либо "Глобальным", либо "Домашним")
* Получаем сообщение о том, что бот нас репостнул
* ...????
* PROFIT!
## 3. Добавляем бота в автозагрузку системы
##
Бот Misskey:
1. Бот-группа
2. Бот-ретранслятор с Twitter
3. Автопостер картинок из заданного каталога

@ -0,0 +1,61 @@
#!/usr/bin/python3
import logging as log
import requests
import json
import msk
import websockets
import asyncio, aiohttp
def json_read(file):
print("Reading config file: {}".format(file))
with open(file) as f:
config = json.load(f)
return config
# Temp
config = json_read('config.json')
#try:
# config = json_read('config.json')
#except FileNotFoundError:
# print("Config file not found. Maybe we should launch setup.py?")
if config['verbosity'].upper() == 'DEBUG':
log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
log.info("Verbose output")
msk = msk.Misskey(i=config['token'], url=config['url'])
async def main():
log.info("Connecting to {}".format(msk.url))
async with websockets.connect(msk.ws_url) as ws:
log.info('Sucessfully connected to {}'.format(msk.url))
log.info('Attemping to watch timeline')
p = {
'type': 'connect',
'body': {
'channel': 'main'
}
}
await ws.send(json.dumps(p))
log.info('Listening to timeline')
while True:
data = await ws.recv()
j = json.loads(data)
if j['type'] == 'channel':
if j['body']['type'] == 'followed':
print("Follow!")
msk.following_create(j['body']['body']['id'])
if j['body']['type'] == 'mention':
if not j['body']['body']['replyId']:
msk.notes_create(renoteId=j['body']['body']['id'])
print(j)
while True:
try:
asyncio.run(main())
except KeyboardInterrupt:
break

@ -1,6 +0,0 @@
{
"name": "[Shitpost] PoridgeClub",
"url" : "https://shitpost.poridge.club",
"token": "ur_token",
"visibility": "public"
}

@ -0,0 +1,7 @@
{
"name": "nyan.nekoea.red",
"url" : "nyan.nekoea.red",
"token": "*****",
"verbosity": "debug"
}

@ -1,116 +0,0 @@
#!/usr/bin/python3
import requests # Для отправки http-запросов
import json
import time
# Функция для чтения JSON-файла (например, конфига), аргумент - адрес файла в ФС
# Возвращает словарь
def json_read(file):
# Создается локальное окружение (или как эта хуйня зовется), где присутствует дескриптор для нашего файла
with open(file) as f:
config = json.load(f)
return config
# Функция для получения уведомлений пользователя из Misskey
# Возвращает список словарей
# 2do: includeTypes как аргумент
def get_notifications(url, i):
print("Getting notifications from", url)
# Формируем URL для доступа к конкретной функции API
req_url = url + "/api/i/notifications"
body = {
"i": i,
# Можно включить лишь определенные уведомления, всю эту залупу следует вынести также в аргументы функции, чтоб реагировать на конкретные события, типа подписки или упоминания, по-разному
#"includeTypes": [
# "reply",
# "mention"
# ],
# Количество уведомлений, которые вытянем
"limit": 3,
"unreadOnly": False,
}
# Отправляем запрос, в тело запроса суем словарь-JSON, которые объявили выше
r = requests.post(req_url, json=body)
# Если все прошло збс, код HTTP 200, то отдаем получанный список уведомлений
if r.status_code == 200:
# Можешь раскомментить, глянуть, что это за черт
#print(r.json())
return r.json()
# Иначе, если не збс, то ругаемся
else:
print("Fuck")
# Функция, создающая пост
# 2do: посты с картинками, ...
def create_post(content, url, i, visibility="public", channel="", fileIds=[]):
print("Post to", url, ":", content)
# Аналогично, адрес нужной функции API
req_url = url + "/api/notes/create"
body = {
# Не ебу, что за noExtract*, надо полуркать, но работает и збс пока что
"noExtractMentions": True,
"noExtractHashtags": True,
"noExtractEmojis": True,
"visibility": visibility,
"text": content,
"fileIds": fileIds,
# Если поставлен канал, то пост только локальный для инстанса
"localOnly": channel != "",
"i": i
}
if channel != "":
body["channelId"] = channel
# Отправляем запрос
r = requests.post(req_url, json=body)
# Аналогично, проверка на 200, в случае успеха 1
if r.status_code == 200:
return 0
else:
print("Failed to post:", r.text)
return 1
# Пока что можешь не пытаться разобраться, я сам отчасти хз, как это работает, лол
def file_upload(file, url, i, isSensitive=False):
print("Uploading file to", url)
req_url = url + "/api/drive/files/create"
with open(file, "rb") as f:
fileo = f.read()
body = {
"isSensitive": False,
"force": True,
"i":i
}
body = json.dumps(body)
payload = {'json_payload': body, 'i': i }
files = {"file": (file, fileo)}
r = requests.post(req_url, data=payload, files=files)
if r.status_code == 200:
return r.json()
else:
print("Upload failed with code", r.status_code)
print(r.text)
def get_file_list(url, i):
req_url = url + "/api/drive/files"
r = requests.post(req_url, json={"i":i})
print(r.json())
### Сюда надо захуярить еще 100500 функций###
# Собсна, содержательная часть программы начинается тут
# Читаем конфиг, получаем словарь
config = json_read('config.json')
#notif_list = get_notifications(config['url'], config['token'])
#print(notif_list)
#file_upload('test.jpg', config['url'], config['token'])
im_info = file_upload('test.jpg', config['url'], config['token'])
create_post("Nya~", config['url'], config['token'], fileIds=[im_info['id']])
#print(notif_list)

@ -0,0 +1,73 @@
import requests
import logging as log
class Misskey:
'''
Class for interaction with Misskey instance
Currently, this class ignores most of the Misskey specific shit like channels =3
'''
def __init__(self, url: str, i: str):
self.url = f"https://{url}"
self.i = i
self.ws_url=f"wss://{url}/streaming?i={i}"
def notes_create(self, text=None, visibility = "public", cw = None, fileIds = list(), replyId = None, renoteId = None):
req_url = self.url + "/api/notes/create"
if renoteId:
body = {
"renoteId": renoteId,
}
else:
body = {
"text": text,
"visibility": visibility,
}
for item in [(cw, "cw"), (fileIds,"fileIds"), (replyId,"replyId")]:
if item[0]:
body[item[1]] = item[0]
body['i'] = self.i
log.info("Trying to post note to {}".format(self.url))
r = requests.post(req_url, json=body)
print(body)
if r.status_code == 200:
log.info("Successfully posted")
else:
log.error("Posting failed with {} error!".format(r.status_code))
return r.json()
def following_create(self, userId: str):
req_url = self.url + "/api/following/create"
r = requests.post(req_url, json={"i":self.i, "userId": userId})
if r.status_code == 200:
res = r.json()
log.info("Successfully followed user {}@{}[{}]".format(res['username'],res['host'] ,userId))
else:
log.error("Failed to follow user [{}] with {} error!".format(userId, r.status_code))
return r.json()
def drive_files_create(self, file, isSensitive=False):
req_url = self.url + "/api/drive/files/create"
with open(file, "rb") as f:
files = {"file": (file, f)}
body = {
"isSensitive": isSensitive,
"i":self.i
}
payload = {'json_payload': body, 'i': self.i }
r = requests.post(req_url, data=payload, files=files)
if r.status_code == 200:
res = r.json()
log.info("Successfully uploaded file {}[{}]".format(res['name'], res['id']))
else:
log.error("Failed to upload file {} with {} error!".format(file, r.status_code))
return r.json()

@ -1,12 +0,0 @@
## API
https://misskey.io/api-doc
## Примеры ботов
https://github.com/yupix/Mi.py
https://github.com/TennousuAthena/RSSToMisskey
https://github.com/theskanthunt42/misskeyInstanceCheckBot
## Twitter API
https://www.earthdatascience.org/courses/use-data-open-source-python/intro-to-apis/twitter-data-in-python/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Loading…
Cancel
Save