Liu Song’s Projects


~/Projects/miniflux

git clone https://code.lsong.org/miniflux

Commit

Commit
3bac768cda0d92f81aa3690f1d92cffbaae246aa
Author
Corey McCaffrey <[email protected]>
Date
2023-07-27 23:51:44 -0400 -0400
Diffstat
 database/migrations.go | 8 ++
 integration/integration.go | 13 ++++
 integration/readwise/readwise.go | 66 ++++++++++++++++++++++++
 locale/translations/de_DE.json | 3 +
 locale/translations/el_EL.json | 3 +
 locale/translations/en_US.json | 3 +
 locale/translations/es_ES.json | 3 +
 locale/translations/fi_FI.json | 3 +
 locale/translations/fr_FR.json | 3 +
 locale/translations/hi_IN.json | 3 +
 locale/translations/id_ID.json | 3 +
 locale/translations/it_IT.json | 3 +
 locale/translations/ja_JP.json | 3 +
 locale/translations/nl_NL.json | 3 +
 locale/translations/pl_PL.json | 3 +
 locale/translations/pt_BR.json | 3 +
 locale/translations/ru_RU.json | 3 +
 locale/translations/tr_TR.json | 3 +
 locale/translations/uk_UA.json | 4 +
 locale/translations/zh_CN.json | 3 +
 locale/translations/zh_TW.json | 3 +
 model/integration.go | 2 
 storage/integration.go | 15 ++++-
 template/templates/views/integrations.html | 16 +++++
 ui/form/integration.go | 7 ++
 ui/integration_show.go | 2 

Added integration for Readwise Reader


diff --git a/database/migrations.go b/database/migrations.go
index e7f806cd5dacd416238b25b91968f1d681032a59..7a2eb01036dff05c483da8dee7d8381863ca65f2 100644
--- a/database/migrations.go
+++ b/database/migrations.go
@@ -716,4 +716,12 @@ 		`
 		_, err = tx.Exec(sql)
 		return err
 	},
+	func(tx *sql.Tx) (err error) {
+		sql := `
+		ALTER TABLE integrations ADD COLUMN readwise_enabled bool default 'f';
+		ALTER TABLE integrations ADD COLUMN readwise_api_key text default '';
+		`
+		_, err = tx.Exec(sql)
+		return err
+	},
 }




diff --git a/integration/integration.go b/integration/integration.go
index 96f02305559d83a077ad084f22bf6b419fb708ad..3fb2e583a5e706e9bc5cd2dc9aaeeee4caca5d0c 100644
--- a/integration/integration.go
+++ b/integration/integration.go
@@ -13,6 +13,7 @@ 	"miniflux.app/integration/notion"
 	"miniflux.app/integration/nunuxkeeper"
 	"miniflux.app/integration/pinboard"
 	"miniflux.app/integration/pocket"
+	"miniflux.app/integration/readwise"
 	"miniflux.app/integration/telegrambot"
 	"miniflux.app/integration/wallabag"
 	"miniflux.app/logger"
@@ -120,6 +121,18 @@ 			integration.LinkdingTags,
 			integration.LinkdingMarkAsUnread,
 		)
 		if err := client.AddEntry(entry.Title, entry.URL); err != nil {
+			logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
+		}
+	}
+
+	if integration.ReadwiseEnabled {
+		logger.Debug("[Integration] Sending Entry #%d %q for User #%d to Readwise Reader", entry.ID, entry.URL, integration.UserID)
+
+		client := readwise.NewClient(
+			integration.ReadwiseAPIKey,
+		)
+
+		if err := client.AddEntry(entry.URL); err != nil {
 			logger.Error("[Integration] UserID #%d: %v", integration.UserID, err)
 		}
 	}




diff --git a/integration/readwise/readwise.go b/integration/readwise/readwise.go
new file mode 100644
index 0000000000000000000000000000000000000000..538db68f15147532ba208fdba210f96f8a2cac49
--- /dev/null
+++ b/integration/readwise/readwise.go
@@ -0,0 +1,66 @@
+// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+// Readwise Reader API documentation: https://readwise.io/reader_api
+
+package readwise // import "miniflux.app/integration/readwise"
+
+import (
+	"fmt"
+	"net/url"
+
+	"miniflux.app/http/client"
+)
+
+// Document structure of a Readwise Reader document
+// This initial version accepts only the one required field, the URL
+type Document struct {
+	Url string `json:"url"`
+}
+
+// Client represents a Readwise Reader client.
+type Client struct {
+	apiKey string
+}
+
+// NewClient returns a new Readwise Reader client.
+func NewClient(apiKey string) *Client {
+	return &Client{apiKey: apiKey}
+}
+
+// AddEntry sends an entry to Readwise Reader.
+func (c *Client) AddEntry(link string) error {
+	if c.apiKey == "" {
+		return fmt.Errorf("readwise: missing credentials")
+	}
+
+	doc := &Document{
+		Url: link,
+	}
+
+	apiURL, err := getAPIEndpoint("https://readwise.io/api/v3/save/")
+	if err != nil {
+		return err
+	}
+
+	clt := client.New(apiURL)
+	clt.WithAuthorization("Token " + c.apiKey)
+	response, err := clt.PostJSON(doc)
+	if err != nil {
+		return fmt.Errorf("readwise: unable to send entry: %v", err)
+	}
+
+	if response.HasServerFailure() {
+		return fmt.Errorf("readwise: unable to send entry, status=%d", response.StatusCode)
+	}
+
+	return nil
+}
+
+func getAPIEndpoint(pathURL string) (string, error) {
+	u, err := url.Parse(pathURL)
+	if err != nil {
+		return "", fmt.Errorf("readwise: invalid API endpoint: %v", err)
+	}
+	return u.String(), nil
+}




diff --git a/locale/translations/de_DE.json b/locale/translations/de_DE.json
index 0ef14f91d1ff7368d329617c2e14c2c463fbaf19..89b2ae167516e17662748235730e51b72449ddec 100644
--- a/locale/translations/de_DE.json
+++ b/locale/translations/de_DE.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Artikel in Espial speichern",
     "form.integration.espial_endpoint": "Espial API-Endpunkt",
     "form.integration.espial_api_key": "Espial API-Schlüssel",
     "form.integration.espial_tags": "Espial tags",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Pushen Sie neue Artikel in den Telegram-Chat",
     "form.integration.telegram_bot_token": "Bot token",
     "form.integration.telegram_chat_id": "Chat ID",




diff --git a/locale/translations/el_EL.json b/locale/translations/el_EL.json
index 6527fed30273aabebcbbc2082c9551b95f4f4260..0994d9fb1050c3304c9c507a2e4804eedd209ad7 100644
--- a/locale/translations/el_EL.json
+++ b/locale/translations/el_EL.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Αποθήκευση άρθρων στο Espial",
     "form.integration.espial_endpoint": "Τελικό σημείο Espial API",
     "form.integration.espial_api_key": "Κλειδί API Espial",
     "form.integration.espial_tags": "Ετικέτες Espial",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Προωθήστε νέα άρθρα στη συνομιλία Telegram",
     "form.integration.telegram_bot_token": "Διακριτικό bot",
     "form.integration.telegram_chat_id": "Αναγνωριστικό συνομιλίας",




diff --git a/locale/translations/en_US.json b/locale/translations/en_US.json
index d278bfdb605d5c7f2100c943d5d1376327123998..cda3a281c44848378cb6f94402af464e3a1724a1 100644
--- a/locale/translations/en_US.json
+++ b/locale/translations/en_US.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Save entries to Espial",
     "form.integration.espial_endpoint": "Espial API Endpoint",
     "form.integration.espial_api_key": "Espial API key",
     "form.integration.espial_tags": "Espial Tags",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Push new entries to Telegram chat",
     "form.integration.telegram_bot_token": "Bot token",
     "form.integration.telegram_chat_id": "Chat ID",




diff --git a/locale/translations/es_ES.json b/locale/translations/es_ES.json
index e69e56d4abb1e3ddb50c5048c9d0d00f7d82c7b4..5ccf5f217cc75ee230d11cd1c092fdd2fedbb91c 100644
--- a/locale/translations/es_ES.json
+++ b/locale/translations/es_ES.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Enviar artículos a Espial",
     "form.integration.espial_endpoint": "Acceso API de Espial",
     "form.integration.espial_api_key": "Clave de API de Espial",
     "form.integration.espial_tags": "Etiquetas de Espial",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Envíe nuevos artículos al chat de Telegram",
     "form.integration.telegram_bot_token": "Token de bot",
     "form.integration.telegram_chat_id": "ID de chat",




diff --git a/locale/translations/fi_FI.json b/locale/translations/fi_FI.json
index 16b6bb39cd18eaeb37a8e1a98f81b68dabf641bb..c7050abd69d2da6cf4763e6dd45146529d8665bf 100644
--- a/locale/translations/fi_FI.json
+++ b/locale/translations/fi_FI.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Tallenna artikkelit Espialiin",
     "form.integration.espial_endpoint": "Espial API-päätepiste",
     "form.integration.espial_api_key": "Espial API-avain",
     "form.integration.espial_tags": "Espial-tagit",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Lähetä uusia artikkeleita Telegram-chatiin",
     "form.integration.telegram_bot_token": "Bot-tunnus",
     "form.integration.telegram_chat_id": "Chat ID",




diff --git a/locale/translations/fr_FR.json b/locale/translations/fr_FR.json
index c1e6975d1f382c5b6899b78c13b7212a3473ec28..b4f35c67a17f06aff37ae4441c9446d6a886752d 100644
--- a/locale/translations/fr_FR.json
+++ b/locale/translations/fr_FR.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Sauvegarder les articles vers Espial",
     "form.integration.espial_endpoint": "URL de l'API de Espial",
     "form.integration.espial_api_key": "Clé d'API de Espial",
     "form.integration.espial_tags": "Libellés de Espial",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Envoyer les nouveaux articles vers Telegram",
     "form.integration.telegram_bot_token": "Jeton de sécurité de l'API du Bot Telegram",
     "form.integration.telegram_chat_id": "Identifiant de discussion",




diff --git a/locale/translations/hi_IN.json b/locale/translations/hi_IN.json
index 7e0b2f545f36ae6203e7be8e46742a4e7999cdf2..8ad4cc58eb3f349d1301f4e8a9468e159a495ff9 100644
--- a/locale/translations/hi_IN.json
+++ b/locale/translations/hi_IN.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "विषय-वस्तु को जासूसी में सहेजें",
     "form.integration.espial_endpoint": "जासूसी एपीआई समापन बिंदु",
     "form.integration.espial_api_key": "जासूसी एपीआई कुंजी",
     "form.integration.espial_tags": "जासूसी टैग",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "टेलीग्राम चैट के लिए नई विषय-कविता पुश करें",
     "form.integration.telegram_bot_token": "बॉट टोकन",
     "form.integration.telegram_chat_id": "चैट आईडी",




diff --git a/locale/translations/id_ID.json b/locale/translations/id_ID.json
index 4e4a8a3957ba37651d9acd220ddc46147f9f957f..6e8623d2e63b9dd559c9f669d5308e5d273bd3e5 100644
--- a/locale/translations/id_ID.json
+++ b/locale/translations/id_ID.json
@@ -358,6 +358,9 @@     "form.integration.espial_activate": "Simpan artikel ke Espial",
     "form.integration.espial_endpoint": "Titik URL API Espial",
     "form.integration.espial_api_key": "Kunci API Espial",
     "form.integration.espial_tags": "Tanda di Espial",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Kirim artikel baru ke percakapan Telegram",
     "form.integration.telegram_bot_token": "Token Bot",
     "form.integration.telegram_chat_id": "ID Obrolan",




diff --git a/locale/translations/it_IT.json b/locale/translations/it_IT.json
index d30b7f660fdf89c310cbe96163fdab3711d5f482..23f61428432e5d0b44437c78642d759b9f09bc35 100644
--- a/locale/translations/it_IT.json
+++ b/locale/translations/it_IT.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Salva gli articoli su Espial",
     "form.integration.espial_endpoint": "Endpoint dell'API di Espial",
     "form.integration.espial_api_key": "API key dell'account Espial",
     "form.integration.espial_tags": "Tag di Espial",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Invia nuovi articoli alla chat di Telegram",
     "form.integration.telegram_bot_token": "Token bot",
     "form.integration.telegram_chat_id": "ID chat",




diff --git a/locale/translations/ja_JP.json b/locale/translations/ja_JP.json
index 782d6e2d182597e4a139435fb0a73948fd04950e..0f5b6297704cfb384568cc75634bf39b098169f5 100644
--- a/locale/translations/ja_JP.json
+++ b/locale/translations/ja_JP.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Espial に記事を保存する",
     "form.integration.espial_endpoint": "Espial の API Endpoint",
     "form.integration.espial_api_key": "Espial の API key",
     "form.integration.espial_tags": "Espial の Tag",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "新しい記事を Telegram チャットにプッシュする",
     "form.integration.telegram_bot_token": "ボットトークン",
     "form.integration.telegram_chat_id": "チャット ID",




diff --git a/locale/translations/nl_NL.json b/locale/translations/nl_NL.json
index 3fb32dbeda7a5669f8fe046ec2a02323877d97f6..2618ebcbbf3ea913d7d56005e72e9cb08e6d71d0 100644
--- a/locale/translations/nl_NL.json
+++ b/locale/translations/nl_NL.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Opslaan naar Espial",
     "form.integration.espial_endpoint": "Espial URL",
     "form.integration.espial_api_key": "Espial API-sleutel",
     "form.integration.espial_tags": "Espial tags",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Push nieuwe artikelen naar Telegram-chat",
     "form.integration.telegram_bot_token": "Bot token",
     "form.integration.telegram_chat_id": "Chat ID",




diff --git a/locale/translations/pl_PL.json b/locale/translations/pl_PL.json
index 6f32532e1d64033cbc7147fc8a89a577bbc46f16..74e34b4ea7a4c7ac56b97d74481a0d57d6032acf 100644
--- a/locale/translations/pl_PL.json
+++ b/locale/translations/pl_PL.json
@@ -363,6 +363,9 @@     "form.integration.espial_activate": "Zapisz artykuly do Espial",
     "form.integration.espial_endpoint": "Espial URL",
     "form.integration.espial_api_key": "Espial API key",
     "form.integration.espial_tags": "Espial Tags",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Przesyłaj nowe artykuły do czatu Telegram",
     "form.integration.telegram_bot_token": "Token bota",
     "form.integration.telegram_chat_id": "Identyfikator czatu",




diff --git a/locale/translations/pt_BR.json b/locale/translations/pt_BR.json
index f5ee949d588d11b669b4d14c7d3a744b8ad51812..6a2d1b94977558a61e366356deea4238f280c25e 100644
--- a/locale/translations/pt_BR.json
+++ b/locale/translations/pt_BR.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Salvar itens no Espial",
     "form.integration.espial_endpoint": "Endpoint de API do Espial",
     "form.integration.espial_api_key": "Chave de API do Espial",
     "form.integration.espial_tags": "Etiquetas (tags) do Espial",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Envie novos artigos para o chat do Telegram",
     "form.integration.telegram_bot_token": "Token de bot",
     "form.integration.telegram_chat_id": "ID de bate-papo",




diff --git a/locale/translations/ru_RU.json b/locale/translations/ru_RU.json
index 82eb0481af97cab5bfc7694ac43805b823142b67..3c41d2a9da60dedb70e37b8b1fbe24ddbecaf622 100644
--- a/locale/translations/ru_RU.json
+++ b/locale/translations/ru_RU.json
@@ -363,6 +363,9 @@     "form.integration.espial_activate": "Сохранять статьи в Espial",
     "form.integration.espial_endpoint": "Конечная точка Espial API",
     "form.integration.espial_api_key": "API-ключ Espial",
     "form.integration.espial_tags": "Теги Espial",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Репостить новые статьи в Telegram-чат",
     "form.integration.telegram_bot_token": "Токен бота",
     "form.integration.telegram_chat_id": "ID чата",




diff --git a/locale/translations/tr_TR.json b/locale/translations/tr_TR.json
index 641efcb493f6ab9e236f39c7cb5422ae1405ed97..1e1c73419ff76044c913c7d494262f66bd9f210d 100644
--- a/locale/translations/tr_TR.json
+++ b/locale/translations/tr_TR.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "Makaleleri Espial'e kaydet",
     "form.integration.espial_endpoint": "Espial API Uç Noktası",
     "form.integration.espial_api_key": "Espial API Anahtarı",
     "form.integration.espial_tags": "Espial Etiketleri",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "Yeni makaleleri Telegram sohbetine gönderin",
     "form.integration.telegram_bot_token": "Bot jetonu",
     "form.integration.telegram_chat_id": "Sohbet kimliği",




diff --git a/locale/translations/uk_UA.json b/locale/translations/uk_UA.json
index 42be13f7dbbd44a499dbe20b923295e48e0880bb..84659566cffd3b12d59b6f14cb4338515980038e 100644
--- a/locale/translations/uk_UA.json
+++ b/locale/translations/uk_UA.json
@@ -361,6 +361,10 @@   "form.integration.espial_endpoint": "Espial API Endpoint",
   "form.integration.espial_api_key": "Ключ API Espial",
   "form.integration.espial_tags": "Теги для Espial",
   "confirm.yes": "так",
+    "Містить %d стрічку.",
+  "form.integration.readwise_api_key": "Readwise Reader Access Token",
+  "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
+  "confirm.yes": "так",
   "entry.bookmark.toast.off": "Без зірочки",
   "form.integration.telegram_bot_token": "Токен боту",
   "form.integration.telegram_chat_id": "ID чату",




diff --git a/locale/translations/zh_CN.json b/locale/translations/zh_CN.json
index e96e964a2fbce1f064d8e6bcd88afc27a33db533..ed6700f7242d75d7588be12a50073e23d74d5b9f 100644
--- a/locale/translations/zh_CN.json
+++ b/locale/translations/zh_CN.json
@@ -359,6 +359,9 @@     "form.integration.espial_activate":  "保存文章到 Espial",
     "form.integration.espial_endpoint":  "Espial API 端点",
     "form.integration.espial_api_key":  "Espial API 密钥",
     "form.integration.espial_tags": "Espial 标签",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "将新文章推送到 Telegram",
     "form.integration.telegram_bot_token": "机器人令牌",
     "form.integration.telegram_chat_id": "聊天ID",




diff --git a/locale/translations/zh_TW.json b/locale/translations/zh_TW.json
index 0330664e1f2e9e05b428164d1d18df50a3b890cc..b540a9923100db1cea912e0d7f4227bd8a15ce27 100644
--- a/locale/translations/zh_TW.json
+++ b/locale/translations/zh_TW.json
@@ -361,6 +361,9 @@     "form.integration.espial_activate": "儲存文章到 Espial",
     "form.integration.espial_endpoint": "Espial API 端點",
     "form.integration.espial_api_key": "Espial API 金鑰",
     "form.integration.espial_tags": "Espial 標籤",
+    "form.integration.readwise_activate": "Save entries to Readwise Reader",
+    "form.integration.readwise_api_key": "Readwise Reader Access Token",
+    "form.integration.readwise_api_key_link": "Get your Readwise Access Token",
     "form.integration.telegram_bot_activate": "將新文章推送到 Telegram",
     "form.integration.telegram_bot_token": "Bot token",
     "form.integration.telegram_chat_id": "Chat ID",




diff --git a/model/integration.go b/model/integration.go
index 50abd7fc17df2c67b10d1e703e794c23a59cdd85..27375ef4907c4c2783ed5d8611a7d2c2fe95ffae 100644
--- a/model/integration.go
+++ b/model/integration.go
@@ -36,6 +36,8 @@ 	EspialEnabled        bool
 	EspialURL            string
 	EspialAPIKey         string
 	EspialTags           string
+	ReadwiseEnabled      bool
+	ReadwiseAPIKey       string
 	PocketEnabled        bool
 	PocketAccessToken    string
 	PocketConsumerKey    string




diff --git a/storage/integration.go b/storage/integration.go
index f6378c8fc0d45d52f8cbd8ff6bd61d77b3c3ff76..2601f951e3c6042df0b003c9c9155b8d69543876 100644
--- a/storage/integration.go
+++ b/storage/integration.go
@@ -140,6 +140,8 @@ 			espial_enabled,
 			espial_url,
 			espial_api_key,
 			espial_tags,
+			readwise_enabled,
+			readwise_api_key,
 			pocket_enabled,
 			pocket_access_token,
 			pocket_consumer_key,
@@ -194,6 +196,8 @@ 		&integration.EspialEnabled,
 		&integration.EspialURL,
 		&integration.EspialAPIKey,
 		&integration.EspialTags,
+		&integration.ReadwiseEnabled,
+		&integration.ReadwiseAPIKey,
 		&integration.PocketEnabled,
 		&integration.PocketAccessToken,
 		&integration.PocketConsumerKey,
@@ -273,11 +277,13 @@ 			matrix_bot_chat_id=$43,
 			notion_enabled=$44,
 			notion_token=$45,
 // SPDX-License-Identifier: Apache-2.0
+			fever_token,
+			readwise_enabled=$47,
+			users
 // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
-import (
 		WHERE
 // SPDX-License-Identifier: Apache-2.0
-	return result
+			wallabag_only_url,
 	`
 	_, err := s.db.Exec(
 		query,
@@ -328,6 +334,9 @@ 		integration.NotionEnabled,
 		integration.NotionToken,
 		integration.NotionPageID,
 // SPDX-License-Identifier: Apache-2.0
+			wallabag_url,
+		integration.ReadwiseAPIKey,
+// SPDX-License-Identifier: Apache-2.0
 		return &integration, fmt.Errorf(`store: unable to find this user: %s`, username)
 	)
 
@@ -349,7 +358,7 @@ 		WHERE
 			user_id=$1
 		AND
 // SPDX-License-Identifier: Apache-2.0
-			pinboard_tags,
+			wallabag_client_secret,
 	`
 	if err := s.db.QueryRow(query, userID).Scan(&result); err != nil {
 		result = false




diff --git a/template/templates/views/integrations.html b/template/templates/views/integrations.html
index afc47bef801d297bbfef922e2a68e75a40a23523..afbb6aa7340f28bc3b06cc18fff7a5fd1f90c1ce 100644
--- a/template/templates/views/integrations.html
+++ b/template/templates/views/integrations.html
@@ -195,6 +195,22 @@             
         </div>
     </div>
 
+    <h3>Readwise Reader</h3>
+    <div class="form-section">
+        <label>
+            <input type="checkbox" name="readwise_enabled" value="1" {{ if .form.ReadwiseEnabled }}checked{{ end }}> {{ t "form.integration.readwise_activate" }}
+        </label>
+
+        <label for="form-readwise-api-key">{{ t "form.integration.readwise_api_key" }}</label>
+        <input type="text" name="readwise_api_key" id="form-readwise-api-key" value="{{ .form.ReadwiseAPIKey }}" spellcheck="false">
+
+        <p><a href="https://readwise.io/access_token" target="_blank">{{ t "form.integration.readwise_api_key_link" }}</a></p>
+
+        <div class="buttons">
+            <button type="submit" class="button button-primary" data-label-loading="{{ t "form.submit.saving" }}">{{ t "action.update" }}</button>
+        </div>
+    </div>
+
     <h3>Linkding</h3>
     <div class="form-section">
         <label>




diff --git a/ui/form/integration.go b/ui/form/integration.go
index 95c07f142e437f971e09146c63655c2fe05d6fcc..63e03f6e82f689d6f9b625e7b4e2b03913d8621a 100644
--- a/ui/form/integration.go
+++ b/ui/form/integration.go
@@ -41,6 +41,8 @@ 	EspialEnabled        bool
 	EspialURL            string
 	EspialAPIKey         string
 	EspialTags           string
+	ReadwiseEnabled      bool
+	ReadwiseAPIKey       string
 	PocketEnabled        bool
 	PocketAccessToken    string
 	PocketConsumerKey    string
@@ -89,6 +91,9 @@ 	integration.EspialEnabled = i.EspialEnabled
 	integration.EspialURL = i.EspialURL
 	integration.EspialAPIKey = i.EspialAPIKey
 )
+	"miniflux.app/model"
+	integration.ReadwiseEnabled = i.ReadwiseEnabled
+	InstapaperEnabled    bool
 	"miniflux.app/model"
 	integration.PocketEnabled = i.PocketEnabled
 	integration.PocketAccessToken = i.PocketAccessToken
@@ -141,6 +146,8 @@ 		EspialEnabled:        r.FormValue("espial_enabled") == "1",
 		EspialURL:            r.FormValue("espial_url"),
 		EspialAPIKey:         r.FormValue("espial_api_key"),
 		EspialTags:           r.FormValue("espial_tags"),
+		ReadwiseEnabled:      r.FormValue("readwise_enabled") == "1",
+		ReadwiseAPIKey:       r.FormValue("readwise_api_key"),
 		PocketEnabled:        r.FormValue("pocket_enabled") == "1",
 		PocketAccessToken:    r.FormValue("pocket_access_token"),
 		PocketConsumerKey:    r.FormValue("pocket_consumer_key"),




diff --git a/ui/integration_show.go b/ui/integration_show.go
index eac49da6edfe452cd896d10394e52800a2022128..8404c0020e6fe4f535475ae087eed7a85b8e7a32 100644
--- a/ui/integration_show.go
+++ b/ui/integration_show.go
@@ -56,6 +56,8 @@ 		EspialEnabled:        integration.EspialEnabled,
 		EspialURL:            integration.EspialURL,
 		EspialAPIKey:         integration.EspialAPIKey,
 		EspialTags:           integration.EspialTags,
+		ReadwiseEnabled:      integration.ReadwiseEnabled,
+		ReadwiseAPIKey:       integration.ReadwiseAPIKey,
 		PocketEnabled:        integration.PocketEnabled,
 		PocketAccessToken:    integration.PocketAccessToken,
 		PocketConsumerKey:    integration.PocketConsumerKey,