Add project files.
This commit is contained in:
56
ModVersionChecker/checkers/ApiChecker.cs
Normal file
56
ModVersionChecker/checkers/ApiChecker.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using ModVersionChecker.data.model;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ModVersionChecker
|
||||
{
|
||||
public class ApiChecker : IVersionChecker
|
||||
{
|
||||
private static readonly HttpClient _httpClient = new HttpClient();
|
||||
|
||||
public async Task<string> GetLatestVersion(Dictionary<string, string> paramsDict, SourceDef source)
|
||||
{
|
||||
if (!paramsDict.TryGetValue("url", out var url) || string.IsNullOrEmpty(url))
|
||||
{
|
||||
throw new ArgumentException("API URL required");
|
||||
}
|
||||
if (!paramsDict.TryGetValue("jsonPath", out var jsonPath) || string.IsNullOrEmpty(jsonPath))
|
||||
{
|
||||
throw new ArgumentException("jsonPath required");
|
||||
}
|
||||
|
||||
var response = await _httpClient.GetAsync(url);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new Exception($"API error: {(int)response.StatusCode} {response.ReasonPhrase}");
|
||||
}
|
||||
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
if (string.IsNullOrEmpty(body))
|
||||
{
|
||||
throw new Exception("Empty API response");
|
||||
}
|
||||
|
||||
using var jsonDoc = JsonDocument.Parse(body);
|
||||
var element = jsonDoc.RootElement;
|
||||
|
||||
foreach (var key in jsonPath.Split('.'))
|
||||
{
|
||||
if (!element.TryGetProperty(key, out var nextElement))
|
||||
{
|
||||
throw new Exception($"JSON key '{key}' not found in response");
|
||||
}
|
||||
element = nextElement;
|
||||
}
|
||||
|
||||
if (element.ValueKind != JsonValueKind.String)
|
||||
{
|
||||
throw new Exception($"JSON value for '{jsonPath}' is not a string");
|
||||
}
|
||||
|
||||
return element.GetString()!.Trim();
|
||||
}
|
||||
}
|
||||
}
|
17
ModVersionChecker/checkers/CheckerFactory.cs
Normal file
17
ModVersionChecker/checkers/CheckerFactory.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace ModVersionChecker
|
||||
{
|
||||
public static class CheckerFactory
|
||||
{
|
||||
public static IVersionChecker CreateChecker(string type)
|
||||
{
|
||||
string[] parts = type.Split(':');
|
||||
|
||||
return parts[0].ToLower() switch
|
||||
{
|
||||
"scrape" => new ScrapeChecker(),
|
||||
"api" => new ApiChecker(),
|
||||
_ => throw new ArgumentException($"Unknown checker type: {type}")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
94
ModVersionChecker/checkers/ScrapeChecker.cs
Normal file
94
ModVersionChecker/checkers/ScrapeChecker.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using ModVersionChecker.data.model;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Chrome;
|
||||
|
||||
namespace ModVersionChecker
|
||||
{
|
||||
public class ScrapeChecker : IVersionChecker
|
||||
{
|
||||
public async Task<string> GetLatestVersion(Dictionary<string, string> paramsDict, SourceDef source)
|
||||
{
|
||||
if (!paramsDict.TryGetValue("url", out var url) || string.IsNullOrEmpty(url))
|
||||
{
|
||||
throw new ArgumentException("URL required");
|
||||
}
|
||||
|
||||
var mode = GetValueOrDefault(paramsDict, "mode", source);
|
||||
var response = "";
|
||||
if (mode == "selenium")
|
||||
{
|
||||
response = await SeleniumFetch(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = await DefaultFetch(url); ;
|
||||
}
|
||||
|
||||
|
||||
string pattern = @">\s+<";
|
||||
response = Regex.Replace(response, pattern, "><");
|
||||
var regex = GetValueOrDefault(paramsDict, "regex", source);
|
||||
|
||||
var match = System.Text.RegularExpressions.Regex.Match(response, regex);
|
||||
if (!match.Success || match.Groups.Count < 2)
|
||||
{
|
||||
throw new Exception($"No match with regex in response");
|
||||
}
|
||||
return match.Groups[1].Value;
|
||||
|
||||
}
|
||||
|
||||
private string GetValueOrDefault(Dictionary<string, string> dict, string key, SourceDef source)
|
||||
{
|
||||
var value = "";
|
||||
if (dict.ContainsKey(key) && !string.IsNullOrEmpty(dict[key]))
|
||||
{
|
||||
value = dict[key];
|
||||
}
|
||||
else if (source.Defaults != null && source.Defaults.ContainsKey(key))
|
||||
{
|
||||
value = source.Defaults[key];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private Task<string> DefaultFetch(string url)
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
|
||||
httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
|
||||
httpClient.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.5");
|
||||
|
||||
return httpClient.GetStringAsync(url);
|
||||
}
|
||||
|
||||
private async Task<string> SeleniumFetch(string url)
|
||||
{
|
||||
var service = ChromeDriverService.CreateDefaultService();
|
||||
service.HideCommandPromptWindow = true;
|
||||
|
||||
var options = new ChromeOptions();
|
||||
options.AddArgument("--headless"); // Run in headless mode
|
||||
options.AddArgument("--disable-gpu");
|
||||
options.AddArgument("--no-sandbox");
|
||||
options.AddArgument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/91.0.4472.124");
|
||||
|
||||
using var driver = new ChromeDriver(service, options);
|
||||
try
|
||||
{
|
||||
driver.Navigate().GoToUrl(url);
|
||||
// Wait for the page to load
|
||||
await Task.Delay(2000); // Adjust as necessary
|
||||
// Example: Get the page source
|
||||
var pageSource = driver.PageSource;
|
||||
// Close the driver
|
||||
return pageSource;
|
||||
}
|
||||
finally
|
||||
{
|
||||
driver.Quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
ModVersionChecker/checkers/VersionChecker.cs
Normal file
9
ModVersionChecker/checkers/VersionChecker.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using ModVersionChecker.data.model;
|
||||
|
||||
namespace ModVersionChecker
|
||||
{
|
||||
public interface IVersionChecker
|
||||
{
|
||||
Task<string> GetLatestVersion(Dictionary<string, string> paramsDict, SourceDef source);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user