Greasy Fork is available in English.
Erweiterung der Produkt Übersicht von Amazon Vine
// ==UserScript== // @name Vine Viewer // @namespace http://tampermonkey.net/ // @version 1.03 // @description Erweiterung der Produkt Übersicht von Amazon Vine // @author Christof // @match *://www.amazon.de/vine/* // @match *://amazon.de/vine/* // @match *://www.amazon.de/-/en/vine/* // @license MIT // @grant GM.xmlHttpRequest // @grant GM.openInTab // @grant unsafeWindow // @connect greasyfork.org // ==/UserScript== (function() { 'use strict'; //#################################################################### // Settings //#################################################################### // Debug Modus // Beim Debug wird die Version automatisch auf 0.0 gesetzt // true = Debug ausgabe in der Konsole des Brwosers // false = Keine Ausgabe var debug = false; // Angabe der Zeit die beim Auto Scan mindestens mit der Weiterleitung gewartet werden soll var redirectMinTime = 2; // Angabe in Sekunden // Angabe der Zeit die beim Auto Scan maximal mit der Weiterleitung gewartet werden soll var redirectMaxTime = 5; // Angabe in Sekunden // Angabe der Zeit wie lange die Meldung eines Updates angezeigt werden soll var updateMessageDuration = 15; // Angabe in Sekunden //#################################################################### // Dont change anything below this //#################################################################### var url; var allData; let redirectTimeout; var addDate; var openList = false; var isSettingsOpen = false; var popupDefaultCount; //################################################## // Der Wert darf nicht unter 24 Stunden gesetzt werden! // Vorgabe von Greasy Fork! var updateCheckInterval = 24; // Angabe in Stunden //################################################## var updateerror; var scriptURL = "https://greasyfork.org/de/scripts/471094"; var lastUpdateCheck; //Einstellungen der IndexedDB const dbName = "VineData"; const dbVersion = 1; const objectStoreName = "Products"; // Einstellungs Menü Optionen const id = [ // Aktuell nur color und checkbox als Type unterstützt //[ID,Label,Type] ["colorHighlight","Highlight Farbe","color"], ["toggleHighlight","Ausblenden","checkbox"], ["toggleScan","Nur Sichtbares Cachen","checkbox"], ["toggleDate","Datum anzeigen","checkbox"], ["toggleRecom","Empfehlungen ausblenden","checkbox"], ["toggleFooter","Footer ausblenden","checkbox"] ]; var uiContainerCSS = ` position: fixed; bottom: 0px; z-index: 9999; background-color: transparent !important; pointer-events: none !important; width: auto; height: auto; ` // CSS UI Button var uiSettingCSS = ` left: 10px; bottom: 10px; z-index: 9999; width: 30px; height: 30px; margin: 5px; background-color: #232f3e; border: black 2px solid; border-radius: 10px; display: flex; justify-content: center; align-items: center; cursor: pointer; opacity: 1; transition: opacity 0.2s, bottom 0.2s ease 0s; pointer-events: auto !important; `; // CSS UI List Button var uiListCSS = ` left: 10px; bottom: 50px; z-index: 9999; width: 30px; height: 30px; margin: 5px; background-color: #232f3e; border: black 2px solid; border-radius: 10px; display: flex; justify-content: center; align-items: center; cursor: pointer; opacity: 1; transition: bottom 0.2s; pointer-events: auto !important; ` var uiSettingsIconCSS = ` cursor: pointer; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; ` var uiButtonContentCSS = ` font-size: 1.75vh; ` //CSS Settings Menu var settingPopupCSS = ` left: 10px; bottom: 10px; width: 30px; height: 30px; margin: 5px; z-index: 9999; border: black 2px solid; border-radius: 10px; background-color: #232f3e; transition: width 0.2s, height 0.2s, bottom 0.2s ease 0s;; color: white; pointer-events: auto; display: flex; justify-content: center; align-items: center; ` var settingPopupContentCSS = ` width: 100%; height: 100%; opacity: 0; position: relative; transition: opacity 0.2s; ` var topDivCSS = ` margin-bottom: 5px; ` var settingPopupCloseButton = ` width: 25px; height: 25px; cursor: pointer; position: absolute; top: 0; right: 0; text-align: center; ` var titleDivCSS = ` width: 100%; height: 25px; display: flex; justify-content: center; align-items: center; font-weight: bold; ` var titleDivContentCSS = ` transform: scale(1); transition: transform 0.5s; ` var settingPopupItemListCSS = ` width: 100%; height: auto; ` var settingPopupItemCSS = ` width: 100%; height: 25px; display: flex; ` var settingPopupItemLeftCSS = ` height: 100%; width: 15%; display: flex; justify-content: center; align-items: center; /* border-right: 1px solid black; */ ` var settingPopupItemRightCSS = ` height: 100%; width: 85%; display: flex; align-items: center; ` var settingFooterCSS = ` width: 100%; /* background-color: white; */ height: 25px; position: absolute; bottom: 0px; justify-content: center; display: flex; ` //Css Update Message Div var updateMessageDivCSS = ` display: none; align-items: center; justify-content: center; margin: 5px; left: 10px; bottom: 10px; width: fit-content; max-width: 500px; overflow-wrap: break-word; height: auto; z-index: 9999; border: black 2px solid; border-radius: 10px; background-color: red; opacity: 0; transition: height 0.2s, opacity 0.2s; color: white; pointer-events: auto !important; ` var updateMessageContentCSS = ` padding: 3px 10px; ` // CSS für den Button zum Löschen der Daten var updateButtonCSS = ` height: 20px; line-height: 20px; padding: 0 10px; background-color: transparent; border: none; color: white; cursor: pointer; `; // CSS für die hervorgehobenen Produkte var highlightedProductCSS = ` background-color: lightgreen !important; border: 1px solid black; `; // CSS für das hinzugefügte Datumselement var dateElementCSS = ` justify-content: center; height: 0px; margin: 0; width: 90%; display: flex; `; //CSS Fav Element var favCSS = ` float: right; display: flex; margin: 0; color: white; height: 0; font-size: 25px; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; cursor: pointer; ` // CSS für das hinzugefügte Favorite Icon var favElementCSS = ` display: inline-flex; justify-content: center; height: auto; font-size: 3vh; width: 10% `; // CSS für die Favoriten var favElementCSShighlighted = ` color: yellow; `; var popupCSS = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 75%; height: 75%; background-color: white; box-shadow: rgba(0, 0, 0, 0.9) 0px 0px 50px 10px; border: 1px solid black; padding: 10px; z-index: 999; border-radius: 15px; `; var popupInnerCSS = ` width: 100%; height: 100%; `; var popupBackgroundDivCSS = ` width: 100%; height: 100%; position: fixed; top: 0; z-index: 999; `; var popupTopContainerCSS = ` width: 100%; height: 140px; padding: 5px; `; var popupTopContainerItemCSS = ` padding-right: 5px; `; var popupContentContainerCSS = ` width: 100%; height: calc(100% - 140px); overflow-y: auto; padding: 10px; `; var popupTopContainerSelectCSS = ` padding: 5px; align-items: center; justify-content: center; display: flex; `; var popupTopContainerPagesCSS = ` padding: 5px; align-items: center; justify-content: center; display: flex; `; var listProductContainerCSS = ` display: flex; align-items: center; margin-bottom: 10px; margin-right: 10px; height: 100px; opacity: 1; transition: height 2s ease, opacity 1s ease, margin-bottom 2s ease; `; var popupContainerItemsSpanCSS = ` margin-right: 10px; `; var popupDisplayPagesCSS = ` margin-left: 10px; margin-right: 10px; `; var listImageElementCSS = ` width: 100px; height: 100px; object-fit: cover; margin-right: 10px; `; var listDateElementCSS = ` margin-right: 10px; width: 100px; text-align: center; `; var listTitleElementCSS = ` flex: 1; `; var listButtonContainerCSS = ` display: flex; align-items: center; `; var listButtonSpanCSS = ` width: 125px; text-align: right; `; // Funktion Aufrufen um eine verbindung mti der Datenbank herzustellen window.addEventListener("DOMContentLoaded", connectDatabase()); // Laden der Einstellungen async function loadSettings(){ for(var x = 0; x < id.length; x++){ var ItemUID = id[x][0]; var value = getToggleStatus(ItemUID); switch (ItemUID) { case "toggleScan": break; case "toggleDate": addDate = value; break; case "toggleRecom": toggleRecommendations(value) break; case "toggleFooter": toggleFooter(value); break; } } //localStorage.getItem("popupDefaultCount") if(localStorage.getItem("popupDefaultCount") == null){ popupDefaultCount = 25; localStorage.setItem("popupDefaultCount", popupDefaultCount) console.log("Default Wert für Popup Count nicht gesetzt. Setze auf Standart Wert: " + popupDefaultCount); }else{ popupDefaultCount = parseInt(localStorage.getItem("popupDefaultCount")); } var updateAvailable = localStorage.getItem("updateAvailable"); if(updateAvailable == null){ //localStorage.setItem("updateAvailable", false); updateAvailable = false; } if(localStorage.getItem("autoScan") == null){ localStorage.setItem("autoScan", false) console.log("Default Wert für AutoScan nicht gesetzt. Wert auf Deafult gesetzt: " + false); }else{ popupDefaultCount = parseInt(localStorage.getItem("popupDefaultCount")); } if(localStorage.getItem("lastUpdateCheck") == null){ localStorage.setItem("lastUpdateCheck",Date()); lastUpdateCheck = new Date(); }else{ lastUpdateCheck = localStorage.getItem("lastUpdateCheck"); } } // Überprüft ob ein Update verfügbar ist. Der Check wird Standartmäßig nur alle 24 Stunden durchgeführt. async function checkUpdate(){ if(debug){console.log("Prüfe auf Updates")}; // Wert aus Speicher in ein Datum Objekt konvertieren var lastUpdateCheckObj = new Date(lastUpdateCheck) // Errechnung der verbleibenen Zeit zwischen jetzt und letzer Prüfung var lastUpdateCheckDiff = ((new Date() - lastUpdateCheckObj) / (1000 * 60 * 60)); // Konvertieren des Datums in ein lesbares Format var lastUpdateCheckLog = new Date(lastUpdateCheck).toLocaleString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit', day: '2-digit', month: '2-digit', year: 'numeric' }); if(debug){console.log("Letzte Überprüfung auf Updates: " + lastUpdateCheckLog);}; // Überprüfen ob Timeout zwischen den Überprüfungen abgelaufen ist if(updateCheckInterval <= lastUpdateCheckDiff || localStorage.getItem("newVersion") == null){ // Setzte das Datum der letzten Überprüfung auf jetzt localStorage.setItem("lastUpdateCheck",Date()); try{ // Abfrage der Version var version = await getVersion(); // Überprüfung ob die Installierte Verion die gleiche Version auf GreasyFork ist if(GM_info?.script?.version != version){ if(debug){console.log("Version " + version + " verfügbar");}; // Lokal Speichern das ein Update verfügbar ist localStorage.setItem("updateAvailable", true); localStorage.setItem("newVersion", version); return true; }else{ // Lokal Speichern das kein Update verfügbar ist console.log("Aktuellste Version installiert"); localStorage.setItem("updateAvailable", false); return false; } } catch (error) { // Ausgabe des Fehlers bei der Abfrage des Updates updateerror = error; console.log("Es gab einen Fehler bei der Versions Abfrage"); console.log("Fehler: " + error); return "error"; } }else{ if(debug){ console.log("Intervall zu gering. Prüfen auf Updates erfolgen nur 1x am Tag."); } // Angabe wann das nächste Update durchgeführt werden kann var nextUpdateCheck = new Date(lastUpdateCheckObj.getTime() + (updateCheckInterval * 60 * 60 * 1000)); var nextUpdateCheckLog = new Date(nextUpdateCheck).toLocaleString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit', day: '2-digit', month: '2-digit', year: 'numeric' }); if(debug){console.log("Nächste Überprüfung Erfolgt: " + nextUpdateCheckLog);}; return "intervall" } } // Abfrage der Version von Greasyfork async function getVersion(){ return new Promise((res, rej) => { GM.xmlHttpRequest({ url: `https://greasyfork.org/scripts/471094.json`, onload: response => { const data = JSON.parse(response.responseText) // Wenn Debug aktiv wird der Wert auf 0.0 gesetzt, um die Update Funktion zu testen if(debug){ return "0.0" } else { return res(data["version"]) }; }, onerror: err => { return rej(err) } }) }) } // Erzeugen der Updatemeldung async function updateMessage() { var msg; var onClick; // Abfrage einer neuer Version switch(await checkUpdate()) { // Update verfügbar case true: var version = localStorage.getItem("newVersion"); msg = "Version " + version + " verfügbar"; onClick = 'window.open(scriptURL, "_blank");' notification(msg, onClick); //updateMessageContent.addEventListener('click', function() { // window.open(scriptURL, "_blank"); //}); break; // Kein Update verfügbar case false: break; // Intervall noch nicht abgelaufen case "intervall": version = localStorage.getItem("newVersion"); // Installierte Verion weicht von neuer Version ab if(GM_info?.script?.version != version){ if(debug){console.log("Neue Version vorhanden, intervall nicht abgelaufen, lade aus Local");}; // Erzeugung der Meldung msg = "Version " + version + " verfügbar"; onClick = 'window.open(scriptURL, "_blank");' notification(msg, onClick); //updateMessageContent.addEventListener('click', function() { // window.open(scriptURL, "_blank"); //}); } break; // Fehler bei der Abfrage case "error": msg = "Fehler Überprüfen von Updates"; onClick = alert("Error: " + updateerror); notification(msg, onClick); //updateMessageContent.addEventListener('click', function() { // alert("Error: " + updateerror); //}); break; } } // Ein / Ausblenden der Nachricht function notification(msg, onClickAction){ if(onClickAction == null || onClickAction == undefined){ onClickAction = ""; } // Update Div erstellen var updateMessageDiv = document.createElement('div'); updateMessageDiv.style.cssText = updateMessageDivCSS; updateMessageDiv.setAttribute('id', 'ui-update'); updateMessageDiv.hidden = true; // Content Div des Update Divs erstellen var updateMessageContent = document.createElement('div'); updateMessageContent.style.cssText = updateMessageContentCSS; updateMessageContent.textContent = msg; // Content Div dem Update Div als Child hinzufügen updateMessageDiv.appendChild(updateMessageContent); // Hinzufügen des Elementes zur Seite var uiContainer = document.getElementById('ui-container') uiContainer.appendChild(updateMessageDiv); updateMessageContent.addEventListener('click', function() { try{ eval(onClickAction); } catch(error) { console.log("Fehler beim Anzeigen der Nachricht"); console.log(error); } }); // Verzögerung bevor die Nachricht setTimeout(() => { // Nachricht aktivieren mit Flex updateMessageDiv.style.display = "flex"; // Anzeigen der Nachricht mit einer kurzen verzögerung setTimeout(() => { updateMessageDiv.hidden = false; updateMessageDiv.style.cursor = "pointer"; updateMessageDiv.style.opacity = "1"; }, 200); }, 100); //Meldung ausblenden nach x Sekunden | Dauer der Einblendungen kann in den Einstellungen geändert werden setTimeout(() => { updateMessageDiv.hidden = true; updateMessageDiv.style.height = "0px"; updateMessageDiv.style.opacity = "0"; // 200ms (Zeit Animation) Warten bis die Nachricht ausgeblendet wird setTimeout(() => { updateMessageDiv.style.display = "none"; }, 200); }, (updateMessageDuration * 1000)); } // Funktion wird nach dem vollständigen Laden der Seite aufgerufen function connectDatabase(){ // Verbindungsaufbau zur Datenbank const request = indexedDB.open(dbName, dbVersion); // Fehler Verbindung Datenbank request.onerror = function(event) { console.log("Fehler beim Öffnen der Datenbank"); }; // Verbindung erfolgreich request.onsuccess = function(event) { console.log("Verbindung zur Datenbank hergestellt"); main(); }; // Falls neue Version von Datenbank vorhanden request.onupgradeneeded = function(event) { const db = event.target.r###lt; const objectStore = db.createObjectStore(objectStoreName, { keyPath: "ID" }); console.log("Problem mit der Datenbank"); }; } // Funktion zum Erstellen des UI async function createUI(){ var uiContainer = document.createElement('div'); uiContainer.style.cssText = uiContainerCSS; uiContainer.setAttribute('id', 'ui-container'); document.body.prepend(uiContainer); // Aufrufen der Funktion zum erstellen des Inhaltes des Einstellungsfensters await createsettingPopup(); // Erstellen des Elementes für die Produktliste var addListButton = document.createElement("div"); addListButton.setAttribute('id', 'ui-list'); addListButton.style.cssText = uiListCSS; // Click Event der Produktliste addListButton.addEventListener('click', function() { // Funktion aufrufen zum erstellen der Produktliste createPopup(); }); // Inhalt des Produktlisten Buttons erstellen var addListButtonContent = document.createElement('span'); addListButtonContent.textContent = '📋'; addListButtonContent.style.cssText = uiButtonContentCSS; // Hinzufügen des Produktlisten Buttons zur Website addListButton.appendChild(addListButtonContent); uiContainer.appendChild(addListButton); //document.body.prepend(uiContainer); } // Erstellen des Einstellungen Menüs async function createsettingPopup(){ // Div Element der Einstellungen öffnen var settingPopup = document.createElement('div'); settingPopup.setAttribute('id', 'ui-setting'); settingPopup.style.cssText = settingPopupCSS; //settingPopup.hidden = true; // Einstellungen beim laden der Seite verstecken settingPopup.style.cursor = "pointer"; var settingPopupIconContainer = document.createElement('div'); settingPopupIconContainer.style.cssText = uiSettingsIconCSS var settingPopupIcon = document.createElement('span'); settingPopupIcon.setAttribute('id', 'ui-setting-icon'); settingPopupIcon.textContent = '⚙️'; settingPopupIcon.style.cssText = uiButtonContentCSS; settingPopupIcon.style.cursor = "pointer"; settingPopup.appendChild(settingPopupIconContainer); settingPopupIconContainer.addEventListener('click', function() { if(!isSettingsOpen){ settingPopupIconContainer.hidden = true; settingPopupIconContainer.style.display = "none" settingPopup.style.cursor = "auto"; settingPopup.style.width = "250px"; //settingPopup.style.height = "auto"; settingPopup.style.overflow = "hidden" settingPopup.hidden = false; //settingPopupContent.hidden = false; settingPopupContent.hidden = false; const element = document.getElementById('ui-setting-content'); const pixel = element.scrollHeight; const wpixel = element.scrollWidth; settingPopup.style.height = pixel + "px"; console.log("Height Pixel: " + pixel); console.log("Width Pixel: " + wpixel); setTimeout(() => { settingPopupContent.style.opacity = "1"; isSettingsOpen = true; },200); // 200ms Animationszeit }; }); settingPopupIconContainer.appendChild(settingPopupIcon); settingPopup.appendChild(settingPopupIconContainer); // Div für den Inhalt erstellen var settingPopupContent = document.createElement('div'); settingPopupContent.setAttribute('id', 'ui-setting-content'); settingPopupContent.style.cssText = settingPopupContentCSS; settingPopupContent.hidden = true; var topDiv = document.createElement('div'); topDiv.setAttribute('id', 'ui-top-div'); topDiv.style.cssText = topDivCSS; // Div für den Schließen Button erstellen var closeButton = document.createElement('div'); closeButton.style.cssText = settingPopupCloseButton; // Inhalt des Schließen Buttons erstellen var closeButtonContent = document.createElement('span'); closeButtonContent.textContent = 'X'; closeButtonContent.addEventListener('click', function() { // Close Setting Popup //var uiList = document.getElementById('ui-list'); if(isSettingsOpen){ var uiSettingIcon = document.getElementById('ui-setting-icon'); settingPopupContent.style.opacity = "0"; // rücksetzten der Werte nach ablaufn der Animation setTimeout(() => { settingPopup.style.width = "30px"; settingPopup.style.height = "30px"; settingPopupContent.hidden = true; settingPopup.hidden = true; //uiSettingIcon.hidden = false; settingPopupIconContainer.hidden = false; settingPopupIconContainer.style.display = "flex" isSettingsOpen = false; }, 150); // 150ms -> Animationszeit Opacity }; }); // Titel Div erstellen var titleDiv = document.createElement("div"); titleDiv.style.cssText = titleDivCSS; // Titel Inhalt erstellen var titleDivContent = document.createElement("span"); titleDivContent.style.cssText = titleDivContentCSS; titleDivContent.textContent = "VineViewer Einstellungen" // Div für den Einstellungsbereich erstellen var itemsDiv = document.createElement("div"); itemsDiv.style.cssText = settingPopupItemListCSS // Funktion zum erstellen der Einstellungen async function addItem(ItemID){ // Laden der Einstellungsoptionen aus der Liste (Einstellungsbereich) var ItemUID = id[ItemID][0]; var titel = id[ItemID][1]; var type = id[ItemID][2]; // Erstellung des Containers für die Einstellungen var itemDiv = document.createElement("div"); itemDiv.style.cssText = settingPopupItemCSS; // Linke Spalte der Einstellungen für den Input var itemLeftDiv = document.createElement("div"); itemLeftDiv.style.cssText = settingPopupItemLeftCSS; // Rechte Spalte der Einstellungen für die Bezeichnung var itemRightDiv = document.createElement("div"); itemRightDiv.style.cssText = settingPopupItemRightCSS; // Erstellung der Inputs var toggleSwitch = document.createElement('input'); // type geladen aus der Liste toggleSwitch.setAttribute('type', type); toggleSwitch.setAttribute('id', ItemUID); toggleSwitch.style.bottom = "0px"; toggleSwitch.setAttribute('value', "#FFFFFF"); // Status auf Gespeicherten Wert setzten if(await getToggleStatus(ItemUID) && type == "checkbox"){ toggleSwitch.setAttribute('checked', 'true'); }else if(type == "color"){ var value = await getColorStatus(ItemUID); toggleSwitch.setAttribute('value', value); // Sonder CSS Einstellungen für Color Input toggleSwitch.style.width = "22px"; toggleSwitch.style.height = "22px"; } // Event Listener für äderungen in den Einstellungen toggleSwitch.addEventListener('change', function() { switch(type){ case "checkbox": // Aufrufen und weitergabe des Status settingsClickEvent(ItemUID, this.checked); // Speichern des neuen Wertes saveToggleStatus(ItemUID, this.checked); break; case "color": // Aufrufen und weitergabe des Wertes settingsClickEvent(ItemUID, this.value); // Speichern des neuen Wertes saveColorStatus(ItemUID, this.value); break; } }); // Beschreibung der Einstellungsoption hinzufügen var toggleLabel = document.createElement('label'); toggleLabel.textContent = titel; toggleLabel.setAttribute('for', ItemUID); // Input und Label dem rechten / linken Div hinzufügen itemLeftDiv.appendChild(toggleSwitch); itemRightDiv.appendChild(toggleLabel); // Linke / Rechte Seite dem Einstellungsdiv hinzufügen itemDiv.appendChild(itemLeftDiv); itemDiv.appendChild(itemRightDiv); // Gibt ein Einstellungselement zurück return itemDiv; } // Ausführen für jeden Einstrag in der Liste for(var x = 0 ; x < id.length; x++){ // Erzeugen der Option var Item = await addItem(x); // hinzufügen der Option ins Einstellungsfenster itemsDiv.appendChild(Item); } // Elemente dem Einstellungsfenster hinzufügen closeButton.appendChild(closeButtonContent); titleDiv.appendChild(titleDivContent); topDiv.appendChild(titleDiv); topDiv.appendChild(closeButton); settingPopupContent.appendChild(topDiv); // Container Alle Daten löschen Button erstellen var buttonDeleteDataDiv = document.createElement('div'); // Button Daten löschen erstellen var buttonDeleteData = document.createElement('button'); // Aufrufen der Funktion zur Angabe der Daten in der Datenbank var cachedProductsCount = await getProductCacheLength(); buttonDeleteData.textContent = cachedProductsCount + ' Daten löschen'; buttonDeleteData.style.margin = "13px"; // Click Event für den Delete Button buttonDeleteData.addEventListener('click', function() { // Sicherheitsabfrage ob wirklich alle Daten gelöscht werden sollen var confirmation = confirm('Möchten Sie wirklich alle Daten löschen?'); if (confirmation) { // Wenn auf OK gedrückt Funktion aufrufen um Daten zu löschen clearCachedData(); } }); // Delete Button dem Container hinzufügen buttonDeleteDataDiv.appendChild(buttonDeleteData); // Hinzufügen des Containers in die Einstellungsübersicht itemsDiv.appendChild(buttonDeleteDataDiv); // Erstellen des Footer Containers var settingFooter = document.createElement("div"); settingFooter.style.cssText = settingFooterCSS; // Erstellung der Footer Verlinkung var footerVersionLink = document.createElement("a"); footerVersionLink.textContent = 'Version: ' + GM_info?.script?.version; footerVersionLink.href = scriptURL; footerVersionLink.target = "_blank" footerVersionLink.style.textDecoration = "none" footerVersionLink.style.color = "inherit" // Footer Verlinkung dem Footer Container hinzufügen settingFooter.appendChild(footerVersionLink); // Erstellung des Einstellungen Fensters settingPopupContent.appendChild(itemsDiv); settingPopupContent.appendChild(settingFooter); // Inhalt dem Einstellungs Container hinzufügen settingPopup.appendChild(settingPopupContent); // Einstellungsfenster der Website hinzufügen var uiContainer = document.getElementById('ui-container') uiContainer.appendChild(settingPopup); //document.body.prepend(settingPopup); } // Auswertung der Click Events der Einstellungsoptionen || Umbau auf for schleife (id länge?) async function settingsClickEvent(ItemUID, value){ switch (ItemUID){ case "colorHighlight": highlightCachedProducts(); break; case "toggleHighlight": toggleHighlightVisibility(value); break; case "toggleDate": toggleDate(value); break; case "toggleRecom": toggleRecommendations(value); break; case "toggleFooter": toggleFooter(value); break; } } // Funktion zum anzeigen / Ausblenden des Datums function toggleDate(value) { const dateElements = document.querySelectorAll('[id="p-date"]'); dateElements.forEach(function(element){ if(value){ element.style.display = "flex"; }else{ element.style.display = "none"; } }); } // Funktion zum ausblenden / anzeigen der Amazon Empfehlen (nähe Footer) function toggleRecommendations(value) { const recom = document.getElementById('rhf'); recom.hidden = value; } // Funktion zum ausblenden des Footers function toggleFooter(value){ const footer = document.getElementById('navFooter'); footer.hidden = value; } // Überprüfen ob der Wert des Auto Scan valide ist -> Aktuell keine Verwendung, Funktion wird ggf. später wieder hinzugefügt function checkScanPageInput(value) { var maxPage = getMaxPage(); if(value > maxPage){ console.log("Eingabe fehlerhaft"); return false; } return true; console.log("Eingabe: " + value); } // Funktion zum ein / ausblenden der Hintergrundfarbe der Produkte function toggleHighlightVisibility(checked) { var highlightedDivs = document.getElementsByClassName('highlighted'); for (var i = 0; i < highlightedDivs.length; i++) { var div = highlightedDivs[i]; div.style.display = checked ? 'none' : 'block'; } } // Funktion zum Speichern des Toggle Status der Einstellungen function saveToggleStatus(ItemUID, value){ localStorage.setItem(ItemUID, value); } // Funktion zum Abfragen der Einstellungen aus dem Lokalen Speicher function getToggleStatus(ItemUID){ const toggleStatus = localStorage.getItem(ItemUID); return toggleStatus === 'true'; } // Funktion zum Speichern der Farbe im Einstellungsmenü function saveColorStatus(ItemUID, value){ localStorage.setItem(ItemUID, value); } // Funktion zum Abrufen der Farbe im Einstellungsmenü aus dem Lokalen Speicher function getColorStatus(ItemUID){ const value = localStorage.getItem(ItemUID); return value; } // Funktion zum Löschen der gespeicherten Daten function clearCachedData() { const request = indexedDB.open(dbName, dbVersion); request.onerror = function(event) { console.log("Fehler beim Öffnen der Datenbank"); }; request.onsuccess = function(event) { const db = event.target.r###lt; const transaction = db.transaction([objectStoreName], "readwrite"); const objectStore = transaction.objectStore(objectStoreName); const clearRequest = objectStore.clear(); clearRequest.onsuccess = function(event) { console.log("Datenbankinhalt gelöscht"); localStorage.removeItem('cachedProductIDs'); }; clearRequest.onerror = function(event) { console.log("Fehler beim Löschen des Datenbankinhalts"); }; }; // Nach dem löschen der Daten Seite neu laden location.reload(); } // Funktion zum Hervorheben der gecachten Produkte und Anzeigen des Datums async function highlightCachedProducts() { // umbennenung zu processCachedProducts()? // Ale Produkt Tiles der Seite erfassen var productTiles = document.getElementsByClassName('vvp-item-tile'); // Aufrufen der Funktion um die IDs aus der Datenbank zu ziehen var cachedProductIDs = await getCachedProductIDs(); // Benötigt überarbeitung. Cache soll beim hinzufügen von Daten zur Datenbank auch im Cache ergänz werden. // Jedes Produkt Tile auf der Seite durchlaufen for (var i = 0; i < productTiles.length; i++) { var productTile = productTiles[i]; var productID = getProductID(productTile); // Aufrufen der Funktion zum abfragen der Farbe aus dem Local Storage var color = await getColorStatus("colorHighlight"); var isFav; // Prüfen ob die ID der Product Tile im Cache vorhanden ist if(cachedProductIDs.includes(productID)){ // Prüfen ob das Produkt in der Datenbank vorhanden ist const productInfo = allData.find(data => data.ID === productID); // Class "highlighted" dem Product Tile hinzufügen productTile.classList.add('highlighted'); // ändern der Hintergrundfarbe der Produkte im Cache productTile.style.backgroundColor = color; // Prüfen ob ein Element mit der Class vorhanden ist var dateDiv = productTile.querySelector('#p-date'); if(!dateDiv){ // Wenn Element nicht vorhanden var date = productInfo.Datum; // Funktion zum hinzufügen des Datums aufrufen addDateElement(productTile, date); } } // Funktion aufrufen zum hinzufügen des Favoriten Zeichens addFavElement(productTile, productID); } } // Funktion zum Hinzufügen des Datums zu einem Produkt-Tile async function addDateElement(productTile, date) { var dateElement = document.createElement('div'); dateElement.setAttribute("id", "p-date"); dateElement.hidden = addDate; dateElement.classList.add('highlightCachedProducts'); dateElement.textContent = date; dateElement.style.cssText = dateElementCSS; // Prüfen ob das Datum versteckt oder angezeigt werden soll if(await getToggleStatus("toggleDate")){ dateElement.style.display = "flex"; } else { dateElement.style.display = "none"; } // Datums Element wird an erster stelle dem Content Tile hinzugefügt var contentContainer = productTile.querySelector('.vvp-item-tile-content'); contentContainer.insertBefore(dateElement, contentContainer.firstChild); } // Funktion zum hinzufügen des Favoriten Elements async function addFavElement(productTile, productID){ // Setzen des Standart Wertes var isFav = false; // Abfrage der Product IDs aus der Datenbank var cachedProductIDs = await getCachedProductIDs(); // Beim laden der Seite einmaliges aufrufen von getCachedProductIDs bzgl. Permormance?? // Auslesen des Favoriten Wertes if(cachedProductIDs.includes(productID)){ const productInfo = allData.find(data => data.ID === productID); isFav = productInfo.Favorit; } // Erstellen des Favoriten Elements var favElement = document.createElement('div'); favElement.setAttribute("id", "p-fav"); favElement.style.cssText = favCSS; favElement.textContent = "★"; // Bei Favoriten den Stern in Gelb if(isFav){ favElement.style.color = "#ffe143"; // "#ffe143" = Gelb } // Event Handler beim Clicken auf den Stern favElement.addEventListener('click', async function() { // Verbindung mit der Datenbank herstellen const request = indexedDB.open(dbName, dbVersion); request.onerror = function(event) { console.log("Fehler beim Öffnen der Datenbank ID: FAV"); }; request.onsuccess = function(event) { const db = event.target.r###lt; const transaction = db.transaction([objectStoreName], "readwrite"); const objectStore = transaction.objectStore(objectStoreName); // Suchen der Product ID in der Datenbank const getRequest = objectStore.get(productID); getRequest.onsuccess = function(event) { const data = event.target.r###lt; if (data) { // Beim scannen des sichtbaren Bereiches kommt es hier zu einem fehler, da die ID die sich halb im sichtfeld befindet, noch nicht in der Datenbank eingetragen ist // Neuen Wert für den Favoriten der Datenbank hinzufügen // Abhilfe könnte schaffen das Produkt dann zur Datenbank hinzuzufügen und als Favorit zu setzten, auch wenn es außerhalb dessichtbaren bereiches ist data.Favorit = !isFav; const updateRequest = objectStore.put(data); updateRequest.onsuccess = async function(event) { if(debug){console.log(`Favorit-Wert für ID ${productID} wurde erfolgreich aktualisiert.`)}; // Visuelle Elemente Updaten isFav = !isFav; if(isFav){ favElement.style.color = "#ffe143"; }else{ favElement.style.color = "white"; } // Aktualisieren der Daten allData = await getAllDataFromDatabase(); }; updateRequest.onerror = function(event) { console.log(`Fehler beim Aktualisieren des Favorit-Werts für ID ${productID}.`); }; } else { // Product ID wurde nicht in der Datenbank gefunden console.log(`Datensatz mit ID ${productID} wurde nicht gefunden.`); } }; getRequest.onerror = function(event) { console.log(`Fehler beim Abrufen des Datensatzes mit ID ${productID}.`); }; }; }); // Hinzufügen des Favoriten Elementes zur roduct Tile var contentContainer = productTile; contentContainer.insertBefore(favElement, contentContainer.firstChild); } // Funktion zum Scannen und Zwischenspeichern der Produkte im vollständigem Sichtbereich function scanAndCacheVisibleProducts() { // Zusammenfügen mit scanAndCacheAllProducts()? Teils doppelter Code var productTiles = document.getElementsByClassName('vvp-item-tile'); var visibleProductIDs = []; var visibleProductTitles = []; var visibleProductLinks = []; var visibleProductImages = []; var visibleProductButtons = []; // Durchlaufen aller Product Tiles der Seite for (var i = 0; i < productTiles.length; i++) { var productTile = productTiles[i]; // Aufrufen der Funktion ob sich das Tile im sichtfeld befindet if (isElementVisible(productTile)) { // Aufrufen der Funktion zum abfragen der Produt ID aus dem Product Tile var productID = getProductID(productTile); // Speichern der Product ID im Array der sichtbaren product IDs visibleProductIDs.push(productID); // Abrufen der Daten aus dem Product Tile var contentContainer = productTile.querySelector('.vvp-item-tile-content'); var imageElement = contentContainer.querySelector('img'); var nameElement = contentContainer.querySelector('a span span.a-truncate-full'); var linkElement = contentContainer.querySelector('a'); visibleProductTitles.push(nameElement.textContent); visibleProductLinks.push(linkElement.href); visibleProductImages.push(imageElement.getAttribute('src')); var buttonContainer = productTile.querySelector('span.a-button-inner'); var buttonContent = buttonContainer.innerHTML; visibleProductButtons.push(buttonContent); } } // Aufrufen der Funktion um die Daten in die Datenbank zu speichern cacheProducts(visibleProductIDs, visibleProductTitles, visibleProductLinks, visibleProductImages, visibleProductButtons); } // Hier setzen wir einen Konsolen-Listener //Auto Scan per Befehlszeile starten -> autoscan(5) -> Scannt bis Seite 5 window.autoscan = function(value) { // Rückgabe in der Konsole das der Befehl erkannt wurde console.log('Autoscan gestartet mit Wert:', value); // Aufrufen der Funktion zum Automatischen Scannen, weitergabe des Wertes, bis zu welcher Seite gescannt werden soll AutoScanStart(value); }; // Funktion zum Starten des Automatischen Scans. Variablen und Listen werden vorbereitet function AutoScanStart(scanToPage) { if(debug == true){console.log("Cur: " + getCurrentPage())}; if(debug == true){console.log("Max: " + getMaxPage())}; var currentPage = getCurrentPage(); if(localStorage.getItem("autoScan")=="false"){ localStorage.setItem("autoScan", "true"); localStorage.setItem("potLuck", "false"); localStorage.setItem("lastChance", "false"); localStorage.setItem("startByPageOne", "false"); localStorage.setItem("firstRedirect", "true"); localStorage.setItem('scanToPage', scanToPage); checkForAutoScan(); }else{ clearTimeout(redirectTimeout); localStorage.setItem("autoScan", "false"); console.log("Auto Scan abgebrochen"); url = ""; redirectTimeout = setTimeout(redirectNextPage, 100, url); } } // Funktion zum überprüfen und Steuern des Auto Scans function checkForAutoScan() { // Prüfen ob ein AutoScan aktiv ist if(localStorage.getItem("autoScan")=="true"){ // generieren der Wartezeit der Weiterleitung, basierend auf den Werten der Einstellungen var rand = random(redirectMinTime * 1000, redirectMaxTime * 1000); console.log("AutoScan aktiv!"); // Funktion aufruen um den aktuellen Wert der Seite azufragen var currentPage = getCurrentPage(); var maxPage = localStorage.getItem("scanToPage") var nextPage = getCurrentPage() + 1; // Speichert alle Produckte der Seite, nachdem das erste mal weitergeleitet wurde if(localStorage.getItem("firstRedirect")=="false") { scanAndCacheAllProducts(); } // Prüfen auf welche Seite als nächstes weitergeleitet werden soll if(localStorage.getItem("potLuck")=="false"){ localStorage.setItem("potLuck", "true"); localStorage.setItem("firstRedirect", "false"); console.log("Next Page in: " + rand); url = "https://www.amazon.de/vine/vine-items?queue=potluck"; redirectTimeout = setTimeout(redirectNextPage, rand, url); } else if (localStorage.getItem("lastChance")=="false") { localStorage.setItem("lastChance", "true"); localStorage.setItem("firstRedirect", "false"); console.log("Next Page in: " + rand); url = "https://www.amazon.de/vine/vine-items?queue=last_chance"; redirectTimeout = setTimeout(redirectNextPage, rand, url); } else if (localStorage.getItem("startByPageOne")=="false") { //Weiterleitung auf Page 1 console.log("Redirecting to Page 1 in: " + rand); localStorage.setItem("startByPageOne", "true"); localStorage.setItem("firstRedirect", "false"); url = "https://www.amazon.de/vine/vine-items?queue=encore&pn=&cn=&page=1"; redirectTimeout = setTimeout(redirectNextPage, rand, url); } else { console.log("NextPage: " + nextPage); console.log("Current Page: " + currentPage); // Aktuelle Seite hat den Wert der zu scannenden Seiten erreicht oder den Wert der maximal vorhandenen Seiten überschritten // Auto Scan abgeschlossen if(currentPage >= maxPage) { console.log("Auto Scan Abgeschlossen!"); localStorage.setItem("autoScan", "false"); localStorage.removeItem('scanToPage'); url = ""; redirectTimeout = setTimeout(redirectNextPage, rand, url); return }else{ localStorage.setItem("firstRedirect", "false"); console.log("Next Page in: " + rand); url = "https://www.amazon.de/vine/vine-items?queue=encore&pn=&cn=&page=" + nextPage; redirectTimeout = setTimeout(redirectNextPage, rand, url); } } // redirectTimeout = setTimeout(redirectNextPage, rand, url); würde hier merh sinn ergeben?? } } // Funktion zum erstellen eines zufälligen Wertes zwischen einem Min und Max Wert function random(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } // Funktion zum weiterleiten auf eine andere Seite function redirectNextPage(nextPage){ location.replace(url); console.log("Redirect"); console.log("Next Page: " + nextPage); } // Funktion zum Scannen aler produkte, auch außerhalb des sichtbereiches -> Zusammenlegen mit scanAndCacheAllVisibleProdut? function scanAndCacheAllProducts() { // Erfassen der product Tiles var productTiles = document.getElementsByClassName('vvp-item-tile'); var ProductIDs = []; var ProductTitles = []; var ProductLinks = []; var ProductImages = []; var ProductButtons = []; // Durchlaufen aller Erfassten Product Tiles for (var i = 0; i < productTiles.length; i++) { var productTile = productTiles[i]; var productID = getProductID(productTile); ProductIDs.push(productID); var contentContainer = productTile.querySelector('.vvp-item-tile-content'); var imageElement = contentContainer.querySelector('img'); var nameElement = contentContainer.querySelector('a span span.a-truncate-full'); var linkElement = contentContainer.querySelector('a'); ProductTitles.push(nameElement.textContent); ProductLinks.push(linkElement.href); ProductImages.push(imageElement.getAttribute('src')); var buttonContainer = productTile.querySelector('span.a-button-inner'); var buttonContent = buttonContainer.innerHTML; ProductButtons.push(buttonContent); } // Aufrufen der Funktion sum speichern der Daten in die Datenbank cacheProducts(ProductIDs, ProductTitles, ProductLinks,ProductImages, ProductButtons); } // Funktion zum speichern der aktuellen Seite in den Lokalen Speicher function saveCurrentPage() { var pagination = document.querySelector('.a-pagination'); if(pagination != null) { var currentPageElement = pagination.querySelector('.a-selected a'); var currentPage = parseInt(currentPageElement.textContent.trim()); localStorage.setItem("currentPage", currentPage); if(debug){console.log('Current Page Saved:', currentPage);} } } // Funktion zur Abfrage der aktuellen Seite aus dem lokalen Speicher function getCurrentPage() { return parseFloat(localStorage.getItem("currentPage")); } // Funktion zum Speichern der maximalen Seite function saveMaxPage(){ // Elelement, welche die höchste Seitenzhl enthält var pagination = document.querySelector('.a-pagination'); if(pagination != null) { if(debug == true){console.log("Max Pages Element: " + pagination.lastChild.previousSibling.lastChild);} // Seitenzahl aus dem Element laden var maxPage = parseInt(pagination.lastChild.previousSibling.lastChild.textContent.trim()); // Speichern der Seitenzahl in den lokalen Speicher localStorage.setItem("maxPage", maxPage); if(debug == true){console.log('Max Page:', maxPage);} } } // Funktion zum auslesen der Maximalen Seite aus dem Lokalen Speicher function getMaxPage() { return parseFloat(localStorage.getItem("maxPage")); } // Gibt das gespeicherte Datum für eine Produkt-ID zurück async function getSavedDate(productID) { var data = await getCachedProductIDInfo(productID); return data.Datum; } // Funktion zum Speichern der Produkt-IDs in die Datenbank async function cacheProducts(productIDs, titles, links, images, buttons) { var cachedProductIDs = await getCachedProductIDs(); var productCacheLength = await getProductCacheLength(); if(debug == true){console.log("Cache: " + productCacheLength)}; // Für jedes Produkt auf der Seite durchlaufen productIDs.forEach(async function(productID, index) { // Prüfen ob die ID bereits in der Datenbank vorhanden ist const findid = await checkForIDInDatabase(productID); if(findid == false){ // ID nicht in der Datenbank if(debug == true){console.log("Produkt hinzuügen")} // Datum in ein Lesbares Format konvertieren var currentDate = new Date().toLocaleString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit', day: '2-digit', month: '2-digit', year: 'numeric' }); // Verbindung zur Datenbank herstellen const request = indexedDB.open(dbName, dbVersion); request.onerror = function(event) { console.log("Fehler beim Öffnen der Datenbank ID:1"); }; request.onsuccess = function(event) { const db = event.target.r###lt; var rand = random(1, 10000); const data = { ID: productID, Titel: titles[index], Link: links[index], BildURL: images[index], Button: buttons[index], Datum: currentDate, Favorit: false }; const transaction = db.transaction([objectStoreName], "readwrite"); const objectStore = transaction.objectStore(objectStoreName); // Daten in dei Datenbank schreiben const addRequest = objectStore.add(data); // Hinzufügen der Daten erfolgreich addRequest.onsuccess = function(event) { if(debug == true){console.log("Daten hinzugefügt")}; }; // Fehler beim hinzufügen der Daten addRequest.onerror = function(event) { console.log("Fehler beim Hinzufügen der Daten"); }; }; }else{ // Produkt bereits in der Datenbank vorhanden if(debug == true){console.log("Produkt bereits vorhanden")}; } }); // Hinzufügen der neu hinzugefügten IDs in den lokal cache localStorage.setItem('cachedProductIDs', JSON.stringify(cachedProductIDs)); // Sinnvoll ?? -> onsuccess mehr sinn?? nicht alle daten auf einmal sondern nur die erfolgreichen } // Überprüfen ob die ID bereits in der Datenbank vorhanden ist function checkIfIDExists(idToCheck) { return new Promise((resolve, reject) => { const request = indexedDB.open(dbName, dbVersion); request.onerror = function(event) { console.log("Fehler beim Öffnen der Datenbank"); reject(new Error("Fehler beim Öffnen der Datenbank")); }; request.onsuccess = function(event) { const db = event.target.r###lt; const transaction = db.transaction([objectStoreName], "readonly"); const objectStore = transaction.objectStore(objectStoreName); // Datenbank filtern nach der ID const getRequest = objectStore.get(idToCheck); getRequest.onsuccess = function(event) { const r###lt = event.target.r###lt; resolve(!!r###lt); // Resolve mit true, wenn die ID vorhanden ist, andernfalls false }; getRequest.onerror = function(event) { console.log("Fehler beim Abrufen der Daten"); reject(new Error("Fehler beim Abrufen der Daten")); }; }; }); } // Alled Daten in der Datenbank abrufen function getAllDataFromDatabase() { return new Promise((resolve, reject) => { const cachedProductIDs = localStorage.getItem('cachedProductIDs'); const request = indexedDB.open(dbName, dbVersion); request.onerror = function(event) { console.log("Fehler beim Öffnen der Datenbank ID:2"); reject([]); }; request.onsuccess = function(event) { const db = event.target.r###lt; const transaction = db.transaction([objectStoreName], "readonly"); const objectStore = transaction.objectStore(objectStoreName); const getRequest = objectStore.getAll(); getRequest.onsuccess = function(event) { const allData = event.target.r###lt; const titles = allData.map(item => item.ID); resolve(allData); }; getRequest.onerror = function(event) { console.log("Fehler beim Abrufen der Daten ID:2"); reject([]); }; }; }); } // Funktion gibt Informationen einer bestimmten Produkt ID zurück async function getCachedProductIDInfo(id) { try { const allData = await getAllDataFromDatabase(); const productInfo = allData.find(item => item.ID === id); if(debug){console.log("Produktinformationen für ID", id, ":", productInfo)}; return productInfo; } catch (error) { console.error("Fehler beim Abrufen der Produktinformationen:", error); throw error; } } // Funktion gibt alle Product IDs die in der Datenbank gespeichert sind zurück async function getCachedProductIDs() { return new Promise((resolve, reject) => { getAllDataFromDatabase() .then(allData => { var productIDs = allData.map(item => item.ID); resolve(productIDs); }) .catch(error => { console.error("Fehler beim Abrufen der Datenbank-IDs:", error); reject(error); }); }); } // Funktion gibt die anzahl der in der Eingetragenen IDS in der Datenbank zurück async function getProductCacheLength() { return new Promise((resolve, reject) => { //getProductIDsFromDatabase() getCachedProductIDs() .then(productIDs => { if(debug == true){console.log("Produkte in der Datenbank: " + productIDs.length)}; resolve(productIDs.length); }) .catch(error => { console.error("Fehler beim Abrufen der Datenbank-IDs:", error); reject(error); }); }); } // Funktion überprüft ob die Podukt ID bereits in der Datenbank ist | gibt true / false zurück async function checkForIDInDatabase(productID) { return new Promise((resolve, reject) => { checkIfIDExists(productID) .then(idExists => { if (idExists) { if(debug == true){console.log("Die ID existiert in der Datenbank")}; resolve(true); } else { if(debug == true){console.log("Die ID existiert nicht in der Datenbank")}; resolve(false); } }) .catch(error => { console.error("Fehler beim Überprüfen der ID in der Datenbank:", error); reject(error); }); }); } // Funktion zum Abrufen der Produkt-ID eines Tiles function getProductID(tile) { return tile.getAttribute('data-recommendation-id'); } // Funktion zum Überprüfen, ob ein Element im sichtbaren Bereich ist function isElementVisible(element) { var rect = element.getBoundingClientRect(); return ( rect.top >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) ); } // Funktion zum Erstellen des Popups async function createPopup() { if(!openList){ openList = 1; var page = 1; var startCount = 0; var stopCount = startCount + popupDefaultCount; var productCacheLength = await getProductCacheLength(); var data = allData; var dataIDs = await getCachedProductIDs(); var popupBackgroundDiv = document.createElement('div'); popupBackgroundDiv.setAttribute("id","popup-background-div"); popupBackgroundDiv.style.cssText = popupBackgroundDivCSS; popupBackgroundDiv.addEventListener('click', function(event) { closePopup(); }) var popup = document.createElement('div'); popup.setAttribute('id', 'vine-viewer-popup'); popup.style.cssText = popupCSS; var popupInner = document.createElement('div'); popupInner.setAttribute('id', 'popup-inner'); popupInner.style.cssText = popupInnerCSS; popup.appendChild(popupInner); // Erstellen des schließen Buttons var closeButton = document.createElement('div'); closeButton.textContent = 'X'; closeButton.style.position = 'absolute'; closeButton.style.top = '5px'; closeButton.style.right = '10px'; closeButton.style.cursor = 'pointer'; closeButton.addEventListener('click', function() { closePopup(); }); var popupTopContainer = document.createElement('div'); popupTopContainer.setAttribute('id', 'popupTopContainer'); popupTopContainer.style.cssText = popupTopContainerCSS; var popupTopContainerNav = document.createElement('div'); popupTopContainerNav.setAttribute('id', 'popupTopContainerNav'); popupTopContainerNav.style.padding = '5px'; popupTopContainer.appendChild(popupTopContainerNav); const navoptions = [ ["favs", "Favoriten"], ["all", "Alle Produkte"] ] for(var no = 0; no <= (navoptions.length -1); no++){ var navigationoption = document.createElement('span'); navigationoption.style.cssText = popupTopContainerItemCSS; navigationoption.textContent = navoptions[no][1] + " |"; navigationoption.setAttribute('id', navoptions[no][0]); if(no == 0){ navigationoption.style.fontWeight = 'bold'; }; navigationoption.addEventListener('click', async function(event) { var clickedItemId = event.target.id; var spanElements = document.querySelectorAll("#popupTopContainerNav span"); spanElements.forEach(function(span) { span.style.fontWeight = 'normal'; }); event.target.style.fontWeight = 'bold'; page = 1; getPopupData(clickedItemId); searchInput.value = ""; }); popupTopContainerNav.appendChild(navigationoption); }; var popupTopContainerSearch = document.createElement('div'); popupTopContainerSearch.setAttribute('id', 'popupTopContainerSearch'); popupTopContainerSearch.style.padding = '5px'; // Erstellen des Titels der Suchleiste var searchTitel = document.createElement('span'); searchTitel.style.height = '30px'; searchTitel.style.width = '50px'; searchTitel.style.paddingRight = '5px'; searchTitel.style.fontWeight = 'bold'; searchTitel.textContent = 'Filter: '; popupTopContainerSearch.appendChild(searchTitel); // Erstellen der Suche var searchInput = document.createElement('input'); searchInput.setAttribute('type', 'text'); searchInput.setAttribute('id', 'popup-search-input'); searchInput.style.height = '30px'; searchInput.style.width = '500px'; searchInput.style.padding = '5px'; searchInput.addEventListener('input', function(event) { // Such Funktion //search(); // <- Kann bei zu großen Datenmengen zu hängern führen }); searchInput.addEventListener("keyup", function(event) { if (event.keyCode === 13) { // Wenn die Enter-Taste gedrückt wurde, Button klicken searchButton.click(); } }); var searchButton = document.createElement('button'); searchButton.textContent = "Suchen"; searchButton.addEventListener('click', function(event) { search(); }); popupTopContainerSearch.appendChild(searchInput); popupTopContainerSearch.appendChild(searchButton); popupTopContainer.appendChild(popupTopContainerSearch); // Navigation var popupTopContainerItems = document.createElement('div'); popupTopContainerItems.setAttribute('id', 'popup-top-items'); popupTopContainerItems.style.cssText = popupTopContainerSelectCSS; popupTopContainer.appendChild(popupTopContainerItems); var popupContainerItemsSpan = document.createElement('span'); popupContainerItemsSpan.textContent = "xx - xx / XXX"; popupContainerItemsSpan.style.cssText = popupContainerItemsSpanCSS; popupTopContainerItems.appendChild(popupContainerItemsSpan); // Angabe der Optionen der Produkt Anzahl Auswahl const options = [ [25,"25"], [50,"50"], [100,"100"], [250,"250"] ]; var popupTopContainerProductCountSelect = document.createElement('select'); popupTopContainerProductCountSelect.addEventListener('change', function(event) { popupDefaultCount = parseInt(event.target.value); localStorage.setItem("popupDefaultCount", popupDefaultCount); updatePopup(); }); popupTopContainerItems.appendChild(popupTopContainerProductCountSelect); for(var o = 0; o <= (options.length -1); o++){ var option = document.createElement("option"); option.value = options[o][0]; option.text = options[o][1]; if(option.value == popupDefaultCount){ option.selected = true; } popupTopContainerProductCountSelect.appendChild(option); } var popupTopContainerPages = document.createElement('div'); popupTopContainerPages.setAttribute('id', 'popup-top-pages'); popupTopContainerPages.style.cssText = popupTopContainerPagesCSS; popupTopContainer.appendChild(popupTopContainerPages); var popupButtonBack = document.createElement('button'); popupButtonBack.textContent = "<"; popupButtonBack.addEventListener('click', function(event) { page--; updatePopup(); }); popupTopContainerPages.appendChild(popupButtonBack); var popupDisplayPages = document.createElement('span'); popupDisplayPages.setAttribute('id', 'popup-top-pages-display'); popupDisplayPages.textContent = " - / - "; popupDisplayPages.style.cssText = popupDisplayPagesCSS; popupTopContainerPages.appendChild(popupDisplayPages); var popupButtonNext = document.createElement('button'); popupButtonNext.textContent = ">"; popupButtonNext.addEventListener('click', function(event) { page++; updatePopup(); }); popupTopContainerPages.appendChild(popupButtonNext); // Beginn Popup Content var popupContentContainer = document.createElement('div'); popupContentContainer.style.cssText = popupContentContainerCSS; function addItemList(data, page){ var cacheLength = data.length; try{ if(cacheLength == 0){ var productListMessage = document.createElement('span'); productListMessage.setAttribute('id', "productListMessage"); productListMessage.textContent = "Es wurden keine Produkte gefunden." popupContentContainer.insertBefore(productListMessage, popupContentContainer.firstChild); page = 0; startCount = -1; stopCount = 0; }else{ startCount = (page * popupDefaultCount) - popupDefaultCount; stopCount = startCount + popupDefaultCount; if(stopCount >= cacheLength){ stopCount = cacheLength; } for(var x = startCount; x <= (stopCount - 1); x++){ var pID = data[x].ID; var title = data[x].Titel; var link = data[x].Link; var image = data[x].BildURL; var buttonContent = data[x].Button; var date = data[x].Datum; var fav = data[x].Favorit; if(title && image && buttonContent){ // Erstellen eines Produkt Containers var productContainer = document.createElement('div'); productContainer.classList.add('product-container'); productContainer.style.cssText = listProductContainerCSS; var listFavElement = document.createElement('span'); listFavElement.textContent = "★" listFavElement.style.cssText = favCSS; listFavElement.setAttribute('id', pID); if(fav){ listFavElement.style.color = "#ffe143"; } listFavElement.addEventListener('click', function(event) { var eventTarget = event.target; var productID = event.target.id; var isFav = false; if(dataIDs.includes(productID)){ const productInfo = data.find(eventData => eventData.ID === productID); isFav = productInfo.Favorit; } // Verbindung mit der Datenbank herstellen const request = indexedDB.open(dbName, dbVersion); request.onerror = function(event) { console.log("Fehler beim Öffnen der Datenbank ID: FAV"); }; request.onsuccess = function(event) { const db = event.target.r###lt; const transaction = db.transaction([objectStoreName], "readwrite"); const objectStore = transaction.objectStore(objectStoreName); // Suchen der Product ID in der Datenbank const getRequest = objectStore.get(productID); getRequest.onsuccess = function(event) { const eventData = event.target.r###lt; if (eventData) { // Beim scannen des sichtbaren Bereiches kommt es hier zu einem fehler, da die ID die sich halb im sichtfeld befindet, noch nicht in der Datenbank eingetragen ist // Neuen Wert für den Favoriten der Datenbank hinzufügen // Abhilfe könnte schaffen das Produkt dann zur Datenbank hinzuzufügen und als Favorit zu setzten, auch wenn es außerhalb dessichtbaren bereiches ist eventData.Favorit = !isFav; const updateRequest = objectStore.put(eventData); updateRequest.onsuccess = async function(event) { var newdata = []; if(debug){console.log(`Favorit-Wert für ID ${productID} wurde erfolgreich aktualisiert.`)}; // Visuelle Elemente Updaten isFav = !isFav; if(isFav){ eventTarget.style.color = "#ffe143"; }else{ eventTarget.style.color = "white"; //setTimeout(() => { // eventTarget.parentNode.style.height = "0px"; // eventTarget.parentNode.style.opacity = "0"; // eventTarget.parentNode.style.marginBottom = "0px"; // setTimeout(() => { // eventTarget.parentNode.remove(); // sumItem--; // stopItem--; // topItems.textContent = startItem + " - " + stopItem + " / " + sumItem; // }, 2100); //}, 5000); } for(var f = 0; f < data.length; f++){ if(data[f].ID === productID){ data[f].Favorit = !data[f].Favorit } } // Aktualisieren der Daten allData = await getAllDataFromDatabase(); }; updateRequest.onerror = function(event) { console.log(`Fehler beim Aktualisieren des Favorit-Werts für ID ${productID}.`); }; } else { // Product ID wurde nicht in der Datenbank gefunden console.log(`Datensatz mit ID ${productID} wurde nicht gefunden.`); } }; getRequest.onerror = function(event) { console.log(`Fehler beim Abrufen des Datensatzes mit ID ${productID}.`); }; }; }); var imageElement = document.createElement('img'); imageElement.src = image; imageElement.style.cssText = listImageElementCSS; var dateElement = document.createElement('div'); dateElement.textContent = date; dateElement.style.cssText = listDateElementCSS; var titleElement = document.createElement('a'); titleElement.classList.add('product-title'); titleElement.textContent = title; titleElement.style.cssText = listTitleElementCSS; titleElement.href = link; titleElement.target = "_blank"; var buttonContainer = document.createElement('span'); buttonContainer.classList.add('a-button'); buttonContainer.classList.add('a-button-primary'); buttonContainer.classList.add('vvp-details-btn'); buttonContainer.style.cssText = listButtonContainerCSS; var buttonSpan = document.createElement('span'); buttonSpan.innerHTML = buttonContent; buttonSpan.classList.add('a-button-inner'); buttonSpan.style.cssText = listButtonSpanCSS; buttonContainer.appendChild(buttonSpan); productContainer.appendChild(listFavElement); productContainer.appendChild(imageElement); productContainer.appendChild(dateElement); productContainer.appendChild(titleElement); productContainer.appendChild(buttonContainer); popupContentContainer.insertBefore(productContainer, popupContentContainer.firstChild); } var Item = document.createElement('p'); Item.setAttribute('id', 'product-container'); Item.textContent = "[" + (x + 1) + "] " + data[x].Titel; //popupContentContainer.appendChild(Item); } } var pageMax = Math.ceil(cacheLength / popupDefaultCount); if(page <=1){ popupButtonBack.disabled = true; popupButtonBack.style.cursor = "not-allowed"; }else{ popupButtonBack.disabled = false; popupButtonBack.style.cursor = "pointer"; } if(page >= pageMax){ popupButtonNext.disabled = true; popupButtonNext.style.cursor = "not-allowed"; } else { popupButtonNext.disabled = false; popupButtonNext.style.cursor = "pointer"; } var pageDisplay = document.getElementById("popup-top-pages-display"); pageDisplay.textContent = page + " / " + pageMax; var topItemsContainer = document.getElementById("popup-top-items"); var topItems = topItemsContainer.querySelector("span"); var startItem = (startCount + 1); var stopItem = stopCount; var sumItem = cacheLength; topItems.textContent = startItem + " - " + stopItem + " / " + sumItem; }catch(error){ console.log("Error: " + error); return; } } function getPopupData(arg){ data = []; switch (arg){ case "favs": for(var fc = 0;fc <= (allData.length - 1); fc++){ var favorit = allData[fc].Favorit; if(favorit){ data.push(allData[fc]); } } break; default: data = allData; } dataIDs = data.map(item => item.ID); updatePopup(); } function search() { var filterData = []; var filter = searchInput.value.toLowerCase(); for (var sc = 0; sc <= (data.length - 1); sc++){ var titel = data[sc].Titel; if (titel.toLowerCase().includes(filter.toLowerCase())) { filterData.push(data[sc]); } } removeItemList(); addItemList(filterData, page) } function updatePopup(){ // Get Search Input var searchInput = document.getElementById('popup-search-input'); var searchQuery = searchInput.value.toLowerCase(); removeItemList(); addItemList(data, page); } function removeItemList() { var elementsToRemove = document.querySelectorAll('.product-container'); try { var productListMessageRemove = document.getElementById("productListMessage"); productListMessageRemove.remove(); } catch (error){ // Message ist nicht vorhanden } for (var i = 0; i < elementsToRemove.length; i++) { var element = elementsToRemove[i]; element.parentNode.removeChild(element); } } document.body.appendChild(popupBackgroundDiv); popupInner.appendChild(closeButton); popupInner.appendChild(popupTopContainer); popupInner.appendChild(popupContentContainer); document.body.appendChild(popup); getPopupData("favs"); } function closePopup(){ document.body.removeChild(popup); document.body.removeChild(popupBackgroundDiv); openList = false; } } // Funktion zum Filtern der Produkte basierend auf der Sucheingabe function filterProducts(searchText) { var productsContainer = document.getElementById('product-list'); if (!productsContainer) return; var productContainers = productsContainer.querySelectorAll('div'); var searchTerm = searchText.toLowerCase(); productContainers.forEach(function(container) { var titleElement = container.querySelector('span'); var title = titleElement.textContent.toLowerCase(); if (title.includes(searchTerm)) { container.style.display = 'flex'; } else { container.style.display = 'none'; } }); } // Main Funktion, wird aufgerufen nachdem eine Verbindung zur Datenbank hergestellt wurde // Steuert den Ablauf des Scriptes, an welcher Reihenolge die Funktionen geladen werden. async function main() { if(debug){console.log("[INI] - Amazon Vine Viewer")}; var nextPage; var currentPage; var maxPage; var rand; checkForAutoScan(); loadSettings(); await saveCurrentPage(); if(debug){console.log("[INI] - Aktuelle Seite gespeichert")}; await saveMaxPage(); if(debug){console.log("[INI] - Maximale Seite gespeichert")}; try{ allData = await getAllDataFromDatabase(); if(debug){console.log("[INI] - Alle Daten abgefragt")}; } catch (error) { console.log("Fehler beim abrufen der Datenbank"); } await createUI(); if(debug){console.log("[INI] - Overlay geladen")}; await updateMessage(); if(debug){console.log("[INI] - Prüfen auf Updates")}; await highlightCachedProducts(); if(debug){console.log("[INI] - Cached Produkte hervorgehoben")}; await checkForAutoScan(); if(debug){console.log("[INI] - Auto Scan überprüft")}; var highlightVisibility = getToggleStatus("toggleHighlight"); await toggleHighlightVisibility(highlightVisibility); if(debug){console.log("[INI] - Sichtbarkeit an / aus")}; if(getToggleStatus("toggleScan")){ scanAndCacheVisibleProducts(); if(debug){console.log("[INI] - Sichtbare Produkte Scannen")}; }else{ await scanAndCacheAllProducts(); if(debug){console.log("[INI] - Alle Produkte Scannen")}; } window.addEventListener('scroll', function(event){ if(localStorage.getItem("autoScan") == "false"){ scanAndCacheVisibleProducts(); } }); window.addEventListener("keydown", function(event) { if (event.keyCode === 27 || event.key === "Escape") { if(openList === 1){ var popup = document.getElementById('vine-viewer-popup'); var popupBackgroundDiv = document.getElementById('popup-background-div'); document.body.removeChild(popup); document.body.removeChild(popupBackgroundDiv); openList = false; } } }); } })();