* Имплементация fail limit
* Добавлен api endpoit mute
* Изменения в конфигурации и уточнения
This commit is contained in:
localhost_frssoft 2022-09-02 15:39:46 +03:00
parent aee5d2a9c9
commit cc2993e59c
4 changed files with 55 additions and 16 deletions

View file

@ -2,9 +2,16 @@ admins_bot = ('drq@mastodon.ml',) # Адреса админов бота, кот
# Example: ('admin_user', 'another_admin_user2@example.example') or ('admin_user',) # Example: ('admin_user', 'another_admin_user2@example.example') or ('admin_user',)
bot_acct = 'fmn' # Ник бота на инстансе bot_acct = 'fmn' # Ник бота на инстансе
instance = 'expired.mentality.rip' # Инстанс, где будет запущен бот instance = 'expired.mentality.rip' # Инстанс, где будет запущен бот
# Лимиты
limit_movies_per_user = 2 # Ограничение количества фильмов на одного пользователя limit_movies_per_user = 2 # Ограничение количества фильмов на одного пользователя
limit_all_movies_poll = 20 # Сколько можно добавить всего фильмов limit_all_movies_poll = 20 # Сколько можно добавить всего фильмов
hour_poll_posting=16 # Час в который будет создан пост с голосовалкой max_fail_limit = 4 # Игнорировать предложения пользователя при достижении указанного числа проваленных поток предложить фильм
logger_default_level=10 # Уровень логгирования 10 - DEBUG, 20 - INFO, 30 - WARN # Часы
# Note: Если на ОС часовой пояс отличается от Мск+3, то рекомендуется сместить эти часы здесь или поменять часовой пояс в ОС
hour_poll_posting = 16 # Час в который будет создан пост с голосовалкой (и завершение сбора)
fmn_next_watching_hour = 21 # Час начала киносеанса
logger_default_level = 10 # Уровень логгирования 10 - DEBUG, 20 - INFO, 30 - WARN

View file

@ -1,6 +1,9 @@
from config import instance
import json import json
import requests import requests
from config import instance import logging
logger = logging.getLogger('fedi_api')
instance_point = f"https://{instance}/api/v1" instance_point = f"https://{instance}/api/v1"
@ -68,3 +71,13 @@ def upload_attachment(file_path):
return r.json()['id'] return r.json()['id']
def mute_user(acct_id=str, acct=str, duration=None):
params = {
"duration": duration
}
r = requests.post(instance_point + '/accounts' + f"/{acct_id}/mute", params, headers=headers)
if r.status_code == 200:
logger.info(f'Пользователь {acct} был заглушен на {duration} secs')
else:
logger.error(f'Ошибка глушения {r.status_code} - {acct}')

View file

@ -1,20 +1,22 @@
import time from config import hour_poll_posting, bot_acct, instance, limit_all_movies_poll, max_fail_limit
from datetime import datetime from src.fedi_api import get_status_context, get_status, post_status, mute_user
from dateutil.parser import parse as dateutilparse
from dateutil.relativedelta import relativedelta, TU
import re
import logging
from config import hour_poll_posting, bot_acct, instance, limit_all_movies_poll
from src.fedi_api import get_status_context, get_status, post_status
from src.kinopoisk_api import get_kinopoisk_movie from src.kinopoisk_api import get_kinopoisk_movie
from src.imdb_datasets_worker import get_title_by_id from src.imdb_datasets_worker import get_title_by_id
from src.fmn_database import add_movie_to_poll, get_already_watched, get_suggested_movies_count from src.fmn_database import add_movie_to_poll, get_already_watched, get_suggested_movies_count
from src.fmn_states_db import get_state, add_state from src.fmn_states_db import get_state, add_state
from src.fmn_poll import create_poll_movies, get_winner_movie from src.fmn_poll import create_poll_movies, get_winner_movie
import time
from datetime import datetime
from dateutil.parser import parse as dateutilparse
from dateutil.relativedelta import relativedelta, TU
from collections import Counter
import re
import logging
logger = logging.getLogger('thread_listener') logger = logging.getLogger('thread_listener')
def parse_links(text=str): def parse_links(text=str):
regex = r"kinopoisk\.ru/" regex = r"kinopoisk\.ru/"
if re.search(regex, text.lower(), flags=re.MULTILINE): if re.search(regex, text.lower(), flags=re.MULTILINE):
@ -34,13 +36,14 @@ def parse_links_imdb(text=str):
def scan_context_thread(): def scan_context_thread():
fail_limit = Counter()
while True: while True:
status_id = get_state('last_thread_id') status_id = get_state('last_thread_id')
poll_created = get_state('poll_status_id') poll_created = get_state('poll_status_id')
stop_thread_scan = get_state('stop_thread_scan') stop_thread_scan = get_state('stop_thread_scan')
flag_scan = 0
time_now = int(time.time()) time_now = int(time.time())
while status_id is None or stop_thread_scan is None: while status_id is None or stop_thread_scan is None:
fail_limit = Counter()
status_id = get_state('last_thread_id') status_id = get_state('last_thread_id')
stop_thread_scan = get_state('stop_thread_scan') stop_thread_scan = get_state('stop_thread_scan')
time.sleep(1) time.sleep(1)
@ -66,11 +69,20 @@ def scan_context_thread():
id_st = status['id'] id_st = status['id']
in_reply_acct = status['in_reply_to_account_id'] in_reply_acct = status['in_reply_to_account_id']
in_reply_id = status['in_reply_to_id'] in_reply_id = status['in_reply_to_id']
muted = status['muted']
acct = status['account']['acct'] acct = status['account']['acct']
acct_id = status['account']['id']
content = status['pleroma']['content']['text/plain'] content = status['pleroma']['content']['text/plain']
if id_st in replyed: # Игнорировать уже отвеченное if id_st in replyed: # Игнорировать уже отвеченное
continue continue
if muted is True:
continue
if fail_limit[acct] >= max_fail_limit: # Игнорировать пользователя если он превысил fail limit
mute_user(acct_id, acct, int(get_state('max_mute_time')) - time_now)
logger.warning(f'{acct} игнорируется - превышение fail limit')
break # Нужно обновить тред, чтобы muted на заглушенном стал True
parsed_result = parse_links(content) parsed_result = parse_links(content)
parsed_result_imdb = parse_links_imdb(content) parsed_result_imdb = parse_links_imdb(content)
@ -80,6 +92,7 @@ def scan_context_thread():
if poll_created: if poll_created:
post_status(f' Приём заявок уже окончен.\n\nГолосовалка здесь: https://{instance}/notice/{poll_created}', id_st) post_status(f' Приём заявок уже окончен.\n\nГолосовалка здесь: https://{instance}/notice/{poll_created}', id_st)
logger.info(f'{acct} был уведомлен о завершенной голосовалке') logger.info(f'{acct} был уведомлен о завершенной голосовалке')
fail_limit[acct] += 1
continue continue
if parsed_result is not None: if parsed_result is not None:
@ -100,10 +113,12 @@ def scan_context_thread():
logger.debug(str(movie)) logger.debug(str(movie))
if movie[index_type] == "404": if movie[index_type] == "404":
message_writer.append("Не найдено.") message_writer.append("Не найдено.")
fail_limit[acct] += 1
elif movie[index_type] not in ("movie", "FILM", "video"): elif movie[index_type] not in ("movie", "FILM", "video"):
type_of_title = movie[index_type] type_of_title = movie[index_type]
message_writer.append(f"Не принято:\n- Нам не подходят: сериалы, короткометражные и документальные фильмы") message_writer.append(f"Не принято:\n- Нам не подходят: сериалы, короткометражные и документальные фильмы")
logger.info(f'Предложение {acct} отклонено: не подходящий тип фильма: {type_of_title}') logger.info(f'Предложение {acct} отклонено: не подходящий тип фильма: {type_of_title}')
fail_limit[acct] += 1
else: else:
name = movie[index_name] name = movie[index_name]
@ -119,6 +134,7 @@ def scan_context_thread():
if get_suggested_movies_count() >= limit_all_movies_poll: if get_suggested_movies_count() >= limit_all_movies_poll:
post_status('🎬 Мы не можем обработать ваше предложение: количество уже предложенных не помещается в лимит голосовалки.', id_st) post_status('🎬 Мы не можем обработать ваше предложение: количество уже предложенных не помещается в лимит голосовалки.', id_st)
logger.warning(f'Предложение {acct} было отклонено: количество уже предложенных фильмов превышает\равно {limit_all_movies_poll}') logger.warning(f'Предложение {acct} было отклонено: количество уже предложенных фильмов превышает\равно {limit_all_movies_poll}')
fail_limit[acct] += 1
break break
if get_already_watched(name, name_ru, year) == True: if get_already_watched(name, name_ru, year) == True:
@ -132,6 +148,7 @@ def scan_context_thread():
else: else:
post_status("❌ Вы не можете добавить больше 2х фильмов", id_st) post_status("❌ Вы не можете добавить больше 2х фильмов", id_st)
logger.info(f'Предложение от {acct} было отлонено - лимит на пользователя') logger.info(f'Предложение от {acct} было отлонено - лимит на пользователя')
fail_limit[acct] += 1
if message_writer != []: if message_writer != []:
post_status('\n'.join(message_writer) + "\nБлагодарим за ваше предложение!", id_st) post_status('\n'.join(message_writer) + "\nБлагодарим за ваше предложение!", id_st)

View file

@ -1,6 +1,6 @@
from src.fedi_api import get_notifications, mark_as_read_notification, post_status, upload_attachment from src.fedi_api import get_notifications, mark_as_read_notification, post_status, upload_attachment
from src.fmn_states_db import add_state, get_state from src.fmn_states_db import add_state, get_state
from config import admins_bot, limit_movies_per_user, limit_all_movies_poll, hour_poll_posting from config import admins_bot, limit_movies_per_user, limit_all_movies_poll, hour_poll_posting, fmn_next_watching_hour
import threading, time import threading, time
from datetime import datetime from datetime import datetime
@ -28,9 +28,10 @@ def get_control_mention():
st_date = i['status']['created_at'] st_date = i['status']['created_at']
thread_created_at = dateutilparse(st_date) thread_created_at = dateutilparse(st_date)
delta = relativedelta(hour=hour_poll_posting, minute=0, second=0, weekday=TU(1)) delta = relativedelta(hour=hour_poll_posting, minute=0, second=0, weekday=TU(1))
next_movie_watching_delta = relativedelta(hour=21, minute=0, second=0, weekday=SU(1)) next_movie_watching_delta = relativedelta(hour=fmn_next_watching_hour, minute=0, second=0, weekday=SU(1))
stop_thread_scan = thread_created_at + delta stop_thread_scan = thread_created_at + delta
next_movie_watching = thread_created_at + next_movie_watching_delta next_movie_watching = thread_created_at + next_movie_watching_delta
max_mute_time = time.mktime(time.struct_time(next_movie_watching.timetuple()))
next_movie_watching = next_movie_watching.strftime('%d.%m.%Y') next_movie_watching = next_movie_watching.strftime('%d.%m.%Y')
movies_accept_time = stop_thread_scan.strftime('%H:%M %d.%m.%Y MSK') movies_accept_time = stop_thread_scan.strftime('%H:%M %d.%m.%Y MSK')
stop_thread_scan = time.mktime(time.struct_time(stop_thread_scan.timetuple())) stop_thread_scan = time.mktime(time.struct_time(stop_thread_scan.timetuple()))
@ -38,6 +39,7 @@ def get_control_mention():
post_status(start_collect_movies_text(movies_accept_time, next_movie_watching), st_id, attachments=[upload_attachment('src/FMN.png')]) post_status(start_collect_movies_text(movies_accept_time, next_movie_watching), st_id, attachments=[upload_attachment('src/FMN.png')])
time.sleep(0.2) time.sleep(0.2)
mark_as_read_notification(i['id']) mark_as_read_notification(i['id'])
add_state('max_mute_time', int(max_mute_time))
add_state('stop_thread_scan', int(stop_thread_scan)) add_state('stop_thread_scan', int(stop_thread_scan))
add_state('last_thread_id', st_id) add_state('last_thread_id', st_id)
break break