diff --git a/bot.py b/bot.py new file mode 100755 index 0000000..a395a30 --- /dev/null +++ b/bot.py @@ -0,0 +1,24 @@ +#!/usr/bin/python3 +import logging as log +import requests +import json +import msk + +def json_read(file): + print("Reading config file: {}".format(file)) + with open(file) as f: + config = json.load(f) + return config + +config = json_read('config.json') + +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']) + + +fid = msk.drive_files_create("yaoshi-jun-Toosaka-Rin-Fate-(series)-Anime-3306019.jpeg", isSensitive=True)['id'] +msk.notes_create(text="Wannya see my picture?", cw="Nya?", fileIds=[fid]) + diff --git a/main.py b/main.py deleted file mode 100755 index 5b442c9..0000000 --- a/main.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/python3 - -import requests # Для отправки http-запросов -import json -import time -import argparse -import logging as log -import pprint - -p = argparse.ArgumentParser() -p.add_argument('--verbose', '-v', action='count', default=0) - -args = p.parse_args() -if args.verbose: - log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG) - log.info("Verbose output.") -else: - log.basicConfig(format="%(levelname)s: %(message)s") - -#log.info("This should be verbose.") -#log.warning("This is a warning.") -#log.error("This is an error.") - -# Функция для чтения JSON-файла (например, конфига), аргумент - адрес файла в ФС -# Возвращает словарь -def json_read(file): - # Создается локальное окружение (или как эта хуйня зовется), где присутствует дескриптор для нашего файла - log.info("Reading config file: %s", file) - with open(file) as f: - config = json.load(f) - return config - -config = json_read('config.json') - -# Функция для получения уведомлений пользователя из Misskey -# Возвращает список словарей -def get_notifications(url, i, includeTypes=["follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "receiveFollowRequest", "followRequestAccepted", "groupInvited","app"], markAsRead=True, unreadOnly=True, following=True, limit=5): - log.info("Getting notifications from %s", url) - # Формируем URL для доступа к конкретной функции API - req_url = url + "/api/i/notifications" - body = { - "i": i, - # Можно включить лишь определенные уведомления, всю эту залупу следует вынести также в аргументы функции, чтоб реагировать на конкретные события, типа подписки или упоминания, по-разному - "includeTypes": includeTypes, - # Количество уведомлений, которые вытянем - "limit": 3, - "unreadOnly": False, - "markAsRead": markAsRead, - "unreadOnly": unreadOnly, - "following": following, - "limit": limit, - } - # Отправляем запрос, в тело запроса суем словарь-JSON, которые объявили выше - r = requests.post(req_url, json=body) - # Если все прошло збс, код HTTP 200, то отдаем получанный список уведомлений - if r.status_code == 200: - # Можешь раскомментить, глянуть, что это за черт - return r.json() - # Иначе, если не збс, то ругаемся - else: - log.error("Fuck you, leatherman") -# Функция, создающая пост -# 2do: посты с картинками, ... -def create_note(url=config['url'], i=config['token'], content="", visibility="public", channel="", fileIds=[], renote=False, renoteId=None): - log.info("Creating note to %s", url) - # Аналогично, адрес нужной функции API - req_url = url + "/api/notes/create" - if renote: - body = { - "renoteId": renoteId, - "i": i - } - else: - 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: - log.error("Failed to post: %s", 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 функций### -def follow_user(userId, url=config['url'], i=config['token']): - req_url = url + "/api/following/create" - r = requests.post(req_url, json={"i":i, "userId": userId}) - #print(r.json()) - if r.status_code == 200: - return r.json() - else: - print("Upload failed with code", r.status_code) - print(r.text) -# Собсна, содержательная часть программы начинается тут - -# Читаем конфиг, получаем словарь - - -#create_note(config['url'], config['token'], renote=True, renoteId="8vxo3hpsdm") - -while True: - notif_list = get_notifications(config['url'], config['token'], includeTypes=["mention"], markAsRead=False, unreadOnly=True, limit=2, following=True) - follow_notif_list = get_notifications(config['url'], config['token'], includeTypes=["follow"], markAsRead=False, unreadOnly=True, limit=2, following=False) - #pprint.pprint(notif_list) - pprint.pprint(follow_notif_list) - notes_to_repost=list() - users_to_follow=list() - for i in range(len(notif_list)): - #pprint.pprint(notif_list[i]['note']['id']) - notes_to_repost.append(notif_list[i]['note']['id']) - for i in range(len(follow_notif_list)): - #pprint.pprint(notif_list[i]['note']['id']) - users_to_follow.append(follow_notif_list[i]['user']['id']) - print(users_to_follow) - #for i in range(len(notes_to_repost)): - # create_note(renote=True, renoteId=notes_to_repost.pop()) - for i in range(len(users_to_follow)): - follow_user(users_to_follow.pop()) - time.sleep(2) diff --git a/msk.py b/msk.py new file mode 100644 index 0000000..83caf0e --- /dev/null +++ b/msk.py @@ -0,0 +1,72 @@ +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 = url + self.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()