utils.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package feed
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/url"
  6. "regexp"
  7. "slices"
  8. "strings"
  9. )
  10. var (
  11. ErrNoContent = errors.New("failed to retrieve any content")
  12. ErrPartialContent = errors.New("failed to retrieve some of the content")
  13. )
  14. func percentChange(current, previous float64) float64 {
  15. return (current/previous - 1) * 100
  16. }
  17. func extractDomainFromUrl(u string) string {
  18. if u == "" {
  19. return ""
  20. }
  21. parsed, err := url.Parse(u)
  22. if err != nil {
  23. return ""
  24. }
  25. return strings.TrimPrefix(strings.ToLower(parsed.Host), "www.")
  26. }
  27. func SvgPolylineCoordsFromYValues(width float64, height float64, values []float64) string {
  28. if len(values) < 2 {
  29. return ""
  30. }
  31. verticalPadding := height * 0.02
  32. height -= verticalPadding * 2
  33. coordinates := make([]string, len(values))
  34. distanceBetweenPoints := width / float64(len(values)-1)
  35. min := slices.Min(values)
  36. max := slices.Max(values)
  37. for i := range values {
  38. coordinates[i] = fmt.Sprintf(
  39. "%.2f,%.2f",
  40. float64(i)*distanceBetweenPoints,
  41. ((max-values[i])/(max-min))*height+verticalPadding,
  42. )
  43. }
  44. return strings.Join(coordinates, " ")
  45. }
  46. func maybeCopySliceWithoutZeroValues[T int | float64](values []T) []T {
  47. if len(values) == 0 {
  48. return values
  49. }
  50. for i := range values {
  51. if values[i] != 0 {
  52. continue
  53. }
  54. c := make([]T, 0, len(values)-1)
  55. for i := range values {
  56. if values[i] != 0 {
  57. c = append(c, values[i])
  58. }
  59. }
  60. return c
  61. }
  62. return values
  63. }
  64. func currencyCodeToSymbol(code string) string {
  65. currencySymbols := map[string]string{
  66. "btc": "₿",
  67. "eth": "Ξ",
  68. "ltc": "Ł",
  69. "bch": "₡",
  70. "bnb": "Ƀ",
  71. "eos": "", // no symbol
  72. "xrp": "", // no symbol
  73. "xlm": "", // no symbol
  74. "link": "", // no symbol
  75. "dot": "", // no symbol
  76. "yfi": "", // no symbol
  77. "usd": "$",
  78. "aed": "د.إ",
  79. "ars": "$",
  80. "aud": "AU$",
  81. "bdt": "৳",
  82. "bhd": ".د.ب",
  83. "bmd": "$",
  84. "brl": "R$",
  85. "cad": "CA$",
  86. "chf": "CHF",
  87. "clp": "$",
  88. "cny": "¥",
  89. "czk": "Kč",
  90. "dkk": "kr",
  91. "eur": "€",
  92. "gbp": "£",
  93. "gel": "ლ",
  94. "hkd": "HK$",
  95. "huf": "Ft",
  96. "idr": "Rp",
  97. "ils": "₪",
  98. "inr": "₹",
  99. "jpy": "¥",
  100. "krw": "₩",
  101. "kwd": "د.ك",
  102. "lkr": "Rs",
  103. "mmk": "K",
  104. "mxn": "$",
  105. "myr": "RM",
  106. "ngn": "₦",
  107. "nok": "kr",
  108. "nzd": "NZ$",
  109. "php": "₱",
  110. "pkr": "Rs",
  111. "pln": "zł",
  112. "rub": "₽",
  113. "sar": "ر.س",
  114. "sek": "kr",
  115. "sgd": "SGD",
  116. "thb": "฿",
  117. "try": "₺",
  118. "twd": "NT$",
  119. "uah": "₴",
  120. "vef": "Bs",
  121. "vnd": "₫",
  122. "zar": "R",
  123. "xdr": "", // no symbol
  124. "xag": "", // no symbol
  125. "xau": "", // no symbol
  126. "bits": "", // no symbol
  127. "sats": "", // no symbol
  128. }
  129. symbol, ok := currencySymbols[code]
  130. if !ok {
  131. symbol = strings.ToUpper(code) + " "
  132. }
  133. return symbol
  134. }
  135. var urlSchemePattern = regexp.MustCompile(`^[a-z]+:\/\/`)
  136. func stripURLScheme(url string) string {
  137. return urlSchemePattern.ReplaceAllString(url, "")
  138. }
  139. func limitStringLength(s string, max int) (string, bool) {
  140. asRunes := []rune(s)
  141. if len(asRunes) > max {
  142. return string(asRunes[:max]), true
  143. }
  144. return s, false
  145. }