diff --git a/internal/database/migrations.go b/internal/database/migrations.go index df2a5dc7..e48217ad 100644 --- a/internal/database/migrations.go +++ b/internal/database/migrations.go @@ -898,4 +898,9 @@ var migrations = []func(tx *sql.Tx) error{ _, err = tx.Exec(sql) return err }, + func(tx *sql.Tx) (err error) { + sql := `ALTER TABLE feeds ADD COLUMN description 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 0f43cfb3..fa3d3a68 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.description": "Beschreibung", "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 34e80d0b..28169261 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.description": "Περιγραφή", "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 ab47eb75..71867ffe 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.description": "Description", "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 499e3eb3..0c7766e8 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.description": "Descripción", "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 7028ad1c..7b6565fc 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.description": "Kuvaus", "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 b73a8d95..b25033b4 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.description": "Description", "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 92922079..2ebe379a 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.description": "विवरण", "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 16e66ff1..06ecd7db 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.description": "Deskripsi", "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 c9edd6f2..fcb5daae 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.description": "Descrizione", "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 0beb0759..f6f3d72c 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.description": "説明", "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 3f17f631..6b73abbc 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.description": "Beschrijving", "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 ddaf0d8b..0044d021 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.description": "Opis", "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 8502b778..1dd3f195 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.description": "Descrição", "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 2d17fae9..d759621b 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.description": "Описание", "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 3edd074b..fbaa3efb 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.description": "Açıklama", "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 a7563fe6..84ed3278 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.description": "Опис", "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 ba0d1f57..7ab55344 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.description": "描述", "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 57f50b08..12ea4c7a 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.description": "描述", "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..7b89dca0 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"` + Description string `json:"description"` 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"` + Description *string `json:"description"` 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.Description != nil && *f.Description != "" { + feed.Description = *f.Description + } + if f.ScraperRules != nil { feed.ScraperRules = *f.ScraperRules } diff --git a/internal/reader/opml/handler.go b/internal/reader/opml/handler.go index 9257d354..2e7bceb9 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, + Description: feed.Description, CategoryName: feed.Category.Title, }) } @@ -68,11 +69,12 @@ func (h *Handler) Import(userID int64, data io.Reader) error { } feed := &model.Feed{ - UserID: userID, - Title: subscription.Title, - FeedURL: subscription.FeedURL, - SiteURL: subscription.SiteURL, - Category: category, + UserID: userID, + Title: subscription.Title, + FeedURL: subscription.FeedURL, + SiteURL: subscription.SiteURL, + Description: subscription.Description, + Category: category, } h.store.CreateFeed(feed) diff --git a/internal/reader/opml/opml.go b/internal/reader/opml/opml.go index 8fe3af09..c6caa9c9 100644 --- a/internal/reader/opml/opml.go +++ b/internal/reader/opml/opml.go @@ -27,11 +27,12 @@ type opmlHeader struct { } type opmlOutline struct { - Title string `xml:"title,attr,omitempty"` - Text string `xml:"text,attr"` - FeedURL string `xml:"xmlUrl,attr,omitempty"` - SiteURL string `xml:"htmlUrl,attr,omitempty"` - Outlines opmlOutlineCollection `xml:"outline,omitempty"` + Title string `xml:"title,attr,omitempty"` + Text string `xml:"text,attr"` + FeedURL string `xml:"xmlUrl,attr,omitempty"` + SiteURL string `xml:"htmlUrl,attr,omitempty"` + Description string `xml:"description,attr,omitempty"` + Outlines opmlOutlineCollection `xml:"outline,omitempty"` } func (outline opmlOutline) MarshalXML(e *xml.Encoder, start xml.StartElement) error { diff --git a/internal/reader/opml/parser.go b/internal/reader/opml/parser.go index 09455a69..6b972d40 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(), + Description: outline.Description, 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..9210c178 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/", Description: "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..229c5a82 100644 --- a/internal/reader/opml/serializer.go +++ b/internal/reader/opml/serializer.go @@ -48,10 +48,11 @@ func convertSubscriptionsToOPML(subscriptions SubcriptionList) *opmlDocument { category := opmlOutline{Text: categoryName, Outlines: make(opmlOutlineCollection, 0, len(groupedSubs[categoryName]))} for _, subscription := range groupedSubs[categoryName] { category.Outlines = append(category.Outlines, opmlOutline{ - Title: subscription.Title, - Text: subscription.Title, - FeedURL: subscription.FeedURL, - SiteURL: subscription.SiteURL, + Title: subscription.Title, + Text: subscription.Title, + FeedURL: subscription.FeedURL, + SiteURL: subscription.SiteURL, + Description: subscription.Description, }) } diff --git a/internal/reader/opml/subscription.go b/internal/reader/opml/subscription.go index 6c05a204..f3a5ac34 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 + Description 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.Description == subscription.Description } // SubcriptionList is a list of subscriptions. diff --git a/internal/storage/entry_query_builder.go b/internal/storage/entry_query_builder.go index 9ab26738..6bc475fc 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.description, 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.Description, &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..36939d3d 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, + description ) 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.Description, ).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, + description=$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.Description, feed.ID, feed.UserID, ) diff --git a/internal/storage/feed_query_builder.go b/internal/storage/feed_query_builder.go index e12107ec..79a752d9 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.description, 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.Description, &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..cda7e251 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..e91b93c7 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, + Description: feed.Description, 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..5a6fd625 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), + Description: model.OptionalString(feedForm.Description), 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..c5345e9d 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 + Description 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.Description = f.Description 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"), + Description: r.FormValue("description"), ScraperRules: r.FormValue("scraper_rules"), UserAgent: r.FormValue("user_agent"), Cookie: r.FormValue("cookie"),