libs.functions.message

libs/functions/message.py

  1"""
  2libs/functions/message.py
  3"""
  4
  5import logging
  6import random
  7import textwrap
  8from configparser import ConfigParser
  9from pathlib import Path
 10from typing import TYPE_CHECKING
 11
 12import libs.global_value as g
 13from libs.functions.compose import text_item
 14from libs.types import CommandType
 15from libs.utils.timekit import ExtendedDatetime as ExtDt
 16
 17if TYPE_CHECKING:
 18    from integrations.protocols import MessageParserProtocol
 19    from libs.domain.datamodels import GameInfo
 20
 21
 22def random_reply(m: "MessageParserProtocol", message_type: str) -> str:
 23    """
 24    メッセージをランダムに返す
 25
 26    Args:
 27        m (MessageParserProtocol): メッセージデータ
 28        message_type (str): 応答メッセージの種類
 29
 30    Returns:
 31        str: 応答メッセージ
 32
 33    """
 34    parser = ConfigParser()
 35    parser.read(g.cfg.config_file, encoding="utf-8")
 36
 37    correct_score = g.params.origin_point * 4  # 配給原点
 38    rpoint_diff = abs(correct_score - m.status.rpoint_sum)
 39
 40    default_message_type = {
 41        "invalid_argument": "使い方が間違っています。",
 42        "no_hits": "{start}{end} に成績記録ワードが見つかりません。",
 43        "no_target": "集計対象データがありません。",
 44        "invalid_score": "素点合計:{rpoint_sum}\n点数差分:{rpoint_diff}",
 45        "restricted_channel": "<@{user_id}> この投稿はデータベースに反映されません。",
 46        "inside_thread": "<@{user_id}> スレッド内から成績登録はできません。",
 47        "same_player": "同名のプレイヤーがいます。",
 48        "not_implemented": "未実装",
 49        "access_denied": "アクセスが拒否されました。",
 50        "rule_mismatch": "集計モード(四人打/三人打)の指定と集計対象ルールに矛盾があります。",
 51    }
 52
 53    msg = default_message_type.get(message_type, "invalid_argument")
 54
 55    if g.cfg.main_parser.has_section(m.status.source):
 56        if channel_config := g.cfg.main_parser[m.status.source].get("channel_config"):
 57            parser.read(Path(channel_config), encoding="utf-8")
 58
 59    if parser.has_section("custom_message"):
 60        msg_list = []
 61        for key, val in parser.items("custom_message"):
 62            if key.startswith(message_type):
 63                msg_list.append(val)
 64        if msg_list:
 65            msg = random.choice(msg_list)
 66
 67    if keywords := g.cfg.rule.keywords(g.params.rule_version):
 68        keyword = list(keywords)[0]
 69    else:
 70        keyword = list(g.cfg.rule.keyword_mapping.keys())[0]
 71
 72    try:
 73        msg = str(
 74            # 文字列置き換え
 75            msg.format(
 76                user_id=m.data.user_id,
 77                keyword=keyword,
 78                start=ExtDt(g.params.starttime).format(ExtDt.FMT.YMD),
 79                end=ExtDt(g.params.onday).format(ExtDt.FMT.YMD),
 80                rpoint_diff=rpoint_diff * 100,
 81                rpoint_sum=m.status.rpoint_sum * 100,
 82            )
 83        )
 84    except KeyError as err:
 85        logging.warning("[unknown keywords] %s: %s", err, msg)
 86        msg = msg.replace("{user_id}", m.data.user_id)
 87
 88    return msg
 89
 90
 91def header(game_info: "GameInfo", m: "MessageParserProtocol", add_text: str = "", indent: int = 1) -> str:
 92    """
 93    見出し生成
 94
 95    Args:
 96        game_info (GameInfo): 集計範囲のゲーム情報
 97        m (MessageParserProtocol): メッセージデータ
 98        add_text (str, optional): 追加表示するテキスト. Defaults to "".
 99        indent (int, optional): 先頭のタブ数. Defaults to 1.
100
101    Returns:
102        str: 生成した見出し
103
104    """
105    msg = ""
106    assert isinstance(game_info.first_game, ExtDt)
107    assert isinstance(game_info.last_game, ExtDt)
108
109    # 集計範囲
110    if g.params.search_word:  # コメント検索の場合はコメントで表示
111        game_range1 = f"最初のゲーム:{game_info.first_comment}\n"
112        game_range1 += f"最後のゲーム:{game_info.last_comment}\n"
113    else:
114        game_range1 = f"最初のゲーム:{game_info.first_game.format(ExtDt.FMT.YMDHMS)}\n"
115        game_range1 += f"最後のゲーム:{game_info.last_game.format(ExtDt.FMT.YMDHMS)}\n"
116    game_range2 = f"集計範囲:{text_item.aggregation_range(game_info)}\n"
117
118    # ゲーム数
119    if game_info.count == 0:
120        msg += f"{random_reply(m, 'no_hits')}"
121    else:
122        match m.status.command_type:
123            case CommandType.RESULTS:
124                if g.params.target_count:  # 直近指定がない場合は検索範囲を付ける
125                    msg += game_range1
126                    msg += f"集計対象:{game_info.count} ゲーム {add_text}\n"
127                else:
128                    msg += f"検索範囲:{str(text_item.search_range(time_pattern='time'))}\n"
129                    msg += game_range1
130                    msg += f"集計対象:{game_info.count} ゲーム {add_text}\n"
131            case CommandType.RANKING | CommandType.REPORT:
132                msg += game_range2
133                msg += f"集計対象:{game_info.count} ゲーム\n"
134            case _:
135                msg += game_range2
136                msg += f"集計対象:{game_info.count} ゲーム\n"
137
138        if remarks_text := text_item.remarks(True):
139            msg += f"{remarks_text}\n"
140        if word_text := text_item.search_word(True):
141            msg += f"{word_text}\n"
142
143    return textwrap.indent(msg, "\t" * indent)
def random_reply( m: integrations.protocols.MessageParserProtocol, message_type: str) -> str:
23def random_reply(m: "MessageParserProtocol", message_type: str) -> str:
24    """
25    メッセージをランダムに返す
26
27    Args:
28        m (MessageParserProtocol): メッセージデータ
29        message_type (str): 応答メッセージの種類
30
31    Returns:
32        str: 応答メッセージ
33
34    """
35    parser = ConfigParser()
36    parser.read(g.cfg.config_file, encoding="utf-8")
37
38    correct_score = g.params.origin_point * 4  # 配給原点
39    rpoint_diff = abs(correct_score - m.status.rpoint_sum)
40
41    default_message_type = {
42        "invalid_argument": "使い方が間違っています。",
43        "no_hits": "{start}{end} に成績記録ワードが見つかりません。",
44        "no_target": "集計対象データがありません。",
45        "invalid_score": "素点合計:{rpoint_sum}\n点数差分:{rpoint_diff}",
46        "restricted_channel": "<@{user_id}> この投稿はデータベースに反映されません。",
47        "inside_thread": "<@{user_id}> スレッド内から成績登録はできません。",
48        "same_player": "同名のプレイヤーがいます。",
49        "not_implemented": "未実装",
50        "access_denied": "アクセスが拒否されました。",
51        "rule_mismatch": "集計モード(四人打/三人打)の指定と集計対象ルールに矛盾があります。",
52    }
53
54    msg = default_message_type.get(message_type, "invalid_argument")
55
56    if g.cfg.main_parser.has_section(m.status.source):
57        if channel_config := g.cfg.main_parser[m.status.source].get("channel_config"):
58            parser.read(Path(channel_config), encoding="utf-8")
59
60    if parser.has_section("custom_message"):
61        msg_list = []
62        for key, val in parser.items("custom_message"):
63            if key.startswith(message_type):
64                msg_list.append(val)
65        if msg_list:
66            msg = random.choice(msg_list)
67
68    if keywords := g.cfg.rule.keywords(g.params.rule_version):
69        keyword = list(keywords)[0]
70    else:
71        keyword = list(g.cfg.rule.keyword_mapping.keys())[0]
72
73    try:
74        msg = str(
75            # 文字列置き換え
76            msg.format(
77                user_id=m.data.user_id,
78                keyword=keyword,
79                start=ExtDt(g.params.starttime).format(ExtDt.FMT.YMD),
80                end=ExtDt(g.params.onday).format(ExtDt.FMT.YMD),
81                rpoint_diff=rpoint_diff * 100,
82                rpoint_sum=m.status.rpoint_sum * 100,
83            )
84        )
85    except KeyError as err:
86        logging.warning("[unknown keywords] %s: %s", err, msg)
87        msg = msg.replace("{user_id}", m.data.user_id)
88
89    return msg

メッセージをランダムに返す

Arguments:
  • m (MessageParserProtocol): メッセージデータ
  • message_type (str): 応答メッセージの種類
Returns:

str: 応答メッセージ