diff --git a/internal/database/migrations.go b/internal/database/migrations.go index fa3c3972..07aa1dc1 100644 --- a/internal/database/migrations.go +++ b/internal/database/migrations.go @@ -888,4 +888,9 @@ var migrations = []func(tx *sql.Tx) error{ _, err = tx.Exec(`DROP INDEX entries_feed_url_idx`) return err }, + func(tx *sql.Tx) (err error) { + sql := `ALTER TABLE feeds ADD COLUMN notes text default ''` + _, err = tx.Exec(sql) + return err + }, } diff --git a/internal/locale/translations/de_DE.json b/internal/locale/translations/de_DE.json index b8cceb46..8dd2cdc7 100644 --- a/internal/locale/translations/de_DE.json +++ b/internal/locale/translations/de_DE.json @@ -317,6 +317,7 @@ "form.feed.label.title": "Titel", "form.feed.label.site_url": "URL der Webseite", "form.feed.label.feed_url": "URL des Abonnements", + "form.feed.label.notes": "Notizen", "form.feed.label.category": "Kategorie", "form.feed.label.crawler": "Originalinhalt herunterladen", "form.feed.label.feed_username": "Benutzername des Abonnements", diff --git a/internal/locale/translations/el_EL.json b/internal/locale/translations/el_EL.json index 42758fb7..86f79c6a 100644 --- a/internal/locale/translations/el_EL.json +++ b/internal/locale/translations/el_EL.json @@ -319,6 +319,7 @@ "form.feed.label.title": "Τίτλος", "form.feed.label.site_url": "Διεύθυνση URL ιστότοπου", "form.feed.label.feed_url": "Διεύθυνση URL ροής", + "form.feed.label.notes": "Σημειώσεις", "form.feed.label.category": "Κατηγορία", "form.feed.label.crawler": "Λήψη αρχικού περιεχομένου", "form.feed.label.feed_username": "Όνομα Χρήστη ροής", diff --git a/internal/locale/translations/en_US.json b/internal/locale/translations/en_US.json index 61e14f8e..931a4a75 100644 --- a/internal/locale/translations/en_US.json +++ b/internal/locale/translations/en_US.json @@ -317,6 +317,7 @@ "form.feed.label.title": "Title", "form.feed.label.site_url": "Site URL", "form.feed.label.feed_url": "Feed URL", + "form.feed.label.notes": "Notes", "form.feed.label.category": "Category", "form.feed.label.crawler": "Fetch original content", "form.feed.label.feed_username": "Feed Username", diff --git a/internal/locale/translations/es_ES.json b/internal/locale/translations/es_ES.json index cdb4b9df..568cb190 100644 --- a/internal/locale/translations/es_ES.json +++ b/internal/locale/translations/es_ES.json @@ -317,6 +317,7 @@ "form.feed.label.title": "Título", "form.feed.label.site_url": "URL del sitio", "form.feed.label.feed_url": "URL de la fuente", + "form.feed.label.notes": "Notas", "form.feed.label.category": "Categoría", "form.feed.label.crawler": "Obtener rastreador original", "form.feed.label.feed_username": "Nombre de usuario de la fuente", diff --git a/internal/locale/translations/fi_FI.json b/internal/locale/translations/fi_FI.json index 922b6356..626e09dc 100644 --- a/internal/locale/translations/fi_FI.json +++ b/internal/locale/translations/fi_FI.json @@ -319,6 +319,7 @@ "form.feed.label.title": "Otsikko", "form.feed.label.site_url": "Sivuston URL-osoite", "form.feed.label.feed_url": "Syötteen URL-osoite", + "form.feed.label.notes": "Huomautukset", "form.feed.label.category": "Kategoria", "form.feed.label.crawler": "Nouda alkuperäinen sisältö", "form.feed.label.feed_username": "Syötteen käyttäjätunnus", diff --git a/internal/locale/translations/fr_FR.json b/internal/locale/translations/fr_FR.json index c533a15c..0c4595ca 100644 --- a/internal/locale/translations/fr_FR.json +++ b/internal/locale/translations/fr_FR.json @@ -317,6 +317,7 @@ "form.feed.label.title": "Titre", "form.feed.label.site_url": "URL du site web", "form.feed.label.feed_url": "URL du flux", + "form.feed.label.notes": "Notes", "form.feed.label.category": "Catégorie", "form.feed.label.crawler": "Récupérer le contenu original", "form.feed.label.feed_username": "Nom d'utilisateur du flux", diff --git a/internal/locale/translations/hi_IN.json b/internal/locale/translations/hi_IN.json index b857b1c9..0a8667af 100644 --- a/internal/locale/translations/hi_IN.json +++ b/internal/locale/translations/hi_IN.json @@ -317,6 +317,7 @@ "form.feed.label.title": "शीर्षक", "form.feed.label.site_url": "साइट यूआरएल", "form.feed.label.feed_url": "फ़ीड यूआरएल", + "form.feed.label.notes": "टिप्पणियाँ", "form.feed.label.category": "श्रेणी", "form.feed.label.crawler": "मूल सामग्री प्राप्त करें", "form.feed.label.feed_username": "फ़ीड उपयोगकर्ता नाम", diff --git a/internal/locale/translations/id_ID.json b/internal/locale/translations/id_ID.json index a0ac7880..f1f17636 100644 --- a/internal/locale/translations/id_ID.json +++ b/internal/locale/translations/id_ID.json @@ -307,6 +307,7 @@ "form.feed.label.title": "Judul", "form.feed.label.site_url": "URL Situs", "form.feed.label.feed_url": "URL Umpan", + "form.feed.label.notes": "Catatan", "form.feed.label.category": "Kategori", "form.feed.label.crawler": "Ambil konten asli", "form.feed.label.feed_username": "Nama Pengguna Umpan", diff --git a/internal/locale/translations/it_IT.json b/internal/locale/translations/it_IT.json index e3b12225..1590d4e4 100644 --- a/internal/locale/translations/it_IT.json +++ b/internal/locale/translations/it_IT.json @@ -317,6 +317,7 @@ "form.feed.label.title": "Titolo", "form.feed.label.site_url": "URL del sito", "form.feed.label.feed_url": "URL del feed", + "form.feed.label.notes": "Note", "form.feed.label.category": "Categoria", "form.feed.label.crawler": "Scarica il contenuto integrale", "form.feed.label.feed_username": "Nome utente del feed", diff --git a/internal/locale/translations/ja_JP.json b/internal/locale/translations/ja_JP.json index 55f6de83..266e3f4c 100644 --- a/internal/locale/translations/ja_JP.json +++ b/internal/locale/translations/ja_JP.json @@ -307,6 +307,7 @@ "form.feed.label.title": "タイトル", "form.feed.label.site_url": "サイト URL", "form.feed.label.feed_url": "フィード URL", + "form.feed.label.notes": "備考", "form.feed.label.category": "カテゴリ", "form.feed.label.crawler": "オリジナルの内容を取得", "form.feed.label.feed_username": "フィードのユーザー名", diff --git a/internal/locale/translations/nl_NL.json b/internal/locale/translations/nl_NL.json index c9b235e2..76cc9151 100644 --- a/internal/locale/translations/nl_NL.json +++ b/internal/locale/translations/nl_NL.json @@ -317,6 +317,7 @@ "form.feed.label.title": "Naam", "form.feed.label.site_url": "Website URL", "form.feed.label.feed_url": "Feed URL", + "form.feed.label.notes": "Notities", "form.feed.label.category": "Categorie", "form.feed.label.crawler": "Download originele content", "form.feed.label.feed_username": "Feed-gebruikersnaam", diff --git a/internal/locale/translations/pl_PL.json b/internal/locale/translations/pl_PL.json index 78c49876..f302d8d2 100644 --- a/internal/locale/translations/pl_PL.json +++ b/internal/locale/translations/pl_PL.json @@ -327,6 +327,7 @@ "form.feed.label.title": "Tytuł", "form.feed.label.site_url": "URL strony", "form.feed.label.feed_url": "URL kanału", + "form.feed.label.notes": "Uwagi", "form.feed.label.category": "Kategoria", "form.feed.label.crawler": "Pobierz oryginalną treść", "form.feed.label.feed_username": "Subskrypcję nazwa użytkownika", diff --git a/internal/locale/translations/pt_BR.json b/internal/locale/translations/pt_BR.json index dd9dca9c..9e08f19c 100644 --- a/internal/locale/translations/pt_BR.json +++ b/internal/locale/translations/pt_BR.json @@ -317,6 +317,7 @@ "form.feed.label.title": "Título", "form.feed.label.site_url": "URL do site", "form.feed.label.feed_url": "URL da fonte", + "form.feed.label.notes": "Notas", "form.feed.label.category": "Categoria", "form.feed.label.crawler": "Obter conteúdo original", "form.feed.label.feed_username": "Nome de usuário da fonte", diff --git a/internal/locale/translations/ru_RU.json b/internal/locale/translations/ru_RU.json index 636ef54e..4eb620de 100644 --- a/internal/locale/translations/ru_RU.json +++ b/internal/locale/translations/ru_RU.json @@ -327,6 +327,7 @@ "form.feed.label.title": "Название", "form.feed.label.site_url": "Адрес сайта", "form.feed.label.feed_url": "Адрес подписки", + "form.feed.label.notes": "Примечания", "form.feed.label.category": "Категория", "form.feed.label.crawler": "Извлечь оригинальное содержимое", "form.feed.label.feed_username": "Имя пользователя подписки", diff --git a/internal/locale/translations/tr_TR.json b/internal/locale/translations/tr_TR.json index 87a67025..b76aed79 100644 --- a/internal/locale/translations/tr_TR.json +++ b/internal/locale/translations/tr_TR.json @@ -154,6 +154,7 @@ "form.feed.label.disabled": "Bu beslemeyi yenileme", "form.feed.label.feed_password": "Besleme Parolası", "form.feed.label.feed_url": "Besleme URL'si", + "form.feed.label.notes": "Notlar", "form.feed.label.feed_username": "Besleme Kullanıcı Adı", "form.feed.label.fetch_via_proxy": "Proxy ile çek", "form.feed.label.hide_globally": "Genel okunmamış listesindeki girişleri gizle", diff --git a/internal/locale/translations/uk_UA.json b/internal/locale/translations/uk_UA.json index 221a4ca9..0a61fbbb 100644 --- a/internal/locale/translations/uk_UA.json +++ b/internal/locale/translations/uk_UA.json @@ -327,6 +327,7 @@ "form.feed.label.title": "Назва", "form.feed.label.site_url": "URL-адреса сайту", "form.feed.label.feed_url": "URL-адреса стрічки", + "form.feed.label.notes": "Примітки", "form.feed.label.category": "Категорія", "form.feed.label.crawler": "Завантажувати оригінальний вміст", "form.feed.label.feed_username": "Ім’я користувача для завантаження", diff --git a/internal/locale/translations/zh_CN.json b/internal/locale/translations/zh_CN.json index d1797c24..86ab5f48 100644 --- a/internal/locale/translations/zh_CN.json +++ b/internal/locale/translations/zh_CN.json @@ -307,6 +307,7 @@ "form.feed.label.title": "标题", "form.feed.label.site_url": "源网站 URL", "form.feed.label.feed_url": "订阅源 URL", + "form.feed.label.notes": "笔记", "form.feed.label.category": "类别", "form.feed.label.crawler": "抓取全文内容", "form.feed.label.feed_username": "源用户名", diff --git a/internal/locale/translations/zh_TW.json b/internal/locale/translations/zh_TW.json index 35be9e2b..8a9082d1 100644 --- a/internal/locale/translations/zh_TW.json +++ b/internal/locale/translations/zh_TW.json @@ -307,6 +307,7 @@ "form.feed.label.title": "標題", "form.feed.label.site_url": "網站 URL", "form.feed.label.feed_url": "訂閱 Feed URL", + "form.feed.label.notes": "笔记", "form.feed.label.category": "類別", "form.feed.label.crawler": "下載原文內容", "form.feed.label.feed_username": "Feed 使用者名稱", diff --git a/internal/model/feed.go b/internal/model/feed.go index 5273eea2..2bc6a025 100644 --- a/internal/model/feed.go +++ b/internal/model/feed.go @@ -28,6 +28,7 @@ type Feed struct { FeedURL string `json:"feed_url"` SiteURL string `json:"site_url"` Title string `json:"title"` + Notes string `json:"notes"` CheckedAt time.Time `json:"checked_at"` NextCheckAt time.Time `json:"next_check_at"` EtagHeader string `json:"etag_header"` @@ -167,6 +168,7 @@ type FeedModificationRequest struct { FeedURL *string `json:"feed_url"` SiteURL *string `json:"site_url"` Title *string `json:"title"` + Notes *string `json:"notes"` ScraperRules *string `json:"scraper_rules"` RewriteRules *string `json:"rewrite_rules"` BlocklistRules *string `json:"blocklist_rules"` @@ -201,6 +203,10 @@ func (f *FeedModificationRequest) Patch(feed *Feed) { feed.Title = *f.Title } + if f.Notes != nil && *f.Notes != "" { + feed.Notes = *f.Notes + } + if f.ScraperRules != nil { feed.ScraperRules = *f.ScraperRules } diff --git a/internal/reader/opml/handler.go b/internal/reader/opml/handler.go index 9257d354..63ba56b6 100644 --- a/internal/reader/opml/handler.go +++ b/internal/reader/opml/handler.go @@ -29,6 +29,7 @@ func (h *Handler) Export(userID int64) (string, error) { Title: feed.Title, FeedURL: feed.FeedURL, SiteURL: feed.SiteURL, + Notes: feed.Notes, CategoryName: feed.Category.Title, }) } @@ -72,6 +73,7 @@ func (h *Handler) Import(userID int64, data io.Reader) error { Title: subscription.Title, FeedURL: subscription.FeedURL, SiteURL: subscription.SiteURL, + Notes: subscription.Notes, Category: category, } diff --git a/internal/reader/opml/opml.go b/internal/reader/opml/opml.go index 8fe3af09..1d537dbf 100644 --- a/internal/reader/opml/opml.go +++ b/internal/reader/opml/opml.go @@ -31,6 +31,7 @@ type opmlOutline struct { Text string `xml:"text,attr"` FeedURL string `xml:"xmlUrl,attr,omitempty"` SiteURL string `xml:"htmlUrl,attr,omitempty"` + Notes string `xml:"description,attr,omitempty"` Outlines opmlOutlineCollection `xml:"outline,omitempty"` } diff --git a/internal/reader/opml/parser.go b/internal/reader/opml/parser.go index 09455a69..b96fd262 100644 --- a/internal/reader/opml/parser.go +++ b/internal/reader/opml/parser.go @@ -34,6 +34,7 @@ func getSubscriptionsFromOutlines(outlines opmlOutlineCollection, category strin Title: outline.GetTitle(), FeedURL: outline.FeedURL, SiteURL: outline.GetSiteURL(), + Notes: outline.Notes, CategoryName: category, }) } else if outline.Outlines.HasChildren() { diff --git a/internal/reader/opml/parser_test.go b/internal/reader/opml/parser_test.go index 4dc855e6..1f185841 100644 --- a/internal/reader/opml/parser_test.go +++ b/internal/reader/opml/parser_test.go @@ -33,7 +33,7 @@ func TestParseOpmlWithoutCategories(t *testing.T) { ` var expected SubcriptionList - expected = append(expected, &Subcription{Title: "CNET News.com", FeedURL: "http://news.com.com/2547-1_3-0-5.xml", SiteURL: "http://news.com.com/"}) + expected = append(expected, &Subcription{Title: "CNET News.com", FeedURL: "http://news.com.com/2547-1_3-0-5.xml", SiteURL: "http://news.com.com/", Notes: "Tech news and business reports by CNET News.com. Focused on information technology, core topics include computers, hardware, software, networking, and Internet media."}) subscriptions, err := Parse(bytes.NewBufferString(data)) if err != nil { diff --git a/internal/reader/opml/serializer.go b/internal/reader/opml/serializer.go index 2ecccbed..fe90071e 100644 --- a/internal/reader/opml/serializer.go +++ b/internal/reader/opml/serializer.go @@ -52,6 +52,7 @@ func convertSubscriptionsToOPML(subscriptions SubcriptionList) *opmlDocument { Text: subscription.Title, FeedURL: subscription.FeedURL, SiteURL: subscription.SiteURL, + Notes: subscription.Notes, }) } diff --git a/internal/reader/opml/subscription.go b/internal/reader/opml/subscription.go index 6c05a204..4b72a185 100644 --- a/internal/reader/opml/subscription.go +++ b/internal/reader/opml/subscription.go @@ -9,12 +9,14 @@ type Subcription struct { SiteURL string FeedURL string CategoryName string + Notes string } // Equals compare two subscriptions. func (s Subcription) Equals(subscription *Subcription) bool { return s.Title == subscription.Title && s.SiteURL == subscription.SiteURL && - s.FeedURL == subscription.FeedURL && s.CategoryName == subscription.CategoryName + s.FeedURL == subscription.FeedURL && s.CategoryName == subscription.CategoryName && + s.Notes == subscription.Notes } // SubcriptionList is a list of subscriptions. diff --git a/internal/storage/entry_query_builder.go b/internal/storage/entry_query_builder.go index 9ab26738..c43556b6 100644 --- a/internal/storage/entry_query_builder.go +++ b/internal/storage/entry_query_builder.go @@ -281,6 +281,7 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) { f.title as feed_title, f.feed_url, f.site_url, + f.notes, f.checked_at, f.category_id, c.title as category_title, @@ -347,6 +348,7 @@ func (e *EntryQueryBuilder) GetEntries() (model.Entries, error) { &entry.Feed.Title, &entry.Feed.FeedURL, &entry.Feed.SiteURL, + &entry.Feed.Notes, &entry.Feed.CheckedAt, &entry.Feed.Category.ID, &entry.Feed.Category.Title, diff --git a/internal/storage/feed.go b/internal/storage/feed.go index e7aaf12a..7a9e589e 100644 --- a/internal/storage/feed.go +++ b/internal/storage/feed.go @@ -238,10 +238,11 @@ func (s *Storage) CreateFeed(feed *model.Feed) error { url_rewrite_rules, no_media_player, apprise_service_urls, - disable_http2 + disable_http2, + notes ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26) RETURNING id ` @@ -272,6 +273,7 @@ func (s *Storage) CreateFeed(feed *model.Feed) error { feed.NoMediaPlayer, feed.AppriseServiceURLs, feed.DisableHTTP2, + feed.Notes, ).Scan(&feed.ID) if err != nil { return fmt.Errorf(`store: unable to create feed %q: %v`, feed.FeedURL, err) @@ -344,9 +346,10 @@ func (s *Storage) UpdateFeed(feed *model.Feed) (err error) { url_rewrite_rules=$25, no_media_player=$26, apprise_service_urls=$27, - disable_http2=$28 + disable_http2=$28, + notes=$29 WHERE - id=$29 AND user_id=$30 + id=$30 AND user_id=$31 ` _, err = s.db.Exec(query, feed.FeedURL, @@ -377,6 +380,7 @@ func (s *Storage) UpdateFeed(feed *model.Feed) (err error) { feed.NoMediaPlayer, feed.AppriseServiceURLs, feed.DisableHTTP2, + feed.Notes, feed.ID, feed.UserID, ) diff --git a/internal/storage/feed_query_builder.go b/internal/storage/feed_query_builder.go index e12107ec..f5b14774 100644 --- a/internal/storage/feed_query_builder.go +++ b/internal/storage/feed_query_builder.go @@ -135,6 +135,7 @@ func (f *FeedQueryBuilder) GetFeeds() (model.Feeds, error) { f.feed_url, f.site_url, f.title, + f.notes, f.etag_header, f.last_modified_header, f.user_id, @@ -202,6 +203,7 @@ func (f *FeedQueryBuilder) GetFeeds() (model.Feeds, error) { &feed.FeedURL, &feed.SiteURL, &feed.Title, + &feed.Notes, &feed.EtagHeader, &feed.LastModifiedHeader, &feed.UserID, diff --git a/internal/template/templates/views/edit_feed.html b/internal/template/templates/views/edit_feed.html index b0b48236..68a66ca3 100644 --- a/internal/template/templates/views/edit_feed.html +++ b/internal/template/templates/views/edit_feed.html @@ -63,6 +63,9 @@ + + + {{ if not .form.CategoryHidden }} {{ end }} diff --git a/internal/ui/feed_edit.go b/internal/ui/feed_edit.go index ba8901bb..1d40a7b0 100644 --- a/internal/ui/feed_edit.go +++ b/internal/ui/feed_edit.go @@ -43,6 +43,7 @@ func (h *handler) showEditFeedPage(w http.ResponseWriter, r *http.Request) { SiteURL: feed.SiteURL, FeedURL: feed.FeedURL, Title: feed.Title, + Notes: feed.Notes, ScraperRules: feed.ScraperRules, RewriteRules: feed.RewriteRules, BlocklistRules: feed.BlocklistRules, diff --git a/internal/ui/feed_update.go b/internal/ui/feed_update.go index da75d59f..0ffc3d3c 100644 --- a/internal/ui/feed_update.go +++ b/internal/ui/feed_update.go @@ -59,6 +59,7 @@ func (h *handler) updateFeed(w http.ResponseWriter, r *http.Request) { FeedURL: model.OptionalString(feedForm.FeedURL), SiteURL: model.OptionalString(feedForm.SiteURL), Title: model.OptionalString(feedForm.Title), + Notes: model.OptionalString(feedForm.Notes), CategoryID: model.OptionalNumber(feedForm.CategoryID), BlocklistRules: model.OptionalString(feedForm.BlocklistRules), KeeplistRules: model.OptionalString(feedForm.KeeplistRules), diff --git a/internal/ui/form/feed.go b/internal/ui/form/feed.go index f78e1784..a7a0d1d0 100644 --- a/internal/ui/form/feed.go +++ b/internal/ui/form/feed.go @@ -15,6 +15,7 @@ type FeedForm struct { FeedURL string SiteURL string Title string + Notes string ScraperRules string RewriteRules string BlocklistRules string @@ -43,6 +44,7 @@ func (f FeedForm) Merge(feed *model.Feed) *model.Feed { feed.Title = f.Title feed.SiteURL = f.SiteURL feed.FeedURL = f.FeedURL + feed.Notes = f.Notes feed.ScraperRules = f.ScraperRules feed.RewriteRules = f.RewriteRules feed.BlocklistRules = f.BlocklistRules @@ -76,6 +78,7 @@ func NewFeedForm(r *http.Request) *FeedForm { FeedURL: r.FormValue("feed_url"), SiteURL: r.FormValue("site_url"), Title: r.FormValue("title"), + Notes: r.FormValue("notes"), ScraperRules: r.FormValue("scraper_rules"), UserAgent: r.FormValue("user_agent"), Cookie: r.FormValue("cookie"),