kopia lustrzana https://github.com/halcy/Mastodon.py
268 wiersze
11 KiB
Python
268 wiersze
11 KiB
Python
# filters.py - Filter-related endpoints
|
|
|
|
import re
|
|
|
|
from mastodon.errors import MastodonIllegalArgumentError
|
|
from mastodon.utility import api_version
|
|
|
|
from mastodon.internals import Mastodon as Internals
|
|
from mastodon.return_types import Filter, FilterV2, Status, Notification, FilterKeyword, FilterStatus
|
|
from mastodon.types_base import PaginatableList, NonPaginatableList, IdType
|
|
|
|
from typing import Union, Optional, List, Dict
|
|
|
|
|
|
class Mastodon(Internals):
|
|
###
|
|
# Reading data: Keyword filters
|
|
###
|
|
@api_version("2.4.3", "2.4.3")
|
|
def filters(self) -> NonPaginatableList[Filter]:
|
|
"""
|
|
Fetch all of the logged-in user's filters.
|
|
"""
|
|
return self.__api_request('GET', '/api/v1/filters')
|
|
|
|
@api_version("2.4.3", "2.4.3")
|
|
def filter(self, id: Union[Filter, IdType]) -> Filter:
|
|
"""
|
|
Fetches information about the filter with the specified `id`.
|
|
"""
|
|
id = self.__unpack_id(id)
|
|
return self.__api_request('GET', f'/api/v1/filters/{id}')
|
|
|
|
@api_version("2.4.3", "2.4.3")
|
|
def filters_apply(self, objects: Union[PaginatableList[Status], PaginatableList[Notification]], filters: Union[NonPaginatableList[Filter], NonPaginatableList[FilterV2]], context: str) -> Union[PaginatableList[Status], PaginatableList[Notification]]:
|
|
"""
|
|
Helper function: Applies a list of filters to a list of either statuses
|
|
or notifications and returns only those matched by none. This function will
|
|
apply all filters that match the context provided in `context`, i.e.
|
|
if you want to apply only notification-relevant filters, specify
|
|
'notifications'. Valid contexts are 'home', 'notifications', 'public' and 'thread'.
|
|
|
|
NB: This is for v1 filters. v2 filters are applied by the server, which adds the "filtered"
|
|
attribute to filtered statuses.
|
|
"""
|
|
# Build filter regex
|
|
filter_strings = []
|
|
for keyword_filter in filters:
|
|
if not context in keyword_filter["context"]:
|
|
continue
|
|
|
|
filter_string = re.escape(keyword_filter["phrase"])
|
|
if keyword_filter["whole_word"]:
|
|
filter_string = "\\b" + filter_string + "\\b"
|
|
filter_strings.append(filter_string)
|
|
filter_re = re.compile("|".join(filter_strings), flags=re.IGNORECASE)
|
|
|
|
# Apply
|
|
filter_results = []
|
|
for filter_object in objects:
|
|
filter_status = filter_object
|
|
if "status" in filter_object:
|
|
filter_status = filter_object["status"]
|
|
filter_text = filter_status["content"]
|
|
filter_text = re.sub(r"<.*?>", " ", filter_text)
|
|
filter_text = re.sub(r"\s+", " ", filter_text).strip()
|
|
if not filter_re.search(filter_text):
|
|
filter_results.append(filter_object)
|
|
return filter_results
|
|
|
|
###
|
|
# Writing data: Keyword filters
|
|
###
|
|
@api_version("2.4.3", "2.4.3")
|
|
def filter_create(self, phrase: str, context: str, irreversible: bool = False, whole_word: bool = True, expires_in: Optional[int] = None) -> Filter:
|
|
"""
|
|
Creates a new keyword filter. `phrase` is the phrase that should be
|
|
filtered out, `context` specifies from where to filter the keywords.
|
|
Valid contexts are 'home', 'notifications', 'public' and 'thread'.
|
|
|
|
Set `irreversible` to True if you want the filter to just delete statuses
|
|
server side. This works only for the 'home' and 'notifications' contexts.
|
|
|
|
Set `whole_word` to False if you want to allow filter matches to
|
|
start or end within a word, not only at word boundaries.
|
|
|
|
Set `expires_in` to specify for how many seconds the filter should be
|
|
kept around.
|
|
|
|
Returns the newly created filter.
|
|
"""
|
|
params = self.__generate_params(locals())
|
|
|
|
for context_val in context:
|
|
if not context_val in ['home', 'notifications', 'public', 'thread']:
|
|
raise MastodonIllegalArgumentError('Invalid filter context.')
|
|
|
|
return self.__api_request('POST', '/api/v1/filters', params)
|
|
|
|
@api_version("2.4.3", "2.4.3")
|
|
def filter_update(self, id: Union[Filter, IdType], phrase: Optional[str] = None, context: Optional[str] = None, irreversible: Optional[bool] = None, whole_word: Optional[bool] = None, expires_in: Optional[int] = None) -> Filter:
|
|
"""
|
|
Updates the filter with the given `id`. Parameters are the same
|
|
as in `filter_create()`.
|
|
|
|
Returns the updated filter.
|
|
"""
|
|
id = self.__unpack_id(id)
|
|
params = self.__generate_params(locals(), ['id'])
|
|
return self.__api_request('PUT', f'/api/v1/filters/{id}', params)
|
|
|
|
@api_version("2.4.3", "2.4.3")
|
|
def filter_delete(self, id: Union[Filter, FilterV2, IdType]):
|
|
"""
|
|
Deletes the filter with the given `id`.
|
|
"""
|
|
id = self.__unpack_id(id)
|
|
self.__api_request('DELETE', f'/api/v1/filters/{id}')
|
|
|
|
###
|
|
# Filters v2 api
|
|
###
|
|
@api_version("4.0.0", "4.0.0")
|
|
def filters_v2(self) -> NonPaginatableList[FilterV2]:
|
|
"""
|
|
Fetch all filters for the authenticated user.
|
|
"""
|
|
return self.__api_request('GET', '/api/v2/filters')
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def filter_v2(self, filter_id: Union[Filter, IdType]) -> Filter:
|
|
"""
|
|
Fetch a specific filter by its ID.
|
|
"""
|
|
filter_id = self.__unpack_id(filter_id)
|
|
return self.__api_request('GET', f'/api/v2/filters/{filter_id}')
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def create_filter_v2(
|
|
self,
|
|
title: str,
|
|
context: List[str],
|
|
filter_action: str,
|
|
expires_in: Optional[int] = None,
|
|
keywords_attributes: Optional[List[Dict[str, Union[str, bool]]]] = None
|
|
) -> FilterV2:
|
|
"""
|
|
Create a new filter with the given parameters.
|
|
|
|
`title` is a human readable name for the filter.
|
|
|
|
`context` is list of contexts where the filter should apply. Valid values are:
|
|
- "home": Filter applies to the home timeline.
|
|
- "notifications": Filter applies to notifications. Filtered notifications land in notification requests.
|
|
- "public": Filter applies to the public timelines.
|
|
- "thread": Filter applies to conversations.
|
|
- "account": Filter applies to account timelines.
|
|
|
|
`filter_action` gives the policy to be applied when the filter is matched. Valid values are:
|
|
- "warn": The user is warned if the content matches the filter.
|
|
- "hide": The content is completely hidden if it matches the filter.
|
|
|
|
NB: Even if you specify "hide", the status will still be returned - it will just have the "filtered" attribute set.
|
|
|
|
pass a number of seconds as `expires_in` to make the filter expire in that many seconds. Use None for no expiration.
|
|
|
|
pass a list of keyword dicts to initially as `keywords_attributes`, each with the following values:
|
|
- "keyword": The term to filter on.
|
|
- "whole_word": Whether word boundaries should be considered.
|
|
|
|
"""
|
|
params = self.__generate_params(locals(), for_json=True)
|
|
return self.__api_request('POST', '/api/v2/filters', params, use_json=True)
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def update_filter_v2(
|
|
self,
|
|
filter_id: Union[FilterV2, IdType],
|
|
title: Optional[str] = None,
|
|
context: Optional[List[str]] = None,
|
|
filter_action: Optional[str] = None,
|
|
expires_in: Optional[int] = None,
|
|
keywords_attributes: Optional[List[Dict[str, Union[str, bool, int]]]] = None
|
|
) -> FilterV2:
|
|
"""
|
|
Update an existing filter with the given parameters.
|
|
|
|
Parameters are as in `create_filter_v2()`. Only the parameters you want to update need to be provided.
|
|
"""
|
|
filter_id = self.__unpack_id(filter_id)
|
|
params = self.__generate_params(locals(), for_json=True)
|
|
return self.__api_request('PUT', f'/api/v2/filters/{filter_id}', params, use_json=True)
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def delete_filter_v2(self, filter_id: Union[FilterV2, IdType]) -> None:
|
|
"""
|
|
Delete an existing filter.
|
|
"""
|
|
filter_id = self.__unpack_id(filter_id)
|
|
self.__api_request('DELETE', f'/api/v2/filters/{filter_id}')
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def filter_keywords_v2(self, filter_id: Union[FilterV2, IdType]) -> NonPaginatableList[FilterKeyword]:
|
|
"""
|
|
Fetch all keywords associated with a given filter.
|
|
"""
|
|
filter_id = self.__unpack_id(filter_id)
|
|
return self.__api_request('GET', f'/api/v2/filters/{filter_id}/keywords')
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def add_filter_keyword_v2(
|
|
self,
|
|
filter_id: Union[FilterV2, IdType],
|
|
keyword: str,
|
|
whole_word: bool = False
|
|
) -> FilterKeyword:
|
|
"""
|
|
Add a single keyword to an existing filter.
|
|
|
|
Parameters are as in `create_filter_v2()` `keywords_attributes`.
|
|
"""
|
|
filter_id = self.__unpack_id(filter_id)
|
|
params = self.__generate_params(locals())
|
|
return self.__api_request('POST', f'/api/v2/filters/{filter_id}/keywords', params)
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def delete_filter_keyword_v2(self, keyword_id: Union[FilterKeyword, IdType]) -> None:
|
|
"""
|
|
Delete a single keyword from any filter.
|
|
"""
|
|
keyword_id = self.__unpack_id(keyword_id)
|
|
self.__api_request('DELETE', f'/api/v2/filters/keywords/{keyword_id}')
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def filter_statuses_v2(self, filter_id: Union[FilterV2, IdType]) -> List[FilterStatus]:
|
|
"""
|
|
Retrieve all status-based filters for a FilterV2.
|
|
"""
|
|
filter_id = self.__unpack_id(filter_id)
|
|
return self.__api_request('GET', f'/api/v2/filters/{filter_id}/statuses')
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def add_filter_status_v2(self, filter_id: Union[FilterV2, IdType], status_id: Union[Status, IdType]) -> FilterStatus:
|
|
"""
|
|
Add a status to a filter, which will then match on that status in addition to any keywords.
|
|
Includes reblogs, does not include replies.
|
|
"""
|
|
filter_id = self.__unpack_id(filter_id)
|
|
status_id = self.__unpack_id(status_id)
|
|
params = self.__generate_params({"status_id": status_id})
|
|
return self.__api_request('POST', f'/api/v2/filters/{filter_id}/statuses', params)
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def filter_status_v2(self, filter_status_id: Union[FilterStatus, IdType]) -> FilterStatus:
|
|
"""
|
|
Fetch a single status-based filter by its ID.
|
|
"""
|
|
filter_status_id = self.__unpack_id(filter_status_id)
|
|
return self.__api_request('GET', f'/api/v2/filters/statuses/{filter_status_id}')
|
|
|
|
@api_version("4.0.0", "4.0.0")
|
|
def delete_filter_status_v2(self, filter_status_id: Union[FilterStatus, IdType]) -> None:
|
|
"""
|
|
Remove a status filter from a FilterV2.
|
|
"""
|
|
filter_status_id = self.__unpack_id(filter_status_id)
|
|
self.__api_request('DELETE', f'/api/v2/filters/statuses/{filter_status_id}')
|