diff --git a/Extension/API.js b/Extension/API.js new file mode 100644 index 0000000..9904fd5 --- /dev/null +++ b/Extension/API.js @@ -0,0 +1,53 @@ +async function ping(){ + fetch ('http://127.0.0.1:5180/api/ping') + .then(data => { + console.log(data); + }); +} +async function setBaseDataHorseAPI(id, basedata) { + try { + console.log("Setting horse data"); + console.log("ID:", id); // Log ID to ensure it's received correctly + console.log("Basedata:", basedata); // Log the entire horse data to check + + const url = `http://127.0.0.1:5180/api/setHorseBasicData/id=${id}`; + + // Wait for the API call to complete + const response = await fetch(url, { + method: 'POST', + body: JSON.stringify(basedata), + headers: { + 'Content-Type': 'application/json' + } + }); + + const data = await response; // Wait for the response from the API + console.log("API Response:", data); // Log the response from the API + + } catch (error) { + console.error("Error setting horse data: " + error.message); + } +} +async function getHorseAPI(id) { + var horseData; + const url = 'http://127.0.0.1:5180/api/getHorseInfo/id=' + id; + await fetch(url) + .then(response => response.json()) + .then(data => { + horseData = data; + }); + return horseData; +} +async function setHorsePedigreeAPI(id, pedigreeData) +{ + const url = `http://127.0.0.1:5180/api/setHorsePedigree/id=${id}`; + const response = await fetch(url, { + method: 'POST', + body: JSON.stringify(pedigreeData), + headers: { + 'Content-Type': 'application/json' + } + }); + const data = await response; + return data; +} \ No newline at end of file diff --git a/Extension/HR-Collector_Icon.png b/Extension/HR-Collector_Icon.png new file mode 100644 index 0000000..513831f Binary files /dev/null and b/Extension/HR-Collector_Icon.png differ diff --git a/Extension/background.js b/Extension/background.js new file mode 100644 index 0000000..1dba519 --- /dev/null +++ b/Extension/background.js @@ -0,0 +1,58 @@ +importScripts("./API.js"); + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message.action === "updateHorseData") { + updateHorseButton(); // Call the function + } +}); + +async function updateHorseButton() { + console.log("Updating horse data"); + + // Query the active tab + chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { + if (tabs.length === 0) { + console.error("No active tab found."); + return; + } + + const activeTabId = tabs[0].id; + + // First: Get horse basic data + chrome.tabs.sendMessage( + activeTabId, + { action: "getHorseBasicData" }, + async function (response) { + if (!response || !response.success) { + console.error("Failed to get horse data from content script."); + return; + } + + console.log("Horse data received:", response.data); + const horseData = response.data; + + // Check if horse exists via API + const existingHorse = await getHorseAPI(horseData.id); + if (!existingHorse || existingHorse.message === "Horse not found") { + console.warn("Horse not found in the API."); + return; + } + + // Update horse data in the API + await setBaseDataHorseAPI(horseData.id, horseData); + + // Second: Get horse current data + chrome.tabs.sendMessage(activeTabId, { action: "getHorseCurrentData", data: { id: horseData.id } }, function (currentDataResponse) + { + if (!currentDataResponse) { + console.error("Failed to get current horse data."); + return; + } + + console.log("Current horse data received:", currentDataResponse); + } + ); + } + ); + }); +} diff --git a/Extension/content.js b/Extension/content.js new file mode 100644 index 0000000..cd7afe5 --- /dev/null +++ b/Extension/content.js @@ -0,0 +1,89 @@ +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === "getHorseBasicData") { + try { + console.log("Getting horse data"); + + const idString = document.querySelector('.right:nth-child(2)').innerText.replace('#', ''); + // Convert the ID to BigInt + const id = BigInt(idString); // Converts to BigInt, equivalent to ulong in C# + + // Convert BigInt to string before sending + const idStringForResponse = id.toString(); // Convert to string to prevent serialization issues + const horseData = { + id: idStringForResponse || "", // Stelle sicher, dass die ID vorhanden ist + age: parseInt(document.querySelector('.right:nth-child(6)').innerText, 10) || 0, // Alter muss eine Zahl sein + name: document.title.replace(/ - Horse Reality.*$/, '') || "Unknown", // Name darf nicht leer sein + gender: document.querySelector('img.icon16')?.alt || "Unknown", // Geschlecht prüfen + breed: document.querySelector('.right:nth-child(4)')?.innerText || "Unknown", // Rasse prüfen + link: window.location.href || "" // Link sicherstellen + }; + + + console.log("Horse data gathered:", horseData); + + // Sending response back to background script + sendResponse({ success: true, data: horseData }); + + } catch (error) { + console.error("Error gathering horse data: " + error.message); + sendResponse({ success: false, message: "Error gathering horse data: " + error.message }); + } + } + else if (request.action === "getHorseCurrentData") + { + console.log("Getting current horse selected tab data"); + var selectedTab = getTabselText(); + console.log("Selected tab:", selectedTab); + if (selectedTab === "Summary") + { + var relatedHorses = Array.from(document.querySelectorAll('.pedigree a')).map(link => link.href); + var response = setHorsePedigreeAPI(request.data.id, relatedHorses); + console.log("Response from API:", response); + sendResponse({ success: true, data: response }); + } + else if (selectedTab === "Training") + { + var training = document.querySelector('.top:nth-child(8)') ? document.querySelector('.top:nth-child(8)').innerText : document.querySelector('.top:nth-child(6)').innerText; + var response = setHorseTrainingAPI(request.data.id, training); + console.log("Response from API:", response); + sendResponse({ success: true, data: response }); + } + else if (selectedTab === "Genetics") + { + const colorGenetics = Array.from(document.querySelectorAll('.genetic_result')).map(x => x.innerText); + const geneticPotential = Array.from(document.querySelectorAll('.genetic_stats')) + .map(x => x.innerText.trim()) + .filter(value => !isNaN(value) && value !== "") + .map(value => parseFloat(value)); + const totalGeneticPotential = (Array.from(document.querySelectorAll('.top div')).find(el => el.innerText.includes('GP'))?.innerText || "").replace("GP total: ", "").trim(); + + var response = setHorseGeneticsAPI(request.data.id, colorGenetics); + console.log("Response from API:", response); + sendResponse({ success: true, data: response }); + } + else if (selectedTab === "Achievements") + { + var genetics = Array.from(document.querySelectorAll('.genetic_stats')).map(x => x.innerText).filter(text => /poor|below average|average|good|very good/i.test(text)); + var response = setHorseGeneticsAPI(request.data.id, genetics); + console.log("Response from API:", response); + } + else if (selectedTab === "Health") + { + var health = [...document.querySelector("#tab_health2 p").innerText.matchAll(/:\s*(\w+)/g)].map(match => match[1]); + var response = setHorseHealthAPI(request.data.id, health); + console.log("Response from API:", response); + } + else + { + console.error("Unknown or no tab selected."); + } + } + return true; // This is necessary to allow asynchronous response +}); +function getTabselText() { + const tabElement = document.querySelector('div.tabsel'); + if (tabElement) { + return tabElement.textContent.trim(); + } + return null; +} \ No newline at end of file diff --git a/Extension/horse.js b/Extension/horse.js new file mode 100644 index 0000000..f5d2da6 --- /dev/null +++ b/Extension/horse.js @@ -0,0 +1,72 @@ +// Modell für ein Pferd +var globalHorse = { + // Basic + id: null, // ID of the horse + age: null, // age of the horse + horse_name: null, // name of the horse + gender: null, // gender of the horse + breed: null, // breed of the horse + link: null, // link to the horse's page + + // Summary, Pedigree + relatedIds: [], // IDs of related horses + // Training + training: null, // training of the horse e.g. Basic Training + // Genetics + GP: 0, // GP of the horse + features: {}, // features of the horse e.g. Dressage, Driving, Endurance etc. + // Genes + Extension: null, // Extension gene of the horse + Agouti: null, // Agouti gene of the horse + Grey: null, // Grey gene of the horse + Cream: null, // Cream gene of the horse + Dun: null, // Dun gene of the horse + Champagne: null, // Champagne gene of the horse + Silver: null, // Silver gene of the horse + Mushroom: null, // Mushroom gene of the horse + Frame: null, // Frame gene of the horse + Appaloosa: null, // Appaloosa gene of the horse + PATN1: null, // PATN1 gene of the horse + MITF: null, // MITF gene of the horse + SW2: null, // SW2 gene of the horse + KIT: null, // KIT gene of the horse + + RAB: null, // RAB gene of the horse + Seal: null, // Seal gene of the horse + Flaxen: null, // Flaxen gene of the horse + + // Achievements + conformation: {}, // conformation of the horse e.g. Walk, Trot, Canter, Gallop, Jumping, Dressage + shortConformation : null, // Short conformation of the horse (e.g. 12VG) + maxShowResult: 0, // max show result of the horse + minShowResult: 0, // min show result of the horse + maxCompetitionResult: 0, // max competition result of the horse + minCompetitionResult: 0, // min competition result of the horse + + // Health + fertility: null, // fertility of the horse + colicRestance: null, // colic resistance of the horse + hoofQuality: null, // hoof quality of the horse + backProblems: null, // back problems of the horse + respiratoryDisease: null, // respiratory disease of the horse + resistanceToLameness: null, // resistance to lameness of the horse +}; + +function createNewHorse(id, age, horse_name, gender, breed, link) { + globalHorse = new globalHorse(); +} + + +// Funktion zum Setzen von Daten +function setHorseData(id, age, horse_name, gender, breed, link) { + globalHorse.id = id; + globalHorse.age = age; + globalHorse.horse_name = horse_name; + globalHorse.gender = gender; + globalHorse.breed = breed; + globalHorse.link = link; +} + +function getHorseData() { + return globalHorse; +} \ No newline at end of file diff --git a/Extension/init.html b/Extension/init.html new file mode 100644 index 0000000..277a7fc --- /dev/null +++ b/Extension/init.html @@ -0,0 +1,9 @@ + + + + + +

+ + + diff --git a/Extension/manifest.json b/Extension/manifest.json new file mode 100644 index 0000000..759108f --- /dev/null +++ b/Extension/manifest.json @@ -0,0 +1,25 @@ +{ + "manifest_version": 3, + "name": "Horse Reality Data Downloader", + "version": "0.0.1", + "permissions": ["tabs", "activeTab", "downloads", "storage"], + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": ["https://www.horsereality.com/*"], + "js": [ + "content.js", + "ui.js", + "API.js" + ] + } + ], + "host_permissions": [ + "http://127.0.0.1:5180/*" + ], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'; connect-src http://127.0.0.1:5180" + } +} diff --git a/Extension/ui.js b/Extension/ui.js new file mode 100644 index 0000000..d7134bf --- /dev/null +++ b/Extension/ui.js @@ -0,0 +1,121 @@ +// Warten, bis das DOM vollständig geladen ist +document.addEventListener("DOMContentLoaded", function () { + // Suche nach dem Element mit der Klasse 'horse_banner' + const banner = document.querySelector('.horse_banner'); + if (banner) { + // Erstelle das container div + const div = document.createElement('div'); + div.className = 'collector_ui'; + Object.assign(div.style, { + position: 'absolute', + right: '-160px', + top: '20px', + zIndex: '1', + padding: '10px', + backgroundColor: '#FFFFFFD9', + width: '120px', + minHeight: '50px', + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + gap: '10px' // Abstand zwischen Button und Tabelle + }); + + // Erstelle den Button + const updateHorseButton = document.createElement('updateHorseButton'); + updateHorseButton.textContent = 'Update Horse'; + Object.assign(updateHorseButton.style, { + padding: '10px 15px', + backgroundColor: '#ffa200', + color: '#fff', + border: 'none', + borderRadius: '5px', + cursor: 'pointer', + alignSelf: 'stretch', // Button auf volle Breite dehnen + transition: 'background-color 0.3s ease' // Übergang für den Hover-Effekt + }); + updateHorseButton.addEventListener("click", function() { + chrome.runtime.sendMessage({ action: "updateHorseData" }); + }); + + // Hover-Effekt hinzufügen + updateHorseButton.addEventListener('mouseenter', function () { + updateHorseButton.style.backgroundColor = '#bf8700'; // Hover-Farbe + }); + updateHorseButton.addEventListener('mouseleave', function () { + updateHorseButton.style.backgroundColor = '#ffa200'; // Originalfarbe + }); + + // Flex-Container für die Tabelle + const table = document.createElement('div'); + Object.assign(table.style, { + display: 'flex', + flexDirection: 'column', + width: '100%', + gap: '12px' // Abstand zwischen den Zeilen + }); + + // Beschriftungen und Emoji-Elemente + const rows = [ + { label: 'Basic', emojiId: 'emojiBasic', emoji: '❌' }, + { label: 'Summary', emojiId: 'emojiSummary', emoji: '❌' }, + { label: 'Training', emojiId: 'emojiTraining', emoji: '❌' }, + { label: 'Genetics', emojiId: 'emojiGenetics', emoji: '❌' }, + { label: 'Achievements', emojiId: 'emojiAchievements', emoji: '❌' }, + { label: 'Health', emojiId: 'emojiHealth', emoji: '❌' }, + ]; + + // Erstelle Zeilen für jede Beschriftung + rows.forEach(row => { + const rowDiv = document.createElement('div'); + Object.assign(rowDiv.style, { + display: 'flex', + justifyContent: 'space-between', // Beschriftung links, Emoji rechts + width: '100%' + }); + + // Linkes Element für die Beschriftung + const labelCell = document.createElement('div'); + labelCell.textContent = row.label; + labelCell.style.flex = '1'; // Beschriftung auf der linken Seite + + // Rechtes Element für das Emoji + const emojiCell = document.createElement('div'); + const emojiSpan = document.createElement('span'); + emojiSpan.id = row.emojiId; + emojiSpan.textContent = row.emoji; + emojiCell.appendChild(emojiSpan); + emojiCell.style.flex = '0'; // Emoji auf der rechten Seite + + // Zeile zur Tabelle hinzufügen + rowDiv.appendChild(labelCell); + rowDiv.appendChild(emojiCell); + table.appendChild(rowDiv); + }); + const infoTextLoaded = document.createElement('p'); + infoTextLoaded.textContent = '✅ Loaded'; + infoTextLoaded.justifyContent = 'space-between'; + infoTextLoaded.width = '100%'; + const infoTextDynamic = document.createElement('p'); + infoTextDynamic.textContent = '☑️ Dynamic'; + infoTextDynamic.justifyContent = 'space-between'; + infoTextDynamic.width = '100%'; + const infoTextNeedRefresh = document.createElement('p'); + infoTextNeedRefresh.textContent = '🔄 Needs Refresh'; + infoTextNeedRefresh.justifyContent = 'space-between'; + infoTextNeedRefresh.width = '100%'; + const infoTextNotLoaded = document.createElement('p'); + infoTextNotLoaded.textContent = '❌ Not Loaded'; + infoTextNotLoaded.justifyContent = 'space-between'; + infoTextNotLoaded.width = '100%'; + + // Button oben hinzufügen, dann die Tabelle + div.appendChild(updateHorseButton); + div.appendChild(table); + div.appendChild(infoTextLoaded); + div.appendChild(infoTextDynamic); + div.appendChild(infoTextNotLoaded); + div.appendChild(infoTextNeedRefresh); + banner.appendChild(div); + } +});