[ADD] script selenium video support

This commit is contained in:
Mathieu Benoit 2023-12-02 14:13:56 -05:00
parent 3f9d243106
commit e7fe4758d2
4 changed files with 263 additions and 10 deletions

View file

@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Get two last .webm file
videos=($(ls -t *.webm | head -n 2))
if [ ${#videos[@]} -ne 2 ]; then
echo "Error : you need two files .webm in root directory"
exit 1
fi
timestamp=$(date +"%Y%m%d_%H%M%S")
output_name="output_${timestamp}.webm"
video1="${videos[0]}"
video2="${videos[1]}"
echo "first video ${video1}"
echo "second video ${video2}"
# Obtenez les durées des vidéos
duration1=$(ffmpeg -i "$video1" 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | tr -d ,)
duration2=$(ffmpeg -i "$video2" 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | tr -d ,)
echo "duration 1 : ${duration1}"
echo "duration 2 : ${duration2}"
# Convertir les durées en secondes
duration1_sec=$(echo "$duration1" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
duration2_sec=$(echo "$duration2" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }')
echo "duration 1 sec : ${duration1_sec}"
echo "duration 2 sec : ${duration2_sec}"
# Déterminer la durée la plus courte
min_duration=$(echo "$duration1_sec $duration2_sec" | awk '{print ($1 < $2) ? $1 : $2}')
echo "Min duration : ${min_duration}"
# Créez la sortie
#output_name="output.mp4"
# Utiliser ffmpeg pour couper et empiler les vidéos
#ffmpeg -i "$video1" -i "$video2" -filter_complex "
# [0:v]trim=start=0:end=$min_duration,setpts=PTS-STARTPTS[v0];
# [1:v]trim=start=0:end=$min_duration,setpts=PTS-STARTPTS[v1];
# [v0][v1]hstack=inputs=2" "$output_name"
#echo "Les vidéos ont été combinées en $output_name"
ffmpeg -i "${videos[0]}" -i "${videos[1]}" -filter_complex "hstack=inputs=2" "${output_name}"
# with normalize size video
#ffmpeg -i "${videos[0]}" -i "${videos[1]}" -filter_complex "[0:v]scale=320:240[v0]; [1:v]scale=320:240[v1]; [v0][v1]hstack=inputs=2" "${output_name}"
echo "${output_name}"

View file

@ -8,7 +8,9 @@ import os
import sys import sys
import time import time
from selenium import webdriver from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.firefox.service import Service from selenium.webdriver.firefox.service import Service
@ -21,7 +23,16 @@ class SeleniumLib(object):
def __init__(self, config): def __init__(self, config):
self.config = config self.config = config
self.video_recorder = None self.video_recorder = None
self.filename = "video_" + time.strftime("%Y_%m_%d-%H_%M_%S") + ".webm" if self.config.video_suffix:
self.filename = (
f"video_{self.config.video_suffix}_"
+ time.strftime("%Y_%m_%d-%H_%M_%S")
+ ".webm"
)
else:
self.filename = (
"video_" + time.strftime("%Y_%m_%d-%H_%M_%S") + ".webm"
)
self.driver = None self.driver = None
def configure(self): def configure(self):
@ -70,6 +81,7 @@ class SeleniumLib(object):
# Ajout de l'enregistrement # Ajout de l'enregistrement
if self.config.record_mode: if self.config.record_mode:
# Create recording
new_path = os.path.normpath( new_path = os.path.normpath(
os.path.join(os.path.dirname(__file__), "..", "..") os.path.join(os.path.dirname(__file__), "..", "..")
) )
@ -164,6 +176,95 @@ class SeleniumLib(object):
return ele[0] return ele[0]
def get_all_element(self, by: str = By.ID, value: str = None, timeout=5):
wait = WebDriverWait(self.driver, timeout)
ele = wait.until(
EC.visibility_of_all_elements_located(
(
by,
value,
)
)
)
return ele
def wait_new_element_and_click(
self,
by: str = By.ID,
value: str = None,
delay_wait=1,
timeout=5,
inject_cursor=False,
):
new_element = self.wait_new_element(
by=by, value=value, delay_wait=delay_wait, timeout=timeout
)
if new_element:
if inject_cursor:
self.inject_cursor()
self.click_with_mouse_move(element=new_element, no_scroll=True)
return new_element
def wait_new_element(
self,
by: str = By.ID,
value: str = None,
delay_wait=1,
timeout=5,
timeout_wait=None,
):
element = None
# TODO support timeout_wait
while element is None:
time.sleep(delay_wait)
try:
element = self.get_element(by, value, timeout)
except TimeoutException as e:
pass
print(f"Waiting {delay_wait} seconds after value '{value}'")
return element
def wait_add_new_element_and_click(
self, by: str = By.ID, value: str = None, delay_wait=1, timeout=5
):
new_element = self.wait_add_new_element(
by=by, value=value, delay_wait=delay_wait, timeout=timeout
)
self.click_with_mouse_move(element=new_element, no_scroll=True)
return new_element
def wait_add_new_element(
self, by: str = By.ID, value: str = None, delay_wait=1, timeout=5
):
all_element_init = self.get_all_element(by=by, value=value)
len_all_element_init = len(all_element_init)
len_all_element = len_all_element_init
all_element = []
while len_all_element_init == len_all_element:
time.sleep(delay_wait)
all_element = self.get_all_element(by=by, value=value)
len_all_element = len(all_element)
print(f"Waiting {delay_wait} seconds after value '{value}'")
new_element = all_element[-1]
return new_element
def wait_increment_number_text_and_click(
self, by: str = By.ID, value: str = None, delay_wait=1, timeout=5
):
element_init = self.get_element(by=by, value=value, timeout=timeout)
actual_number = int(element_init.text)
number_goal = actual_number + 1
while actual_number < number_goal:
time.sleep(delay_wait)
element_goal = self.get_element(
by=by, value=value, timeout=timeout
)
actual_number = int(element_goal.text)
print(f"Waiting {delay_wait} seconds after value '{value}'")
self.click_with_mouse_move(element=element_init, no_scroll=True)
return element_init
def click_with_mouse_move( def click_with_mouse_move(
self, self,
by: str = By.ID, by: str = By.ID,
@ -172,9 +273,13 @@ class SeleniumLib(object):
no_scroll: bool = False, no_scroll: bool = False,
viewport_ele_by: str = By.ID, viewport_ele_by: str = By.ID,
viewport_ele_value: str = None, viewport_ele_value: str = None,
element: WebElement = None,
): ):
# ele = self.driver.find_element(by, value) # ele = self.driver.find_element(by, value)
ele = self.get_element(by, value, timeout) if element:
ele = element
else:
ele = self.get_element(by, value, timeout)
if not no_scroll: if not no_scroll:
viewport_ele = None viewport_ele = None
if viewport_ele_value: if viewport_ele_value:
@ -185,14 +290,17 @@ class SeleniumLib(object):
ActionChains(self.driver).move_to_element(ele).perform() ActionChains(self.driver).move_to_element(ele).perform()
time.sleep(self.config.selenium_default_delay) time.sleep(self.config.selenium_default_delay)
wait = WebDriverWait(self.driver, timeout) wait = WebDriverWait(self.driver, timeout)
button = wait.until( if element:
EC.element_to_be_clickable( button = wait.until(EC.element_to_be_clickable(element))
( else:
by, button = wait.until(
value, EC.element_to_be_clickable(
(
by,
value,
)
) )
) )
)
button.click() button.click()
def click_canvas_form( def click_canvas_form(
@ -368,7 +476,50 @@ class SeleniumLib(object):
cursor.style.top = e.pageY - 5 + 'px'; cursor.style.top = e.pageY - 5 + 'px';
}); });
""" """
self.driver.execute_script(cursor_script) try:
try:
self.driver.execute_script(cursor_script)
except Exception as e:
time.sleep(1)
print("Error execute script cursor, wait 1 second")
self.driver.execute_script(cursor_script)
except Exception as e:
time.sleep(3)
print("Error execute script cursor, wait 3 second")
self.driver.execute_script(cursor_script)
def scenario_create_new_account_with_random_user(
self, show_cursor=False, def_action_before_submit=None
):
# Click no account
if show_cursor:
self.inject_cursor()
self.click_with_mouse_move(
By.XPATH, "/html/body/div[1]/main/div/form/div[3]/div[1]/a[1]"
)
# Trouvez les éléments du formulaire
if show_cursor:
self.inject_cursor()
# Remplissez le courriel et le mot de passe
first_name = self.get_french_word_no_space_no_accent()
password = first_name.lower()
second_name = self.get_french_word_no_space_no_accent()
full_name = f"{first_name} {second_name}"
domain = self.get_french_word_no_space_no_accent().lower()
self.input_text_with_mouse_move(
By.NAME, "login", f"{password}@{domain}.com"
)
self.input_text_with_mouse_move(By.NAME, "name", full_name)
self.input_text_with_mouse_move(By.NAME, "password", password)
self.input_text_with_mouse_move(By.NAME, "confirm_password", password)
if def_action_before_submit:
def_action_before_submit()
self.click_with_mouse_move(
By.XPATH, "/html/body/div[1]/main/div/form/div[6]/button"
)
def open_tab(self, url): def open_tab(self, url):
# Open a new window # Open a new window
@ -389,6 +540,34 @@ class SeleniumLib(object):
def start_record(self): def start_record(self):
# Démarrer l'enregistrement # Démarrer l'enregistrement
if self.config.record_mode: if self.config.record_mode:
# Sync before record
has_sync_error = False
if self.config.sync_file_record_read:
if not self.config.sync_file_record_write:
print(
"Error, cannot sync, missing 'sync_file_record_write'"
)
has_sync_error = True
if self.config.sync_file_record_write:
if not self.config.sync_file_record_read:
print(
"Error, cannot sync, missing 'sync_file_record_read'"
)
has_sync_error = True
if (
not has_sync_error
and self.config.sync_file_record_read
and self.config.sync_file_record_write
):
# Do sync
file_name_1 = f"/tmp/erplibre_sync_temp_file{self.config.sync_file_record_write}"
file_name_2 = f"/tmp/erplibre_sync_temp_file{self.config.sync_file_record_read}"
with open(file_name_1, "w") as file:
file.write(f"Recording {self.filename}\n")
while not os.path.exists(file_name_2):
var_wait_time = 0.001
print(f"File {self.filename} wait {var_wait_time} seconds")
time.sleep(var_wait_time)
self.video_recorder.start() self.video_recorder.start()
def stop_record(self): def stop_record(self):
@ -399,6 +578,7 @@ class SeleniumLib(object):
time.sleep(self.config.selenium_video_time_waiting_end) time.sleep(self.config.selenium_video_time_waiting_end)
self.video_recorder.stop() self.video_recorder.stop()
print("End of recording video") print("End of recording video")
print(self.filename)
if self.config.selenium_video_auto_play_video: if self.config.selenium_video_auto_play_video:
print(f"Play video {self.filename}") print(f"Play video {self.filename}")
@ -456,6 +636,27 @@ def fill_parser(parser):
action="store_true", action="store_true",
help="Start recording (not finish to be implemented).", help="Start recording (not finish to be implemented).",
) )
parser.add_argument(
"--video_suffix",
default="",
help="Will modify video name.",
)
parser.add_argument(
"--sync_file_record_read",
default="",
help=(
"Will sync and check file from tmp before record, write before"
" read."
),
)
parser.add_argument(
"--sync_file_record_write",
default="",
help=(
"Will sync and check file from tmp before record, write before"
" read."
),
)
group_record.add_argument( group_record.add_argument(
"--selenium_video_time_waiting_end", "--selenium_video_time_waiting_end",
default=5, default=5,

View file

@ -26,7 +26,7 @@ class VideoRecorder(object):
self, self,
driver, driver,
filename="video.webm", filename="video.webm",
framerate="25/1", framerate="33/1",
width=None, width=None,
height=None, height=None,
): ):

View file

@ -105,6 +105,7 @@ def run(config, selenium_tool):
if config.open_dashboard: if config.open_dashboard:
selenium_tool.click( selenium_tool.click(
"/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[3]/a", "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[3]/a",
timeout=15,
) )
# Open conversation chat # Open conversation chat