Prune Amazon Vine

Remove things you don't want to see from Amazon Vine listings

// ==UserScript==
// @name         Prune Amazon Vine
// @namespace    http://tampermonkey.net/
// @version      2025-10-11
// @description  Remove things you don't want to see from Amazon Vine listings
// @author       ZetaGecko
// @license      MIT
// @match        https://www.amazon.com/vine/vine-items?queue=encore*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=amazon.com
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_listValues
// @grant        GM_deleteValue
// ==/UserScript==

(function() {
    'use strict';

    var i,showmode,remove,exceptions,temp,el1,el2,el3,removeedit,exceptionedit,hidecount,pvexpanded,pvcollapsed;

    function PVUpdateDisplay() {
        var j,k,hid,titleel,title,matched;

        hid=0;
        for (i=0;i<items.length;i++){
            titleel=items[i].getElementsByClassName('a-truncate-full');
            if (titleel.length) {
                title = titleel[0].innerText.toLowerCase();
                for (j=0;j<remove.length;j++) {
                    matched=0;
                    if (typeof(remove[j]) === 'string') {
                        if (title.indexOf(remove[j])>-1) matched=1;
                    } else {
                        for (k=0;k<remove[j].length;k++) if (title.indexOf(remove[j][k])<0) break;
                        if (k==remove[j].length) matched=1;
                    }
                    if (matched) {
                        for (k=0;k<exceptions.length;k++) {
                            if (title.indexOf(exceptions[k])>-1) break;
                        }
                        if (k<exceptions.length) matched=0;
                        else break;
                    }
                }
                if ((matched == 1) == (showmode == 0)) {
                    items[i].style.display='none';
                    hid++;
                } else items[i].style.display='block';
            }
        }
        hidecount.innerText = 'Pruned: '+hid;
    }

    function PVSortSettings(a,b) {
        var i;
        if (typeof(a) === 'string') {
            if (typeof(b) === 'string') return (a<b)?-1:((b<a)?1:0);
            return -1;
        }
        if (typeof(b) === 'string') return 1;
        for (i=0;(i<a.length)&&(i<b.length);i++) if (a[i]!=b[i]) break;
        return (i<a.length) ? ((i<b.length) ? ((a[i]<b[i])?-1:((b[i]<a[i])?1:0)) : 1) : -1;
    }
    function PVSetJSON() {
        var t = JSON.parse(removeedit.value.trim().toLowerCase());
        if ((typeof(t) !== 'object') || !t.length) {
            alert('JSON error or no settings found.');
            return;
        }
        if (!confirm('Replace entire contents of prune list?')) return;
        GM_setValue('hidethese',JSON.stringify(t));
        PVUpdateDisplay();
    }
    function PVGetJSON() {
        removeedit.value = JSON.stringify(remove);
    }
    function PVSetJSONEx() {
       var t = JSON.parse(exceptionedit.value.trim().toLowerCase());
       if ((typeof(t) !== 'object') || !t.length) {
           alert('JSON error or no settings found.');
           return;
       }
       if (!confirm('Replace entire contents of exceptions list?')) return;
       GM_setValue('showthese',JSON.stringify(t));
       PVUpdateDisplay();
   }
   function PVGetJSONEx() {
       exceptionedit.value = JSON.stringify(exceptions);
   }
   function PVAddBlock() {
        var newone;
        newone = removeedit.value.replaceAll("\r","\n").replace(/\n{2,}/g,"\n").toLowerCase().split("\n");
        remove.push((newone.length == 1) ? newone[0] : newone);
        remove.sort(PVSortSettings);
        GM_setValue('hidethese',JSON.stringify(remove));
        PVUpdateDisplay();
    }
    function PVAddException() {
        var newone;
        newone = exceptionedit.value.replaceAll("\r","\n").replace(/\n{2,}/g,"\n").toLowerCase().split("\n");
        exceptions.push((newone.length == 1) ? newone[0] : newone);
        exceptions.sort(PVSortSettings);
        GM_setValue('showthese',JSON.stringify(exceptions));
        PVUpdateDisplay();
    }
    function PVRemoveBlock(event) {
        var n = parseInt(event.target.id.substr(13));
        remove.splice(n,1);
        GM_setValue('hidethese',JSON.stringify(remove));
        event.target.parentNode.parentNode.removeChild(event.target.parentNode);
        PVUpdateDisplay();
    }
    function PVRemoveException(event) {
        var n = parseInt(event.target.id.substr(13));
        exceptions.splice(n,1);
        GM_setValue('showthese',JSON.stringify(exceptions));
        event.target.parentNode.parentNode.removeChild(event.target.parentNode);
        PVUpdateDisplay();
    }
    function PVToggleShowMode() {
        showmode = 1 - showmode;
        PVUpdateDisplay();
    }
    function PVCollapse() {
        pvexpanded.style.display='none';
        pvcollapsed.style.display='block';
    }
    function PVExpand() {
        pvexpanded.style.display='block';
        pvcollapsed.style.display='none';
    }

    showmode = 0;
    temp = GM_getValue('hidethese','');
    remove = temp.length ? JSON.parse(temp) : [];
    temp = GM_getValue('showthese','');
    exceptions = temp.length ? JSON.parse(temp) : [];

    var items=document.getElementsByClassName('vvp-item-tile');

    temp=document.createElement('div');
    temp.style.zIndex=100000;
    temp.style.position='fixed';
    temp.style.top='3px';
    temp.style.left='3px';
    temp.style.backgroundColor='#ccc';
    temp.style.padding='2px 12px 8px 12px';
    temp.style.borderRadius='5px';
    temp.style.width='250px';

    temp.appendChild(pvexpanded = document.createElement('div'));

    pvexpanded.appendChild(hidecount = document.createElement('div'));
    hidecount.style.float='right';

    pvexpanded.appendChild(el1 = document.createElement('span'));
    el1.innerText = '-';
    el1.style.display='inline-block';
    el1.style.color='#fff';
    el1.style.backgroundColor='#555';
    el1.style.padding='2px 10px';
    el1.style.borderRadius='20px';
    el1.addEventListener('click',PVCollapse);

    pvexpanded.appendChild(el1 = document.createElement('span'));
    el1.innerText = ' Prune';
    pvexpanded.appendChild(document.createElement('br'));
    pvexpanded.appendChild(removeedit = document.createElement('textarea'));
    removeedit.style.width='100%';
    removeedit.style.height='60px';
    removeedit.style.overflow='auto';
    pvexpanded.appendChild(el1 = document.createElement('button'));
    el1.innerText='Add';
    el1.addEventListener('click',PVAddBlock);
    pvexpanded.appendChild(el1 = document.createElement('button'));
    el1.innerText='Set (JSON)';
    el1.addEventListener('click',PVSetJSON);
    pvexpanded.appendChild(el1 = document.createElement('button'));
    el1.innerText='Get JSON';
    el1.addEventListener('click',PVGetJSON);

    pvexpanded.appendChild(el1 = document.createElement('div'));
    el1.innerText = 'Exceptions';
    pvexpanded.appendChild(exceptionedit = document.createElement('textarea'));
    exceptionedit.style.width='100%';
    exceptionedit.style.height='60px';
    exceptionedit.style.overflow='auto';
    pvexpanded.appendChild(el1 = document.createElement('button'));
    el1.innerText='Add';
    el1.addEventListener('click',PVAddException);
    pvexpanded.appendChild(el1 = document.createElement('button'));
    el1.innerText='Set (JSON)';
    el1.addEventListener('click',PVSetJSONEx);
    pvexpanded.appendChild(el1 = document.createElement('button'));
    el1.innerText='Get JSON';
    el1.addEventListener('click',PVGetJSONEx);

    pvexpanded.appendChild(el1 = document.createElement('div'));
    el1.innerHTML = '<b>Prune List</b>';
    pvexpanded.appendChild(el1 = document.createElement('div'));
    el1.style.height='150px';
    el1.style.overflow='auto';
    for (i=0;i<remove.length;i++) {
        el1.appendChild(el2=document.createElement('div'));
        el2.appendChild(el3=document.createElement('span'));
        el3.style.color='#fff';
        el3.style.backgroundColor='#555';
        el3.style.padding='2px 8px';
        el3.style.borderRadius='30px';
        el3.style.cursor='pointer';
        el3.innerText='X';
        el3.id='PruneVineRDel'+i;
        el3.addEventListener('click',PVRemoveBlock);
        el2.appendChild(el3=document.createElement('span'));
        el3.innerHTML = ' ' + ((typeof(remove[i]) === 'string') ? remove[i] : remove[i].join(', '));
    }

    pvexpanded.appendChild(el1 = document.createElement('div'));
    el1.innerHTML = '<b>Exception List</b>';
    pvexpanded.appendChild(el1 = document.createElement('div'));
    el1.style.height='60px';
    el1.style.overflow='auto';
    for (i=0;i<exceptions.length;i++) {
        el1.appendChild(el2=document.createElement('div'));
        el2.appendChild(el3=document.createElement('span'));
        el3.style.color='#fff';
        el3.style.backgroundColor='#555';
        el3.style.padding='2px 8px';
        el3.style.borderRadius='30px';
        el3.style.cursor='pointer';
        el3.innerText='X';
        el3.id='PruneVineEDel'+i;
        el3.addEventListener('click',PVRemoveException);
        el2.appendChild(el3=document.createElement('span'));
        el3.innerHTML = ' ' + ((typeof(exceptions[i]) === 'string') ? exceptions[i] : exceptions[i].join(', '));
    }

    pvexpanded.appendChild(el1=document.createElement('div'));
    el1.style.color='#fff';
    el1.style.backgroundColor='#555';
    el1.style.padding='2px 12px';
    el1.style.borderRadius='15px';
    el1.innerText='hide <-> show';
    el1.align='center';
    el1.addEventListener('click',PVToggleShowMode);

    temp.appendChild(pvcollapsed = document.createElement('div'));
    pvcollapsed.style.display='none';
    pvcollapsed.appendChild(el1 = document.createElement('span'));
    el1.innerText = '+';
    el1.style.display='inline-block';
    el1.style.color='#fff';
    el1.style.backgroundColor='#555';
    el1.style.padding='2px 10px';
    el1.style.borderRadius='20px';
    el1.addEventListener('click',PVExpand);

    document.getElementById('a-page').appendChild(temp);

    PVUpdateDisplay();
})();