diff --git a/.gitignore b/.gitignore
index 77575d5..689cf55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+Password.txt
+*/Password.txt
+
# ---> VisualStudioCode
.vscode/*
!.vscode/settings.json
diff --git a/BadmintonBooker.csproj b/BadmintonBooker.csproj
new file mode 100644
index 0000000..b2fd81a
--- /dev/null
+++ b/BadmintonBooker.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BadmintonBooker.sln b/BadmintonBooker.sln
new file mode 100644
index 0000000..a0a3810
--- /dev/null
+++ b/BadmintonBooker.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BadmintonBooker", "BadmintonBooker.csproj", "{64D6B026-79C7-8E9B-78B3-7E47FF75FA6D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {64D6B026-79C7-8E9B-78B3-7E47FF75FA6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {64D6B026-79C7-8E9B-78B3-7E47FF75FA6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {64D6B026-79C7-8E9B-78B3-7E47FF75FA6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {64D6B026-79C7-8E9B-78B3-7E47FF75FA6D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {30C191B7-3059-49DA-8326-9D39D1120073}
+ EndGlobalSection
+EndGlobal
diff --git a/BrowserManager.cs b/BrowserManager.cs
new file mode 100644
index 0000000..5ac7431
--- /dev/null
+++ b/BrowserManager.cs
@@ -0,0 +1,59 @@
+using System.Diagnostics;
+using System.Net.Sockets;
+using Microsoft.Playwright;
+
+namespace BadmintonBooker;
+
+internal static class BrowserManager
+{
+ private const int DebugPort = 9222;
+ private const string ChromeExe = @"C:\Program Files\Google\Chrome\Application\chrome.exe";
+ private const string UserDataDir = @"C:\Users\Shaamil\PlaywrightData";
+
+ public static async Task GetContextAsync(IPlaywright playwright)
+ {
+ await EnsureChromeRunningAsync();
+ var browser = await playwright.Chromium.ConnectOverCDPAsync($"http://127.0.0.1:{DebugPort}");
+ return browser.Contexts[0];
+ }
+
+ private static async Task EnsureChromeRunningAsync()
+ {
+ if (IsPortListening(DebugPort))
+ return;
+
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = ChromeExe,
+ Arguments = $"--remote-debugging-port={DebugPort} --user-data-dir=\"{UserDataDir}\"",
+ UseShellExecute = true
+ });
+
+ // Wait for Chrome to bind the debug port
+ const int maxWaitMs = 10000;
+ const int intervalMs = 500;
+ var elapsed = 0;
+
+ while (!IsPortListening(DebugPort) && elapsed < maxWaitMs)
+ {
+ await Task.Delay(intervalMs);
+ elapsed += intervalMs;
+ }
+
+ if (!IsPortListening(DebugPort))
+ throw new TimeoutException("Chrome did not open the remote debugging port in time.");
+ }
+
+ private static bool IsPortListening(int port)
+ {
+ try
+ {
+ using var tcp = new TcpClient();
+ tcp.Connect("127.0.0.1", port);
+ return true;
+ }
+ catch { return false; }
+ }
+
+
+}
\ No newline at end of file
diff --git a/OTPExtractor.cs b/OTPExtractor.cs
new file mode 100644
index 0000000..28d76da
--- /dev/null
+++ b/OTPExtractor.cs
@@ -0,0 +1,29 @@
+using System.Text.RegularExpressions;
+using Microsoft.Playwright;
+
+namespace BadmintonBooker;
+
+public static class OTPExtractor
+{
+ public static async Task GetEgovOTP(IBrowserContext context, IPage originalPage)
+ {
+ var msgPage = await context.NewPageAsync();
+ await msgPage.GotoAsync("https://messages.google.com/web/u/0/conversations/CgjwUsdGGwxxGhIBNw", new PageGotoOptions { WaitUntil = WaitUntilState.Load });
+
+ var messageElement = msgPage.Locator("mws-text-message-part").Last;
+ string messageText = await messageElement.InnerTextAsync();
+
+ await originalPage.BringToFrontAsync();
+
+ var match = Regex.Match(messageText, @"\b\d{5,}\b");
+ if (match.Success)
+ {
+ return match.Value;
+ }
+ else
+ {
+ Console.WriteLine("No OTP found in the message.");
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..cce6f2d
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,32 @@
+using BadmintonBooker;
+using Microsoft.Playwright;
+
+using var playwright = await Playwright.CreateAsync();
+var context = await BrowserManager.GetContextAsync(playwright);
+var page = context.Pages.Count > 0 ? context.Pages[0] : await context.NewPageAsync();
+await page.GotoAsync("https://my.hdc.mv/");
+await page.GetByRole(AriaRole.Link, new() { Name = "Login" }).ClickAsync();
+await page.GetByRole(AriaRole.Button, new() { Name = "eFaas" }).ClickAsync();
+await page.GetByRole(AriaRole.Tab, new() { Name = "Password Login" }).ClickAsync(new () { Delay = 1000 });
+await page.GetByPlaceholder("Username").FillAsync("A384347");
+var password = File.ReadAllText("password.txt");
+await page.GetByPlaceholder("Password").FillAsync(password);
+await page.GetByRole(AriaRole.Button, new() { Name = "LOGIN" }).ClickAsync();
+await page.GetByRole(AriaRole.Button, new() { Name = "CONTINUE" }).ClickAsync(new () { Delay = 1000 });
+await Task.Delay(5000);
+
+var egovOtp = await OTPExtractor.GetEgovOTP(context, page);
+if (egovOtp != null)
+ Console.WriteLine($"Extracted eGov OTP: {egovOtp}");
+else
+ return;
+
+await page.GetByPlaceholder("OTP").FillAsync(egovOtp);
+await page.GetByRole(AriaRole.Button, new() { Name = "CONTINUE" }).ClickAsync();
+await page.GetByText("Make a booking").ClickAsync();
+await page.GetByText("Fahiveni").ClickAsync();
+await page.GetByText("Sports and Leisure").ClickAsync();
+await page.GetByText(" Fahiveni Community Center ").First.ClickAsync(new () { Delay = 1500 });
+await page.GetByText("Badminton Court 1").ClickAsync(new () { Delay = 1500 });
+
+Console.ReadLine();
\ No newline at end of file