Files
TrackTrendsDoc/temp_annexes/Code/F1TVEmulator.md
T

10 KiB

F1TVEmulator.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<Cookie> cookies = new List<Cookie>();
            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<int> 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;
        }
    }
}