diff --git a/desktop/go.mod b/desktop/go.mod
index c9af7cd..5a702a2 100644
--- a/desktop/go.mod
+++ b/desktop/go.mod
@@ -43,6 +43,7 @@ require (
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/net v0.48.0 // indirect
+ golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/time v0.14.0 // indirect
diff --git a/internal/api/handlers.go b/internal/api/handlers.go
index dc5a533..bd16918 100644
--- a/internal/api/handlers.go
+++ b/internal/api/handlers.go
@@ -17,8 +17,8 @@ import (
"time"
"git.quad4.io/Go-Libs/RSS"
- readability "github.com/go-shiori/go-readability"
"git.quad4.io/Quad4-Software/webnews/internal/storage"
+ readability "github.com/go-shiori/go-readability"
"golang.org/x/sync/singleflight"
"golang.org/x/time/rate"
)
diff --git a/internal/storage/sqlite.go b/internal/storage/sqlite.go
index decc5c4..e1b190e 100644
--- a/internal/storage/sqlite.go
+++ b/internal/storage/sqlite.go
@@ -330,7 +330,7 @@ func (s *SQLiteDB) GetArticles(feedId string, offset, limit int) (string, error)
} else {
rows, err = s.db.Query("SELECT id, feedId, title, link, description, content, author, pubDate, read, saved, imageUrl, readAt FROM articles ORDER BY pubDate DESC LIMIT ? OFFSET ?", limit, offset)
}
-
+
if err != nil {
return "[]", err
}
@@ -377,7 +377,7 @@ func (s *SQLiteDB) SearchArticles(query string, limit int) (string, error) {
FROM articles
WHERE title LIKE ? OR description LIKE ? OR content LIKE ?
ORDER BY pubDate DESC LIMIT ?`, q, q, q, limit)
-
+
if err != nil {
return "[]", err
}
diff --git a/src/components/AddFeedModal.svelte b/src/components/AddFeedModal.svelte
index 86a08f7..159cb77 100644
--- a/src/components/AddFeedModal.svelte
+++ b/src/components/AddFeedModal.svelte
@@ -1,8 +1,10 @@
diff --git a/src/components/ArticleCard.svelte b/src/components/ArticleCard.svelte
index 6da4e16..8e4ac2d 100644
--- a/src/components/ArticleCard.svelte
+++ b/src/components/ArticleCard.svelte
@@ -5,6 +5,7 @@
import { Bookmark, Share2, MoreVertical, Check, FileText, Loader2 } from 'lucide-svelte';
let { article }: { article: Article } = $props();
+ const feed = $derived(newsStore.feeds.find((f) => f.id === article.feedId));
let copied = $state(false);
let loadingFullText = $state(false);
@@ -18,9 +19,11 @@
return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
}
- function getSource(feedId: string) {
- const feed = newsStore.feeds.find((f) => f.id === feedId);
- return feed?.title || new URL(feedId).hostname;
+ function getSourceTitle() {
+ return (
+ feed?.title ||
+ (article.feedId.startsWith('http') ? new URL(article.feedId).hostname : article.feedId)
+ );
}
async function shareArticle(e: MouseEvent) {
@@ -78,6 +81,30 @@
? 'ring-2 ring-accent-blue shadow-lg bg-accent-blue/5'
: ''}"
>
+
+ {#if article.imageUrl || feed?.icon}
+
+ {#if article.imageUrl && article.imageUrl !== feed?.icon}
+
+

+
+ {:else if feed?.icon}
+
+

+
+ {/if}
+
+ {/if}
+
{#if newsStore.isSelectMode}
@@ -112,8 +139,11 @@
+ {#if feed?.icon}
+

+ {/if}
{getSource(article.feedId)}{getSourceTitle()}
•
{formatDate(article.pubDate)}
@@ -174,16 +204,4 @@
-
- {#if article.imageUrl}
-
-

-
- {/if}
diff --git a/src/lib/store.svelte.ts b/src/lib/store.svelte.ts
index 3e6f5c3..0780aad 100644
--- a/src/lib/store.svelte.ts
+++ b/src/lib/store.svelte.ts
@@ -51,6 +51,7 @@ class NewsStore {
isOnline = $state(true);
ping = $state
(null);
lastStatusCheck = $state(Date.now());
+ lastArticlesUpdate = $state(Date.now());
authInfo = $state<{ required: boolean; mode: string; canReg: boolean } | null>(null);
isAuthenticated = $state(false);
newlyRegisteredToken = $state(null);
@@ -277,11 +278,20 @@ class NewsStore {
this.statusInterval = setInterval(() => this.checkStatus(), 30000);
}
- window.addEventListener('online', () => this.checkStatus());
- window.addEventListener('offline', () => {
- this.isOnline = false;
- this.ping = null;
- });
+ if (typeof window !== 'undefined') {
+ window.addEventListener('online', () => this.checkStatus());
+ window.addEventListener('offline', () => {
+ this.isOnline = false;
+ this.ping = null;
+ });
+
+ // Auto-refresh when tab becomes visible
+ document.addEventListener('visibilitychange', () => {
+ if (document.visibilityState === 'visible' && this.isAuthenticated) {
+ this.refresh();
+ }
+ });
+ }
}
async loadArticles() {
@@ -324,6 +334,7 @@ class NewsStore {
} else {
this.articles = articles;
}
+ this.lastArticlesUpdate = Date.now();
}
private rankArticles(articles: Article[]): Article[] {
@@ -633,6 +644,7 @@ class NewsStore {
art.read = true;
art.readAt = Date.now();
if (data.content) art.content = data.content;
+ data.feedId = art.feedId;
}
if (data.content) {
@@ -760,7 +772,9 @@ class NewsStore {
startAutoFetch() {
if (this.fetchInterval) clearInterval(this.fetchInterval);
this.fetchInterval = setInterval(() => {
- this.refresh();
+ if (this.isAuthenticated) {
+ this.refresh();
+ }
}, this.settings.globalFetchInterval * 60000);
}
}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 6ec808b..ec8afd1 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1064,7 +1064,7 @@
- {#if newsStore.readingArticle.image}
+ {#if newsStore.readingArticle.image && newsStore.readingArticle.image !== newsStore.feeds.find((f) => f.id === newsStore.readingArticle.feedId)?.icon}
+ {#if newsStore.feeds.find((f) => f.id === newsStore.readingArticle.feedId)?.icon}
+
)
f.id === newsStore.readingArticle.feedId)
+ ?.icon}
+ alt=""
+ class="w-4 h-4 rounded-sm"
+ />
+ {/if}
{newsStore.readingArticle.siteName || ''}
@@ -1118,7 +1126,7 @@
{/if}
- Updated {new Date(newsStore.lastStatusCheck).toLocaleTimeString([], {
+ Updated {new Date(newsStore.lastArticlesUpdate).toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
})}
@@ -1269,7 +1277,7 @@
- {#if newsStore.readingArticle.image}
+ {#if newsStore.readingArticle.image && newsStore.readingArticle.image !== newsStore.feeds.find((f) => f.id === newsStore.readingArticle.feedId)?.icon}

{newsStore.readingArticle.title}
-
- {newsStore.readingArticle.byline || newsStore.readingArticle.siteName || ''}
-
+
+ {#if newsStore.feeds.find((f) => f.id === newsStore.readingArticle.feedId)?.icon}
+
)
f.id === newsStore.readingArticle.feedId)
+ ?.icon}
+ alt=""
+ class="w-4 h-4 rounded-sm"
+ />
+ {/if}
+
{newsStore.readingArticle.byline ||
+ newsStore.readingArticle.siteName ||
+ ''}
+