MountainDash / nonebot-bison

A nonebot2 plugin to repost social media posts to QQ group
https://nonebot-bison.netlify.app
MIT License
160 stars 33 forks source link

实现 `Post.content` 相关扩展协议 #553

Closed GuGuMur closed 1 month ago

GuGuMur commented 2 months ago

fix #526

~图片直接删 爽!~

netlify[bot] commented 2 months ago

Deploy request for nonebot-bison pending review.

Visit the deploys page to approve it

Name Link
Latest commit ad5309f03a4bff98f84f93a3500ec285c25e0d27
codecov[bot] commented 2 months ago

Codecov Report

Attention: Patch coverage is 78.94737% with 16 lines in your changes missing coverage. Please review.

Project coverage is 84.90%. Comparing base (0c1012b) to head (ad5309f).

Files Patch % Lines
nonebot_bison/platform/rss.py 33.33% 8 Missing :warning:
nonebot_bison/theme/themes/ht2i/build.py 44.44% 5 Missing :warning:
nonebot_bison/platform/arknights.py 95.45% 1 Missing :warning:
nonebot_bison/theme/themes/arknights/build.py 50.00% 1 Missing :warning:
nonebot_bison/theme/themes/ceobe_canteen/build.py 50.00% 1 Missing :warning:
Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #553 +/- ## ========================================== - Coverage 85.01% 84.90% -0.11% ========================================== Files 88 89 +1 Lines 4491 4546 +55 ========================================== + Hits 3818 3860 +42 - Misses 673 686 +13 ``` | [Flag](https://app.codecov.io/gh/MountainDash/nonebot-bison/pull/553/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MountainDash) | Coverage Δ | | |---|---|---| | [smoke-test](https://app.codecov.io/gh/MountainDash/nonebot-bison/pull/553/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MountainDash) | `84.90% <78.94%> (-0.11%)` | :arrow_down: | Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MountainDash#carryforward-flags-in-the-pull-request-comment) to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

felinae98 commented 2 months ago

可以搞成

@property
def content():

可以少改很多

felinae98 commented 2 months ago

当然已经改了就算了

AzideCupric commented 2 months ago

考虑尽可能保留content内的信息比较好,毕竟有些富文本格式在某些theme内是可以使用的

希望是可以有一个

@property
def plain_content(self):
    ...

然后不同的theme按需选择使用content还是plain_content,这样好一点。

但目前有个问题,PostPlatform 基本上是独立的,每个 Platform 对应的 plain_content 的提取行为显然不可能完全一样,如何把 Platform 生成 plain_content 的这个行为放进 Post 里是需要考虑的。~同时我不喜欢在Platform里蹦出来一个对Post的继承~

得益于函数是一等公民的好处,或许可以有这样的一种实现


class APlatform(NewMessage):
    #...

    async def parse(...):
        def _get_plain_content(content: str):
            # 诸如正则之类的提取
            return plain_content

        # 1
        post = Post(
            # ...
            plain_content_func = _get_plain_content
            )
        # 2
        post.register_plain_content_func(_get_plain_content)
        return post

在原有的Post中添加

class Post(...):
    plain_content_func: Callable[...] | None = None

    def __init__(..., plain_content_func: Callable[...] | None = None):
        self.plain_content_func = plain_content_func

    def register_plain_content_func(self, func: Callable[...]):
        self.plain_content_func = func

    @property
    def plain_content(self):
        if self.plain_content_func:
            return self.plain_content_func(self.content)
        return self.content

类似这样的实现方案

felinae98 commented 2 months ago

还是 plain_content() 吧))

AzideCupric commented 2 months ago

还是 plain_content 吧,考虑了一下应该很难用得着这么复杂的情况

felinae98 commented 1 month ago

Post 的定义不应该变,应该新搞一个 HTMLPost 继承 Post,里面有一个 html_content 的字段。 platform 返回 HTMLPost,theme 检查这个 post 是不是 htmlpost

GuGuMur commented 1 month ago

(挠头)这么一来,是不是还得整个 MarkdownPost 什么的啊(

yysy 早知道中间折腾下这么多版本,群友说法一个星期一遍,一开始就写 plain_content 了,折腾什么装饰器什么函数啊

启示各位处理pr要趁早,拖的越久越解决不了

AzideCupric commented 1 month ago

新写的Demo

# post.py
from functools import partial
from typing import Protocol, runtime_checkable
from dataclasses import dataclass

@dataclass
class Post:
    title: str
    content: str

@runtime_checkable
class PlainContentSupport(Protocol):
    async def get_plain_content(self) -> str:
        ...

@runtime_checkable
class HTMLContentSupport(Protocol):
    async def get_html_content(self) -> str:
        ...

@runtime_checkable
class MarkdownContentSupport(Protocol):
    async def get_markdown_content(self) -> str:
        ...

# platform
## bilibili.py
class BilibiliPost(Post, PlainContentSupport, HTMLContentSupport):
    async def get_plain_content(self) -> str:
        return self.content

    async def get_html_content(self) -> str:
        return f"<p>{self.content}</p>"

class Bilibili:
    def parse(self) -> BilibiliPost:
        return BilibiliPost(title="蒙古上单", content="柠檬什么时候熟啊")

## weibo.py
class WeiboPost(Post):
    async def get_markdown_content(self) -> str:
        return f"**{self.content}**"

class Weibo:
    def parse(self) -> WeiboPost:
        return WeiboPost(title="1+1", content="芝士雪豹")

## ncm.py
class Ncm:
    def parse(self) -> Post:
        return Post(title="塞壬唱片", content="发布了新专辑")

# theme.py
class PlainTheme:
    async def render(self, post: Post) -> str:
        if isinstance(post, PlainContentSupport):
            content = await post.get_plain_content()
        else:
            content = post.content

        return f"{post.title}\n{content}"

class RichTheme:
    async def render(self, post: Post) -> str:
        if isinstance(post, HTMLContentSupport):
            content = await post.get_html_content()
        else:
            content = post.content

        return f"<title>{post.title}<title>\n{content}"

class MarkdownTheme:
    async def render(self, post: Post) -> str:
        if isinstance(post, MarkdownContentSupport):
            content = await post.get_markdown_content()
        elif isinstance(post, HTMLContentSupport):
            content = await post.get_html_content()
        else:
            content = post.content

        return f"# {post.title}\n\n{content}"

if __name__ == "__main__":
    bilibili = Bilibili().parse()
    weibo = Weibo().parse()
    ncm = Ncm().parse()

    plain_theme = PlainTheme()
    rich_theme = RichTheme()
    markdown_theme = MarkdownTheme()

    _print = partial(print, end="\n\n---\n\n")

    async def main():
        _print(await plain_theme.render(bilibili))
        _print(await rich_theme.render(bilibili))
        _print(await markdown_theme.render(bilibili))

        _print(await plain_theme.render(weibo))
        _print(await rich_theme.render(weibo))
        _print(await markdown_theme.render(weibo))

        _print(await plain_theme.render(ncm))
        _print(await rich_theme.render(ncm))
        _print(await markdown_theme.render(ncm))

    import asyncio
    asyncio.run(main())
AzideCupric commented 1 month ago

@GuGuMur 改一下title就能合了