Last active
January 20, 2025 09:43
-
-
Save f4iey/70c587d96055f128ee3b1131d963d8d0 to your computer and use it in GitHub Desktop.
PoC for posting scores on 3830 via DXLog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Required namespaces | |
using System; | |
using System.Collections.Generic; | |
using System.Net.Http; | |
using System.Threading.Tasks; | |
using HtmlAgilityPack; // Make sure to add HtmlAgilityPack via NuGet | |
namespace DXLog.net | |
{ | |
public class ContestSubmission : IScriptClass | |
{ | |
private HttpClient httpClient; | |
// Executes at DXLog.net start | |
public void Initialize(FrmMain main) | |
{ | |
httpClient = new HttpClient(); | |
} | |
// Executes as DXLog.net close down | |
public void Deinitialize() | |
{ | |
httpClient.Dispose(); | |
} | |
// Main execution method | |
public async void Main(FrmMain mainForm, ContestData cdata, COMMain comMain, MidiEvent midiEvent) | |
{ | |
// Get input variables from DXLog | |
string email = mainForm.GetVariable("Email"); | |
string callUsed = mainForm.GetVariable("CallUsed"); | |
string callOp = mainForm.GetVariable("CallOp"); | |
string callStation = mainForm.GetVariable("CallStation"); | |
string classType = mainForm.GetVariable("ClassType"); | |
string power = mainForm.GetVariable("Power"); | |
string qth = mainForm.GetVariable("QTH"); | |
string club = mainForm.GetVariable("Club"); | |
string comments = mainForm.GetVariable("Comments"); | |
// Optional fields | |
bool tworadio = mainForm.GetVariable("TwoRadio") == "True"; | |
bool twobsiq = mainForm.GetVariable("TwoBSIQ") == "True"; | |
bool remoteop = mainForm.GetVariable("RemoteOp") == "True"; | |
// Fetch current contests | |
var contests = await FetchCurrentContests(); | |
// Example: Submit score for the first contest | |
if (contests.Count > 0) | |
{ | |
var firstContest = contests[0]; | |
await SubmitScore(firstContest.Value, email, callUsed, callOp, callStation, classType, power, qth, club, comments, tworadio, twobsiq, remoteop); | |
} | |
else | |
{ | |
mainForm.SetMainStatusText("No contests found."); | |
} | |
} | |
private async Task<List<KeyValuePair<string, string>>> FetchCurrentContests() | |
{ | |
var contests = new List<KeyValuePair<string, string>>(); | |
var url = "https://www.3830scores.com/contests.php"; | |
var response = await httpClient.GetStringAsync(url); | |
var htmlDoc = new HtmlDocument(); | |
htmlDoc.LoadHtml(response); | |
// Find the "Recent Contests" section | |
var recentContestsSection = htmlDoc.DocumentNode.SelectSingleNode("//div[contains(@class, 'leftcollabel') and text()='Recent Contests']"); | |
if (recentContestsSection != null) | |
{ | |
var contestsList = recentContestsSection.SelectSingleNode("following-sibling::ul"); | |
if (contestsList != null) | |
{ | |
foreach (var li in contestsList.SelectNodes("li")) | |
{ | |
var aTag = li.SelectSingleNode("a"); | |
if (aTag != null) | |
{ | |
string contestName = aTag.InnerText.Trim(); | |
string submitLink = aTag.GetAttributeValue("href", string.Empty); | |
contests.Add(new KeyValuePair<string, string>(contestName, submitLink)); | |
} | |
} | |
} | |
} | |
return contests; | |
} | |
private async Task SubmitScore(string submitLink, string email, string callUsed, string callOp, string callStation, string classType, string power, string qth, string club, string comments, bool tworadio, bool twobsiq, bool remoteop) | |
{ | |
var formData = new Dictionary<string, string> | |
{ | |
{ "action", "process" }, | |
{ "formaction", "1" }, | |
{ "required_emailadr", email }, | |
{ "required_callused", callUsed }, | |
{ "callop", callOp }, | |
{ "callstation", callStation }, | |
{ "required_class", classType }, | |
{ "required_power", power }, | |
{ "optime", "3" }, // Example value, adjust as needed | |
{ "qth", qth }, | |
{ "stdclub", club }, | |
{ "clubnotonlist", "" }, | |
{ "subsubtotals[0]", "" }, | |
{ "subsubtotals[1]", "" }, | |
{ "subsubtotals[2]", "" }, | |
{ "subsubtotals[3]", "" }, | |
{ "subsubtotals[4]", "0" }, | |
{ "subsubtotals[5]", "" }, | |
{ "sumsubtot[0]", "0" }, | |
{ "sumsubtot[1]", "0" }, | |
{ "required_totscore_nf", "0" }, | |
{ "comments", comments }, | |
{ "required_emailadr2", email }, | |
{ "required_callused2", callUsed } | |
}; | |
// Add optional fields if the corresponding boolean is True | |
if (tworadio) | |
{ | |
formData["tworadio"] = "+"; | |
} | |
if (twobsiq) | |
{ | |
formData["twobsiq"] = "+"; | |
} | |
if (remoteop) | |
{ | |
formData["remoteop"] = "+"; | |
} | |
// Send the POST request | |
var content = new FormUrlEncodedContent(formData); | |
var response = await httpClient.PostAsync(submitLink, content); | |
if (response.IsSuccessStatusCode) | |
{ | |
// Optionally, you can read the response content if needed | |
string responseBody = await response.Content.ReadAsStringAsync(); | |
Console.WriteLine("Score submitted successfully!"); | |
} | |
else | |
{ | |
string errorResponse = await response.Content.ReadAsStringAsync(); | |
Console.WriteLine($"Failed to submit score: {errorResponse}"); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Required libraries | |
local http = require("socket.http") -- Make sure to have LuaSocket installed | |
local lxp = require("lxp.lom") -- LuaExpat for XML/HTML parsing | |
-- Function to fetch current contests | |
function fetchCurrentContests() | |
local contests = {} | |
local url = "https://www.3830scores.com/contests.php" | |
local response, status = http.request(url) | |
if status ~= 200 then | |
return contests -- Return empty if the request failed | |
end | |
-- Parse HTML | |
local html = lxp.lom.parse(response) | |
local recentContestsSection = findNode(html, "Recent Contests") | |
if recentContestsSection then | |
local contestsList = recentContestsSection[1].children[1] -- Assuming it's the first child | |
for _, li in ipairs(contestsList.children) do | |
if li.tag == "li" then | |
local aTag = findNode(li, "a") | |
if aTag then | |
local contestName = aTag[1] | |
local submitLink = aTag.attr.href | |
table.insert(contests, { name = contestName, value = submitLink }) | |
end | |
end | |
end | |
end | |
return contests | |
end | |
-- Helper function to find a node by text | |
function findNode(node, text) | |
for _, child in ipairs(node) do | |
if child.tag == "div" and child.attr.class and child.attr.class:find("leftcollabel") and child[1] == text then | |
return child | |
end | |
end | |
return nil | |
end | |
-- Function to submit score | |
function submitScore(submitLink, email, callUsed, callOp, callStation, classType, power, qth, club, comments, tworadio, twobsiq, remoteop) | |
local formData = { | |
action = "process", | |
formaction = "1", | |
required_emailadr = email, | |
required_callused = callUsed, | |
callop = callOp, | |
callstation = callStation, | |
required_class = classType, | |
required_power = power, | |
optime = "3", -- Example value, adjust as needed | |
qth = qth, | |
stdclub = club, | |
clubnotonlist = "", | |
subsubtotals = {"", "", "", "", "0", ""}, -- 160, 80, 40, 20, 15, 10 | |
sumsubtot = {"0", "0"}, -- total QSOs, total MULTs | |
required_totscore_nf = "0", | |
comments = comments, | |
required_emailadr2 = email, | |
required_callused2 = callUsed | |
} | |
-- Add optional fields if the corresponding boolean is True | |
if tworadio then | |
formData["tworadio"] = "+" | |
end | |
if twobsiq then | |
formData["twobsiq"] = "+" | |
end | |
if remoteop then | |
formData["remoteop"] = "+" | |
end | |
-- Prepare form data for POST request | |
local postData = "" | |
for key, value in pairs(formData) do | |
postData = postData .. key .. "=" .. value .. "&" | |
end | |
postData = postData:sub(1, -2) -- Remove the last '&' | |
-- Send the POST request | |
local response, status = http.request{ | |
url = submitLink, | |
method = "POST", | |
headers = { | |
["Content-Type"] = "application/x-www-form-urlencoded", | |
["Content-Length"] = tostring(#postData) | |
}, | |
source = ltn12.source.string(postData) | |
} | |
if status == 200 then | |
print("Score submitted successfully!") | |
else | |
print("Failed to submit score: " .. (response or "Unknown error")) | |
end | |
end | |
-- Example usage | |
local email = "[email protected]" | |
local callUsed = wtContest:GetMyCallsign() | |
local callOp = "Operator" | |
local callStation = "Station" | |
local classType = "Class" | |
local power = "Power" | |
local qth = "QTH" | |
local club = "Club" | |
local comments = "Comments" | |
local tworadio = true | |
local twobsiq = false | |
local remoteop = false | |
-- Fetch contests and submit score for the first contest | |
local contests = fetchCurrentContests() | |
if #contests > 0 then | |
-- prompt use with the list and choose the one | |
local prompt = "" | |
for index, value in ipairs(contests) do | |
prompt = prompt + tostring(index) + ": " + value + "\n" | |
end | |
local ctestIndex = wtApp:InputInteger(prompt, "Select 3830 score contest number", 0) | |
local firstContest = contests[ctestIndex] | |
submitScore(firstContest.value, email, callUsed, callOp, callStation, classType, power, qth, club, comments, tworadio, twobsiq, remoteop) | |
else | |
print("No contests found.") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment