2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2014 Gabriele <pmzqla.git@gmail.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
31 window
.qBittorrent
??= {};
32 window
.qBittorrent
.Misc
??= (() => {
33 const exports
= () => {
35 createDebounceHandler
: createDebounceHandler
,
36 friendlyUnit
: friendlyUnit
,
37 friendlyDuration
: friendlyDuration
,
38 friendlyPercentage
: friendlyPercentage
,
39 friendlyFloat
: friendlyFloat
,
40 parseHtmlLinks
: parseHtmlLinks
,
41 parseVersion
: parseVersion
,
42 escapeHtml
: escapeHtml
,
43 naturalSortCollator
: naturalSortCollator
,
45 toFixedPointString
: toFixedPointString
,
46 containsAllTerms
: containsAllTerms
,
49 FILTER_INPUT_DELAY
: 400,
54 const createDebounceHandler
= (delay
, func
) => {
56 return (...params
) => {
58 timer
= setTimeout(() => {
67 * JS counterpart of the function in src/misc.cpp
69 const friendlyUnit = function(value
, isSpeed
) {
71 "QBT_TR(B)QBT_TR[CONTEXT=misc]",
72 "QBT_TR(KiB)QBT_TR[CONTEXT=misc]",
73 "QBT_TR(MiB)QBT_TR[CONTEXT=misc]",
74 "QBT_TR(GiB)QBT_TR[CONTEXT=misc]",
75 "QBT_TR(TiB)QBT_TR[CONTEXT=misc]",
76 "QBT_TR(PiB)QBT_TR[CONTEXT=misc]",
77 "QBT_TR(EiB)QBT_TR[CONTEXT=misc]"
80 if ((value
=== undefined) || (value
=== null) || (value
< 0))
81 return "QBT_TR(Unknown)QBT_TR[CONTEXT=misc]";
84 while ((value
>= 1024.0) && (i
< 6)) {
89 function friendlyUnitPrecision(sizeUnit
) {
90 if (sizeUnit
<= 2) // KiB, MiB
92 else if (sizeUnit
=== 3) // GiB
100 ret
= value
+ " " + units
[i
];
103 const precision
= friendlyUnitPrecision(i
);
104 const offset
= Math
.pow(10, precision
);
106 ret
= (Math
.floor(offset
* value
) / offset
).toFixed(precision
) + " " + units
[i
];
110 ret
+= "QBT_TR(/s)QBT_TR[CONTEXT=misc]";
115 * JS counterpart of the function in src/misc.cpp
117 const friendlyDuration = function(seconds
, maxCap
= -1) {
118 if ((seconds
< 0) || ((seconds
>= maxCap
) && (maxCap
>= 0)))
123 return "QBT_TR(< 1m)QBT_TR[CONTEXT=misc]";
124 let minutes
= seconds
/ 60;
126 return "QBT_TR(%1m)QBT_TR[CONTEXT=misc]".replace("%1", Math
.floor(minutes
));
127 let hours
= minutes
/ 60;
130 return "QBT_TR(%1h %2m)QBT_TR[CONTEXT=misc]".replace("%1", Math
.floor(hours
)).replace("%2", Math
.floor(minutes
));
131 let days
= hours
/ 24;
134 return "QBT_TR(%1d %2h)QBT_TR[CONTEXT=misc]".replace("%1", Math
.floor(days
)).replace("%2", Math
.floor(hours
));
135 const years
= days
/ 365;
137 return "QBT_TR(%1y %2d)QBT_TR[CONTEXT=misc]".replace("%1", Math
.floor(years
)).replace("%2", Math
.floor(days
));
140 const friendlyPercentage = function(value
) {
141 let percentage
= (value
* 100).round(1);
142 if (isNaN(percentage
) || (percentage
< 0))
144 if (percentage
> 100)
146 return percentage
.toFixed(1) + "%";
149 const friendlyFloat = function(value
, precision
) {
150 return parseFloat(value
).toFixed(precision
);
154 * JS counterpart of the function in src/misc.cpp
156 const parseHtmlLinks = function(text
) {
157 const exp
= /(\b(https?|ftp|file):\/\/[-\w+&@#/%?=~|!:,.;]*[-\w
+&@#/%=~|])/gi;
158 return text
.replace(exp
, "<a target='_blank' rel='noopener noreferrer' href='$1'>$1</a>");
161 const parseVersion = function(versionString
) {
166 if (typeof versionString
!== "string")
169 const tryToNumber
= (str
) => {
170 const num
= Number(str
);
171 return (isNaN(num
) ? str
: num
);
174 const ver
= versionString
.split(".", 4).map(val
=> tryToNumber(val
));
184 const escapeHtml
= (() => {
185 const div
= document
.createElement("div");
187 div
.textContent
= str
;
188 return div
.innerHTML
;
192 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#parameters
193 const naturalSortCollator
= new Intl
.Collator(undefined, { numeric
: true, usage
: "sort" });
195 const safeTrim = function(value
) {
200 if (e
instanceof TypeError
)
206 const toFixedPointString = function(number
, digits
) {
207 // Do not round up number
208 const power
= Math
.pow(10, digits
);
209 return (Math
.floor(power
* number
) / power
).toFixed(digits
);
214 * @param {String} text the text to search
215 * @param {Array<String>} terms terms to search for within the text
216 * @returns {Boolean} true if all terms match the text, false otherwise
218 const containsAllTerms = function(text
, terms
) {
219 const textToSearch
= text
.toLowerCase();
220 return terms
.every((term
) => {
221 const isTermRequired
= (term
[0] === "+");
222 const isTermExcluded
= (term
[0] === "-");
223 if (isTermRequired
|| isTermExcluded
) {
225 if (term
.length
=== 1)
228 term
= term
.substring(1);
231 const textContainsTerm
= (textToSearch
.indexOf(term
) !== -1);
232 return isTermExcluded
? !textContainsTerm
: textContainsTerm
;
236 const sleep
= (ms
) => {
237 return new Promise((resolve
) => {
238 setTimeout(resolve
, ms
);
244 Object
.freeze(window
.qBittorrent
.Misc
);