Vine Viewer

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.result;
            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.result;

            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.result;

                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.result;
                    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.result;
                    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.result;

                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 result = event.target.result;
                    resolve(!!result); // 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.result;
                const transaction = db.transaction([objectStoreName], "readonly");
                const objectStore = transaction.objectStore(objectStoreName);
                const getRequest = objectStore.getAll();

                getRequest.onsuccess = function(event) {
                    const allData = event.target.result;
                    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.result;

                                        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.result;
                                            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;
            }
        }
        });
    }
})();