linkding.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package linkding // import "miniflux.app/v2/internal/integration/linkding"
  4. import (
  5. "bytes"
  6. "encoding/json"
  7. "fmt"
  8. "net/http"
  9. "strings"
  10. "time"
  11. "miniflux.app/v2/internal/urllib"
  12. "miniflux.app/v2/internal/version"
  13. )
  14. const defaultClientTimeout = 10 * time.Second
  15. type Client struct {
  16. baseURL string
  17. apiKey string
  18. tags string
  19. unread bool
  20. }
  21. func NewClient(baseURL, apiKey, tags string, unread bool) *Client {
  22. return &Client{baseURL: baseURL, apiKey: apiKey, tags: tags, unread: unread}
  23. }
  24. func (c *Client) CreateBookmark(entryURL, entryTitle string) error {
  25. if c.baseURL == "" || c.apiKey == "" {
  26. return fmt.Errorf("linkding: missing base URL or API key")
  27. }
  28. tagsSplitFn := func(c rune) bool {
  29. return c == ',' || c == ' '
  30. }
  31. apiEndpoint, err := urllib.JoinBaseURLAndPath(c.baseURL, "/api/bookmarks/")
  32. if err != nil {
  33. return fmt.Errorf(`linkding: invalid API endpoint: %v`, err)
  34. }
  35. requestBody, err := json.Marshal(&linkdingBookmark{
  36. Url: entryURL,
  37. Title: entryTitle,
  38. TagNames: strings.FieldsFunc(c.tags, tagsSplitFn),
  39. Unread: c.unread,
  40. })
  41. if err != nil {
  42. return fmt.Errorf("linkding: unable to encode request body: %v", err)
  43. }
  44. request, err := http.NewRequest(http.MethodPost, apiEndpoint, bytes.NewReader(requestBody))
  45. if err != nil {
  46. return fmt.Errorf("linkding: unable to create request: %v", err)
  47. }
  48. request.Header.Set("Content-Type", "application/json")
  49. request.Header.Set("User-Agent", "Miniflux/"+version.Version)
  50. request.Header.Set("Authorization", "Token "+c.apiKey)
  51. httpClient := &http.Client{Timeout: defaultClientTimeout}
  52. response, err := httpClient.Do(request)
  53. if err != nil {
  54. return fmt.Errorf("linkding: unable to send request: %v", err)
  55. }
  56. defer response.Body.Close()
  57. if response.StatusCode >= 400 {
  58. return fmt.Errorf("linkding: unable to create bookmark: url=%s status=%d", apiEndpoint, response.StatusCode)
  59. }
  60. return nil
  61. }
  62. type linkdingBookmark struct {
  63. Url string `json:"url,omitempty"`
  64. Title string `json:"title,omitempty"`
  65. TagNames []string `json:"tag_names,omitempty"`
  66. Unread bool `json:"unread,omitempty"`
  67. }