nandi/gleanpublic Fork 0
144a7d4
Commits
Clone
git clone https://git.rickub.com/nandi/glean.git
git clone ssh://git@rickub.com/nandi/glean.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Filter read articles in recommendations and mark read statusUnverified

Julien Robert committed 2026-04-23T23:35:50+02:00 Browse files
144a7d4 parent: e38807c
modified internal/cluster/scoring.go +6 -2
@@ -36,6 +36,7 @@ type ArticleRecommendation struct {
3636 Author string
3737 Summary string
3838 Published sql.NullTime
39+ IsRead bool
3940 Score float64
4041 }
4142
@@ -218,6 +219,7 @@ func (e *Engine) ComputeArticleRecommendationsOnDemand(ctx context.Context, user
218219 SELECT a.id, a.title, COALESCE(a.url, ''), la.feed_url, COALESCE(f.title, ''),
219220 COALESCE(f.favicon_url, ''),
220221 COALESCE(a.author, ''), COALESCE(a.summary, ''), a.published,
222+ COALESCE(rs.is_read, 0),
221223 COALESCE(la.like_signal, 0) * ?
222224 + COALESCE(sl.social, 0) * ?
223225 + EXP(-0.023 * CAST(julianday('now') - julianday(a.published) AS REAL)) * 0.2
@@ -226,9 +228,11 @@ func (e *Engine) ComputeArticleRecommendationsOnDemand(ctx context.Context, user
226228 JOIN articles.articles a ON a.feed_url = la.feed_url AND a.url = la.article_url
227229 LEFT JOIN articles.feeds f ON f.feed_url = la.feed_url
228230 LEFT JOIN social_likes sl ON sl.feed_url = la.feed_url AND sl.article_url = la.article_url
231+ LEFT JOIN articles.read_state rs ON rs.article_id = a.id AND rs.user_did = ?
232+ WHERE COALESCE(rs.is_read, 0) = 0
229233 ORDER BY score DESC, (CASE WHEN a.published > 'now' THEN 1 ELSE 0 END), a.published DESC
230234 LIMIT ?
231- `, userDID, userDID, userDID, userDID, userDID, userDID, w.WLike, w.WSocial, limit)
235+ `, userDID, userDID, userDID, userDID, userDID, userDID, w.WLike, w.WSocial, userDID, limit)
232236 if err != nil {
233237 return nil, err
234238 }
@@ -238,7 +242,7 @@ func (e *Engine) ComputeArticleRecommendationsOnDemand(ctx context.Context, user
238242 for rows.Next() {
239243 rec := &ArticleRecommendation{}
240244 if err := rows.Scan(&rec.ArticleID, &rec.Title, &rec.URL, &rec.FeedURL, &rec.FeedTitle,
241- &rec.FaviconURL, &rec.Author, &rec.Summary, &rec.Published, &rec.Score); err != nil {
245+ &rec.FaviconURL, &rec.Author, &rec.Summary, &rec.Published, &rec.IsRead, &rec.Score); err != nil {
242246 return nil, err
243247 }
244248 recs = append(recs, rec)
@@ -36,6 +36,7 @@ type ArticleRecommendation struct {
36 Author string36 Author string
37 Summary string37 Summary string
38 Published sql.NullTime38 Published sql.NullTime
39+ IsRead bool
39 Score float6440 Score float64
40 }41 }
41 42
@@ -218,6 +219,7 @@ func (e *Engine) ComputeArticleRecommendationsOnDemand(ctx context.Context, user
218 SELECT a.id, a.title, COALESCE(a.url, ''), la.feed_url, COALESCE(f.title, ''),219 SELECT a.id, a.title, COALESCE(a.url, ''), la.feed_url, COALESCE(f.title, ''),
219 COALESCE(f.favicon_url, ''),220 COALESCE(f.favicon_url, ''),
220 COALESCE(a.author, ''), COALESCE(a.summary, ''), a.published,221 COALESCE(a.author, ''), COALESCE(a.summary, ''), a.published,
222+ COALESCE(rs.is_read, 0),
221 COALESCE(la.like_signal, 0) * ?223 COALESCE(la.like_signal, 0) * ?
222 + COALESCE(sl.social, 0) * ?224 + COALESCE(sl.social, 0) * ?
223 + EXP(-0.023 * CAST(julianday('now') - julianday(a.published) AS REAL)) * 0.2225 + EXP(-0.023 * CAST(julianday('now') - julianday(a.published) AS REAL)) * 0.2
@@ -226,9 +228,11 @@ func (e *Engine) ComputeArticleRecommendationsOnDemand(ctx context.Context, user
226 JOIN articles.articles a ON a.feed_url = la.feed_url AND a.url = la.article_url228 JOIN articles.articles a ON a.feed_url = la.feed_url AND a.url = la.article_url
227 LEFT JOIN articles.feeds f ON f.feed_url = la.feed_url229 LEFT JOIN articles.feeds f ON f.feed_url = la.feed_url
228 LEFT JOIN social_likes sl ON sl.feed_url = la.feed_url AND sl.article_url = la.article_url230 LEFT JOIN social_likes sl ON sl.feed_url = la.feed_url AND sl.article_url = la.article_url
231+ LEFT JOIN articles.read_state rs ON rs.article_id = a.id AND rs.user_did = ?
232+ WHERE COALESCE(rs.is_read, 0) = 0
229 ORDER BY score DESC, (CASE WHEN a.published > 'now' THEN 1 ELSE 0 END), a.published DESC233 ORDER BY score DESC, (CASE WHEN a.published > 'now' THEN 1 ELSE 0 END), a.published DESC
230 LIMIT ?234 LIMIT ?
231- `, userDID, userDID, userDID, userDID, userDID, userDID, w.WLike, w.WSocial, limit)235+ `, userDID, userDID, userDID, userDID, userDID, userDID, w.WLike, w.WSocial, userDID, limit)
232 if err != nil {236 if err != nil {
233 return nil, err237 return nil, err
234 }238 }
@@ -238,7 +242,7 @@ func (e *Engine) ComputeArticleRecommendationsOnDemand(ctx context.Context, user
238 for rows.Next() {242 for rows.Next() {
239 rec := &ArticleRecommendation{}243 rec := &ArticleRecommendation{}
240 if err := rows.Scan(&rec.ArticleID, &rec.Title, &rec.URL, &rec.FeedURL, &rec.FeedTitle,244 if err := rows.Scan(&rec.ArticleID, &rec.Title, &rec.URL, &rec.FeedURL, &rec.FeedTitle,
241- &rec.FaviconURL, &rec.Author, &rec.Summary, &rec.Published, &rec.Score); err != nil {245+ &rec.FaviconURL, &rec.Author, &rec.Summary, &rec.Published, &rec.IsRead, &rec.Score); err != nil {
242 return nil, err246 return nil, err
243 }247 }
244 recs = append(recs, rec)248 recs = append(recs, rec)
modified internal/tmpl/partials/recommendation-article-card.html +1 -1
@@ -3,7 +3,7 @@
33 <div class="flex items-start justify-between gap-4">
44 <div class="min-w-0 flex-1">
55 <div class="flex items-center gap-2">
6- <span class="w-2 h-2 rounded-full bg-spot-green shrink-0"></span>
6+ {{if not .IsRead}}<span class="w-2 h-2 rounded-full bg-spot-green shrink-0"></span>{{end}}
77 <a href="/articles/{{.ArticleID}}" class="font-bold text-spot-text hover:text-spot-green transition text-lg leading-tight">{{.Title}}</a>
88 </div>
99 <div class="text-sm text-spot-secondary mt-1 flex items-center gap-2">
@@ -3,7 +3,7 @@
3 <div class="flex items-start justify-between gap-4">3 <div class="flex items-start justify-between gap-4">
4 <div class="min-w-0 flex-1">4 <div class="min-w-0 flex-1">
5 <div class="flex items-center gap-2">5 <div class="flex items-center gap-2">
6- <span class="w-2 h-2 rounded-full bg-spot-green shrink-0"></span>6+ {{if not .IsRead}}<span class="w-2 h-2 rounded-full bg-spot-green shrink-0"></span>{{end}}
7 <a href="/articles/{{.ArticleID}}" class="font-bold text-spot-text hover:text-spot-green transition text-lg leading-tight">{{.Title}}</a>7 <a href="/articles/{{.ArticleID}}" class="font-bold text-spot-text hover:text-spot-green transition text-lg leading-tight">{{.Title}}</a>
8 </div>8 </div>
9 <div class="text-sm text-spot-secondary mt-1 flex items-center gap-2">9 <div class="text-sm text-spot-secondary mt-1 flex items-center gap-2">