Skip to content

Commit

Permalink
Merge pull request #449 from maooyer/feat/render-rss-item-tags
Browse files Browse the repository at this point in the history
  • Loading branch information
Rongronggg9 committed Apr 25, 2024
2 parents b9eb248 + d81ace4 commit 9a50560
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 34 deletions.
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### Highlights

- **#Hashtags from post (feed entry)**: If enabled in `/set` or `/set_default`, hashtags from posts (feed entries), merged with the custom hashtags of the feed, will be added to the message. The term "hashtags from post" refers to `<category>` elements in RSS `<item>` or Atom `<entry>`. This feature is disabled by default. Thanks [@maooyer](https://github.com/maooyer) for their first contribution in [#449](https://github.com/Rongronggg9/RSS-to-Telegram-Bot/pull/449).
- **Support Python 3.12**: Minor fixes have been made to support Python 3.12. The official Docker image is now based on Python 3.12 as well.
- **Helper scripts to make contributions easier**: When performing contributions that update database models, creating database migration files is not an easy job. [scripts/aerich_helper.py](../scripts/aerich_helper.py) is a helper script that can simplify the process. Passing `--help` to the script to see a detailed usage guide.

Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### 亮点

- **来自文章 (源条目) 的 #hashtag**: 如果在 `/set``/set_default` 中启用,来自文章 (源条目) 的 hashtag,与源的自定义 hashtag 合并后,将被添加到消息中。术语 "来自文章的 hashtag" 指的是 RSS `<item>` 或 Atom `<entry>` 中的 `<category>` 元素。此功能默认禁用。感谢 [@maooyer](https://github.com/maooyer)[#449](https://github.com/Rongronggg9/RSS-to-Telegram-Bot/pull/449) 中的作出的初次贡献。
- **支持 Python 3.12**: 进行了一些小的修复以支持 Python 3.12。官方 Docker 镜像现在也基于 Python 3.12。
- **使贡献更容易的辅助脚本**: 在进行更新数据库模型的贡献时,创建数据库迁移文件并不是一件容易的事。[scripts/aerich_helper.py](../scripts/aerich_helper.py) 是一个可以简化这个流程的辅助脚本。将 `--help` 传递给脚本以查看详细的使用指南。

Expand Down
7 changes: 4 additions & 3 deletions src/command/customization.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ async def callback_set(event: events.CallbackQuery.Event,
display_author: -1=disable, 0=auto, 1=force display
display_via: -2=completely disable, -1=disable but display link, 0=auto, 1=force display
display_title: -1=disable, 0=auto, 1=force display
display_entry_tags: -1=disable, 1=force display
style: 0=RSStT, 1=flowerss
"""
chat_id = chat_id or event.chat_id
Expand Down Expand Up @@ -162,7 +163,7 @@ async def callback_reset(event: events.CallbackQuery.Event,
sub.interval = None
update_interval_flag = True
sub.length_limit = sub.notify = sub.send_mode = sub.link_preview = sub.display_author = sub.display_media = \
sub.display_title = sub.display_via = sub.style = -100
sub.display_title = sub.display_entry_tags = sub.display_via = sub.style = -100
await sub.save()
if update_interval_flag:
await inner.utils.update_interval(sub)
Expand Down Expand Up @@ -206,9 +207,9 @@ async def callback_reset_all(event: events.CallbackQuery.Event,
tasks.append(inner.utils.update_interval(sub))
sub.interval = None
sub.length_limit = sub.notify = sub.send_mode = sub.link_preview = sub.display_author = sub.display_media = \
sub.display_title = sub.display_via = sub.style = -100
sub.display_title = sub.display_entry_tags = sub.display_via = sub.style = -100
await db.Sub.bulk_update(subs, ('interval', 'length_limit', 'notify', 'send_mode', 'link_preview', 'display_author',
'display_media', 'display_title', 'display_via', 'style'))
'display_media', 'display_title', 'display_entry_tags', 'display_via', 'style'))
for task in tasks:
env.loop.create_task(task)
await event.edit(i18n[lang]['reset_all_successful'])
Expand Down
19 changes: 17 additions & 2 deletions src/command/inner/customization.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"display_author": (0, 1, -1),
"display_via": (0, 1, -3, -1, -4, -2),
"display_title": (0, 1, -1),
"display_entry_tags": (1, -1),
"style": (0, 1)
}

Expand Down Expand Up @@ -54,7 +55,7 @@ async def get_customization_buttons(sub_or_user: Union[db.Sub, db.User],
is_user = isinstance(sub_or_user, db.User)
if is_user:
interval_d = length_limit_d = notify_d = send_mode_d = link_preview_d = display_media_d = display_author_d = \
display_via_d = display_title_d = style_d = False
display_via_d = display_title_d = display_entry_tags_d = style_d = False
all_default = None
else:
if not isinstance(sub_or_user.user, db.User):
Expand All @@ -68,9 +69,10 @@ async def get_customization_buttons(sub_or_user: Union[db.Sub, db.User],
display_author_d = sub_or_user.display_author == -100
display_via_d = sub_or_user.display_via == -100
display_title_d = sub_or_user.display_title == -100
display_entry_tags_d = sub_or_user.display_entry_tags == -100
style_d = sub_or_user.style == -100
all_default = all((interval_d, length_limit_d, notify_d, send_mode_d, link_preview_d, display_media_d,
display_author_d, display_via_d, display_title_d, style_d))
display_author_d, display_via_d, display_title_d, display_entry_tags_d, style_d))
interval = sub_or_user.user.interval if interval_d else sub_or_user.interval
length_limit = sub_or_user.user.length_limit if length_limit_d else sub_or_user.length_limit
notify = sub_or_user.user.notify if notify_d else sub_or_user.notify
Expand All @@ -80,6 +82,7 @@ async def get_customization_buttons(sub_or_user: Union[db.Sub, db.User],
display_author = sub_or_user.user.display_author if display_author_d else sub_or_user.display_author
display_via = sub_or_user.user.display_via if display_via_d else sub_or_user.display_via
display_title = sub_or_user.user.display_title if display_title_d else sub_or_user.display_title
display_entry_tags = sub_or_user.user.display_entry_tags if display_entry_tags_d else sub_or_user.display_entry_tags
style = sub_or_user.user.style if style_d else sub_or_user.style
buttons = (
(
Expand Down Expand Up @@ -180,6 +183,18 @@ async def get_customization_buttons(sub_or_user: Union[db.Sub, db.User],
),
),
),
(
Button.inline(
f"{i18n[lang]['display_entry_tags']}: "
+ (FALLBACK_TO_USER_DEFAULT_EMOJI if display_entry_tags_d else '')
+ i18n[lang][f'display_entry_tags_{display_entry_tags}'],
data=(
f'set_default=display_entry_tags{tail}'
if is_user
else f'set={sub_or_user.id},display_entry_tags|{page}{tail}'
),
),
),
(
Button.inline(
f"{i18n[lang]['display_via']}: "
Expand Down
29 changes: 17 additions & 12 deletions src/command/inner/sub.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,23 @@ async def sub(user_id: int,
sub_title = sub_title if feed.title != sub_title else None

if not _sub: # create a new sub if needed
_sub, created_new_sub = await db.Sub.get_or_create(user_id=user_id, feed=feed,
defaults={'title': sub_title if sub_title else None,
'interval': None,
'notify': -100,
'send_mode': -100,
'length_limit': -100,
'link_preview': -100,
'display_author': -100,
'display_via': -100,
'display_title': -100,
'style': -100,
'display_media': -100})
_sub, created_new_sub = await db.Sub.get_or_create(
user_id=user_id, feed=feed,
defaults={
'title': sub_title if sub_title else None,
'interval': None,
'notify': -100,
'send_mode': -100,
'length_limit': -100,
'link_preview': -100,
'display_author': -100,
'display_via': -100,
'display_title': -100,
'display_entry_tags': -100,
'style': -100,
'display_media': -100
}
)

if not created_new_sub:
if _sub.title == sub_title and _sub.state == 1:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from tortoise import BaseDBAsyncClient


async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "sub" ADD "display_entry_tags" SMALLINT NOT NULL DEFAULT -100;
ALTER TABLE "user" ADD "display_entry_tags" SMALLINT NOT NULL DEFAULT -1;"""


async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "sub" DROP COLUMN "display_entry_tags";
ALTER TABLE "user" DROP COLUMN "display_entry_tags";"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from tortoise import BaseDBAsyncClient


async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "sub" ADD "display_entry_tags" SMALLINT NOT NULL DEFAULT -100;
ALTER TABLE "user" ADD "display_entry_tags" SMALLINT NOT NULL DEFAULT -1;"""


async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "sub" DROP COLUMN "display_entry_tags";
ALTER TABLE "user" DROP COLUMN "display_entry_tags";"""
5 changes: 5 additions & 0 deletions src/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class User(Model, Base):
display_author = fields.SmallIntField(default=0)
display_via = fields.SmallIntField(default=0)
display_title = fields.SmallIntField(default=0)
display_entry_tags = fields.SmallIntField(default=-1)
style = fields.SmallIntField(default=0)
display_media = fields.SmallIntField(default=0)

Expand Down Expand Up @@ -88,6 +89,8 @@ def __str__(self):
return self.link


# TODO: migrate the default value of all fields after `notify` (inclusive) to -100
# TODO: description makes a lot trouble on SQLite, remove the description of all fields after `notify` (inclusive)
class Sub(Model, Base):
"""
Sub model.
Expand Down Expand Up @@ -122,6 +125,8 @@ class Sub(Model, Base):
'0=auto, 1=force display')
display_title = fields.SmallIntField(default=0, description='Display title or not?'
'-1=disable, 0=auto, 1=force display')
# new field, use the de facto default value (-100) and with description unset to avoid future migration
display_entry_tags = fields.SmallIntField(default=-100)
style = fields.SmallIntField(default=0, description='Style of posts: '
'0=RSStT, 1=flowerss')
display_media = fields.SmallIntField(default=0, description='Display media or not?'
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@
"display_title_-1": "Disable",
"display_title_0": "Auto",
"display_title_1": "Enable",
"display_entry_tags": "Hashtags from post (feed entry)",
"display_entry_tags_-1": "Disable",
"display_entry_tags_1": "Enable",
"style": "Style",
"style_0": "RSStT",
"style_1": "flowerss",
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/yue.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@
"display_title_-1": "",
"display_title_0": "自動",
"display_title_1": "",
"display_entry_tags": "嚟自文章 (源條目) 嘅 hashtag",
"display_entry_tags_-1": "",
"display_entry_tags_1": "",
"style": "格式",
"style_0": "",
"style_1": "",
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/zh-Hans.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@
"display_title_-1": "禁用",
"display_title_0": "自动",
"display_title_1": "启用",
"display_entry_tags": "来自文章 (源条目) 的 hashtag",
"display_entry_tags_-1": "禁用",
"display_entry_tags_1": "启用",
"style": "风格",
"style_0": "",
"style_1": "",
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/zh-Hant.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@
"display_title_-1": "禁用",
"display_title_0": "自動",
"display_title_1": "啟用",
"display_entry_tags": "來自文章 (源條目) 的 hashtag",
"display_entry_tags_-1": "禁用",
"display_entry_tags_1": "啟用",
"style": "樣式",
"style_0": "",
"style_1": "",
Expand Down
41 changes: 30 additions & 11 deletions src/parsing/post.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations
from typing import Optional

from .. import db, env
from .. import db
from ..errors_collection import MediaSendFailErrors
from .utils import parse_entry, logger, Enclosure
from .post_formatter import PostFormatter
Expand All @@ -10,8 +10,16 @@

async def get_post_from_entry(entry, feed_title: str, feed_link: str = None) -> 'Post':
entry_parsed = await parse_entry(entry, feed_link)
return Post(entry_parsed.content, entry_parsed.title, feed_title, entry_parsed.link, entry_parsed.author,
feed_link=feed_link, enclosures=entry_parsed.enclosures)
return Post(
html=entry_parsed.content,
title=entry_parsed.title,
feed_title=feed_title,
link=entry_parsed.link,
author=entry_parsed.author,
tags=entry_parsed.tags,
feed_link=feed_link,
enclosures=entry_parsed.enclosures
)


class Post:
Expand All @@ -21,6 +29,7 @@ def __init__(self,
feed_title: Optional[str] = None,
link: Optional[str] = None,
author: Optional[str] = None,
tags: Optional[list[str]] = None,
feed_link: Optional[str] = None,
enclosures: list[Enclosure] = None):
"""
Expand All @@ -29,23 +38,28 @@ def __init__(self,
:param feed_title: feed title
:param link: post link
:param author: post author
:param tags: post tags
:param feed_link: the url of the feed where the post from
"""
self.html = html
self.title = title
self.feed_title = feed_title
self.link = link
self.author = author
self.tags = tags
self.feed_link = feed_link
self.enclosures = enclosures

self.post_formatter = PostFormatter(html=self.html,
title=self.title,
feed_title=self.feed_title,
link=self.link,
author=self.author,
feed_link=self.feed_link,
enclosures=self.enclosures)
self.post_formatter = PostFormatter(
html=self.html,
title=self.title,
feed_title=self.feed_title,
link=self.link,
author=self.author,
tags=self.tags,
feed_link=self.feed_link,
enclosures=self.enclosures
)

async def send_formatted_post_according_to_sub(self, sub: db.Sub):
if not isinstance(sub.feed, db.User):
Expand All @@ -61,6 +75,7 @@ async def send_formatted_post_according_to_sub(self, sub: db.Sub):
display_author=sub.display_author if sub.display_author != -100 else user.display_author,
display_via=sub.display_via if sub.display_via != -100 else user.display_via,
display_title=sub.display_title if sub.display_title != -100 else user.display_title,
display_entry_tags=sub.display_entry_tags if sub.display_entry_tags != -100 else user.display_entry_tags,
style=sub.style if sub.style != -100 else user.style,
display_media=sub.display_media if sub.display_media != -100 else user.display_media,
silent=not (sub.notify if sub.notify != -100 else user.notify)
Expand All @@ -76,6 +91,7 @@ async def send_formatted_post(self,
display_author: int = 0,
display_via: int = 0,
display_title: int = 0,
display_entry_tags: int = -1,
style: int = 0,
display_media: int = 0,
silent: bool = False):
Expand All @@ -92,6 +108,7 @@ async def send_formatted_post(self,
:param display_author: -1=disable, 0=auto, 1=force display
:param display_via: -2=completely disable, -1=disable but display link, 0=auto, 1=force display
:param display_title: -1=disable, 0=auto, 1=force display
:param display_entry_tags: -1=disable, 1=force display
:param style: 0=RSStT, 1=flowerss
:param display_media: -1=disable, 0=enable
:param silent: whether to send with notification sound
Expand All @@ -107,6 +124,7 @@ async def send_formatted_post(self,
display_author=display_author,
display_via=display_via,
display_title=display_title,
display_entry_tags=display_entry_tags,
style=style,
display_media=display_media)

Expand Down Expand Up @@ -168,6 +186,7 @@ async def test_format(self, user_id: int):
display_title=user.display_title,
style=user.style,
display_media=user.display_media,
silent=not user.notify
silent=not user.notify,
display_entry_tags=user.display_entry_tags,
)
return await self.send_formatted_post_according_to_sub(sub=sub)
Loading

0 comments on commit 9a50560

Please sign in to comment.