From 6d842054250fb9f605ab5476b6477df0ffec3b3a Mon Sep 17 00:00:00 2001 From: BreadTube Date: Thu, 14 May 2026 23:20:55 +0900 Subject: [PATCH] Fix convert yt url message being too long * Add long message check * Minor lint rule fix --- breadtube_bot/bot.py | 75 +++++++++++++------ breadtube_bot/discord_manager.py | 4 + ...code_data.py => generate_unidecode_data.py | 0 pyproject.toml | 1 + tests/test_youtube_manager.py | 2 +- 5 files changed, 60 insertions(+), 22 deletions(-) rename generated_unidecode_data.py => generate_unidecode_data.py (100%) diff --git a/breadtube_bot/bot.py b/breadtube_bot/bot.py index ea47bce..89156ba 100644 --- a/breadtube_bot/bot.py +++ b/breadtube_bot/bot.py @@ -141,6 +141,59 @@ class Bot: last_message_id = message_batch[-1].id return messages + def _convert_yt_channel_url(self, message: Message, delayed_delete: dict[int, Message]): + self.logger.debug('Parsing message for youtube channel name conversion: %s', message) + answers: list[str] = [] + for line in message.content.splitlines(): + if line.startswith(self.YT_CHANNEL_NAME_URL): + channel_name = line.rstrip()[len(self.YT_CHANNEL_NAME_URL):] + try: + channel_id = self.yt_manager.request_channel_id( + channel_name, request_timeout=self.config.request_timeout) + answers.append( + f'{channel_name}{self.config.youtube_channel_id_answer_seperator}{channel_id}') + except RuntimeError as error: + answers.append(f'{channel_name}{self.config.youtube_channel_id_answer_seperator}{error}') + if len('\n'.join(answers)) < self.discord_manager.MAX_MESSAGE_LENGTH: + bot_message = self.discord_manager.create_message(self.bot_channel, { + 'content': '\n'.join(answers), + 'message_reference': MessageReference( + type=MessageReferenceType.DEFAULT, + message_id=message.id, + channel_id=self.bot_channel.id, + guild_id=None, + fail_if_not_exists=None)}, request_timeout=self.config.request_timeout) + delayed_delete[bot_message.id] = bot_message + else: + content_buffer = [] + content_size = 0 + for line in answers: + if content_size + len(line) + 1 >= self.discord_manager.MAX_MESSAGE_LENGTH: + bot_message = self.discord_manager.create_message(self.bot_channel, { + 'content': '\n'.join(content_buffer), + 'message_reference': MessageReference( + type=MessageReferenceType.DEFAULT, + message_id=message.id, + channel_id=self.bot_channel.id, + guild_id=None, + fail_if_not_exists=None)}, request_timeout=self.config.request_timeout) + delayed_delete[bot_message.id] = bot_message + content_buffer = [] + content_size = 0 + content_buffer.append(line) + content_size += len(line) + 1 + if content_buffer: + bot_message = self.discord_manager.create_message(self.bot_channel, { + 'content': '\n'.join(content_buffer), + 'message_reference': MessageReference( + type=MessageReferenceType.DEFAULT, + message_id=message.id, + channel_id=self.bot_channel.id, + guild_id=None, + fail_if_not_exists=None)}, request_timeout=self.config.request_timeout) + delayed_delete[bot_message.id] = bot_message + return delayed_delete + def _scan_bot_channel(self): # noqa: PLR0915 self.logger.debug('Starting scanning bot channel') messages = self._get_all_channel_messages(self.bot_channel) @@ -153,27 +206,7 @@ class Bot: for message in messages: if message.author.id != self.bot_user.id and message.content.startswith(self.YT_CHANNEL_NAME_URL): try: - self.logger.debug('Parsing message for youtube channel name conversion: %s', message) - answers: list[str] = [] - for line in message.content.splitlines(): - if line.startswith(self.YT_CHANNEL_NAME_URL): - channel_name = line.rstrip()[len(self.YT_CHANNEL_NAME_URL):] - try: - channel_id = self.yt_manager.request_channel_id( - channel_name, request_timeout=self.config.request_timeout) - answers.append( - f'{channel_name}{self.config.youtube_channel_id_answer_seperator}{channel_id}') - except RuntimeError as error: - answers.append(f'{channel_name}{self.config.youtube_channel_id_answer_seperator}{error}') - bot_message = self.discord_manager.create_message(self.bot_channel, { - 'content': '\n'.join(answers), - 'message_reference': MessageReference( - type=MessageReferenceType.DEFAULT, - message_id=message.id, - channel_id=self.bot_channel.id, - guild_id=None, - fail_if_not_exists=None)}, request_timeout=self.config.request_timeout) - delayed_delete[bot_message.id] = bot_message + self._convert_yt_channel_url(message, delayed_delete) except Exception as error: self.logger.error('Unexpected error while searching channel id from name: %s', error) delayed_delete[message.id] = message diff --git a/breadtube_bot/discord_manager.py b/breadtube_bot/discord_manager.py index 66b51fd..d10ecf6 100644 --- a/breadtube_bot/discord_manager.py +++ b/breadtube_bot/discord_manager.py @@ -31,6 +31,7 @@ class ApiEncoder(json.JSONEncoder): class DiscordManager: MIN_API_VERSION = 9 TOO_MANY_REQUEST_STATUS = 429 + MAX_MESSAGE_LENGTH = 2000 @dataclass class RateLimit: @@ -151,6 +152,9 @@ class DiscordManager: def create_message(self, channel: TextChannel, params: Api.Message.CreateParams, request_timeout: float, upload_files: list[tuple[str, FileMime, bytes]] | None = None) -> Message: + if 'content' in params and len(params['content']) >= self.MAX_MESSAGE_LENGTH: + raise RuntimeError(f"Cannot send message of length {len(params['content'])}" + f', max length is {self.MAX_MESSAGE_LENGTH}') _, message_info = self._send_request( *Api.Message.create(channel_id=channel.id), request_timeout=request_timeout, data=json.dumps(params, cls=ApiEncoder).encode(), upload_files=upload_files) diff --git a/generated_unidecode_data.py b/generate_unidecode_data.py similarity index 100% rename from generated_unidecode_data.py rename to generate_unidecode_data.py diff --git a/pyproject.toml b/pyproject.toml index 684d936..e489f74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ ignore = ["E275", "FURB140", "I001", "PERF203", "RET502", "RET503", "SIM105"] [tool.ruff.lint.per-file-ignores] "tests/*" = ["SLF001", "PLR2004"] "breadtube_bot/unidecode_data.py" = ["E501"] +"generate_unidecode_data.py" = ["T201"] [tool.ruff.lint.flake8-quotes] inline-quotes = "single" diff --git a/tests/test_youtube_manager.py b/tests/test_youtube_manager.py index 7b51b84..db2a7a5 100644 --- a/tests/test_youtube_manager.py +++ b/tests/test_youtube_manager.py @@ -8,7 +8,7 @@ from breadtube_bot.youtube_subscription import ChannelInfo def test_rss_parsing(): logger = logging.getLogger('breadtube-bot-test') manager = YoutubeManager('', logger=logger) - channel_info, videos = manager._parse_rss_data(Path('tests/data/rss_feed_sample.xml').read_text(encoding='utf-8')) + channel_info, videos = manager._parse_rss_data(Path('tests/data/rss_feed_sample.xml')) assert channel_info == ChannelInfo( channel_id='UCFemKOoYVrTGUhuVzuNPt4A', title='Actu Réfractaire', url='https://www.youtube.com/channel/UCFemKOoYVrTGUhuVzuNPt4A')