browsertime 14.9.0 → 14.11.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
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Browsertime changelog (we do [semantic versioning](https://semver.org))
|
|
2
2
|
|
|
3
|
+
## 14.11.0 - 2021-11-23
|
|
4
|
+
### Fixed
|
|
5
|
+
* Use the viewport to determine if more cropping is needed in visual metrics. Thank you [Gregory Mierzwinski](https://github.com/gmierz) for PR [#1680](https://github.com/sitespeedio/browsertime/pull/1680).
|
|
6
|
+
### Added
|
|
7
|
+
* Updated to Selenium 4.1.0 [#1679](https://github.com/sitespeedio/browsertime/pull/1679)
|
|
8
|
+
|
|
9
|
+
## 14.10.2 - 2021-11-20
|
|
10
|
+
### Fixed
|
|
11
|
+
* Disabled the version check for Edge/Edgedriver in Edgedriver [#1678](https://github.com/sitespeedio/browsertime/pull/1678).
|
|
12
|
+
|
|
13
|
+
## 14.10.1 - 2021-11-19
|
|
14
|
+
### Fixed
|
|
15
|
+
* Disabled the automatic Chrome/Chromedriver version check in Chromedriver [#1676](https://github.com/sitespeedio/browsertime/pull/1676).
|
|
16
|
+
* Loop until we find a frame with a good viewport or until we run out of retries for Visual Metrics. Thank you [Gregory Mierzwinski](https://github.com/gmierz) for PR [#1668](https://github.com/sitespeedio/browsertime/pull/1668).
|
|
17
|
+
|
|
18
|
+
## 14.10.0 - 2021-11-16
|
|
19
|
+
### Added
|
|
20
|
+
* Updated to Chromedriver 96 and Chrome 96 in the Docker container [#1670](https://github.com/sitespeedio/browsertime/pull/1670).
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
* Added checks for Firefox HAR that it actually has a page.
|
|
24
|
+
* Updated day js.
|
|
3
25
|
|
|
4
26
|
## 14.9.0 - 2021-11-07
|
|
5
27
|
### Added
|
|
@@ -44,12 +44,12 @@ import shutil
|
|
|
44
44
|
import subprocess
|
|
45
45
|
import tempfile
|
|
46
46
|
|
|
47
|
-
if
|
|
48
|
-
GZIP_TEXT =
|
|
49
|
-
GZIP_READ_TEXT =
|
|
47
|
+
if sys.version_info > (3, 0):
|
|
48
|
+
GZIP_TEXT = "wt"
|
|
49
|
+
GZIP_READ_TEXT = "rt"
|
|
50
50
|
else:
|
|
51
|
-
GZIP_TEXT =
|
|
52
|
-
GZIP_READ_TEXT =
|
|
51
|
+
GZIP_TEXT = "w"
|
|
52
|
+
GZIP_READ_TEXT = "r"
|
|
53
53
|
|
|
54
54
|
# Globals
|
|
55
55
|
options = None
|
|
@@ -72,6 +72,9 @@ def video_to_frames(
|
|
|
72
72
|
multiple,
|
|
73
73
|
find_viewport,
|
|
74
74
|
viewport_time,
|
|
75
|
+
viewport_retries,
|
|
76
|
+
viewport_min_height,
|
|
77
|
+
viewport_min_width,
|
|
75
78
|
full_resolution,
|
|
76
79
|
timeline_file,
|
|
77
80
|
trim_end,
|
|
@@ -92,8 +95,14 @@ def video_to_frames(
|
|
|
92
95
|
os.mkdir(directory, 0o755)
|
|
93
96
|
if os.path.isdir(directory):
|
|
94
97
|
directory = os.path.realpath(directory)
|
|
95
|
-
viewport = find_video_viewport(
|
|
96
|
-
video,
|
|
98
|
+
viewport, cropped = find_video_viewport(
|
|
99
|
+
video,
|
|
100
|
+
directory,
|
|
101
|
+
find_viewport,
|
|
102
|
+
viewport_time,
|
|
103
|
+
viewport_retries,
|
|
104
|
+
viewport_min_height,
|
|
105
|
+
viewport_min_width,
|
|
97
106
|
)
|
|
98
107
|
gc.collect()
|
|
99
108
|
if extract_frames(video, directory, full_resolution, viewport):
|
|
@@ -113,12 +122,12 @@ def video_to_frames(
|
|
|
113
122
|
remove_orange_frames(dir, orange_file)
|
|
114
123
|
find_first_frame(dir, white_file)
|
|
115
124
|
blank_first_frame(dir)
|
|
116
|
-
find_render_start(dir, orange_file, gray_file)
|
|
125
|
+
find_render_start(dir, orange_file, gray_file, cropped)
|
|
117
126
|
find_last_frame(dir, white_file)
|
|
118
127
|
adjust_frame_times(dir)
|
|
119
128
|
if timeline_file is not None and not multiple:
|
|
120
129
|
synchronize_to_timeline(dir, timeline_file)
|
|
121
|
-
eliminate_duplicate_frames(dir)
|
|
130
|
+
eliminate_duplicate_frames(dir, cropped)
|
|
122
131
|
eliminate_similar_frames(dir)
|
|
123
132
|
# See if we are limiting the number of frames to keep
|
|
124
133
|
# (before processing them to save processing time)
|
|
@@ -169,10 +178,10 @@ def extract_frames(video, directory, full_resolution, viewport):
|
|
|
169
178
|
]
|
|
170
179
|
logging.debug(" ".join(command))
|
|
171
180
|
lines = []
|
|
172
|
-
if
|
|
173
|
-
|
|
181
|
+
if sys.version_info > (3, 0):
|
|
182
|
+
proc = subprocess.Popen(command, stderr=subprocess.PIPE, encoding="UTF-8")
|
|
174
183
|
else:
|
|
175
|
-
|
|
184
|
+
proc = subprocess.Popen(command, stderr=subprocess.PIPE)
|
|
176
185
|
while proc.poll() is None:
|
|
177
186
|
lines.extend(iter(proc.stderr.readline, ""))
|
|
178
187
|
|
|
@@ -354,68 +363,124 @@ def find_image_viewport(file):
|
|
|
354
363
|
return viewport
|
|
355
364
|
|
|
356
365
|
|
|
357
|
-
def find_video_viewport(
|
|
366
|
+
def find_video_viewport(
|
|
367
|
+
video,
|
|
368
|
+
directory,
|
|
369
|
+
find_viewport,
|
|
370
|
+
viewport_time,
|
|
371
|
+
viewport_retries,
|
|
372
|
+
viewport_min_height,
|
|
373
|
+
viewport_min_width,
|
|
374
|
+
):
|
|
358
375
|
logging.debug("Finding Video Viewport...")
|
|
359
376
|
viewport = None
|
|
377
|
+
|
|
378
|
+
# cropped will be True if the viewport setting changes
|
|
379
|
+
# the original frame
|
|
380
|
+
cropped = False
|
|
381
|
+
|
|
360
382
|
try:
|
|
361
383
|
from PIL import Image
|
|
362
384
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
background = pixels[x, y]
|
|
384
|
-
top = None
|
|
385
|
-
while top is None and y < middle:
|
|
386
|
-
if not colors_are_similar(background, pixels[x, y]):
|
|
387
|
-
top = y
|
|
388
|
-
else:
|
|
389
|
-
y += 1
|
|
390
|
-
if top is None:
|
|
391
|
-
top = 0
|
|
392
|
-
logging.debug("Window top edge is {0:d}".format(top))
|
|
393
|
-
|
|
394
|
-
# Find the bottom edge
|
|
395
|
-
x = 0
|
|
396
|
-
y = height - 1
|
|
397
|
-
bottom = None
|
|
398
|
-
while bottom is None and y > middle:
|
|
399
|
-
if not colors_are_similar(background, pixels[x, y]):
|
|
400
|
-
bottom = y
|
|
401
|
-
else:
|
|
402
|
-
y -= 1
|
|
403
|
-
if bottom is None:
|
|
404
|
-
bottom = height - 1
|
|
405
|
-
logging.debug("Window bottom edge is {0:d}".format(bottom))
|
|
385
|
+
retries = -1
|
|
386
|
+
|
|
387
|
+
while (
|
|
388
|
+
viewport is None
|
|
389
|
+
or viewport["height"] <= viewport_min_height
|
|
390
|
+
or viewport["width"] <= viewport_min_width
|
|
391
|
+
):
|
|
392
|
+
retries += 1
|
|
393
|
+
if retries >= 1:
|
|
394
|
+
# In some cases, the first frame is not an orange screen or a screen
|
|
395
|
+
# with a solid color. In this case, we need to try finding the viewport
|
|
396
|
+
# using the next frame. The `viewport_retries` dictates the maximum number
|
|
397
|
+
# of frames to check.
|
|
398
|
+
if retries >= viewport_retries:
|
|
399
|
+
logging.exception(
|
|
400
|
+
"Could not calculate a viewport after %s tries.",
|
|
401
|
+
viewport_retries,
|
|
402
|
+
)
|
|
403
|
+
break
|
|
404
|
+
logging.info("Failed to find a good viewport. Retrying...")
|
|
406
405
|
|
|
407
|
-
|
|
406
|
+
logging.debug("Using frame " + str(retries))
|
|
408
407
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
viewport = {"x": 0, "y": 0, "width": width, "height": height}
|
|
413
|
-
os.remove(frame)
|
|
408
|
+
frame = os.path.join(directory, "viewport.png")
|
|
409
|
+
if os.path.isfile(frame):
|
|
410
|
+
os.remove(frame)
|
|
414
411
|
|
|
415
|
-
|
|
412
|
+
command = ["ffmpeg", "-i", video]
|
|
413
|
+
if viewport_time:
|
|
414
|
+
command.extend(["-ss", viewport_time])
|
|
415
|
+
|
|
416
|
+
# Pull one frame from the video starting with the frame at
|
|
417
|
+
# the `retries` index
|
|
418
|
+
command.extend(["-vf", "select=gte(n\\,%s)" % retries])
|
|
419
|
+
command.extend(["-frames:v", "1", frame])
|
|
420
|
+
subprocess.check_output(command)
|
|
421
|
+
|
|
422
|
+
if os.path.isfile(frame):
|
|
423
|
+
with Image.open(frame) as im:
|
|
424
|
+
width, height = im.size
|
|
425
|
+
logging.debug("%s is %dx%d", frame, width, height)
|
|
426
|
+
if options.notification:
|
|
427
|
+
im = Image.open(frame)
|
|
428
|
+
pixels = im.load()
|
|
429
|
+
middle = int(math.floor(height / 2))
|
|
430
|
+
# Find the top edge (at ~40% in to deal with browsers that
|
|
431
|
+
# color the notification area)
|
|
432
|
+
x = int(width * 0.4)
|
|
433
|
+
y = 0
|
|
434
|
+
background = pixels[x, y]
|
|
435
|
+
top = None
|
|
436
|
+
while top is None and y < middle:
|
|
437
|
+
if not colors_are_similar(background, pixels[x, y]):
|
|
438
|
+
top = y
|
|
439
|
+
else:
|
|
440
|
+
y += 1
|
|
441
|
+
if top is None:
|
|
442
|
+
top = 0
|
|
443
|
+
logging.debug("Window top edge is {0:d}".format(top))
|
|
444
|
+
|
|
445
|
+
# Find the bottom edge
|
|
446
|
+
x = 0
|
|
447
|
+
y = height - 1
|
|
448
|
+
bottom = None
|
|
449
|
+
while bottom is None and y > middle:
|
|
450
|
+
if not colors_are_similar(background, pixels[x, y]):
|
|
451
|
+
bottom = y
|
|
452
|
+
else:
|
|
453
|
+
y -= 1
|
|
454
|
+
if bottom is None:
|
|
455
|
+
bottom = height - 1
|
|
456
|
+
logging.debug("Window bottom edge is {0:d}".format(bottom))
|
|
457
|
+
|
|
458
|
+
viewport = {
|
|
459
|
+
"x": 0,
|
|
460
|
+
"y": top,
|
|
461
|
+
"width": width,
|
|
462
|
+
"height": (bottom - top),
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
elif find_viewport:
|
|
466
|
+
viewport = find_image_viewport(frame)
|
|
467
|
+
else:
|
|
468
|
+
viewport = {"x": 0, "y": 0, "width": width, "height": height}
|
|
469
|
+
|
|
470
|
+
os.remove(frame)
|
|
471
|
+
|
|
472
|
+
if viewport is not None and viewport != {
|
|
473
|
+
"x": 0,
|
|
474
|
+
"y": 0,
|
|
475
|
+
"width": width,
|
|
476
|
+
"height": height,
|
|
477
|
+
}:
|
|
478
|
+
cropped = True
|
|
479
|
+
|
|
480
|
+
except Exception as e:
|
|
416
481
|
viewport = None
|
|
417
482
|
|
|
418
|
-
return viewport
|
|
483
|
+
return viewport, cropped
|
|
419
484
|
|
|
420
485
|
|
|
421
486
|
def trim_video_end(directory, trim_time):
|
|
@@ -564,7 +629,7 @@ def find_last_frame(directory, white_file):
|
|
|
564
629
|
logging.exception("Error finding last frame")
|
|
565
630
|
|
|
566
631
|
|
|
567
|
-
def find_render_start(directory, orange_file, gray_file):
|
|
632
|
+
def find_render_start(directory, orange_file, gray_file, cropped):
|
|
568
633
|
logging.debug("Finding Render Start...")
|
|
569
634
|
try:
|
|
570
635
|
if (
|
|
@@ -590,6 +655,10 @@ def find_render_start(directory, orange_file, gray_file):
|
|
|
590
655
|
mask["y"] = int(math.floor(height / 2 - mask["height"] / 2))
|
|
591
656
|
else:
|
|
592
657
|
mask = None
|
|
658
|
+
|
|
659
|
+
im_width = width
|
|
660
|
+
im_height = height
|
|
661
|
+
|
|
593
662
|
top = 10
|
|
594
663
|
right_margin = 10
|
|
595
664
|
bottom_margin = 24
|
|
@@ -609,6 +678,14 @@ def find_render_start(directory, orange_file, gray_file):
|
|
|
609
678
|
width = max(client_viewport["width"] - right_margin, 1)
|
|
610
679
|
left += client_viewport["x"]
|
|
611
680
|
top += client_viewport["y"]
|
|
681
|
+
elif cropped:
|
|
682
|
+
# The image was already cropped, so only cutout the bottom
|
|
683
|
+
# to get rid of the network request/etc. information
|
|
684
|
+
top = 0
|
|
685
|
+
left = 0
|
|
686
|
+
width = im_width
|
|
687
|
+
height = im_height - bottom_margin
|
|
688
|
+
|
|
612
689
|
crop = "{0:d}x{1:d}+{2:d}+{3:d}".format(width, height, left, top)
|
|
613
690
|
for i in range(1, count):
|
|
614
691
|
if frames_match(first, files[i], 10, 0, crop, mask):
|
|
@@ -628,7 +705,7 @@ def find_render_start(directory, orange_file, gray_file):
|
|
|
628
705
|
logging.exception("Error getting render start")
|
|
629
706
|
|
|
630
707
|
|
|
631
|
-
def eliminate_duplicate_frames(directory):
|
|
708
|
+
def eliminate_duplicate_frames(directory, cropped):
|
|
632
709
|
logging.debug("Eliminating Duplicate Frames...")
|
|
633
710
|
global client_viewport
|
|
634
711
|
try:
|
|
@@ -646,6 +723,9 @@ def eliminate_duplicate_frames(directory):
|
|
|
646
723
|
):
|
|
647
724
|
client_viewport = None
|
|
648
725
|
|
|
726
|
+
im_width = width
|
|
727
|
+
im_height = height
|
|
728
|
+
|
|
649
729
|
# Figure out the region of the image that we care about
|
|
650
730
|
top = 40
|
|
651
731
|
right_margin = 10
|
|
@@ -663,6 +743,13 @@ def eliminate_duplicate_frames(directory):
|
|
|
663
743
|
width = max(client_viewport["width"] - right_margin, 1)
|
|
664
744
|
left += client_viewport["x"]
|
|
665
745
|
top += client_viewport["y"]
|
|
746
|
+
elif cropped:
|
|
747
|
+
# The image was already cropped, so only cutout the bottom
|
|
748
|
+
# to get rid of the network request/etc. information
|
|
749
|
+
top = 0
|
|
750
|
+
left = 0
|
|
751
|
+
width = im_width
|
|
752
|
+
height = im_height - bottom_margin
|
|
666
753
|
|
|
667
754
|
crop = "{0:d}x{1:d}+{2:d}+{3:d}".format(width, height, left, top)
|
|
668
755
|
logging.debug("Viewport cropping set to " + crop)
|
|
@@ -787,10 +874,14 @@ def crop_viewport(directory):
|
|
|
787
874
|
def get_decimate_filter():
|
|
788
875
|
decimate = None
|
|
789
876
|
try:
|
|
790
|
-
if
|
|
791
|
-
filters = subprocess.check_output(
|
|
877
|
+
if sys.version_info > (3, 0):
|
|
878
|
+
filters = subprocess.check_output(
|
|
879
|
+
["ffmpeg", "-filters"], stderr=subprocess.STDOUT, encoding="UTF-8"
|
|
880
|
+
)
|
|
792
881
|
else:
|
|
793
|
-
filters = subprocess.check_output(
|
|
882
|
+
filters = subprocess.check_output(
|
|
883
|
+
["ffmpeg", "-filters"], stderr=subprocess.STDOUT
|
|
884
|
+
)
|
|
794
885
|
lines = filters.split("\n")
|
|
795
886
|
match = re.compile(
|
|
796
887
|
r"(?P<filter>[\w]*decimate).*V->V.*Remove near-duplicate frames"
|
|
@@ -864,10 +955,14 @@ def is_color_frame(file, color_file):
|
|
|
864
955
|
image_magick["compare"],
|
|
865
956
|
)
|
|
866
957
|
|
|
867
|
-
if
|
|
868
|
-
|
|
958
|
+
if sys.version_info > (3, 0):
|
|
959
|
+
compare = subprocess.Popen(
|
|
960
|
+
command, stderr=subprocess.PIPE, shell=True, encoding="UTF-8"
|
|
961
|
+
)
|
|
869
962
|
else:
|
|
870
|
-
compare = subprocess.Popen(
|
|
963
|
+
compare = subprocess.Popen(
|
|
964
|
+
command, stderr=subprocess.PIPE, shell=True
|
|
965
|
+
)
|
|
871
966
|
out, err = compare.communicate()
|
|
872
967
|
if re.match("^[0-9]+$", err):
|
|
873
968
|
different_pixels = int(err)
|
|
@@ -908,9 +1003,11 @@ def is_white_frame(file, white_file):
|
|
|
908
1003
|
).format(
|
|
909
1004
|
image_magick["convert"], white_file, file, crop, image_magick["compare"]
|
|
910
1005
|
)
|
|
911
|
-
if
|
|
912
|
-
compare = subprocess.Popen(
|
|
913
|
-
|
|
1006
|
+
if sys.version_info > (3, 0):
|
|
1007
|
+
compare = subprocess.Popen(
|
|
1008
|
+
command, stderr=subprocess.PIPE, shell=True, encoding="UTF-8"
|
|
1009
|
+
)
|
|
1010
|
+
else:
|
|
914
1011
|
compare = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True)
|
|
915
1012
|
out, err = compare.communicate()
|
|
916
1013
|
if re.match("^[0-9]+$", err):
|
|
@@ -966,9 +1063,11 @@ def frames_match(image1, image2, fuzz_percent, max_differences, crop_region, mas
|
|
|
966
1063
|
)
|
|
967
1064
|
if platform.system() != "Windows":
|
|
968
1065
|
command = command.replace("(", "\\(").replace(")", "\\)")
|
|
969
|
-
if
|
|
970
|
-
compare = subprocess.Popen(
|
|
971
|
-
|
|
1066
|
+
if sys.version_info > (3, 0):
|
|
1067
|
+
compare = subprocess.Popen(
|
|
1068
|
+
command, stderr=subprocess.PIPE, shell=True, encoding="UTF-8"
|
|
1069
|
+
)
|
|
1070
|
+
else:
|
|
972
1071
|
compare = subprocess.Popen(command, stderr=subprocess.PIPE, shell=True)
|
|
973
1072
|
out, err = compare.communicate()
|
|
974
1073
|
if re.match("^[0-9]+$", err):
|
|
@@ -1686,7 +1785,7 @@ def calculate_contentful_speed_index(progress, directory):
|
|
|
1686
1785
|
command = "{0} {1} -canny 2x2+8%+8% -define histogram:unique-colors=true -format %c histogram:info:-".format(
|
|
1687
1786
|
image_magick["convert"], current_frame
|
|
1688
1787
|
)
|
|
1689
|
-
output = subprocess.check_output(command, shell=True).decode(
|
|
1788
|
+
output = subprocess.check_output(command, shell=True).decode("utf-8")
|
|
1690
1789
|
logging.debug("Output %s" % output)
|
|
1691
1790
|
|
|
1692
1791
|
# Take the last matching pixel count, which is the pixel count from the last
|
|
@@ -1887,28 +1986,28 @@ def calculate_hero_time(progress, directory, hero, viewport):
|
|
|
1887
1986
|
def check_config():
|
|
1888
1987
|
ok = True
|
|
1889
1988
|
|
|
1890
|
-
print("ffmpeg: "
|
|
1989
|
+
print("ffmpeg: ")
|
|
1891
1990
|
if get_decimate_filter() is not None:
|
|
1892
1991
|
print("OK")
|
|
1893
1992
|
else:
|
|
1894
1993
|
print("FAIL")
|
|
1895
1994
|
ok = False
|
|
1896
1995
|
|
|
1897
|
-
print("convert: "
|
|
1996
|
+
print("convert: ")
|
|
1898
1997
|
if check_process("{0} -version".format(image_magick["convert"]), "ImageMagick"):
|
|
1899
1998
|
print("OK")
|
|
1900
1999
|
else:
|
|
1901
2000
|
print("FAIL")
|
|
1902
2001
|
ok = False
|
|
1903
2002
|
|
|
1904
|
-
print("compare: "
|
|
2003
|
+
print("compare: ")
|
|
1905
2004
|
if check_process("{0} -version".format(image_magick["compare"]), "ImageMagick"):
|
|
1906
2005
|
print("OK")
|
|
1907
2006
|
else:
|
|
1908
2007
|
print("FAIL")
|
|
1909
2008
|
ok = False
|
|
1910
2009
|
|
|
1911
|
-
print("Pillow: "
|
|
2010
|
+
print("Pillow: ")
|
|
1912
2011
|
try:
|
|
1913
2012
|
from PIL import Image, ImageDraw # noqa
|
|
1914
2013
|
|
|
@@ -1917,7 +2016,7 @@ def check_config():
|
|
|
1917
2016
|
print("FAIL")
|
|
1918
2017
|
ok = False
|
|
1919
2018
|
|
|
1920
|
-
print("SSIM: "
|
|
2019
|
+
print("SSIM: ")
|
|
1921
2020
|
try:
|
|
1922
2021
|
from ssim import compute_ssim # noqa
|
|
1923
2022
|
|
|
@@ -1932,8 +2031,10 @@ def check_config():
|
|
|
1932
2031
|
def check_process(command, output):
|
|
1933
2032
|
ok = False
|
|
1934
2033
|
try:
|
|
1935
|
-
if
|
|
1936
|
-
out = subprocess.check_output(
|
|
2034
|
+
if sys.version_info > (3, 0):
|
|
2035
|
+
out = subprocess.check_output(
|
|
2036
|
+
command, stderr=subprocess.STDOUT, shell=True, encoding="UTF-8"
|
|
2037
|
+
)
|
|
1937
2038
|
else:
|
|
1938
2039
|
out = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True)
|
|
1939
2040
|
if out.find(output) > -1:
|
|
@@ -1976,7 +2077,7 @@ def main():
|
|
|
1976
2077
|
"--logfile", help="Write log messages to given file instead of stdout"
|
|
1977
2078
|
)
|
|
1978
2079
|
parser.add_argument(
|
|
1979
|
-
|
|
2080
|
+
"--logformat",
|
|
1980
2081
|
help="Formatting for the log messages",
|
|
1981
2082
|
default="%(asctime)s.%(msecs)03d - %(message)s",
|
|
1982
2083
|
)
|
|
@@ -2081,6 +2182,28 @@ def main():
|
|
|
2081
2182
|
help="Time of the video frame to use for identifying the viewport "
|
|
2082
2183
|
"(in HH:MM:SS.xx format).",
|
|
2083
2184
|
)
|
|
2185
|
+
parser.add_argument(
|
|
2186
|
+
"--viewportretries",
|
|
2187
|
+
type=int,
|
|
2188
|
+
default=5,
|
|
2189
|
+
help="Number of times to attempt to obtain a viewport. Analagous to the "
|
|
2190
|
+
"number of frames to try to find a viewport with. By default, up to the "
|
|
2191
|
+
"first 5 frames are used.",
|
|
2192
|
+
)
|
|
2193
|
+
parser.add_argument(
|
|
2194
|
+
"--viewportminheight",
|
|
2195
|
+
type=int,
|
|
2196
|
+
default=0,
|
|
2197
|
+
help="The minimum possible height (in pixels) for the viewport. Used when "
|
|
2198
|
+
"attempting to find the viewport size. Defaults to 0.",
|
|
2199
|
+
)
|
|
2200
|
+
parser.add_argument(
|
|
2201
|
+
"--viewportminwidth",
|
|
2202
|
+
type=int,
|
|
2203
|
+
default=0,
|
|
2204
|
+
help="The minimum possible width (in pixels) for the viewport. Used when "
|
|
2205
|
+
"attempting to find the viewport size. Defaults to 0.",
|
|
2206
|
+
)
|
|
2084
2207
|
parser.add_argument(
|
|
2085
2208
|
"-s",
|
|
2086
2209
|
"--start",
|
|
@@ -2213,9 +2336,7 @@ def main():
|
|
|
2213
2336
|
)
|
|
2214
2337
|
else:
|
|
2215
2338
|
logging.basicConfig(
|
|
2216
|
-
level=log_level,
|
|
2217
|
-
format=options.logformat,
|
|
2218
|
-
datefmt="%H:%M:%S",
|
|
2339
|
+
level=log_level, format=options.logformat, datefmt="%H:%M:%S"
|
|
2219
2340
|
)
|
|
2220
2341
|
|
|
2221
2342
|
if options.multiple:
|
|
@@ -2285,6 +2406,9 @@ def main():
|
|
|
2285
2406
|
options.multiple,
|
|
2286
2407
|
options.viewport,
|
|
2287
2408
|
options.viewporttime,
|
|
2409
|
+
options.viewportretries,
|
|
2410
|
+
options.viewportminheight,
|
|
2411
|
+
options.viewportminwidth,
|
|
2288
2412
|
options.full,
|
|
2289
2413
|
options.timeline,
|
|
2290
2414
|
options.trimend,
|
|
@@ -25,6 +25,10 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const serviceBuilder = new chrome.ServiceBuilder(chromedriverPath);
|
|
28
|
+
|
|
29
|
+
// Remove the check that matches the Chromedriver version with Chrome version.
|
|
30
|
+
serviceBuilder.addArguments('--disable-build-check');
|
|
31
|
+
|
|
28
32
|
if (options.chrome && options.chrome.chromedriverPort) {
|
|
29
33
|
serviceBuilder.setPort(options.chrome.chromedriverPort);
|
|
30
34
|
}
|
|
@@ -38,7 +42,6 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
38
42
|
serviceBuilder.enableVerboseLogging();
|
|
39
43
|
}
|
|
40
44
|
chrome.setDefaultService(serviceBuilder.build());
|
|
41
|
-
|
|
42
45
|
hasConfiguredChromeDriverService = true;
|
|
43
46
|
}
|
|
44
47
|
|
|
@@ -25,6 +25,10 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const serviceBuilder = new edge.ServiceBuilder(edgedriverPath);
|
|
28
|
+
|
|
29
|
+
// Remove the check that matches the Edgedriver version with Edge version.
|
|
30
|
+
serviceBuilder.addArguments('--disable-build-check');
|
|
31
|
+
|
|
28
32
|
if (
|
|
29
33
|
options.verbose >= 2 ||
|
|
30
34
|
chromeConfig.enableChromeDriverLog ||
|
package/lib/firefox/getHAR.js
CHANGED
|
@@ -10,8 +10,12 @@ module.exports = async function (runner, includeResponseBodies) {
|
|
|
10
10
|
async function triggerExport() {
|
|
11
11
|
try {
|
|
12
12
|
const result = await HAR.triggerExport();
|
|
13
|
-
result.pages
|
|
14
|
-
|
|
13
|
+
if (result.pages.length > 0) {
|
|
14
|
+
result.pages[0].title = document.URL;
|
|
15
|
+
return callback({'har': {log: result}});
|
|
16
|
+
} else {
|
|
17
|
+
return callback({'error': 'The HAR export trigger returned an empty HAR' + JSON.stringify(result)});
|
|
18
|
+
}
|
|
15
19
|
}
|
|
16
20
|
catch(e) {
|
|
17
21
|
// Sometimes the HAR trigger is really slow so then HAR is not defined.
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"description": "Browsertime",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.11.0",
|
|
4
4
|
"bin": "./bin/browsertime.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@sitespeed.io/throttle": "3.0.0",
|
|
7
7
|
"@devicefarmer/adbkit": "2.11.3",
|
|
8
8
|
"btoa": "1.2.1",
|
|
9
|
-
"@sitespeed.io/chromedriver": "
|
|
9
|
+
"@sitespeed.io/chromedriver": "96.0.4664-35",
|
|
10
10
|
"chrome-har": "0.12.0",
|
|
11
11
|
"chrome-remote-interface": "0.31.0",
|
|
12
|
-
"dayjs": "1.10.
|
|
12
|
+
"dayjs": "1.10.7",
|
|
13
13
|
"execa": "5.1.1",
|
|
14
14
|
"fast-stats": "0.0.6",
|
|
15
15
|
"find-up": "5.0.0",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"lodash.merge": "4.6.2",
|
|
23
23
|
"lodash.pick": "4.4.0",
|
|
24
24
|
"lodash.set": "4.3.2",
|
|
25
|
-
"selenium-webdriver": "4.
|
|
25
|
+
"selenium-webdriver": "4.1.0",
|
|
26
26
|
"@sitespeed.io/edgedriver": "95.0.1020-30",
|
|
27
27
|
"@sitespeed.io/geckodriver": "0.29.1-2",
|
|
28
28
|
"@sitespeed.io/tracium": "0.3.3",
|