readingtime.go 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. // Package readingtime provides a function to estimate the reading time of an article.
  4. package readingtime
  5. import (
  6. "strings"
  7. "unicode"
  8. "unicode/utf8"
  9. "miniflux.app/v2/internal/reader/sanitizer"
  10. )
  11. // EstimateReadingTime returns the estimated reading time of an article in minute.
  12. func EstimateReadingTime(content string, defaultReadingSpeed, cjkReadingSpeed int) int {
  13. sanitizedContent := sanitizer.StripTags(content)
  14. truncationPoint := min(len(sanitizedContent), 50)
  15. if isCJK(sanitizedContent[:truncationPoint]) {
  16. return (utf8.RuneCountInString(sanitizedContent) + cjkReadingSpeed - 1) / cjkReadingSpeed
  17. }
  18. return (countWords(sanitizedContent) + defaultReadingSpeed - 1) / defaultReadingSpeed
  19. }
  20. func countWords(s string) int {
  21. n := 0
  22. for range strings.FieldsSeq(s) {
  23. n++
  24. }
  25. return n
  26. }
  27. func isCJK(text string) bool {
  28. totalCJK := 0
  29. for _, r := range text[:min(len(text), 50)] {
  30. if unicode.Is(unicode.Han, r) ||
  31. unicode.Is(unicode.Hangul, r) ||
  32. unicode.Is(unicode.Hiragana, r) ||
  33. unicode.Is(unicode.Katakana, r) ||
  34. unicode.Is(unicode.Yi, r) ||
  35. unicode.Is(unicode.Bopomofo, r) {
  36. totalCJK++
  37. }
  38. }
  39. // if at least 50% of the text is CJK, odds are that the text is in CJK.
  40. return totalCJK > len(text)/50
  41. }