File: readability.patch

package info (click to toggle)
epiphany-browser 49.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 26,032 kB
  • sloc: ansic: 77,370; javascript: 7,062; xml: 720; python: 190; sh: 77; makefile: 14
file content (94 lines) | stat: -rw-r--r-- 3,806 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
--- Readability.js.orig	2025-05-07 21:45:49.710343570 +0200
+++ Readability.js	2025-05-08 06:50:13.641779085 +0200
@@ -2206,6 +2206,81 @@
   },
 
   /**
+  /* getReadingSpeedForLanguage and _get_reading_time from Firefox mobile/android/android-components/components/feature/readerview/src/main/assets/extensions/readerview/readerview.js
+   *
+   * This Source Code Form is subject to the terms of the Mozilla Public
+   * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+   * You can obtain one at http://mozilla.org/MPL/2.0/
+   */
+
+  /**
+   * Returns the reading speed of a selection of languages with likely variance.
+   *
+   * Reading speed estimated from a study done on reading speeds in various languages.
+   * study can be found here: http://iovs.arvojournals.org/article.aspx?articleid=2166061
+   *
+   * @return object with characters per minute and variance. Defaults to English
+   * if no suitable language is found in the collection.
+   */
+  getReadingSpeedForLanguage(lang) {
+    const readingSpeed = new Map([
+      ["en", { cpm: 987, variance: 118 }],
+      ["ar", { cpm: 612, variance: 88 }],
+      ["de", { cpm: 920, variance: 86 }],
+      ["es", { cpm: 1025, variance: 127 }],
+      ["fi", { cpm: 1078, variance: 121 }],
+      ["fr", { cpm: 998, variance: 126 }],
+      ["he", { cpm: 833, variance: 130 }],
+      ["it", { cpm: 950, variance: 140 }],
+      ["ja", { cpm: 357, variance: 56 }],
+      ["nl", { cpm: 978, variance: 143 }],
+      ["pl", { cpm: 916, variance: 126 }],
+      ["pt", { cpm: 913, variance: 145 }],
+      ["ru", { cpm: 986, variance: 175 }],
+      ["sl", { cpm: 885, variance: 145 }],
+      ["sv", { cpm: 917, variance: 156 }],
+      ["tr", { cpm: 1054, variance: 156 }],
+      ["zh", { cpm: 255, variance: 29 }],
+    ]);
+
+    return readingSpeed.has(lang)
+      ? [readingSpeed.get(lang), lang]
+      : [readingSpeed.get("en"), "en"];
+  },
+
+  _get_reading_time: function(length, lang = "en") {
+    const [readingSpeed, readingSpeedLang] = this.getReadingSpeedForLanguage(lang);
+    const charactersPerMinuteLow = readingSpeed.cpm - readingSpeed.variance;
+    const charactersPerMinuteHigh = readingSpeed.cpm + readingSpeed.variance;
+    const readingTimeMinsSlow = Math.ceil(length / charactersPerMinuteLow);
+    const readingTimeMinsFast = Math.ceil(length / charactersPerMinuteHigh);
+
+    // Construct a localized and "humanized" reading time in minutes.
+    // If we have both a fast and slow reading time we'll show both e.g.
+    // "2 - 4 minutes", otherwise we'll just show "4 minutes".
+    try {
+      var parts = new Intl.RelativeTimeFormat(readingSpeedLang).formatToParts(
+        readingTimeMinsSlow,
+        "minute"
+      );
+      if (parts.length == 3) {
+        // No need to use part[0] which represents the literal "in".
+        var readingTime = parts[1].value; // reading time in minutes
+        var minutesLiteral = parts[2].value; // localized singular or plural literal of 'minute'
+        var readingTimeString = `${readingTime} ${minutesLiteral}`;
+        if (readingTimeMinsSlow != readingTimeMinsFast) {
+          readingTimeString = `${readingTimeMinsFast} - ${readingTimeString}`;
+        }
+        return readingTimeString;
+      }
+    } catch (error) {
+      console.error(`Failed to format reading time: ${error}`);
+    }
+
+    return "";
+  },
+
+  /**
    * Runs readability.
    *
    * Workflow:
@@ -2267,7 +2342,8 @@
       textContent: textContent,
       length: textContent.length,
       excerpt: metadata.excerpt,
-      siteName: metadata.siteName || this._articleSiteName
+      siteName: metadata.siteName || this._articleSiteName,
+      reading_time: this._get_reading_time(textContent.length, this._doc.lang),
     };
   }
 };