# F1TVEmulator.cs ``` cs /// Author : Maxime Rohmer /// Date : 08/05/2023 /// File : F1TVEmulator.cs /// Brief : Class that contains methods to emulate a browser and navigate the F1TV website /// Version : 0.1 using OpenQA.Selenium; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Interactions; using OpenQA.Selenium.Support.UI; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Test_Merge { internal class F1TVEmulator { public const string COOKIE_HOST = ".formula1.com"; public const string PYTHON_COOKIE_RETRIEVAL_FILENAME = "recoverCookiesCSV.py"; public const string GECKODRIVER_FILENAME = @"geckodriver-v0.27.0-win64\geckodriver.exe"; //BE CAREFULL IF YOU CHANGE IT HERE YOU NEED TO CHANGE IT IN THE PYTHON SCRIPT TOO public const string COOKIES_CSV_FILENAME = "cookies.csv"; private FirefoxDriver Driver; private bool _ready; private string _grandPrixUrl; public string GrandPrixUrl { get => _grandPrixUrl; private set => _grandPrixUrl = value; } public bool Ready { get => _ready; set => _ready = value; } public F1TVEmulator(string grandPrixUrl) { GrandPrixUrl = grandPrixUrl; Ready = false; } private void StartCookieRecovering() { string scriptPath = PYTHON_COOKIE_RETRIEVAL_FILENAME; Process process = new Process(); process.StartInfo.FileName = "python.exe"; process.StartInfo.Arguments = scriptPath; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.Start(); string output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); } public string GetCookie(string host, string name) { StartCookieRecovering(); string value = ""; List cookies = new List(); using (var reader = new StreamReader(COOKIES_CSV_FILENAME)) { // Read the header row and validate column order string header = reader.ReadLine(); string[] expectedColumns = { "host_key", "name", "value", "path", "expires_utc", "is_secure", "is_httponly" }; string[] actualColumns = header.Split(','); for (int i = 0; i < expectedColumns.Length; i++) { if (expectedColumns[i] != actualColumns[i]) { throw new InvalidOperationException($"Expected column '{expectedColumns[i]}' at index {i} but found '{actualColumns[i]}'"); } } // Read each data row and parse values into a Cookie object while (!reader.EndOfStream) { string line = reader.ReadLine(); string[] fields = line.Split(','); string hostname = fields[0]; string cookieName = fields[1]; if (hostname == host && cookieName == name) { value = fields[2]; } } } return value; } public async Task Start() { Ready = false; string loginCookieName = "login"; string loginSessionCookieName = "login-session"; string loginCookieValue = GetCookie(COOKIE_HOST, loginCookieName); string loginSessionValue = GetCookie(COOKIE_HOST, loginSessionCookieName); int windowWidth = 1920; int windowHeight = 768; var service = FirefoxDriverService.CreateDefaultService(GECKODRIVER_FILENAME); service.Host = "127.0.0.1"; service.Port = 5555; FirefoxProfile profile = new FirefoxProfile(); FirefoxOptions options = new FirefoxOptions(); //profile.SetPreference("full-screen-api.ignore-widgets", true); //profile.SetPreference("media.hardware-video-decoding.enabled", true); //profile.SetPreference("full-screen-api.enabled", true); options.Profile = profile; profile.SetPreference("layout.css.devPixelsPerPx", "1.0"); options.AcceptInsecureCertificates = true; options.AddArgument("--headless"); //options.AddArgument("--start-maximized"); //options.AddArgument("--window-size=1920x1080"); //options.AddArgument("--width=" + windowWidth); //options.AddArgument("--height=" + windowHeight); //options.AddArgument("-window-size=1920x1080"); //options.AddArgument("--width=1920"); //options.AddArgument("--height=1080"); //profile try { Driver = new FirefoxDriver(service, options); } catch { Ready = false; return 101; } Actions actions = new Actions(Driver); var loginCookie = new Cookie(loginCookieName, loginCookieValue, COOKIE_HOST, "/", DateTime.Now.AddDays(5)); var loginSessionCookie = new Cookie(loginSessionCookieName, loginSessionValue, COOKIE_HOST, "/", DateTime.Now.AddDays(5)); Driver.Navigate().GoToUrl("https://f1tv.formula1.com/"); Driver.Manage().Cookies.AddCookie(loginCookie); Driver.Manage().Cookies.AddCookie(loginSessionCookie); try { Driver.Navigate().GoToUrl(GrandPrixUrl); } catch { //The url is not a valid url Driver.Dispose(); return 103; } //Waits for the page to fully load Driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(30); //Removes the cookie prompt try { IWebElement conscentButton = Driver.FindElement(By.Id("truste-consent-button")); conscentButton.Click(); } catch { //Could not locate the cookie button Screenshot("ERROR104"); Driver.Dispose(); return 104; } //Again waits for the page to fully load (when you accept cookies it takes a little time for the page to load) //Cannot use The timeout because the feed loading is not really loading so there is not event or anything Thread.Sleep(5000); //Switches to the Data channel try { IWebElement dataChannelButton = Driver.FindElement(By.ClassName("data-button")); dataChannelButton.Click(); } catch { //If the data button does not exists its because the user is not connected Screenshot("ERROR102"); Driver.Dispose(); return 102; } //Open settings // Press the space key, this should make the setting button visible // It does not matter if the feed is paused because when changing channel it autoplays actions.SendKeys(OpenQA.Selenium.Keys.Space).Perform(); //Clicks on the settings Icon int tries = 0; bool success = false; while (tries < 100 && !success) { Thread.Sleep(100); try { IWebElement settingsButton = Driver.FindElement(By.ClassName("bmpui-ui-settingstogglebutton")); settingsButton.Click(); IWebElement selectElement = Driver.FindElement(By.ClassName("bmpui-ui-videoqualityselectbox")); SelectElement select = new SelectElement(selectElement); IWebElement selectOption = selectElement.FindElement(By.CssSelector("option[value^='1080_']")); selectOption.Click(); success = true; } catch { //Sometimes it can crash because it could not get the options to show up in time. When it happens just retry success = false; tries++; } } if (!success) { Screenshot("ERROR105"); Driver.Dispose(); return 105; } Screenshot("BEFOREFULLSCREEN"); //Makes the feed fullscreen //Driver.Manage().Window.Size = new System.Drawing.Size(windowWidth, windowHeight); Driver.Manage().Window.Maximize(); WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(10)); try { IWebElement fullScreenButton = Driver.FindElement(By.ClassName("bmpui-ui-fullscreentogglebutton")); fullScreenButton.Click(); } catch { Screenshot("ERROR106"); Driver.Dispose(); return 106; } Screenshot("AFTERFULLSCREEN"); //STARTUP FINISHED READY TO SCREENSHOT Ready = true; return 0; } public Bitmap Screenshot(string name = "TEST") { Bitmap result = new Bitmap(4242, 6969); try { //Screenshot scrsht = ((ITakesScreenshot)Driver).GetScreenshot(); //profileriver.SetPreference("layout.css.devPixelsPerPx", "1.0"); //Screenshot scrsht = Driver.GetFullPageScreenshot(); Screenshot scrsht = Driver.GetScreenshot(); byte[] screenshotBytes = Convert.FromBase64String(scrsht.AsBase64EncodedString); MemoryStream stream = new MemoryStream(screenshotBytes); result = new Bitmap(stream); //result.Save(name + ".png"); scrsht.SaveAsFile(name + ".png"); } catch { //Nothing for now } return result; } public void Stop() { Ready = false; Driver.Dispose(); } public void ResetDriver() { Ready = false; Driver.Dispose(); Driver = null; } } } ```