Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support to render rss item tags #449

Merged
merged 6 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
return self.link


# TODO: migrate the default value of all fields after `notify` (inclusive) to -100

Check notice on line 92 in src/db/models.py

View check run for this annotation

codefactor.io / CodeFactor

src/db/models.py#L92

unresolved comment '# TODO: migrate the default value of all fields after `notify` (inclusive) to -100' (C100)
# TODO: description makes a lot trouble on SQLite, remove the description of all fields after `notify` (inclusive)

Check notice on line 93 in src/db/models.py

View check run for this annotation

codefactor.io / CodeFactor

src/db/models.py#L93

unresolved comment '# TODO: description makes a lot trouble on SQLite, remove the description of all fields after `notify` (inclusive)' (C100)
class Sub(Model, Base):
"""
Sub model.
Expand Down Expand Up @@ -122,6 +125,8 @@
'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
Loading