Skip to content
Closed
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
8 changes: 7 additions & 1 deletion damus/Features/Settings/Models/UserSettingsStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,13 @@ class UserSettingsStore: ObservableObject {

@Setting(key: "hide_nsfw_tagged_content", default_value: false)
var hide_nsfw_tagged_content: Bool


@Setting(key: "hide_hashtag_spam", default_value: true)
var hide_hashtag_spam: Bool

@Setting(key: "max_hashtags", default_value: 3)
var max_hashtags: Int

@Setting(key: "reduce_bitcoin_content", default_value: false)
var reduce_bitcoin_content: Bool

Expand Down
16 changes: 16 additions & 0 deletions damus/Features/Settings/Views/AppearanceSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ struct AppearanceSettingsView: View {
@State var showing_enable_animation_alert: Bool = false
@State var enable_animation_toggle_is_user_initiated: Bool = true

var max_hashtags_binding: Binding<Double> {
Binding<Double>(get: {
return Double(settings.max_hashtags)
}, set: {
settings.max_hashtags = Int($0)
})
}

var FontSize: some View {
VStack(alignment: .leading) {
Slider(value: $settings.font_size, in: 0.5...2.0, step: 0.1)
Expand Down Expand Up @@ -104,6 +112,14 @@ struct AppearanceSettingsView: View {
.toggleStyle(.switch)
Toggle(NSLocalizedString("Hide notes with #nsfw tags", comment: "Setting to hide notes with the #nsfw (not safe for work) tags"), isOn: $settings.hide_nsfw_tagged_content)
.toggleStyle(.switch)
Toggle(NSLocalizedString("Hide posts with too many hashtags", comment: "Setting to hide notes that contain too many hashtags (spam)"), isOn: $settings.hide_hashtag_spam)
.toggleStyle(.switch)
if settings.hide_hashtag_spam {
VStack(alignment: .leading) {
Text(String(format: NSLocalizedString("Maximum hashtags: %d", comment: "Label showing the maximum number of hashtags allowed before a post is hidden"), settings.max_hashtags))
Slider(value: max_hashtags_binding, in: 1...20, step: 1)
}
}
}

// MARK: - Profiles
Expand Down
20 changes: 20 additions & 0 deletions damus/Features/Timeline/Models/ContentFilters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,22 @@ func nsfw_tag_filter(ev: NostrEvent) -> Bool {
return ev.referenced_hashtags.first(where: { t in t.hashtag.caseInsensitiveCompare("nsfw") == .orderedSame }) == nil
}

/// Filter to hide posts with too many hashtags (spam detection)
/// Checks both the event's "t" tags and hashtags in content text.
/// If either exceeds the threshold, the post is filtered.
func hashtag_spam_filter(ev: NostrEvent, max_hashtags: Int) -> Bool {
// Check "t" tags count
var tag_count = 0
for _ in ev.referenced_hashtags {
tag_count += 1
if tag_count > max_hashtags {
return false
}
}

return true
}
Comment on lines +57 to +71
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update misleading documentation comment.

The documentation comment at lines 58-59 states that the function "Checks both the event's 't' tags and hashtags in content text," but the implementation only checks ev.referenced_hashtags (the "t" tags). Content text scanning is not performed.

According to the PR description, a follow-up commit by jb55 removed the content filter, noting that "only spam in tags is relevant." The comment should be updated to reflect the actual implementation.

🔎 Proposed fix
 /// Filter to hide posts with too many hashtags (spam detection)
-/// Checks both the event's "t" tags and hashtags in content text.
-/// If either exceeds the threshold, the post is filtered.
+/// Checks the event's "t" tags (referenced_hashtags).
+/// If the count exceeds the threshold, the post is filtered.
 func hashtag_spam_filter(ev: NostrEvent, max_hashtags: Int) -> Bool {
🤖 Prompt for AI Agents
In @damus/Features/Timeline/Models/ContentFilters.swift around lines 57 - 71,
The doc comment for hashtag_spam_filter is inaccurate: the function only checks
ev.referenced_hashtags (the "t" tags) against max_hashtags and does not scan
content text; update the documentation comment above func
hashtag_spam_filter(ev: NostrEvent, max_hashtags: Int) -> Bool to state that it
only enforces a tag-count limit (spam detection based solely on "t"
tags/referenced_hashtags) and remove any mention of scanning hashtags in the
event content. Ensure the comment references ev.referenced_hashtags and
max_hashtags so readers understand the check being performed.


@MainActor
func get_repost_of_muted_user_filter(damus_state: DamusState) -> ((_ ev: NostrEvent) -> Bool) {
return { ev in
Expand Down Expand Up @@ -97,6 +113,10 @@ extension ContentFilters {
if damus_state.settings.hide_nsfw_tagged_content {
filters.append(nsfw_tag_filter)
}
if damus_state.settings.hide_hashtag_spam {
let max_hashtags = damus_state.settings.max_hashtags
filters.append({ ev in hashtag_spam_filter(ev: ev, max_hashtags: max_hashtags) })
}
filters.append(get_repost_of_muted_user_filter(damus_state: damus_state))
filters.append(timestamp_filter)
return filters
Expand Down