FMN_bot/src/listener_context.py

184 lines
9.8 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from config import hour_poll_posting, bot_acct, instance, limit_all_movies_poll, limit_movies_per_user, max_fail_limit
from src.fedi_api import get_status_context, get_status, post_status, mute_user
from src.kinopoisk_api import get_kinopoisk_movie_to_imdb
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_states_db import states_stor, write_states
from src.fmn_poll import create_poll_movies, get_winner_movie
import re
import time
from datetime import datetime
from dateutil.parser import parse as dateutilparse
from dateutil.relativedelta import relativedelta, TU
from collections import Counter
from loguru import logger
def parse_links(text=str):
regex = r"kinopoisk\.ru/"
if re.search(regex, text.lower(), flags=re.MULTILINE):
kinopoisk_ids = re.findall(r"film/(\d{1,})", text.lower())
if kinopoisk_ids != []:
return kinopoisk_ids[:limit_movies_per_user]
def parse_links_imdb(text=str):
regex = r"imdb\.com/|libremdb\.leemoon\.network/|libremdb\.pussthecat\.org/|libremdb\.esmailelbob\.xyz/|libremdb\.herokuapp\.com/|libremdbeu\.herokuapp\.com/|lmdb\.tokhmi\.xyz/|libremdb\.lqs5fjmajyp7rvp4qvyubwofzi6d4imua7vs237rkc4m5qogitqwrgyd\.onion/"
if re.search(regex, text.lower(), flags=re.MULTILINE):
imdb_ids = re.findall(r"tt(\d{1,})", text.lower())
if imdb_ids != []:
return imdb_ids[:limit_movies_per_user]
def scan_context_thread():
fail_limit = Counter()
while True:
states = states_stor.states
status_id = states.get('last_thread_id')
poll_created = states.get('poll_status_id')
stop_thread_scan = states.get('stop_thread_scan')
time_now = int(time.time())
reserve_time = False
while status_id is None or stop_thread_scan is None:
states = states_stor.states
fail_limit = Counter()
status_id = states.get('last_thread_id')
stop_thread_scan = states.get('stop_thread_scan')
time.sleep(1)
if time_now >= int(stop_thread_scan):
reserve_time = True
logger.debug('Сбор завершён, сканирование треда на опоздавших')
if poll_created is None:
create_poll_movies()
poll_created = states_stor.states.get('poll_status_id')
else:
if time_now >= int(states.get('poll_expires_at')):
get_winner_movie(poll_created)
else:
endings = int(stop_thread_scan) - time_now
logger.debug(f'Осталось до закрытия сбора: {endings}')
if reserve_time: # Reduce instance load
time.sleep(30)
get_thread_time = time.time()
descendants = get_status_context(status_id)['descendants']
get_thread_time2 = time.time()
get_thread_delta = get_thread_time2 - get_thread_time
logger.debug(f'Get thread time: {get_thread_delta}')
replyed = []
for status in descendants:
if status['account']['acct'] == bot_acct:
replyed.append(status['in_reply_to_id'])
for status in descendants:
id_st = status['id']
in_reply_acct = status['in_reply_to_account_id']
in_reply_id = status['in_reply_to_id']
muted = status['muted']
acct = status['account']['acct']
acct_id = status['account']['id']
content = status['pleroma']['content']['text/plain']
if id_st in replyed: # Игнорировать уже отвеченное
continue
if muted is True:
continue
if fail_limit[acct] >= max_fail_limit: # Игнорировать пользователя если он превысил fail limit
mute_user(acct_id, acct, int(states.get('max_mute_time')) - time_now)
logger.warning(f'{acct} игнорируется - превышение fail limit')
break # Нужно обновить тред, чтобы muted на заглушенном стал True
parsed_result = parse_links(content)
parsed_result_imdb = parse_links_imdb(content)
if parsed_result is None and parsed_result_imdb is None:
continue
if poll_created:
post_status(f' Приём заявок уже окончен.\n\nГолосовалка здесь: https://{instance}/notice/{poll_created}', id_st)
logger.info(f'{acct} был уведомлен о завершенной голосовалке')
fail_limit[acct] += 1
continue
index_type = 1
index_name = 2
index_ru_name = 3
index_year = 4
if parsed_result is not None:
print(parsed_result)
suggested_movies = get_kinopoisk_movie_to_imdb(parsed_result)
if suggested_movies is None:
post_status('Не удалось выполнить запрос: возможно некорректный тип фильма, попробуйте использовать imdb.com', id_st)
fail_limit[acct] += 1
continue
elif parsed_result_imdb is not None:
suggested_movies = get_title_by_id(parsed_result_imdb)
if suggested_movies is None:
post_status('❌ Фильм(ы) не найден в базе данных IMDB, пожалуйста обратитесь к администратору, чтобы обновить базу. Примечание: IMDB выкладывает новые изменения не сразу.', id_st)
fail_limit[acct] += 1
continue
message_writer = []
success = False
for movie in suggested_movies:
logger.debug(str(movie))
if movie[index_type] == "404":
message_writer.append("Не найдено.")
fail_limit[acct] += 1
elif movie[index_type] not in ("movie", "tvMovie", "video"):
type_of_title = movie[index_type]
message_writer.append(f"Не принято:\n- Нам не подходят: сериалы, короткометражные и документальные фильмы")
logger.info(f'Предложение {acct} отклонено: не подходящий тип фильма: {type_of_title}')
fail_limit[acct] += 1
else:
name = movie[index_name]
name_ru = movie[index_ru_name]
year = movie[index_year]
movie_string = f"{name_ru} / {name}, {year}"
if name is None:
movie_string = f"{name_ru}, {year}"
if name_ru is None:
movie_string = f"{name}, {year}"
if year is None:
post_status('🎬 Мы временно не можем обработать ваше предложение: Обработка фильма без наличия года невозможна.', id_st)
fail_limit[acct] += 1
break
if get_suggested_movies_count() >= limit_all_movies_poll:
post_status('🎬 Мы не можем обработать ваше предложение: количество уже предложенных не помещается в лимит голосовалки.', id_st)
logger.warning(f'Предложение {acct} было отклонено: количество уже предложенных фильмов превышает\равно {limit_all_movies_poll}')
fail_limit[acct] += 1
break
if get_already_watched(name, name_ru, year) == True:
message_writer.append(f" Этот фильм уже был на FMN: {movie_string}")
logger.info(f'Попытка предложить уже просмотренный фильм: {acct} {name} {name_ru} {year}')
fail_limit[acct] += 1
continue
add_result = add_movie_to_poll(acct, name, name_ru, year)
if add_result == 0:
message_writer.append(f"✅ Принято: {movie_string}")
logger.success(f'Предложение от {acct} принято: {name} {name_ru} {year}')
success = True
elif add_result == 1:
message_writer.append("❌ Этот фильм уже был предложен")
logger.info(f'Предложение от {acct} было отлонено - фильм в опросе существует')
fail_limit[acct] += 1
else:
message_writer.append(f"❌ Вы не можете добавить больше {limit_movies_per_user}x фильмов")
logger.info(f'Предложение от {acct} было отлонено - лимит на пользователя')
fail_limit[acct] += 1
if message_writer != []:
message = ''
if success:
message = "\nБлагодарим за ваше предложение!"
post_status('\n'.join(message_writer) + message, id_st)
time.sleep(30)