1
0
Fork 0

Added a all other filters

This commit is contained in:
Casey 2022-08-28 01:05:14 +03:00
parent d19a3d2005
commit bba6168f2b
Signed by: hkc
GPG Key ID: F0F6CFE11CDB0960
6 changed files with 115 additions and 0 deletions

View File

@ -1,4 +1,14 @@
from typing import List
from mastoposter.types import Status
from .base import BaseFilter # NOQA from .base import BaseFilter # NOQA
from mastoposter.filters.boost import BoostFilter # NOQA from mastoposter.filters.boost import BoostFilter # NOQA
from mastoposter.filters.combined import CombinedFilter # NOQA from mastoposter.filters.combined import CombinedFilter # NOQA
from mastoposter.filters.mention import MentionFilter # NOQA from mastoposter.filters.mention import MentionFilter # NOQA
from mastoposter.filters.media import MediaFilter # NOQA
from mastoposter.filters.text import TextFilter # NOQA
from mastoposter.filters.spoiler import SpoilerFilter # NOQA
def run_filters(filters: List[BaseFilter], status: Status) -> bool:
return all((fil(status) for fil in filters))

View File

@ -0,0 +1,27 @@
from configparser import SectionProxy
from typing import Set
from mastoposter.filters.base import BaseFilter
from mastoposter.types import Status
class MediaFilter(BaseFilter, filter_name="media"):
def __init__(self, section: SectionProxy):
super().__init__(section)
self.valid_media: Set[str] = set(section.get("valid_media").split())
self.mode = section.get("mode", "include")
if self.mode not in ("include", "exclude", "only"):
raise ValueError(f"{self.mode=} is not valid")
def __call__(self, status: Status) -> bool:
if not status.media_attachments:
return False
types: Set[str] = {a.type for a in status.media_attachments}
if self.mode == "include":
return len(types & self.valid_media) > 0
elif self.mode == "exclude":
return len(types & self.valid_media) == 0
elif self.mode == "only":
return len((types ^ self.valid_media) & types) == 0
raise ValueError(f"{self.mode=} is not valid")

View File

@ -0,0 +1,13 @@
from configparser import SectionProxy
from re import Pattern, compile as regexp
from mastoposter.filters.base import BaseFilter
from mastoposter.types import Status
class SpoilerFilter(BaseFilter, filter_name="spoiler"):
def __init__(self, section: SectionProxy):
super().__init__(section)
self.regexp: Pattern = regexp(section["regexp"])
def __call__(self, status: Status) -> bool:
return self.regexp.match(status.spoiler_text) is not None

View File

@ -0,0 +1,51 @@
from configparser import SectionProxy
from re import Pattern, compile as regexp
from typing import Optional, Set
from bs4 import BeautifulSoup, PageElement, Tag
from mastoposter.filters.base import BaseFilter
from mastoposter.types import Status
class TextFilter(BaseFilter, filter_name="content"):
def __init__(self, section: SectionProxy):
super().__init__(section)
self.mode = section["mode"]
self.tags: Set[str] = set()
self.regexp: Optional[Pattern] = None
if self.mode == "regexp":
self.regexp = regexp(section["regexp"])
elif self.mode == "hashtag":
self.tags = set(section["tags"].split())
else:
raise ValueError(f"Invalid filter mode {self.mode}")
@classmethod
def node_to_text(cls, el: PageElement) -> str:
if isinstance(el, Tag):
if el.name == "br":
return "\n"
elif el.name == "p":
return (
str.join("", map(cls.node_to_text, el.children)) + "\n\n"
)
return str.join("", map(cls.node_to_text, el.children))
return str(el)
@classmethod
def html_to_plain(cls, html: str) -> str:
soup = BeautifulSoup(html, "lxml")
return cls.node_to_text(soup).rstrip()
def __call__(self, status: Status) -> bool:
source = status.reblog or status
if self.regexp is not None:
return (
self.regexp.match(self.html_to_plain(source.content))
is not None
)
elif self.tags:
return len(self.tags & {t.name for t in source.tags}) > 0
else:
raise ValueError("Neither regexp or tags were set. Why?")

View File

@ -0,0 +1,12 @@
from configparser import SectionProxy
from mastoposter.filters.base import BaseFilter
from mastoposter.types import Status
class VisibilityFilter(BaseFilter, filter_name="visibility"):
def __init__(self, section: SectionProxy):
super().__init__(section)
self.options = tuple(section["options"].split())
def __call__(self, status: Status) -> bool:
return status.visibility in self.options

View File

@ -263,6 +263,7 @@ class Status:
favourites_count: int favourites_count: int
replies_count: int replies_count: int
mentions: List[Mention] mentions: List[Mention]
tags: List[Tag]
application: Optional[Application] = None application: Optional[Application] = None
url: Optional[str] = None url: Optional[str] = None
in_reply_to_id: Optional[str] = None in_reply_to_id: Optional[str] = None
@ -300,6 +301,7 @@ class Status:
language=data.get("language"), language=data.get("language"),
text=data.get("text"), text=data.get("text"),
mentions=[Mention.from_dict(m) for m in data.get("mentions", [])], mentions=[Mention.from_dict(m) for m in data.get("mentions", [])],
tags=[Tag.from_dict(m) for m in data.get("tags", [])],
) )
@property @property