browsertime 15.4.0 → 16.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/browsertime/visualmetrics-portable.py +39 -21
- package/docs/examples/firefox.md +3 -1
- package/lib/chrome/webdriver/setupChromiumOptions.js +22 -0
- package/lib/core/engine/iteration.js +1 -1
- package/lib/support/cli.js +6 -0
- package/lib/support/dns.js +2 -2
- package/lib/support/fileUtil.js +4 -0
- package/lib/video/postprocessing/finetune/index.js +6 -5
- package/lib/video/postprocessing/visualmetrics/visualMetrics.js +7 -1
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Browsertime changelog (we do [semantic versioning](https://semver.org))
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## 16.1.0 - 2022-04-20
|
|
5
|
+
### Fixed
|
|
6
|
+
* Handle negative x/y offsets when cropping images in the new portable visual metrocs script, thank you [Gregory Mierzwinski](https://github.com/gmierz) for PR [#1770](https://github.com/sitespeedio/browsertime/pull/1770).
|
|
7
|
+
* Bumped Throttle dependency [#1769](https://github.com/sitespeedio/browsertime/pull/1769).
|
|
8
|
+
* Bumped chrome-har, chrome-remote-interface, dayjs and yargs dependencies [#1771](https://github.com/sitespeedio/browsertime/pull/1771).
|
|
9
|
+
### Added
|
|
10
|
+
* Added blocking of Chrome and Edge phone home domains [#1763](https://github.com/sitespeedio/browsertime/pull/1763).
|
|
11
|
+
|
|
12
|
+
## 16.0.1 - 2022-04-06
|
|
13
|
+
### Fixed
|
|
14
|
+
* If visual metrics fails and you also use --visualElements, make sure that file is also stored so we can reporduce the issue [#1757](https://github.com/sitespeedio/browsertime/pull/1757).
|
|
15
|
+
## 16.0.0 - 2022-04-05
|
|
16
|
+
### Changed
|
|
17
|
+
* When I introduced flushing of the DNS per run I missed that it makes you need to run sudo to do it (Mac/Linux). That sucks so instead of being able to disable the flushing `--disableDNSFlush` you now enables it with `--flushDNS` [#1752](https://github.com/sitespeedio/browsertime/pull/1752).
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
* Firefox 99 in the Docker container
|
|
21
|
+
* Edge and Edgedriver 100
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
* Automatically save the original video if visual metrics fails [#1755](https://github.com/sitespeedio/browsertime/pull/1755).
|
|
25
|
+
|
|
3
26
|
## 15.4.0 - 2022-03-30
|
|
4
27
|
### Added
|
|
5
28
|
* Updated to Chrome and Chromedriver 100 [#1743](https://github.com/sitespeedio/browsertime/pull/1743).
|
|
@@ -108,6 +108,11 @@ def crop_im(img, crop_x, crop_y, crop_x_offset, crop_y_offset, gravity=None):
|
|
|
108
108
|
base_x += crop_x_offset
|
|
109
109
|
base_y += crop_y_offset
|
|
110
110
|
|
|
111
|
+
# Take the maximum in case the offset was negative, and
|
|
112
|
+
# smaller than the base position
|
|
113
|
+
base_x = max(base_x, 0)
|
|
114
|
+
base_y = max(base_y, 0)
|
|
115
|
+
|
|
111
116
|
return Image.fromarray(
|
|
112
117
|
img[base_y : base_y + crop_y, base_x : base_x + crop_x, :]
|
|
113
118
|
)
|
|
@@ -137,7 +142,7 @@ def resize(img, width, height):
|
|
|
137
142
|
def scale(img, maxsize):
|
|
138
143
|
"""Scale an image to the given max size."""
|
|
139
144
|
width, height = img.size
|
|
140
|
-
ratio = min(maxsize / width, maxsize / height)
|
|
145
|
+
ratio = min(float(maxsize) / width, float(maxsize) / height)
|
|
141
146
|
return resize(img, int(width * ratio), int(height * ratio))
|
|
142
147
|
|
|
143
148
|
|
|
@@ -2109,9 +2114,10 @@ def calculate_contentful_speed_index(progress, directory):
|
|
|
2109
2114
|
content.append(value)
|
|
2110
2115
|
|
|
2111
2116
|
for i, value in enumerate(content):
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2117
|
+
if maxContent > 0:
|
|
2118
|
+
content[i] = float(content[i]) / float(maxContent)
|
|
2119
|
+
else:
|
|
2120
|
+
content[i] = 0.0
|
|
2115
2121
|
|
|
2116
2122
|
# Assume 0 content for first frame
|
|
2117
2123
|
cont_si = 1 * (progress[1]["time"] - progress[0]["time"])
|
|
@@ -2286,47 +2292,52 @@ def calculate_hero_time(progress, directory, hero, viewport):
|
|
|
2286
2292
|
def check_config():
|
|
2287
2293
|
ok = True
|
|
2288
2294
|
|
|
2289
|
-
|
|
2295
|
+
|
|
2290
2296
|
if get_decimate_filter() is not None:
|
|
2291
|
-
|
|
2297
|
+
logging.debug('FFMPEG found')
|
|
2298
|
+
else:
|
|
2299
|
+
print("ffmpeg: FAIL")
|
|
2300
|
+
ok = False
|
|
2301
|
+
|
|
2302
|
+
|
|
2303
|
+
if sys.version_info >= (3, 6):
|
|
2304
|
+
logging.debug('Python 3.6+ found')
|
|
2292
2305
|
else:
|
|
2293
|
-
print("FAIL")
|
|
2306
|
+
print("Python 3.6+: FAIL")
|
|
2294
2307
|
ok = False
|
|
2295
2308
|
|
|
2296
|
-
print("Numpy: ")
|
|
2297
2309
|
try:
|
|
2298
2310
|
import numpy as np
|
|
2299
2311
|
|
|
2300
|
-
|
|
2312
|
+
logging.debug('Numpy found')
|
|
2301
2313
|
except BaseException:
|
|
2302
|
-
print("FAIL")
|
|
2314
|
+
print("Numpy: FAIL")
|
|
2303
2315
|
ok = False
|
|
2304
2316
|
|
|
2305
|
-
|
|
2317
|
+
|
|
2306
2318
|
try:
|
|
2307
2319
|
import cv2
|
|
2308
|
-
|
|
2309
|
-
|
|
2320
|
+
|
|
2321
|
+
logging.debug('OpenCV-Python found')
|
|
2310
2322
|
except BaseException:
|
|
2311
|
-
print("FAIL")
|
|
2323
|
+
print("OpenCV-Python: FAIL")
|
|
2312
2324
|
ok = False
|
|
2313
2325
|
|
|
2314
|
-
|
|
2326
|
+
|
|
2315
2327
|
try:
|
|
2316
2328
|
from PIL import Image, ImageCms, ImageDraw, ImageOps # noqa
|
|
2317
2329
|
|
|
2318
|
-
|
|
2330
|
+
logging.debug('Pillow found')
|
|
2319
2331
|
except BaseException:
|
|
2320
|
-
print("FAIL")
|
|
2332
|
+
print("Pillow: FAIL")
|
|
2321
2333
|
ok = False
|
|
2322
2334
|
|
|
2323
|
-
|
|
2335
|
+
|
|
2324
2336
|
try:
|
|
2325
2337
|
from ssim import compute_ssim # noqa
|
|
2326
|
-
|
|
2327
|
-
print("OK")
|
|
2338
|
+
logging.debug('SSIM found')
|
|
2328
2339
|
except BaseException:
|
|
2329
|
-
print("FAIL")
|
|
2340
|
+
print("SSIM: FAIL")
|
|
2330
2341
|
ok = False
|
|
2331
2342
|
|
|
2332
2343
|
return ok
|
|
@@ -2656,6 +2667,13 @@ def main():
|
|
|
2656
2667
|
ok = False
|
|
2657
2668
|
try:
|
|
2658
2669
|
if not options.check:
|
|
2670
|
+
# Run a quick check to make sure all requirements exist,
|
|
2671
|
+
# otherwise failures might be silent due to how this code is
|
|
2672
|
+
# structured.
|
|
2673
|
+
ok = check_config()
|
|
2674
|
+
if not ok:
|
|
2675
|
+
raise Exception("Please install requirements before running.")
|
|
2676
|
+
|
|
2659
2677
|
if options.video:
|
|
2660
2678
|
orange_file = None
|
|
2661
2679
|
if options.orange:
|
package/docs/examples/firefox.md
CHANGED
|
@@ -3,6 +3,8 @@ Firefox Examples
|
|
|
3
3
|
|
|
4
4
|
This page shows a few of the options specific to Firefox.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
```
|
|
7
|
+
browsertime https://www.sitespeed.io -b firefox --firefox.binaryPath '/Applications/Firefox.app/Contents/MacOS/firefox-bin'
|
|
8
|
+
```
|
|
7
9
|
|
|
8
10
|
- Path to custom Firefox binary (e.g. Firefox Nightly). On OS X, the path should be to the binary inside the app bundle. (e.g. /Applications/Firefox.app/Contents/MacOS/firefox-bin)
|
|
@@ -5,6 +5,17 @@ const getViewPort = require('../../support/getViewPort');
|
|
|
5
5
|
const util = require('../../support/util');
|
|
6
6
|
const log = require('intel').getLogger('browsertime.chrome');
|
|
7
7
|
|
|
8
|
+
const CHROME_AMD_EDGE_INTERNAL_PHONE_HOME = [
|
|
9
|
+
'"MAP cache.pack.google.com 127.0.0.1"',
|
|
10
|
+
'"MAP clients1.google.com 127.0.0.1"',
|
|
11
|
+
'"MAP update.googleapis.com 127.0.0.1"',
|
|
12
|
+
'"MAP redirector.gvt1.com 127.0.0.1"',
|
|
13
|
+
'"MAP laptop-updates.brave.com 127.0.0.1"',
|
|
14
|
+
'"MAP offlinepages-pa.googleapis.com 127.0.0.1"',
|
|
15
|
+
'"MAP edge.microsoft.com 127.0.0.1"',
|
|
16
|
+
'"MAP optimizationguide-pa.googleapis.com 127.0.0.1"'
|
|
17
|
+
];
|
|
18
|
+
|
|
8
19
|
module.exports = function (seleniumOptions, browserOptions, options, baseDir) {
|
|
9
20
|
// Fixing save password popup, only on Desktop
|
|
10
21
|
if (!options.android) {
|
|
@@ -64,6 +75,17 @@ module.exports = function (seleniumOptions, browserOptions, options, baseDir) {
|
|
|
64
75
|
excludes += 'MAP * 127.0.0.1, EXCLUDE ' + domain + ',';
|
|
65
76
|
}
|
|
66
77
|
seleniumOptions.addArguments('--host-resolver-rules=' + excludes);
|
|
78
|
+
} else {
|
|
79
|
+
// Make sure we only set this if we do not have any other host resolver rules
|
|
80
|
+
const chromeCommandLineArgs = util.toArray(browserOptions.args);
|
|
81
|
+
const argsWithHostResolverRules = chromeCommandLineArgs.filter(arg =>
|
|
82
|
+
arg.includes('host-resolver-rules')
|
|
83
|
+
);
|
|
84
|
+
if (argsWithHostResolverRules.length === 0) {
|
|
85
|
+
seleniumOptions.addArguments(
|
|
86
|
+
'--host-resolver-rules=' + CHROME_AMD_EDGE_INTERNAL_PHONE_HOME.join(',')
|
|
87
|
+
);
|
|
88
|
+
}
|
|
67
89
|
}
|
|
68
90
|
|
|
69
91
|
if (options.extension) {
|
|
@@ -102,7 +102,7 @@ class Iteration {
|
|
|
102
102
|
const engineDelegate = this.engineDelegate;
|
|
103
103
|
|
|
104
104
|
try {
|
|
105
|
-
if (
|
|
105
|
+
if (options.flushDNS) {
|
|
106
106
|
await flushDNS(options);
|
|
107
107
|
}
|
|
108
108
|
if (options.connectivity && options.connectivity.variance) {
|
package/lib/support/cli.js
CHANGED
|
@@ -1117,6 +1117,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1117
1117
|
describe:
|
|
1118
1118
|
'Start gnirehtet and reverse tethering the traffic from your Android phone.'
|
|
1119
1119
|
})
|
|
1120
|
+
.option('flushDNS', {
|
|
1121
|
+
type: 'boolean',
|
|
1122
|
+
default: false,
|
|
1123
|
+
describe:
|
|
1124
|
+
'Flush DNS between runs, works on Mac OS and Linux. Your user needs sudo rights to be able to flush the DNS.'
|
|
1125
|
+
})
|
|
1120
1126
|
.option('extension', {
|
|
1121
1127
|
describe:
|
|
1122
1128
|
'Path to a WebExtension to be installed in the browser. Note that --extension can be passed multiple times.'
|
package/lib/support/dns.js
CHANGED
|
@@ -14,7 +14,7 @@ module.exports = async function (options) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
if (process.platform === 'darwin') {
|
|
17
|
-
log.
|
|
17
|
+
log.info('Flush DNS cache on MacOS');
|
|
18
18
|
await execa('sudo', ['killall', '-HUP', 'mDNSResponder'], {
|
|
19
19
|
reject: false
|
|
20
20
|
});
|
|
@@ -25,7 +25,7 @@ module.exports = async function (options) {
|
|
|
25
25
|
reject: false
|
|
26
26
|
});
|
|
27
27
|
} else if (process.platform === 'linux') {
|
|
28
|
-
log.
|
|
28
|
+
log.info('Flush DNS cache on Linux');
|
|
29
29
|
await execa('sudo', ['systemd-resolve', '--flush-caches'], {
|
|
30
30
|
reject: false
|
|
31
31
|
});
|
package/lib/support/fileUtil.js
CHANGED
|
@@ -6,6 +6,7 @@ const readdir = promisify(fs.readdir);
|
|
|
6
6
|
const lstat = promisify(fs.lstat);
|
|
7
7
|
const unlink = promisify(fs.unlink);
|
|
8
8
|
const rmdir = promisify(fs.rmdir);
|
|
9
|
+
const copyFile = promisify(fs.copyFile);
|
|
9
10
|
const rename = promisify(fs.rename);
|
|
10
11
|
const readFile = promisify(fs.readFile);
|
|
11
12
|
const filters = require('./filters');
|
|
@@ -15,6 +16,9 @@ module.exports = {
|
|
|
15
16
|
async rename(old, newName) {
|
|
16
17
|
return rename(old, newName);
|
|
17
18
|
},
|
|
19
|
+
async copyFile(source, destination) {
|
|
20
|
+
return copyFile(source, destination);
|
|
21
|
+
},
|
|
18
22
|
async removeFile(fileName) {
|
|
19
23
|
return unlink(fileName);
|
|
20
24
|
},
|
|
@@ -9,6 +9,7 @@ const fs = require('fs');
|
|
|
9
9
|
const get = require('lodash.get');
|
|
10
10
|
const { promisify } = require('util');
|
|
11
11
|
const rename = promisify(fs.rename);
|
|
12
|
+
const copyFile = promisify(fs.copyFile);
|
|
12
13
|
const unlink = promisify(fs.unlink);
|
|
13
14
|
const defaults = require('../../defaults');
|
|
14
15
|
|
|
@@ -23,6 +24,11 @@ module.exports = async function (
|
|
|
23
24
|
const newStart = videoMetrics.videoRecordingStart / 1000;
|
|
24
25
|
let tmpFile = path.join(videoDir, 'tmp.mp4');
|
|
25
26
|
|
|
27
|
+
if (get(options, 'videoParams.keepOriginalVideo', false)) {
|
|
28
|
+
const originalFile = path.join(videoDir, index + '-original.mp4');
|
|
29
|
+
await copyFile(videoPath, originalFile);
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
// if there's no orange (too slow instance like travis?)
|
|
27
33
|
// we don't wanna cut
|
|
28
34
|
if (videoMetrics.videoRecordingStart > 0) {
|
|
@@ -45,11 +51,6 @@ module.exports = async function (
|
|
|
45
51
|
tmpFile = videoPath;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
if (get(options, 'videoParams.keepOriginalVideo', false)) {
|
|
49
|
-
const originalFile = path.join(videoDir, index + '-original.mp4');
|
|
50
|
-
await rename(videoPath, originalFile);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
54
|
if (
|
|
54
55
|
options.android &&
|
|
55
56
|
get(options, 'videoParams.convert', defaults.convert)
|
|
@@ -4,7 +4,7 @@ const execa = require('execa');
|
|
|
4
4
|
const log = require('intel').getLogger('browsertime.video');
|
|
5
5
|
const get = require('lodash.get');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const { readFile, removeFile } = require('../../../support/fileUtil');
|
|
7
|
+
const { readFile, removeFile, copyFile } = require('../../../support/fileUtil');
|
|
8
8
|
|
|
9
9
|
const SCRIPT_PATH = path.join(
|
|
10
10
|
__dirname,
|
|
@@ -149,6 +149,12 @@ module.exports = {
|
|
|
149
149
|
return JSON.parse(result.stdout);
|
|
150
150
|
} catch (e) {
|
|
151
151
|
log.error('VisualMetrics failed to run', e);
|
|
152
|
+
await copyFile(videoPath, videoPath + '.failed.mp4');
|
|
153
|
+
|
|
154
|
+
if (options.visualElements) {
|
|
155
|
+
await copyFile(elementsFile, elementsFile + '.failed.json');
|
|
156
|
+
}
|
|
157
|
+
|
|
152
158
|
// If something goes wrong, dump the visual metrics log to our log
|
|
153
159
|
const visualMetricLog = await readFile(visualMetricsLogFile);
|
|
154
160
|
log.error('Log from VisualMetrics: %s', visualMetricLog);
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"description": "Browsertime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.1.0",
|
|
4
4
|
"bin": "./bin/browsertime.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@cypress/xvfb": "1.2.4",
|
|
7
7
|
"@devicefarmer/adbkit": "2.11.3",
|
|
8
8
|
"@sitespeed.io/chromedriver": "100.0.4896-20",
|
|
9
|
-
"@sitespeed.io/edgedriver": "
|
|
9
|
+
"@sitespeed.io/edgedriver": "100.0.1185-29",
|
|
10
10
|
"@sitespeed.io/geckodriver": "0.30.0",
|
|
11
|
-
"@sitespeed.io/throttle": "3.
|
|
11
|
+
"@sitespeed.io/throttle": "3.1.1",
|
|
12
12
|
"@sitespeed.io/tracium": "0.3.3",
|
|
13
13
|
"btoa": "1.2.1",
|
|
14
|
-
"chrome-har": "0.
|
|
15
|
-
"chrome-remote-interface": "0.31.
|
|
16
|
-
"dayjs": "1.
|
|
14
|
+
"chrome-har": "0.13.0",
|
|
15
|
+
"chrome-remote-interface": "0.31.2",
|
|
16
|
+
"dayjs": "1.11.1",
|
|
17
17
|
"execa": "5.1.1",
|
|
18
18
|
"fast-stats": "0.0.6",
|
|
19
19
|
"find-up": "5.0.0",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"lodash.pick": "4.4.0",
|
|
28
28
|
"lodash.set": "4.3.2",
|
|
29
29
|
"selenium-webdriver": "4.1.1",
|
|
30
|
-
"yargs": "17.
|
|
30
|
+
"yargs": "17.4.1"
|
|
31
31
|
},
|
|
32
32
|
"optionalDependencies": {
|
|
33
33
|
"jimp": "0.16.1"
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"serve": "13.0.2"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
|
-
"node": ">=
|
|
45
|
+
"node": ">=14.19.1"
|
|
46
46
|
},
|
|
47
47
|
"files": [
|
|
48
48
|
"CHANGELOG.md",
|