From 9aff2b8a93da741112b15e31337ca4fc1e6a66c7 Mon Sep 17 00:00:00 2001 From: Alessio Date: Thu, 12 Oct 2023 10:30:33 -0700 Subject: [PATCH] Add search filters for 'media' (union of video and image) and negative search filters (prefixed with '-') --- pkg/persistence/compound_ssf_queries.go | 27 ++++++++++++++++++++ pkg/persistence/compound_ssf_queries_test.go | 21 +++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/pkg/persistence/compound_ssf_queries.go b/pkg/persistence/compound_ssf_queries.go index 6550a7f..8fe79cc 100644 --- a/pkg/persistence/compound_ssf_queries.go +++ b/pkg/persistence/compound_ssf_queries.go @@ -116,6 +116,7 @@ type Cursor struct { FilterLinks Filter FilterImages Filter FilterVideos Filter + FilterMedia Filter FilterPolls Filter FilterSpaces Filter FilterReplies Filter @@ -266,12 +267,30 @@ func (c *Cursor) apply_token(token string) error { c.FilterImages = REQUIRE case "videos": c.FilterVideos = REQUIRE + case "media": + c.FilterMedia = REQUIRE case "polls": c.FilterPolls = REQUIRE case "spaces": c.FilterSpaces = REQUIRE } + case "-filter": + switch parts[1] { + case "links": + c.FilterLinks = EXCLUDE + case "images": + c.FilterImages = EXCLUDE + case "videos": + c.FilterVideos = EXCLUDE + case "media": + c.FilterMedia = EXCLUDE + case "polls": + c.FilterPolls = EXCLUDE + case "spaces": + c.FilterSpaces = EXCLUDE + } } + if err != nil { return fmt.Errorf("query token %q: %w", token, ErrInvalidQuery) } @@ -335,6 +354,14 @@ func (p Profile) NextPage(c Cursor, current_user_id scraper.UserID) (Feed, error case EXCLUDE: where_clauses = append(where_clauses, "not exists (select 1 from videos where videos.tweet_id = tweets.id)") } + switch c.FilterMedia { + case REQUIRE: + where_clauses = append(where_clauses, `(exists (select 1 from videos where videos.tweet_id = tweets.id) + or exists (select 1 from images where images.tweet_id = tweets.id))`) + case EXCLUDE: + where_clauses = append(where_clauses, `not (exists (select 1 from videos where videos.tweet_id = tweets.id) + or exists (select 1 from images where images.tweet_id = tweets.id))`) + } switch c.FilterPolls { case REQUIRE: where_clauses = append(where_clauses, "exists (select 1 from polls where polls.tweet_id = tweets.id)") diff --git a/pkg/persistence/compound_ssf_queries_test.go b/pkg/persistence/compound_ssf_queries_test.go index 0daaf38..f9e88e5 100644 --- a/pkg/persistence/compound_ssf_queries_test.go +++ b/pkg/persistence/compound_ssf_queries_test.go @@ -250,6 +250,18 @@ func TestSearchMediaFilters(t *testing.T) { assert.Equal(feed.Items[0].TweetID, TweetID(1426619468327882761)) assert.Equal(feed.Items[1].TweetID, TweetID(1453461248142495744)) + // Media (generic) + c = persistence.NewCursor() + c.SortOrder = persistence.SORT_ORDER_MOST_LIKES + c.FilterMedia = persistence.REQUIRE + feed, err = profile.NextPage(c, UserID(0)) + require.NoError(err) + assert.Len(feed.Items, 4) + assert.Equal(feed.Items[0].TweetID, TweetID(1426619468327882761)) + assert.Equal(feed.Items[1].TweetID, TweetID(1261483383483293700)) + assert.Equal(feed.Items[2].TweetID, TweetID(1426669666928414720)) + assert.Equal(feed.Items[3].TweetID, TweetID(1453461248142495744)) + // Polls c = persistence.NewCursor() c.FilterPolls = persistence.REQUIRE @@ -265,4 +277,13 @@ func TestSearchMediaFilters(t *testing.T) { require.NoError(err) assert.Len(feed.Items, 1) assert.Equal(feed.Items[0].TweetID, TweetID(1624833173514293249)) + + // Negative filter (images) + c = persistence.NewCursor() + c.FilterImages = persistence.EXCLUDE + c.FromUserHandle = UserHandle("covfefeanon") + feed, err = profile.NextPage(c, UserID(0)) + require.NoError(err) + assert.Len(feed.Items, 1) + assert.Equal(feed.Items[0].TweetID, TweetID(1428951883058753537)) }