Skip to content

Instantly share code, notes, and snippets.

@muhdiboy
Last active June 21, 2023 02:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muhdiboy/27568d2f55f3e2b4b622668a07287e1b to your computer and use it in GitHub Desktop.
Save muhdiboy/27568d2f55f3e2b4b622668a07287e1b to your computer and use it in GitHub Desktop.
Mediamarkt Handy Tarife On-Site Calculator script

Mediamarkt Handy Tarife Kalkulation

Dies ist ein UserScript, mit dem auf der Mediamarkt Tarifwelt "Smartphones mit Vertrag" Seite (https://tarife.mediamarkt.de/smartphones/) die Gesamtsumme von jedem angebotenen Vertrag eines Smartphones berechnet wird.

Funktion

Es wird die monatliche Grundgebühr, der einmalige Anschluss- und Gerätepreis inkl. Versand sowie jeglicher Bonus (z.B. Rufnummernmitnahme) mit einbezogen. Daraus wird dann eine neue Summe (für 2 Jahre) und ein neuer monatlicher Durchschnittspreis ermittelt.

Anhand dessen können alle Verträge neu sortiert werden, indem sie nach Gesamtpreis aufsteigend geordnet werden. Es ist außerdem möglich, einen Verkaufspreis einzugeben, falls man vorhat, das Gerät zu verkaufen. Daraus ergibt sich dann eine neue Summe und ein neuer monatlicher Durchschnittspreis.

Voraussetzungen

Man benötigt einen UserScript-Interpreter/Injektor-Plugin und einen kompatiblen Browser.

  • Für Google Chrome und Chromium-basierte Browser (z. B. Vivaldi, Opera oder Brave) benötigt man das Tampermonkey-Plugin. Einfach auf den Link klicken oder selbst im Chrome Web Store danach suchen und die Erweiterung hinzufügen.
  • Für Firefox benötigt man ebenfalls das Tampermonkey-Plugin (oder alternativ Greasemonkey). Einfach auf einen der gewünschten Links klicken oder selbst auf der Firefox Browser Add-Ons Seite danach suchen.

Skript-Installation

Einfach auf die Schaltfläche "Raw" in der oberen rechten Ecke der Skriptdatei oder hier klicken. Die Erweiterung sollte ein Installationsfenster öffnen, in dem man die Installation des UserScripts bestätigen kann.

Nutzungshinweise

Darstellung

Auf der rechten Seite der Webseite werden Buttons dargestellt, die vom Skript erstellt werden. Die Gesamtsumme und der monatliche Durchschnittspreis werden neben der monatlichen Grundgebühr eingefügt.

Buttons

  • Load all: lädt alle Verträge auf der Seite.
  • Calculate: berechnet den Gesamtpreis und den monatlichen Durchschnittspreis.
  • Order € > €€: sortiert alle angezeigten Verträge aufsteigend basierend auf dem Gesamtpreis.
  • Selling Price: ist ein Eingabefeld für den Verkaufspreis.
  • Subtract: zieht den eingegebenen Verkaufspreis von den Verträgen ab und errechnet einen neuen Gesamtpreis und einen neuen monatlichen Durchschnittspreis.

Sonstiges

  • Jeder Button kann alleine benutzt werden.
    • Das Neusortieren berechnet auch direkt den Gesamtpreis und den monatlichen Durchschnittspreis. Gleiches gilt für das Abziehen des Verkaufspreises.
  • Beim Neuladen der Seite gehen alle Änderungen verloren.
  • Es wird nichts im Browser gespeichert.

Zukünftige Updates

  • Die Buttons könnten etwas dynamischer auf die Auflösung reagieren.
  • Ein Tooltip mit der angewandten Berechnung könnte neben der Summe angezeigt werden.
// ==UserScript==
// @name Mediamarkt Handy Tarife Calculator
// @namespace https://gist.github.com/muhdiboy
// @version 1.1
// @downloadURL https://gist.github.com/muhdiboy/27568d2f55f3e2b4b622668a07287e1b/raw/mediamarkt-handy-tarife-calculator.user.js
// @updateURL https://gist.github.com/muhdiboy/27568d2f55f3e2b4b622668a07287e1b/raw/mediamarkt-handy-tarife-calculator.user.js
// @description Calculate and display the total sum and average monthly cost of subscription prices on the webpage, taking into account all bonuses and the option to sell the device
// @author muhdiboy
// @match https://tarife.mediamarkt.de/smartphones/*/*
// @grant none
// ==/UserScript==
(function() {
// Set default values
const months = 24;
let subtractValue = 0;
// Add the buttons to the page
addLoadButton();
addCalculateButton();
addReorderButton();
addContainerDiv();
// Function to append the sum and new monthly to the value of priceElement
function appendSumToPrice() {
// Find the elements that represent subscription options
const subscriptionOptions = document.querySelectorAll('[class*="OfferList__StyledCol"]');
// Create an array to store the option elements and sums
const optionSums = [];
// Iterate over the subscription options and calculate the sum per option
subscriptionOptions.forEach((option, index) => {
// Remove any previously appended sum
const existingSumElement = option.querySelector('.sum');
if (existingSumElement) {
existingSumElement.remove();
}
// Remove any previously appended monthly cost
const existingmonthlyCostElement = option.querySelector('.monthly');
if (existingmonthlyCostElement) {
existingmonthlyCostElement.remove();
}
// Extract the price information from each option
const priceElement = option.querySelector('[class*="Price__StyledPrice"]');
const pricePart1 = parseFloat(priceElement.textContent.trim());
const pricePart2Element = priceElement.querySelector('sup');
const pricePart2 = parseFloat(pricePart2Element.textContent.trim());
// Calculate the sum for each subscription option
let sum = pricePart1 + (pricePart2 / 100);
sum *= months;
// Extract single-time payments
const singlePaymentElements = option.querySelectorAll('[class*="PriceDisplay__Span"]');
// Iterate over the single-time payments and add them to the sum
singlePaymentElements.forEach((singlePaymentElement) => {
const singlePaymentText = singlePaymentElement.textContent.trim();
// Exclude elements containing a specific text
if (singlePaymentText.includes('Monatlicher Grundpreis')) return; // Skip this element
const singlePayment = parseFloat(singlePaymentText.replace(/[^\d.]/g, ''));
sum += singlePayment;
});
// Extract the change bonus
const changeBonusElements = option.querySelectorAll('[class*="Bulletlist__List-sc"]');
// Iterate over the change bonus and cut them from the sum
changeBonusElements.forEach((changeBonusElement) => {
const changeBonusText = changeBonusElement.textContent.trim();
// Exclude elements containing a specific text
if (!changeBonusText.includes('Wechselbonus')) return; // Skip this element
const changeBonus = parseFloat(changeBonusText.match(/\d+€/));
sum -= changeBonus;
});
// Extract the delivery costs
const deliveryPriceElement = document.querySelector('span[data-codeception="deliveryPrice"] > span[data-codeception="price"]');
const deliveryPriceParts = deliveryPriceElement.textContent.trim().split('\n');
const deliveryPrice = parseFloat(deliveryPriceParts[0].match(/[\d,]/g).join('').replace(',', '.'));
// Subtract the delivery costs
sum += deliveryPrice;
// Store the calculated sum in a separate attribute
priceElement.setAttribute('data-sum', sum);
// Create a new element to display the sum
const sumElement = document.createElement('span');
sumElement.classList.add('sum');
sumElement.style.cssText = priceElementStyles;
sumElement.textContent = `Σ: ${sum.toFixed(2)}`;
// Append the sum element after the price element
priceElement.insertAdjacentElement('afterend', sumElement);
// Calculate monthly cost
const monthlyCost = sum / months;
// Create a container for the monthly cost
const monthlyCostElement = document.createElement('span');
monthlyCostElement.classList.add('monthly');
monthlyCostElement.style.cssText = priceElementStyles;
monthlyCostElement.textContent = `Ø: ${monthlyCost.toFixed(2)}`;
// Append the monthly cost container after the sum element
sumElement.insertAdjacentElement('afterend', monthlyCostElement);
// Modify the font size of the price
pricePart2Element.style.fontSize = '18px';
priceElement.style.fontSize = '24px';
});
}
// Function to reorder the based on the value of sum
function reorderOptions() {
appendSumToPrice(); // Call appendSumToPrice to calculate the sums
const optionSums = Array.from(document.querySelectorAll('[class*="OfferList__StyledCol"]')).map(option => {
const priceElement = option.querySelector('[class*="Price__StyledPrice"]');
const sum = parseFloat(priceElement.getAttribute('data-sum'));
return { option, sum };
});
// Sort the optionSums array based on the sum in ascending order
optionSums.sort((a, b) => a.sum - b.sum);
// Create a temporary container to hold the sorted option elements
const tempContainer = document.createElement('div');
// Append the option elements to the temporary container in the new order
optionSums.forEach(({ option }) => {
tempContainer.appendChild(option);
});
// Clear the existing options container
const optionsContainer = document.querySelectorAll('[class*="FilterSection__StyledRow"] > [class*="Col-sc"] > div > [class*="Row-sc"]');
optionsContainer.innerHTML = '';
// Append the sorted option elements back to the options container
optionsContainer.forEach((container) => {
optionSums.forEach(({ option }) => {
container.appendChild(option);
});
});
}
// Function to subtract the entered value from sum and monthly
function subtractFromSum() {
appendSumToPrice(); // Call appendSumToPrice to calculate the sums
const subtractInput = document.querySelector('input[type="number"]');
subtractValue = parseFloat(subtractInput.value);
const priceElements = document.querySelectorAll('[class*="OfferList__StyledCol"]');
// Iterate over the price elements and subtract the specified value from the sums
priceElements.forEach(function (priceElement) {
const sumElement = priceElement.querySelector('.sum');
const monthlyCostElement = priceElement.querySelector('.monthly');
if (sumElement) {
const sum = parseFloat(sumElement.textContent.replace(/[^\d.]/g, ''));
const newSum = sum - subtractValue;
sumElement.textContent = `Σ: ${newSum.toFixed(2)}`;
const monthlyCost = parseFloat(monthlyCostElement.textContent.replace(/[^\d.]/g, ''));
const newMonthlyCost = newSum / months;
monthlyCostElement.textContent = `Ø: ${newMonthlyCost.toFixed(2)}`;
}
});
}
// Function to load all options
function clickLoadButton() {
const loadButton = document.querySelector('[class*="OfferList__StyledButton"]');
if (loadButton) {
loadButton.click();
setTimeout(clickLoadButton, 100);
}
}
// Buttons, containers and styles
function createSubtractContainer() {
const subtractContainer = document.createElement('div');
subtractContainer.style.display = 'flex';
subtractContainer.style.alignItems = 'center';
const subtractLabel = document.createElement('label');
subtractLabel.textContent = 'Selling Price: ';
subtractContainer.appendChild(subtractLabel);
const inputContainer = document.createElement('div');
inputContainer.style.position = 'relative';
const subtractInput = document.createElement('input');
subtractInput.type = 'number';
subtractInput.min = '0';
subtractInput.style.width = '70px';
subtractInput.style.marginLeft = '10px';
subtractInput.style.border = 'groove';
subtractInput.addEventListener('input', function(event) {
subtractValue = parseFloat(event.target.value);
});
subtractContainer.appendChild(subtractInput);
const subtractButton = document.createElement('button');
subtractButton.textContent = 'Subtract';
subtractButton.style.position = 'fixed';
subtractButton.style.top = '100%';
subtractButton.style.right = '10px';
subtractButton.addEventListener('click', subtractFromSum);
subtractContainer.appendChild(subtractButton);
subtractContainer.appendChild(inputContainer);
return subtractContainer;
}
function addLoadButton() {
const loadButton = document.createElement('button');
loadButton.textContent = 'Load all';
loadButton.style.position = 'fixed';
loadButton.style.top = '50%';
loadButton.style.right = '20px';
loadButton.style.transform = 'translateY(-50%)';
loadButton.addEventListener('click', clickLoadButton);
document.body.appendChild(loadButton);
}
function addCalculateButton() {
const calculateButton = document.createElement('button');
calculateButton.textContent = 'Calculate';
calculateButton.style.position = 'fixed';
calculateButton.style.top = '53%';
calculateButton.style.right = '20px';
calculateButton.style.transform = 'translateY(-50%)';
calculateButton.addEventListener('click', appendSumToPrice);
document.body.appendChild(calculateButton);
}
function addReorderButton() {
const reorderButton = document.createElement('button');
reorderButton.textContent = 'Order € > €€';
reorderButton.style.position = 'fixed';
reorderButton.style.top = '56%';
reorderButton.style.right = '20px';
reorderButton.style.transform = 'translateY(-50%)';
reorderButton.addEventListener('click', reorderOptions);
document.body.appendChild(reorderButton);
}
function addContainerDiv() {
const containerDiv = document.createElement('div');
containerDiv.style.position = 'fixed';
containerDiv.style.top = '60%';
containerDiv.style.right = '20px';
containerDiv.style.transform = 'translateY(-50%)';
containerDiv.style.padding = '10px';
const subtractContainer = createSubtractContainer();
containerDiv.appendChild(subtractContainer);
document.body.appendChild(containerDiv);
}
// CSS styles
const priceElementStyles = `
font-family: MMPrice, sans-serif;
letter-spacing: 0.09em;
font-size: 18px;
padding-left: 10px;
text-shadow: rgb(255, 255, 255) 0.04em 0px 0px, rgb(255, 255, 255) -0.04em 0px 0px, rgb(255, 255, 255) 0px -0.04em 0px, rgb(255, 255, 255) 0px 0.04em 0px, rgb(255, 255, 255) 0.04em 0.04em 0px, rgb(255, 255, 255) 0.04em -0.04em 0px, rgb(255, 255, 255) -0.04em -0.04em 0px, rgb(255, 255, 255) -0.04em 0.04em 0px, rgba(0, 0, 0, 0.2) 0.1em 0px 0.05em, rgba(0, 0, 0, 0.2) 0px 0.1em 0.05em, rgba(0, 0, 0, 0.2) 0.1em 0.1em 0.05em;
`;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment