integration.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package integration // import "miniflux.app/v2/internal/integration"
  4. import (
  5. "log/slog"
  6. "miniflux.app/v2/internal/integration/apprise"
  7. "miniflux.app/v2/internal/integration/betula"
  8. "miniflux.app/v2/internal/integration/cubox"
  9. "miniflux.app/v2/internal/integration/discord"
  10. "miniflux.app/v2/internal/integration/espial"
  11. "miniflux.app/v2/internal/integration/instapaper"
  12. "miniflux.app/v2/internal/integration/karakeep"
  13. "miniflux.app/v2/internal/integration/linkace"
  14. "miniflux.app/v2/internal/integration/linkding"
  15. "miniflux.app/v2/internal/integration/linktaco"
  16. "miniflux.app/v2/internal/integration/linkwarden"
  17. "miniflux.app/v2/internal/integration/matrixbot"
  18. "miniflux.app/v2/internal/integration/notion"
  19. "miniflux.app/v2/internal/integration/ntfy"
  20. "miniflux.app/v2/internal/integration/nunuxkeeper"
  21. "miniflux.app/v2/internal/integration/omnivore"
  22. "miniflux.app/v2/internal/integration/pinboard"
  23. "miniflux.app/v2/internal/integration/pushover"
  24. "miniflux.app/v2/internal/integration/raindrop"
  25. "miniflux.app/v2/internal/integration/readeck"
  26. "miniflux.app/v2/internal/integration/readwise"
  27. "miniflux.app/v2/internal/integration/shaarli"
  28. "miniflux.app/v2/internal/integration/shiori"
  29. "miniflux.app/v2/internal/integration/slack"
  30. "miniflux.app/v2/internal/integration/telegrambot"
  31. "miniflux.app/v2/internal/integration/wallabag"
  32. "miniflux.app/v2/internal/integration/webhook"
  33. "miniflux.app/v2/internal/model"
  34. )
  35. // SendEntry sends the entry to third-party providers when the user click on "Save".
  36. func SendEntry(entry *model.Entry, userIntegrations *model.Integration) {
  37. if userIntegrations.BetulaEnabled {
  38. slog.Debug("Sending entry to Betula",
  39. slog.Int64("user_id", userIntegrations.UserID),
  40. slog.Int64("entry_id", entry.ID),
  41. slog.String("entry_url", entry.URL),
  42. )
  43. client := betula.NewClient(userIntegrations.BetulaURL, userIntegrations.BetulaToken)
  44. err := client.CreateBookmark(
  45. entry.URL,
  46. entry.Title,
  47. entry.Tags,
  48. )
  49. if err != nil {
  50. slog.Error("Unable to send entry to Betula",
  51. slog.Int64("user_id", userIntegrations.UserID),
  52. slog.Int64("entry_id", entry.ID),
  53. slog.String("entry_url", entry.URL),
  54. slog.Any("error", err),
  55. )
  56. }
  57. }
  58. if userIntegrations.PinboardEnabled {
  59. slog.Debug("Sending entry to Pinboard",
  60. slog.Int64("user_id", userIntegrations.UserID),
  61. slog.Int64("entry_id", entry.ID),
  62. slog.String("entry_url", entry.URL),
  63. )
  64. client := pinboard.NewClient(userIntegrations.PinboardToken)
  65. err := client.CreateBookmark(
  66. entry.URL,
  67. entry.Title,
  68. userIntegrations.PinboardTags,
  69. userIntegrations.PinboardMarkAsUnread,
  70. )
  71. if err != nil {
  72. slog.Error("Unable to send entry to Pinboard",
  73. slog.Int64("user_id", userIntegrations.UserID),
  74. slog.Int64("entry_id", entry.ID),
  75. slog.String("entry_url", entry.URL),
  76. slog.Any("error", err),
  77. )
  78. }
  79. }
  80. if userIntegrations.InstapaperEnabled {
  81. slog.Debug("Sending entry to Instapaper",
  82. slog.Int64("user_id", userIntegrations.UserID),
  83. slog.Int64("entry_id", entry.ID),
  84. slog.String("entry_url", entry.URL),
  85. )
  86. client := instapaper.NewClient(userIntegrations.InstapaperUsername, userIntegrations.InstapaperPassword)
  87. if err := client.AddURL(entry.URL, entry.Title); err != nil {
  88. slog.Error("Unable to send entry to Instapaper",
  89. slog.Int64("user_id", userIntegrations.UserID),
  90. slog.Int64("entry_id", entry.ID),
  91. slog.String("entry_url", entry.URL),
  92. slog.Any("error", err),
  93. )
  94. }
  95. }
  96. if userIntegrations.WallabagEnabled {
  97. slog.Debug("Sending entry to Wallabag",
  98. slog.Int64("user_id", userIntegrations.UserID),
  99. slog.Int64("entry_id", entry.ID),
  100. slog.String("entry_url", entry.URL),
  101. )
  102. client := wallabag.NewClient(
  103. userIntegrations.WallabagURL,
  104. userIntegrations.WallabagClientID,
  105. userIntegrations.WallabagClientSecret,
  106. userIntegrations.WallabagUsername,
  107. userIntegrations.WallabagPassword,
  108. userIntegrations.WallabagOnlyURL,
  109. )
  110. if err := client.CreateEntry(entry.URL, entry.Title, entry.Content); err != nil {
  111. slog.Error("Unable to send entry to Wallabag",
  112. slog.Int64("user_id", userIntegrations.UserID),
  113. slog.Int64("entry_id", entry.ID),
  114. slog.String("entry_url", entry.URL),
  115. slog.Any("error", err),
  116. )
  117. }
  118. }
  119. if userIntegrations.NotionEnabled {
  120. slog.Debug("Sending entry to Notion",
  121. slog.Int64("user_id", userIntegrations.UserID),
  122. slog.Int64("entry_id", entry.ID),
  123. slog.String("entry_url", entry.URL),
  124. )
  125. client := notion.NewClient(
  126. userIntegrations.NotionToken,
  127. userIntegrations.NotionPageID,
  128. )
  129. if err := client.UpdateDocument(entry.URL, entry.Title); err != nil {
  130. slog.Error("Unable to send entry to Notion",
  131. slog.Int64("user_id", userIntegrations.UserID),
  132. slog.Int64("entry_id", entry.ID),
  133. slog.String("entry_url", entry.URL),
  134. slog.Any("error", err),
  135. )
  136. }
  137. }
  138. if userIntegrations.NunuxKeeperEnabled {
  139. slog.Debug("Sending entry to NunuxKeeper",
  140. slog.Int64("user_id", userIntegrations.UserID),
  141. slog.Int64("entry_id", entry.ID),
  142. slog.String("entry_url", entry.URL),
  143. )
  144. client := nunuxkeeper.NewClient(
  145. userIntegrations.NunuxKeeperURL,
  146. userIntegrations.NunuxKeeperAPIKey,
  147. )
  148. if err := client.AddEntry(entry.URL, entry.Title, entry.Content); err != nil {
  149. slog.Error("Unable to send entry to NunuxKeeper",
  150. slog.Int64("user_id", userIntegrations.UserID),
  151. slog.Int64("entry_id", entry.ID),
  152. slog.String("entry_url", entry.URL),
  153. slog.Any("error", err),
  154. )
  155. }
  156. }
  157. if userIntegrations.EspialEnabled {
  158. slog.Debug("Sending entry to Espial",
  159. slog.Int64("user_id", userIntegrations.UserID),
  160. slog.Int64("entry_id", entry.ID),
  161. slog.String("entry_url", entry.URL),
  162. )
  163. client := espial.NewClient(
  164. userIntegrations.EspialURL,
  165. userIntegrations.EspialAPIKey,
  166. )
  167. if err := client.CreateLink(entry.URL, entry.Title, userIntegrations.EspialTags); err != nil {
  168. slog.Error("Unable to send entry to Espial",
  169. slog.Int64("user_id", userIntegrations.UserID),
  170. slog.Int64("entry_id", entry.ID),
  171. slog.String("entry_url", entry.URL),
  172. slog.Any("error", err),
  173. )
  174. }
  175. }
  176. if userIntegrations.LinkAceEnabled {
  177. slog.Debug("Sending entry to LinkAce",
  178. slog.Int64("user_id", userIntegrations.UserID),
  179. slog.Int64("entry_id", entry.ID),
  180. slog.String("entry_url", entry.URL),
  181. )
  182. client := linkace.NewClient(
  183. userIntegrations.LinkAceURL,
  184. userIntegrations.LinkAceAPIKey,
  185. userIntegrations.LinkAceTags,
  186. userIntegrations.LinkAcePrivate,
  187. userIntegrations.LinkAceCheckDisabled,
  188. )
  189. if err := client.AddURL(entry.URL, entry.Title); err != nil {
  190. slog.Error("Unable to send entry to LinkAce",
  191. slog.Int64("user_id", userIntegrations.UserID),
  192. slog.Int64("entry_id", entry.ID),
  193. slog.String("entry_url", entry.URL),
  194. slog.Any("error", err),
  195. )
  196. }
  197. }
  198. if userIntegrations.LinkdingEnabled {
  199. slog.Debug("Sending entry to Linkding",
  200. slog.Int64("user_id", userIntegrations.UserID),
  201. slog.Int64("entry_id", entry.ID),
  202. slog.String("entry_url", entry.URL),
  203. )
  204. client := linkding.NewClient(
  205. userIntegrations.LinkdingURL,
  206. userIntegrations.LinkdingAPIKey,
  207. userIntegrations.LinkdingTags,
  208. userIntegrations.LinkdingMarkAsUnread,
  209. )
  210. if err := client.CreateBookmark(entry.URL, entry.Title); err != nil {
  211. slog.Error("Unable to send entry to Linkding",
  212. slog.Int64("user_id", userIntegrations.UserID),
  213. slog.Int64("entry_id", entry.ID),
  214. slog.String("entry_url", entry.URL),
  215. slog.Any("error", err),
  216. )
  217. }
  218. }
  219. if userIntegrations.LinktacoEnabled {
  220. slog.Debug("Sending entry to LinkTaco",
  221. slog.Int64("user_id", userIntegrations.UserID),
  222. slog.Int64("entry_id", entry.ID),
  223. slog.String("entry_url", entry.URL),
  224. )
  225. client := linktaco.NewClient(
  226. userIntegrations.LinktacoAPIToken,
  227. userIntegrations.LinktacoOrgSlug,
  228. userIntegrations.LinktacoTags,
  229. userIntegrations.LinktacoVisibility,
  230. )
  231. if err := client.CreateBookmark(entry.URL, entry.Title, entry.Content); err != nil {
  232. slog.Error("Unable to send entry to LinkTaco",
  233. slog.Int64("user_id", userIntegrations.UserID),
  234. slog.Int64("entry_id", entry.ID),
  235. slog.String("entry_url", entry.URL),
  236. slog.Any("error", err),
  237. )
  238. }
  239. }
  240. if userIntegrations.LinkwardenEnabled {
  241. slog.Debug("Sending entry to linkwarden",
  242. slog.Int64("user_id", userIntegrations.UserID),
  243. slog.Int64("entry_id", entry.ID),
  244. slog.String("entry_url", entry.URL),
  245. )
  246. client := linkwarden.NewClient(
  247. userIntegrations.LinkwardenURL,
  248. userIntegrations.LinkwardenAPIKey,
  249. )
  250. if err := client.CreateBookmark(entry.URL, entry.Title); err != nil {
  251. slog.Error("Unable to send entry to Linkwarden",
  252. slog.Int64("user_id", userIntegrations.UserID),
  253. slog.Int64("entry_id", entry.ID),
  254. slog.String("entry_url", entry.URL),
  255. slog.Any("error", err),
  256. )
  257. }
  258. }
  259. if userIntegrations.ReadeckEnabled {
  260. slog.Debug("Sending entry to Readeck",
  261. slog.Int64("user_id", userIntegrations.UserID),
  262. slog.Int64("entry_id", entry.ID),
  263. slog.String("entry_url", entry.URL),
  264. )
  265. client := readeck.NewClient(
  266. userIntegrations.ReadeckURL,
  267. userIntegrations.ReadeckAPIKey,
  268. userIntegrations.ReadeckLabels,
  269. userIntegrations.ReadeckOnlyURL,
  270. )
  271. if err := client.CreateBookmark(entry.URL, entry.Title, entry.Content); err != nil {
  272. slog.Error("Unable to send entry to Readeck",
  273. slog.Int64("user_id", userIntegrations.UserID),
  274. slog.Int64("entry_id", entry.ID),
  275. slog.String("entry_url", entry.URL),
  276. slog.Any("error", err),
  277. )
  278. }
  279. }
  280. if userIntegrations.ReadwiseEnabled {
  281. slog.Debug("Sending entry to Readwise",
  282. slog.Int64("user_id", userIntegrations.UserID),
  283. slog.Int64("entry_id", entry.ID),
  284. slog.String("entry_url", entry.URL),
  285. )
  286. client := readwise.NewClient(
  287. userIntegrations.ReadwiseAPIKey,
  288. )
  289. if err := client.CreateDocument(entry.URL); err != nil {
  290. slog.Error("Unable to send entry to Readwise",
  291. slog.Int64("user_id", userIntegrations.UserID),
  292. slog.Int64("entry_id", entry.ID),
  293. slog.String("entry_url", entry.URL),
  294. slog.Any("error", err),
  295. )
  296. }
  297. }
  298. if userIntegrations.CuboxEnabled {
  299. slog.Debug("Sending entry to Cubox",
  300. slog.Int64("user_id", userIntegrations.UserID),
  301. slog.Int64("entry_id", entry.ID),
  302. slog.String("entry_url", entry.URL),
  303. )
  304. client := cubox.NewClient(userIntegrations.CuboxAPILink)
  305. if err := client.SaveLink(entry.URL); err != nil {
  306. slog.Error("Unable to send entry to Cubox",
  307. slog.Int64("user_id", userIntegrations.UserID),
  308. slog.Int64("entry_id", entry.ID),
  309. slog.String("entry_url", entry.URL),
  310. slog.Any("error", err),
  311. )
  312. }
  313. }
  314. if userIntegrations.ShioriEnabled {
  315. slog.Debug("Sending entry to Shiori",
  316. slog.Int64("user_id", userIntegrations.UserID),
  317. slog.Int64("entry_id", entry.ID),
  318. slog.String("entry_url", entry.URL),
  319. )
  320. client := shiori.NewClient(
  321. userIntegrations.ShioriURL,
  322. userIntegrations.ShioriUsername,
  323. userIntegrations.ShioriPassword,
  324. )
  325. if err := client.CreateBookmark(entry.URL, entry.Title); err != nil {
  326. slog.Error("Unable to send entry to Shiori",
  327. slog.Int64("user_id", userIntegrations.UserID),
  328. slog.Int64("entry_id", entry.ID),
  329. slog.String("entry_url", entry.URL),
  330. slog.Any("error", err),
  331. )
  332. }
  333. }
  334. if userIntegrations.ShaarliEnabled {
  335. slog.Debug("Sending entry to Shaarli",
  336. slog.Int64("user_id", userIntegrations.UserID),
  337. slog.Int64("entry_id", entry.ID),
  338. slog.String("entry_url", entry.URL),
  339. )
  340. client := shaarli.NewClient(
  341. userIntegrations.ShaarliURL,
  342. userIntegrations.ShaarliAPISecret,
  343. )
  344. if err := client.CreateLink(entry.URL, entry.Title); err != nil {
  345. slog.Error("Unable to send entry to Shaarli",
  346. slog.Int64("user_id", userIntegrations.UserID),
  347. slog.Int64("entry_id", entry.ID),
  348. slog.String("entry_url", entry.URL),
  349. slog.Any("error", err),
  350. )
  351. }
  352. }
  353. if userIntegrations.WebhookEnabled {
  354. var webhookURL string
  355. if entry.Feed != nil && entry.Feed.WebhookURL != "" {
  356. webhookURL = entry.Feed.WebhookURL
  357. } else {
  358. webhookURL = userIntegrations.WebhookURL
  359. }
  360. slog.Debug("Sending entry to Webhook",
  361. slog.Int64("user_id", userIntegrations.UserID),
  362. slog.Int64("entry_id", entry.ID),
  363. slog.String("entry_url", entry.URL),
  364. slog.String("webhook_url", webhookURL),
  365. )
  366. webhookClient := webhook.NewClient(webhookURL, userIntegrations.WebhookSecret)
  367. if err := webhookClient.SendSaveEntryWebhookEvent(entry); err != nil {
  368. slog.Error("Unable to send entry to Webhook",
  369. slog.Int64("user_id", userIntegrations.UserID),
  370. slog.Int64("entry_id", entry.ID),
  371. slog.String("entry_url", entry.URL),
  372. slog.String("webhook_url", webhookURL),
  373. slog.Any("error", err),
  374. )
  375. }
  376. }
  377. if userIntegrations.OmnivoreEnabled {
  378. slog.Debug("Sending entry to Omnivore",
  379. slog.Int64("user_id", userIntegrations.UserID),
  380. slog.Int64("entry_id", entry.ID),
  381. slog.String("entry_url", entry.URL),
  382. )
  383. client := omnivore.NewClient(userIntegrations.OmnivoreAPIKey, userIntegrations.OmnivoreURL)
  384. if err := client.SaveUrl(entry.URL); err != nil {
  385. slog.Error("Unable to send entry to Omnivore",
  386. slog.Int64("user_id", userIntegrations.UserID),
  387. slog.Int64("entry_id", entry.ID),
  388. slog.String("entry_url", entry.URL),
  389. slog.Any("error", err),
  390. )
  391. }
  392. }
  393. if userIntegrations.KarakeepEnabled {
  394. slog.Debug("Sending entry to Karakeep",
  395. slog.Int64("user_id", userIntegrations.UserID),
  396. slog.Int64("entry_id", entry.ID),
  397. slog.String("entry_url", entry.URL),
  398. )
  399. client := karakeep.NewClient(userIntegrations.KarakeepAPIKey, userIntegrations.KarakeepURL)
  400. if err := client.SaveURL(entry.URL); err != nil {
  401. slog.Error("Unable to send entry to Karakeep",
  402. slog.Int64("user_id", userIntegrations.UserID),
  403. slog.Int64("entry_id", entry.ID),
  404. slog.String("entry_url", entry.URL),
  405. slog.Any("error", err),
  406. )
  407. }
  408. }
  409. if userIntegrations.RaindropEnabled {
  410. slog.Debug("Sending entry to Raindrop",
  411. slog.Int64("user_id", userIntegrations.UserID),
  412. slog.Int64("entry_id", entry.ID),
  413. slog.String("entry_url", entry.URL),
  414. )
  415. client := raindrop.NewClient(userIntegrations.RaindropToken, userIntegrations.RaindropCollectionID, userIntegrations.RaindropTags)
  416. if err := client.CreateRaindrop(entry.URL, entry.Title); err != nil {
  417. slog.Error("Unable to send entry to Raindrop",
  418. slog.Int64("user_id", userIntegrations.UserID),
  419. slog.Int64("entry_id", entry.ID),
  420. slog.String("entry_url", entry.URL),
  421. slog.Any("error", err),
  422. )
  423. }
  424. }
  425. }
  426. // PushEntries pushes a list of entries to activated third-party providers during feed refreshes.
  427. func PushEntries(feed *model.Feed, entries model.Entries, userIntegrations *model.Integration) {
  428. if userIntegrations.MatrixBotEnabled {
  429. slog.Debug("Sending new entries to Matrix",
  430. slog.Int64("user_id", userIntegrations.UserID),
  431. slog.Int("nb_entries", len(entries)),
  432. slog.Int64("feed_id", feed.ID),
  433. )
  434. err := matrixbot.PushEntries(
  435. feed,
  436. entries,
  437. userIntegrations.MatrixBotURL,
  438. userIntegrations.MatrixBotUser,
  439. userIntegrations.MatrixBotPassword,
  440. userIntegrations.MatrixBotChatID,
  441. )
  442. if err != nil {
  443. slog.Error("Unable to send new entries to Matrix",
  444. slog.Int64("user_id", userIntegrations.UserID),
  445. slog.Int("nb_entries", len(entries)),
  446. slog.Int64("feed_id", feed.ID),
  447. slog.Any("error", err),
  448. )
  449. }
  450. }
  451. if userIntegrations.WebhookEnabled {
  452. var webhookURL string
  453. if feed.WebhookURL != "" {
  454. webhookURL = feed.WebhookURL
  455. } else {
  456. webhookURL = userIntegrations.WebhookURL
  457. }
  458. slog.Debug("Sending new entries to Webhook",
  459. slog.Int64("user_id", userIntegrations.UserID),
  460. slog.Int("nb_entries", len(entries)),
  461. slog.Int64("feed_id", feed.ID),
  462. slog.String("webhook_url", webhookURL),
  463. )
  464. webhookClient := webhook.NewClient(webhookURL, userIntegrations.WebhookSecret)
  465. if err := webhookClient.SendNewEntriesWebhookEvent(feed, entries); err != nil {
  466. slog.Debug("Unable to send new entries to Webhook",
  467. slog.Int64("user_id", userIntegrations.UserID),
  468. slog.Int("nb_entries", len(entries)),
  469. slog.Int64("feed_id", feed.ID),
  470. slog.String("webhook_url", webhookURL),
  471. slog.Any("error", err),
  472. )
  473. }
  474. }
  475. if userIntegrations.NtfyEnabled && feed.NtfyEnabled {
  476. ntfyTopic := feed.NtfyTopic
  477. if ntfyTopic == "" {
  478. ntfyTopic = userIntegrations.NtfyTopic
  479. }
  480. slog.Debug("Sending new entries to Ntfy",
  481. slog.Int64("user_id", userIntegrations.UserID),
  482. slog.Int("nb_entries", len(entries)),
  483. slog.Int64("feed_id", feed.ID),
  484. slog.String("topic", ntfyTopic),
  485. )
  486. client := ntfy.NewClient(
  487. userIntegrations.NtfyURL,
  488. ntfyTopic,
  489. userIntegrations.NtfyAPIToken,
  490. userIntegrations.NtfyUsername,
  491. userIntegrations.NtfyPassword,
  492. userIntegrations.NtfyIconURL,
  493. userIntegrations.NtfyInternalLinks,
  494. feed.NtfyPriority,
  495. )
  496. if err := client.SendMessages(feed, entries); err != nil {
  497. slog.Warn("Unable to send new entries to Ntfy", slog.Any("error", err))
  498. }
  499. }
  500. if userIntegrations.AppriseEnabled {
  501. slog.Debug("Sending new entries to Apprise",
  502. slog.Int64("user_id", userIntegrations.UserID),
  503. slog.Int("nb_entries", len(entries)),
  504. slog.Int64("feed_id", feed.ID),
  505. )
  506. appriseServiceURLs := userIntegrations.AppriseServicesURL
  507. if feed.AppriseServiceURLs != "" {
  508. appriseServiceURLs = feed.AppriseServiceURLs
  509. }
  510. client := apprise.NewClient(
  511. appriseServiceURLs,
  512. userIntegrations.AppriseURL,
  513. )
  514. if err := client.SendNotification(feed, entries); err != nil {
  515. slog.Warn("Unable to send new entries to Apprise", slog.Any("error", err))
  516. }
  517. }
  518. if userIntegrations.DiscordEnabled {
  519. slog.Debug("Sending new entries to Discord",
  520. slog.Int64("user_id", userIntegrations.UserID),
  521. slog.Int("nb_entries", len(entries)),
  522. slog.Int64("feed_id", feed.ID),
  523. )
  524. client := discord.NewClient(
  525. userIntegrations.DiscordWebhookLink,
  526. )
  527. if err := client.SendDiscordMsg(feed, entries); err != nil {
  528. slog.Warn("Unable to send new entries to Discord", slog.Any("error", err))
  529. }
  530. }
  531. if userIntegrations.SlackEnabled {
  532. slog.Debug("Sending new entries to Slack",
  533. slog.Int64("user_id", userIntegrations.UserID),
  534. slog.Int("nb_entries", len(entries)),
  535. slog.Int64("feed_id", feed.ID),
  536. )
  537. client := slack.NewClient(
  538. userIntegrations.SlackWebhookLink,
  539. )
  540. if err := client.SendSlackMsg(feed, entries); err != nil {
  541. slog.Warn("Unable to send new entries to Slack", slog.Any("error", err))
  542. }
  543. }
  544. if userIntegrations.PushoverEnabled && feed.PushoverEnabled {
  545. slog.Debug("Sending new entries to Pushover",
  546. slog.Int64("user_id", userIntegrations.UserID),
  547. slog.Int("nb_entries", len(entries)),
  548. slog.Int64("feed_id", feed.ID),
  549. )
  550. client := pushover.New(
  551. userIntegrations.PushoverUser,
  552. userIntegrations.PushoverToken,
  553. feed.PushoverPriority,
  554. userIntegrations.PushoverDevice,
  555. userIntegrations.PushoverPrefix,
  556. )
  557. if err := client.SendMessages(feed, entries); err != nil {
  558. slog.Warn("Unable to send new entries to Pushover", slog.Any("error", err))
  559. }
  560. }
  561. // Integrations that only support sending individual entries
  562. if userIntegrations.TelegramBotEnabled {
  563. for _, entry := range entries {
  564. if userIntegrations.TelegramBotEnabled {
  565. slog.Debug("Sending a new entry to Telegram",
  566. slog.Int64("user_id", userIntegrations.UserID),
  567. slog.Int64("entry_id", entry.ID),
  568. slog.String("entry_url", entry.URL),
  569. )
  570. if err := telegrambot.PushEntry(
  571. feed,
  572. entry,
  573. userIntegrations.TelegramBotToken,
  574. userIntegrations.TelegramBotChatID,
  575. userIntegrations.TelegramBotTopicID,
  576. userIntegrations.TelegramBotDisableWebPagePreview,
  577. userIntegrations.TelegramBotDisableNotification,
  578. userIntegrations.TelegramBotDisableButtons,
  579. ); err != nil {
  580. slog.Error("Unable to send entry to Telegram",
  581. slog.Int64("user_id", userIntegrations.UserID),
  582. slog.Int64("entry_id", entry.ID),
  583. slog.String("entry_url", entry.URL),
  584. slog.Any("error", err),
  585. )
  586. }
  587. }
  588. }
  589. }
  590. }