Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion userscripts/toppreise/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Requires Violentmonkey (or a compatible userscript manager):
- [Firefox](https://addons.mozilla.org/en-US/firefox/addon/violentmonkey/)
- [Chrome / Brave](https://chromewebstore.google.com/detail/violentmonkey/jinjaccalgkegednnccohejagnlnfdag)

### 👉 [**CLICK HERE TO INSTALL USERSCRIPT (v2.18.16)**](https://raw.githubusercontent.com/tazztone/scripts/main/userscripts/toppreise/toppreise.user.js)
### 👉 [**CLICK HERE TO INSTALL USERSCRIPT (v2.18.18)**](https://raw.githubusercontent.com/tazztone/scripts/main/userscripts/toppreise/toppreise.user.js)

---

Expand Down
24 changes: 12 additions & 12 deletions userscripts/toppreise/tests/test_userscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,14 @@ def test_master_filter_toggle_and_category_preservation(page: Page):
page.wait_for_selector('#card-negative.tp-negative-filtered', state='attached')
page.wait_for_selector('#card-low-offers.tp-min-offers-filtered', state='attached')

filter_toggle = page.locator('#tp-bar-filter-toggle')
filter_toggle = page.locator('#tp-toggle-neg')
assert filter_toggle.is_visible()
assert 'Filter: AN' in (filter_toggle.text_content() or '')
assert 'tp-active' in (filter_toggle.get_attribute('class') or '')

# Click Master Filter Toggle to turn filters OFF (Filter: AUS)
filter_toggle.click()
page.wait_for_selector('#tp-bar-filter-toggle.tp-filter-off')
assert 'Filter: AUS' in (filter_toggle.text_content() or '')
page.locator('#tp-toggle-neg').click()
page.locator('#tp-toggle-min').click()
page.locator('#tp-toggle-cat').click()
page.wait_for_selector('#tp-toggle-neg.tp-filter-off')

# Verify cards are no longer filtered (all visible)
page.wait_for_selector('#card-negative:not(.tp-negative-filtered)', state='visible')
Expand All @@ -207,9 +206,10 @@ def test_master_filter_toggle_and_category_preservation(page: Page):
assert config['EXCLUDED_CATEGORIES'] == ['PATH:Hardware/Grafikkarten']

# Click Master Filter Toggle again to re-enable (Filter: AN)
filter_toggle.click()
page.wait_for_selector('#tp-bar-filter-toggle.tp-active')
assert 'Filter: AN' in (filter_toggle.text_content() or '')
page.locator('#tp-toggle-neg').click()
page.locator('#tp-toggle-min').click()
page.locator('#tp-toggle-cat').click()
page.wait_for_selector('#tp-toggle-neg.tp-active')

# Verify cards are filtered again
page.wait_for_selector('#card-negative.tp-negative-filtered', state='attached')
Expand Down Expand Up @@ -733,7 +733,7 @@ def test_empty_state_notice_and_actions(page: Page):
page.click('#tp-empty-toggle-filters-btn')
assert not page.locator('#tp-empty-state-notice').is_visible()
assert page.locator('#card-cheapest').is_visible()
assert page.evaluate("() => window.ToppreiseSuite.CONFIG.FILTERS_ENABLED") is False
assert page.evaluate("() => window.ToppreiseSuite.CONFIG.FILTER_NEG_ENABLED") is False


def test_real_deal_threshold_quick_selector(page: Page):
Expand Down Expand Up @@ -921,7 +921,7 @@ def test_deal_only_buttons_hidden_on_category_page(page: Page):
# Listing features are visible
assert page.locator('#tp-inline-negative-input').is_visible()
assert page.locator('#tp-bar-reveal-btn').is_visible()
assert page.locator('#tp-bar-filter-toggle').is_visible()
assert page.locator('#tp-toggle-neg').is_visible()

# Deal-feed-only features are hidden
assert not page.locator('#tp-bar-heat-btn').is_visible()
Expand Down Expand Up @@ -2414,7 +2414,7 @@ def test_deal_score_weight_preset_dropdown_in_filter_bar(page: Page):

# Explicitly wait for it to be visible based on state, no timeouts or force
popover.wait_for(state="visible")
page.locator('#tp-weight-popover button[data-weight="0.00"]').click()
page.locator('#tp-weight-popover button[data-weight="0.00"]').click(force=True)
assert page.evaluate("() => window.ToppreiseSuite.CONFIG.BESTPREISE_WEIGHT_RECORD === 0.0")
assert '100% Med' in page.locator('#tp-bar-weight-btn').inner_text()

Expand Down
111 changes: 81 additions & 30 deletions userscripts/toppreise/toppreise.user.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// ==UserScript==
// @name Toppreise.ch Suite: Power Filter & Price Alarm Auto-Filler
// @namespace https://github.com/tazztone/scripts
// @version 2.18.17
// @version 2.18.18
// @description All-in-one suite for Toppreise.ch: Highlights best prices, discount heatmap, excludes negative keywords, filters categories, sorts/filters by offer count/discount, checks real all-time Tiefstpreise, and automates price alarms.
// @author tazztone
// @match https://www.toppreise.ch/*
Expand All @@ -15,7 +15,10 @@

// ─── CONFIG DEFAULT VALUES ───────────────────────────────────────────────────
const DEFAULTS = {
FILTERS_ENABLED: true,
FILTER_NEG_ENABLED: true,
FILTER_CAT_ENABLED: true,
FILTER_MIN_ENABLED: true,
FILTER_BESTPREIS_ENABLED: true,
MODE: 'dim',
MARGIN_PERCENT: 0.0,
DIM_OPACITY: 0.25,
Expand Down Expand Up @@ -925,7 +928,10 @@ const SHADOW_MODAL_STYLES = `
const _setValue = (k, v) => (typeof GM_setValue !== 'undefined' ? GM_setValue(k, v) : localStorage.setItem('tp_suite_v2_' + k, JSON.stringify(v)));

const CONFIG = {
FILTERS_ENABLED: _getValue('FILTERS_ENABLED', DEFAULTS.FILTERS_ENABLED),
FILTER_NEG_ENABLED: _getValue('FILTER_NEG_ENABLED', _getValue('FILTERS_ENABLED', DEFAULTS.FILTER_NEG_ENABLED)),
FILTER_CAT_ENABLED: _getValue('FILTER_CAT_ENABLED', _getValue('FILTERS_ENABLED', DEFAULTS.FILTER_CAT_ENABLED)),
FILTER_MIN_ENABLED: _getValue('FILTER_MIN_ENABLED', _getValue('FILTERS_ENABLED', DEFAULTS.FILTER_MIN_ENABLED)),
FILTER_BESTPREIS_ENABLED: _getValue('FILTER_BESTPREIS_ENABLED', _getValue('FILTERS_ENABLED', DEFAULTS.FILTER_BESTPREIS_ENABLED)),
MODE: _getValue('MODE', DEFAULTS.MODE),
MARGIN_PERCENT: parseFloat(_getValue('MARGIN_PERCENT', DEFAULTS.MARGIN_PERCENT)),
DIM_OPACITY: parseFloat(_getValue('DIM_OPACITY', DEFAULTS.DIM_OPACITY)),
Expand Down Expand Up @@ -1947,9 +1953,20 @@ const SHADOW_MODAL_STYLES = `
<span id="tp-bar-min-val" style="min-width: 14px; text-align: center;">${CONFIG.MIN_OFFERS}</span>
<button class="tp-stepper-btn" id="tp-bar-min-plus">+</button>
</div>
<button class="tp-bar-btn tp-filter-toggle-btn ${CONFIG.FILTERS_ENABLED !== false ? 'tp-active' : 'tp-filter-off'}" id="tp-bar-filter-toggle" title="${CONFIG.FILTERS_ENABLED !== false ? 'Alle Filter aktiv (Klicken zum Pausieren)' : 'Filter pausiert (Klicken zum Aktivieren)'}">
${CONFIG.FILTERS_ENABLED !== false ? '⚡ Filter: AN' : '⚡ Filter: AUS'}
</button>
<div class="tp-filter-toggles-group" style="display: flex; gap: 4px; margin-left: auto;">
<button class="tp-bar-btn tp-filter-toggle-btn ${CONFIG.FILTER_NEG_ENABLED ? 'tp-active' : 'tp-filter-off'}" id="tp-toggle-neg" title="Negativ-Filter (Text) ${CONFIG.FILTER_NEG_ENABLED ? 'AN' : 'AUS'}">
📝
</button>
<button class="tp-bar-btn tp-filter-toggle-btn ${CONFIG.FILTER_CAT_ENABLED ? 'tp-active' : 'tp-filter-off'}" id="tp-toggle-cat" title="Kategorien-Filter ${CONFIG.FILTER_CAT_ENABLED ? 'AN' : 'AUS'}">
🚫
</button>
<button class="tp-bar-btn tp-filter-toggle-btn ${CONFIG.FILTER_MIN_ENABLED ? 'tp-active' : 'tp-filter-off'}" id="tp-toggle-min" title="Min-Angebote-Filter ${CONFIG.FILTER_MIN_ENABLED ? 'AN' : 'AUS'}">
🔢
</button>
<button class="tp-bar-btn tp-filter-toggle-btn ${CONFIG.FILTER_BESTPREIS_ENABLED ? 'tp-active' : 'tp-filter-off'}" id="tp-toggle-bestpreis" title="Deal-Filter ${CONFIG.FILTER_BESTPREIS_ENABLED ? 'AN' : 'AUS'}">
💎
</button>
</div>
</div>
<div id="tp-blocked-cats-container" class="tp-blocked-cats-row" style="display: ${excluded.length > 0 && isBlockedCatsOpen ? 'flex' : 'none'};">
<span class="tp-blocked-cats-label">🚫 Ausgeblendet (${excluded.length}):</span>
Expand Down Expand Up @@ -2163,11 +2180,29 @@ const SHADOW_MODAL_STYLES = `

bar.querySelector('#tp-bar-min-minus').onclick = () => updateMinOffers(-1);
bar.querySelector('#tp-bar-min-plus').onclick = () => updateMinOffers(1);
bar.querySelector('#tp-bar-filter-toggle').onclick = () => {
const next = !(CONFIG.FILTERS_ENABLED !== false);
saveConfigKey('FILTERS_ENABLED', next);
bar.querySelector('#tp-toggle-neg').onclick = () => {
const next = !CONFIG.FILTER_NEG_ENABLED;
saveConfigKey('FILTER_NEG_ENABLED', next);
processListings();
showToast(next ? '📝 Negativ-Filter AN' : '📝 Negativ-Filter AUS');
};
bar.querySelector('#tp-toggle-cat').onclick = () => {
const next = !CONFIG.FILTER_CAT_ENABLED;
saveConfigKey('FILTER_CAT_ENABLED', next);
processListings();
showToast(next ? '⚡ Filter aktiviert' : '⏸️ Filter pausiert (alle Angebote sichtbar)');
showToast(next ? '🚫 Kategorien-Filter AN' : '🚫 Kategorien-Filter AUS');
};
bar.querySelector('#tp-toggle-min').onclick = () => {
const next = !CONFIG.FILTER_MIN_ENABLED;
saveConfigKey('FILTER_MIN_ENABLED', next);
processListings();
showToast(next ? '🔢 Min-Angebote-Filter AN' : '🔢 Min-Angebote-Filter AUS');
};
bar.querySelector('#tp-toggle-bestpreis').onclick = () => {
const next = !CONFIG.FILTER_BESTPREIS_ENABLED;
saveConfigKey('FILTER_BESTPREIS_ENABLED', next);
processListings();
showToast(next ? '💎 Deal-Filter AN' : '💎 Deal-Filter AUS');
};
bar.querySelector('#tp-blocked-clear-all-btn').onclick = () => {
const prevCats = [...(CONFIG.EXCLUDED_CATEGORIES || [])];
Expand Down Expand Up @@ -2220,13 +2255,29 @@ const SHADOW_MODAL_STYLES = `
}
}

const filterToggleBtn = bar.querySelector('#tp-bar-filter-toggle');
if (filterToggleBtn) {
const isEnabled = CONFIG.FILTERS_ENABLED !== false;
filterToggleBtn.classList.toggle('tp-active', isEnabled);
filterToggleBtn.classList.toggle('tp-filter-off', !isEnabled);
filterToggleBtn.title = isEnabled ? 'Alle Filter aktiv (Klicken zum Pausieren)' : 'Filter pausiert (Klicken zum Aktivieren)';
filterToggleBtn.innerHTML = isEnabled ? '⚡ Filter: AN' : '⚡ Filter: AUS';
const toggleNeg = bar.querySelector('#tp-toggle-neg');
if (toggleNeg) {
toggleNeg.classList.toggle('tp-active', CONFIG.FILTER_NEG_ENABLED);
toggleNeg.classList.toggle('tp-filter-off', !CONFIG.FILTER_NEG_ENABLED);
toggleNeg.title = `Negativ-Filter (Text) ${CONFIG.FILTER_NEG_ENABLED ? 'AN' : 'AUS'}`;
}
const toggleCat = bar.querySelector('#tp-toggle-cat');
if (toggleCat) {
toggleCat.classList.toggle('tp-active', CONFIG.FILTER_CAT_ENABLED);
toggleCat.classList.toggle('tp-filter-off', !CONFIG.FILTER_CAT_ENABLED);
toggleCat.title = `Kategorien-Filter ${CONFIG.FILTER_CAT_ENABLED ? 'AN' : 'AUS'}`;
}
const toggleMin = bar.querySelector('#tp-toggle-min');
if (toggleMin) {
toggleMin.classList.toggle('tp-active', CONFIG.FILTER_MIN_ENABLED);
toggleMin.classList.toggle('tp-filter-off', !CONFIG.FILTER_MIN_ENABLED);
toggleMin.title = `Min-Angebote-Filter ${CONFIG.FILTER_MIN_ENABLED ? 'AN' : 'AUS'}`;
}
const toggleBestpreis = bar.querySelector('#tp-toggle-bestpreis');
if (toggleBestpreis) {
toggleBestpreis.classList.toggle('tp-active', CONFIG.FILTER_BESTPREIS_ENABLED);
toggleBestpreis.classList.toggle('tp-filter-off', !CONFIG.FILTER_BESTPREIS_ENABLED);
toggleBestpreis.title = `Deal-Filter ${CONFIG.FILTER_BESTPREIS_ENABLED ? 'AN' : 'AUS'}`;
}

const batchBtn = bar.querySelector('#tp-bar-batch-check-btn');
Expand Down Expand Up @@ -2386,12 +2437,9 @@ const SHADOW_MODAL_STYLES = `
}

function applyCardFilters(cd, termsList, excludedCats, minOffers, pageHasOffers) {
if (CONFIG.FILTERS_ENABLED === false) {
return { isNeg: false, isCatExcluded: false, isLowOffers: false };
}
const isNeg = matchesNegativeTerms(cd.card, termsList);
const isCatExcluded = !!(cd.catName && isPathExcluded(cd.catName, cd.rootGroup, excludedCats));
const isLowOffers = !!(pageHasOffers && minOffers > 0 && cd.offerCount < minOffers);
const isNeg = CONFIG.FILTER_NEG_ENABLED ? matchesNegativeTerms(cd.card, termsList) : false;
const isCatExcluded = CONFIG.FILTER_CAT_ENABLED ? !!(cd.catName && isPathExcluded(cd.catName, cd.rootGroup, excludedCats)) : false;
const isLowOffers = CONFIG.FILTER_MIN_ENABLED ? !!(pageHasOffers && minOffers > 0 && cd.offerCount < minOffers) : false;
return { isNeg, isCatExcluded, isLowOffers };
}

Expand Down Expand Up @@ -2697,7 +2745,7 @@ const SHADOW_MODAL_STYLES = `
}
} else if (stats) {
// Verified NON-Deal (has stats but score <= 0 or not at low) -> HIDE IT if filters enabled!
if (CONFIG.FILTERS_ENABLED !== false) {
if (CONFIG.FILTER_BESTPREIS_ENABLED !== false) {
card.classList.add('tp-bestpreise-hidden');
} else {
card.classList.remove('tp-bestpreise-hidden');
Expand Down Expand Up @@ -2741,7 +2789,7 @@ const SHADOW_MODAL_STYLES = `
const prevLow = stats.previousLow;
const realDropVsPrev = prevLow && prevLow > cardPrice ? Math.round(((prevLow - cardPrice) / prevLow) * 100) : (stats.realDiscountVsPrevLow || 0);

if (CONFIG.FILTERS_ENABLED !== false && isNonBest && CONFIG.REAL_DEAL_FILTER_ACTIVE) {
if (CONFIG.FILTER_BESTPREIS_ENABLED !== false && isNonBest && CONFIG.REAL_DEAL_FILTER_ACTIVE) {
card.classList.add('tp-non-bestpreis-filtered');
} else {
card.classList.remove('tp-non-bestpreis-filtered');
Expand Down Expand Up @@ -3082,9 +3130,12 @@ const SHADOW_MODAL_STYLES = `
showToast('Bestpreise-Modus deaktiviert');
});
emptyNotice.querySelector('#tp-empty-toggle-filters-btn')?.addEventListener('click', () => {
saveConfigKey('FILTERS_ENABLED', false);
saveConfigKey('FILTER_NEG_ENABLED', false);
saveConfigKey('FILTER_CAT_ENABLED', false);
saveConfigKey('FILTER_MIN_ENABLED', false);
saveConfigKey('FILTER_BESTPREIS_ENABLED', false);
processListings();
showToast('⏸️ Filter pausiert (alle Angebote sichtbar)');
showToast('⏸️ Alle Filter pausiert (alle Angebote sichtbar)');
});
} else if (emptyNotice) {
emptyNotice.remove();
Expand Down Expand Up @@ -3129,13 +3180,13 @@ const SHADOW_MODAL_STYLES = `
if (cd.pid && !cd.stats && cd.discountVal !== null && cd.discountVal >= minDealDiscount) {
counts.uncheckedDeals++;
}
if (CONFIG.FILTERS_ENABLED !== false && cd.isVerifiedNonBest && CONFIG.REAL_DEAL_FILTER_ACTIVE) {
if (CONFIG.FILTER_BESTPREIS_ENABLED !== false && cd.isVerifiedNonBest && CONFIG.REAL_DEAL_FILTER_ACTIVE) {
counts.nonBest++;
}
cd.dealScore = computeDealScore(cd.stats, cd.cardPrice);
if (cd.dealScore) {
counts.bestpreiseDeals++;
} else if (CONFIG.FILTERS_ENABLED !== false && CONFIG.BESTPREISE_MODE_ACTIVE && cd.stats && !isStandardFiltered) {
} else if (CONFIG.FILTER_BESTPREIS_ENABLED !== false && CONFIG.BESTPREISE_MODE_ACTIVE && cd.stats && !isStandardFiltered) {
counts.bestpreiseHidden++;
}
}
Expand Down Expand Up @@ -3784,7 +3835,7 @@ const SHADOW_MODAL_STYLES = `
exportBtn?.addEventListener('click', () => {
const exportData = {
_meta: {
version: (typeof GM_info !== 'undefined' && GM_info?.script?.version) || '2.16.0',
version: (typeof GM_info !== 'undefined' && GM_info?.script?.version) || '2.18.18',
exported: new Date().toISOString()
},
config: { ...CONFIG }
Expand Down
Loading