interstellar icon indicating copy to clipboard operation
interstellar copied to clipboard

Replace filter lists with rules

Open jwr1 opened this issue 5 months ago • 5 comments

Describe the feature

Rules (or rule lists) will provide many more features than filter lists have and replace filter lists entirely.

Each rule can be individually enabled/disabled. Each rule will be contained within a "rule list". Each rule list will have an associated name and can be enabled/disabled. Each rule list can also be "shared", similarly to a profile.

There should be new context menus on posts, comments, users, communities, and domains that make it extremely easy to create a new rule. For instance, a post should have the option to create a rule based on the associated user, community, or instance.

Each rule will be associated with the following:

Types

  • Phrase: Will match against phrases contained in post titles, post bodies, and comment bodies.
  • User: Will match against post and comment owners.
  • Community: Will match against a post's community.
  • Link: Will match against a post's main web link.
  • Instance: Will match against a post/comment user/community instance.

Actions

  • Hide post/comment: Will completely hide from feed or comment tree.
  • Show post/comment with warning: Will display in feed or comment tree, but with a warning.
  • Rewrite phrase/link: Will rewrite the phrase or link based on the provided "replace" text. Basically acts like a find & replace function.
  • Add alternate link: Will add an additional alternate link based on the provided text.
  • Highlight post/comment with color.

When regex match mode is used with rewrite or alternate link actions, $1, $2, etc. will be replaced with their corresponding regex groups.

Match Mode

Each rule will have one of the following match modes selected. The whole match mode will be the default due to making sense with most of the rule types.

  • Whole: Will match against the whole phrase or name.
  • Contained: Will literally match any occurrence, even in the middle of a word.
  • Regex: Will match based on the specified regular expression.

Case Senesitive

When enabled, will only match content with the same casing as the phrase.

Additional context

https://piefed.social/comment/6565193

Boost has options to filter and mute things without an account, using the device to store these instead of an account on a server. The best type of block is the kind that is not detectable by an offending party, either an user on the platform or even an abusive moderator or admin. One beauty of using a third party is to have greater control of this. Mute is the same as block but it's purposely not associated with an account. I would like more apps, including Interstellar to have these options:

Muting options

  • Muted communities
  • Muted users
  • Muted Instances
  • Muted words
  • Muted web links (Boost does not have this functionality; for example I do not want to see posts with nytimes.com linked articles)

jwr1 avatar Jul 15 '25 00:07 jwr1

Some things I'd like feedback on:

  • Should it be rule lists, which can contain multiple rules where each rule has its own type, action, and match mode. Or should it be just rules (no rule lists), but each rule can contain multiple phrases, but the rule will still manage the type, action, and match mode.
  • A simple implementation would be to have rules only match against content in the feed (not explore), which is actually how filter lists work now. I could see it useful though to be able to match stuff in explore, such as hiding magazines from the magazine list. However that would make things much more complicated. If this were an option, though, would it be better as a per rule list option or a per rule option?
  • Are there any more rule types or rule actions y'all would be interested in?

jwr1 avatar Jul 15 '25 00:07 jwr1

  • So for my usecase, I would like rule sets or lists. I currently have a "Mental health saver" list that I turn off and on as I have capacity to deal with the... it all. For the same reason, I'd like to request that sets be disable-able at a parent level rather than just being for categorization.
  • I have no strong opinions here, but I think logistically that would have to be at the individual rule level if it were to be implemented. Some matchers wouldn't make sense otherwise. What would a 'link' match mean in that context for example?
  • Some potential nice-to-haves:
    • Multiple matchers per rule, so you could have 1 rule to warn for links to low quality news sources, with multiple source listed
    • Two levels for warnings: 1 that shows the content anyway, 1 that hides content, but allows you to view it on tap, like spoiler tags
    • Rule subsets, rather than 1 flat structure
    • Rules sets that only affect specific signed in accounts
    • Matchers with proximity modifiers: "Nicole" WITHIN '7' WORDS OF "Fediverse Chick" <- to filter out all Nicole discussions
    • Some sort of whitelisting capability: Hide posts with phrase "Donald Duck" UNLESS posted by jwr1
    • Logical operators in matcher: "Donald" AND "Duck" NOT "Glover"
    • Time based rule set activation: "Mental health saver" active on weekdays before 6pm
    • Exporting/importing rules as json. Would allow the community to collab on powerful rule sets
    • Analytics: Ye this is really pushing it, but it would be cool to see "This rule has activated 7 times in the last week" as an example

I realise some of those add significant complication, so perhaps they're better as potential future enhancements

Some other things that will need to be considered:

  • Rule priorities: If I have a rule to warn against poor quality links, and one to hide mentions of "Donald Duck" and someone posts a poor quality link about donald duck, is it hidden or does it show a warning?
  • Image/embedded media links. It would be nice to have an explicit way to rewrite, block or warn about image or video embeds. Youtube -> Piped or whatever it's called
  • Migration of existing filter lists: It would be nice if they simply turn into their rules based equivalents on update

Kraiden avatar Jul 15 '25 02:07 Kraiden

  • I think having rule lists with each rule allowing multiple matchers would be best. That way you could combine different rule types in the same list and could combine rules which have similar actions/ match modes. E.g.
    • Mental Health List
      • Phrases-Hide: [Lots, of, really, bad, stuff, here]
      • Phrases-Warning: [Some, kinda, bad, stuff, here]
      • User-Hide: [These, users, are, toxic]
  • If we're filtering users and communities then I think it makes sense to filter in more places like explore and comments. For comments from a filtered user I think we should have options to either completely hide a filtered comments children or maybe just auto collapse the comment chain.
  • For logical operators I believe this can be achieved through regex. Perhaps we can have a UI that converts to a regex to make this simpler for those of us who aren't good at regex.
  • Likewise for proximity matches.

For potential implementation ideas. Currently filter warning info is stored in the feed screen, I think if a filtered variable is added to the post model it would be simpler to manage filtered state similar to how the read status of a post is currently managed.

olorin99 avatar Jul 19 '25 00:07 olorin99

Thank you @Kraiden and @olorin99 for the input. Once I get a chance, I'll start working on a PR, and then we can do further feedback from there.

jwr1 avatar Jul 19 '25 01:07 jwr1

Here's my new proposal. It's more complex than the initial proposal, but you can definitely do much more with it.

Rules are structured as a tree. Any parent rule can be enabled/disabled (which basically just enables/disables all sub-rules) and can also be shared (which also shares all sub-rules). Rules can also be freely rearranged, which allows moving rules in and out of parent rules and also allows changing rule priority, as rules will be evaluated top down. Parent rules can not have their own actions associated with them and only act as "folders" for other rules.

Each (non-parent) rule will have the following associated with it:

Triggers

This will ultimately specify in what context a rule will be triggered in and what fields are available for use. Here are some ideas for triggers I have:

  • Post or comment is encountered
  • Post is encountered
  • Comment is encountered
  • User is encountered
  • Community is encountered
  • Push notification is received

Initially, I thought I wasn't going to need to concept of a "trigger", but if we want to support something like hiding users or communities from the explore list, then this is something we will need in order to distinguish the two contexts.

To give an example of different usage, "Post or comment is encountered" could be used to check if a post contains the word "apple", and then change all instances of "apple" to "banana" since you like bananas more. "Community is encountered" could be used to check if the community's name contains "meme" in it and to hide communities (and their posts) if one is seen.

Conditions

Once a rule is triggered, the conditions will be checked. The root condition must evaluate to true in order for the rule actions to be executed. Here my ideas I have for conditions:

Logical Conditions

Logic conditions only take child conditions as input.

  • Always: Always evaluate as true
  • Not: Inverts the value of its child condition
  • And: Evaluates to true only if all of its children are true
  • Or: Evaluates to true if at least one of its children is true

Relational Conditions

Relational conditions will usually take a field, an operator, and a value as input. The list of available fields depends on the rule's trigger; for instance, if either "Post or comment is encountered" or "Post is encountered" is used, then there would be a "post title" field that's available. An operator allows you to check a field from a given list of operations based on the field's type; a text field might have a "starts with" operator, and a number field might have a "less than" operator.

Fields
  • body: string

  • title: string

  • bodyWithTitle: string

  • lang: string

  • link: url

  • imageSrc: url

  • imageAlt: string

  • userName: name

  • userAvatarSrc: link

  • userCreatedAt: date

  • userIsBot: bool

  • communityName: name

  • communityIconSrc: url

  • upVotes: number

  • downVotes: number

  • points: number

  • boosts: number

  • numComments: number

  • createdAt: date

  • editedAt: date

  • lastActiveAt: date

  • isNsfw: bool

  • isPinned: bool

  • isRead: bool

  • canMod: bool

URL field
Subfields
  • full: string
  • local: string
  • global: string
Name field
Subfields
  • full: string
  • scheme: string
  • host: string
  • path: string
  • query: string
  • fragment: string
Boolean field

Just evaluates as is, no operations needed.

String field
Subfields
  • charCount: number
  • wordCount: number
  • lineCount: number
Operators
  • equals
  • contains
  • startsWith
  • endsWith
  • matchesRegex
Number field
Operators
  • greaterThan
  • greaterThanOrEqualTo
  • lessThan
  • lessThanOrEqualTo
  • inRangeOf
Date field
Subfields
  • second: number
  • minute: number
  • hour: number
  • day: number
  • month: number
  • year: number
Operators
  • dateBefore
  • dateAfter

Actions

Once the rule is triggered and the root condition is evaluated as true, then the actions will be run. Like fields, available actions depends on the rule trigger.

  • Hide: works for all triggers and will hide the post, comment, user, community, push notification, etc. from view (including the feed or explore screen)
  • Replace: replaces the whole post/comment with the provided value
  • Find/replace: finds instances of a value and replaces them with a separate value
  • Regex/replace: replaces regex matches with the provided value
  • Treat post as NSFW
  • Collapse comment
  • Add alternate post link
  • Highlight background with color
  • Add info/success/warn/error icon or text with specified color and tooltip text
  • Mark as read
  • Stop evaluating rules
  • Set default reply value

Each action that has associated text inputs (such as find/replace, add info icon, add alternate link, etc.) will allow you to insert any field that is available in the conditions section. I think using curly brackets ({}) to indicate a field is being inserted would be best, and dots to separate fields from subfields. For example, Hello, {userName.local}! could render Hello, jwr1!. Regex group results can be used with {regex.0}, {regex.1}, and so on.

Examples

Add informational banner to top of posts

Trigger: Post is encountered

Condition:

  • Always

Actions:

  • Replace
This post was created by {userName.local} and contains {body.wordCount} words!

---

{body}

Add politics warning

Trigger: Post or comment is encountered

Condition:

  • Or
    • bodyWithTitle contains "trump"
    • bodyWithTitle contains "biden"
    • bodyWithTitle contains "musk"
    • bodyWithTitle contains "johnsmith"

Actions:

  • Add warn icon #FF0000 with text
Post contains politics

Block meme communities

Trigger: Community is encountered

Condition:

  • communityName.full contains "meme"

Actions:

  • Hide

Block specific users

Trigger: User is encountered

Condition:

Actions:

  • Hide

Highlight unread modable posts

Trigger: Post is encountered

Condition:

  • And
    • canMod
    • Not
      • isRead

Actions:

  • Highlight post background with #FF00FF

jwr1 avatar Jul 24 '25 16:07 jwr1