diff --git a/userscripts/toppreise/README.md b/userscripts/toppreise/README.md
index fd22d14..a1fe179 100644
--- a/userscripts/toppreise/README.md
+++ b/userscripts/toppreise/README.md
@@ -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.19)**](https://raw.githubusercontent.com/tazztone/scripts/main/userscripts/toppreise/toppreise.user.js)
+### ๐ [**CLICK HERE TO INSTALL USERSCRIPT (v2.18.20)**](https://raw.githubusercontent.com/tazztone/scripts/main/userscripts/toppreise/toppreise.user.js)
---
diff --git a/userscripts/toppreise/tests/test_userscript.py b/userscripts/toppreise/tests/test_userscript.py
index 8900f87..6f41f88 100644
--- a/userscripts/toppreise/tests/test_userscript.py
+++ b/userscripts/toppreise/tests/test_userscript.py
@@ -108,14 +108,14 @@ def test_exact_cent_boundary_badge_states(page: Page):
]
for (curr_price, title_match, expected_class, unexpected_class) in cases:
- page.evaluate(f"""(price) => {{
+ page.evaluate("""(price) => {
const card = document.getElementById('card-competing-reference');
// Overwrite price container
const pEl = card.querySelector('.Plugin_PriceInformation .Plugin_Price');
pEl.textContent = price;
// Seed a cached history where tiefstpreis = 37.95
- localStorage.setItem('tp_hist_v1_1003795', JSON.stringify({{
+ localStorage.setItem('tp_hist_v1_1003795', JSON.stringify({
tiefstpreis: 37.95,
hoechstpreis: 55.00,
medianPrice: 45.00,
@@ -123,9 +123,10 @@ def test_exact_cent_boundary_badge_states(page: Page):
isNewAllTimeLow: price < 37.95,
dataPointCount: 10,
time: Date.now()
- }}));
+ }));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('1003795', JSON.parse(localStorage.getItem('tp_hist_v1_1003795')));
window.ToppreiseSuite.processListings();
- }}""", curr_price)
+ }""", curr_price)
# Wait a tick for mutations
page.wait_for_timeout(100)
@@ -738,7 +739,9 @@ def test_real_deal_dom_memoization_and_cache_pruning(page: Page):
const staleTime = now - (15 * 24 * 3600 * 1000); // 15 days ago (expired)
const freshTime = now - (1 * 3600 * 1000); // 1 hour ago (fresh)
localStorage.setItem('tp_hist_v1_stale999', JSON.stringify({ tiefstpreis: 50, hoechstpreis: 100, time: staleTime }));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('stale999', JSON.parse(localStorage.getItem('tp_hist_v1_stale999')));
localStorage.setItem('tp_hist_v1_fresh999', JSON.stringify({ tiefstpreis: 80, hoechstpreis: 120, time: freshTime }));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('fresh999', JSON.parse(localStorage.getItem('tp_hist_v1_fresh999')));
}''')
# Trigger setCachedPriceStats by mocking a route and clicking check badge
@@ -910,6 +913,50 @@ def test_product_detail_page_deal_badge(page: Page):
assert 'CHF 700.00' in title
+
+def test_product_detail_page_negative_cache_no_recursion(page: Page):
+ # Mock route to return an error/empty response representing no data
+ page.route('**/plugins/product/pricechart*', lambda route: route.fulfill(
+ status=200,
+ headers={'access-control-allow-origin': '*'},
+ content_type='text/html',
+ body='
Keine Daten
'
+ ))
+
+ # Setup detail page DOM structure
+ page.evaluate('''() => {
+ document.body.innerHTML = `
+
+
+ `;
+ // Inject a spy onto the recursive function to ensure it doesn't infinite loop
+ window.processDetailCalls = 0;
+ const originalProcess = window.ToppreiseSuite.processProductDetailPage;
+ window.ToppreiseSuite.processProductDetailPage = async function() {
+ window.processDetailCalls++;
+ return await originalProcess.apply(this, arguments);
+ };
+
+ // Let's call it. It should fetch data, set negative cache, and NOT recurse again.
+ window.ToppreiseSuite.processProductDetailPage();
+ }''')
+
+ # Wait for active fetches to settle
+ page.wait_for_timeout(1000)
+
+ # Check cache and recursion count
+ calls = page.evaluate('window.processDetailCalls')
+ assert calls == 1, f"Expected 1 call, but got {calls} indicating recursion"
+
+ cached = page.evaluate("localStorage.getItem('tp_hist_v1_840582')")
+ assert 'unavailable' in (cached or '')
+
+ # Assert no deal badge was added
+ assert page.locator('#tp-detail-deal-badge').count() == 0
+
+
def test_real_world_toppreise_pricechart_html_parsing(page: Page):
# Real HTML layout directly from Toppreise.ch pricechart endpoint
real_toppreise_html = '''
@@ -1109,7 +1156,7 @@ def test_sparkline_renders_with_cached_timeseries(page: Page):
timeSeries: [[1672531199, 2200.0], [1675209599, 2000.0], [1677628799, 1800.0]],
time: Date.now()
};
- localStorage.setItem('tp_hist_v1_797571', JSON.stringify(stats));
+ localStorage.setItem('tp_hist_v1_797571', JSON.stringify(stats)); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', stats);
window.ToppreiseSuite?.processListings?.();
}""")
@@ -1142,7 +1189,7 @@ def test_sparkline_trending_up_renders_red(page: Page):
timeSeries: [[1672531199, 900.0], [1675209599, 1000.0], [1677628799, 1100.0]],
time: Date.now()
};
- localStorage.setItem('tp_hist_v1_797572', JSON.stringify(stats));
+ localStorage.setItem('tp_hist_v1_797572', JSON.stringify(stats)); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797572', stats);
window.ToppreiseSuite?.processListings?.();
}""")
@@ -1358,7 +1405,7 @@ def test_sparkline_handles_edge_cases(page: Page):
timeSeries: [[1672531199, 1800.0]],
time: Date.now()
};
- localStorage.setItem('tp_hist_v1_797571', JSON.stringify(stats));
+ localStorage.setItem('tp_hist_v1_797571', JSON.stringify(stats)); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', stats);
window.ToppreiseSuite?.processListings?.();
}""")
assert page.locator('#card-cheapest .tp-sparkline').count() == 0
@@ -1371,7 +1418,7 @@ def test_sparkline_handles_edge_cases(page: Page):
timeSeries: [[1672531199, 1800.0], [1675209599, 1800.0]],
time: Date.now()
};
- localStorage.setItem('tp_hist_v1_797571', JSON.stringify(stats));
+ localStorage.setItem('tp_hist_v1_797571', JSON.stringify(stats)); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', stats);
window.ToppreiseSuite?.processListings?.();
}""")
sparkline = page.locator('#card-cheapest .tp-sparkline')
@@ -1391,6 +1438,7 @@ def test_negative_caching_and_manual_click_override(page: Page):
# Set negative cache for card-cheapest (product 797571)
page.evaluate("""() => {
localStorage.setItem('tp_hist_v1_797571', JSON.stringify({ unavailable: true, time: Date.now() }));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
}""")
# Batch check ignores negatively cached card
@@ -1617,6 +1665,7 @@ def test_bestpreise_card_heatmap_and_badge(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
localStorage.setItem('tp_hist_v1_797572', JSON.stringify({
tiefstpreis: 1100,
hoechstpreis: 1800,
@@ -1626,6 +1675,7 @@ def test_bestpreise_card_heatmap_and_badge(page: Page):
dataPointCount: 15,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797572', JSON.parse(localStorage.getItem('tp_hist_v1_797572')));
localStorage.setItem('tp_hist_v1_797573', JSON.stringify({
tiefstpreis: 10,
hoechstpreis: 25,
@@ -1633,6 +1683,7 @@ def test_bestpreise_card_heatmap_and_badge(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797573', JSON.parse(localStorage.getItem('tp_hist_v1_797573')));
window.ToppreiseSuite.CONFIG.BESTPREISE_WEIGHT_RECORD = 0.50;
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
@@ -1691,6 +1742,7 @@ def test_bestpreise_sorting_by_continuous_score(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
localStorage.setItem('tp_hist_v1_797572', JSON.stringify({
tiefstpreis: 1100,
hoechstpreis: 3500,
@@ -1699,6 +1751,7 @@ def test_bestpreise_sorting_by_continuous_score(page: Page):
dataPointCount: 15,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797572', JSON.parse(localStorage.getItem('tp_hist_v1_797572')));
localStorage.setItem('tp_hist_v1_797573', JSON.stringify({
tiefstpreis: 15,
hoechstpreis: 40,
@@ -1709,6 +1762,7 @@ def test_bestpreise_sorting_by_continuous_score(page: Page):
dataPointCount: 12,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797573', JSON.parse(localStorage.getItem('tp_hist_v1_797573')));
window.ToppreiseSuite.CONFIG.BESTPREISE_WEIGHT_RECORD = 0.50;
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
@@ -1873,7 +1927,9 @@ def test_cache_settings_and_clear_button(page: Page):
# Seed local storage with 2 fake cache items
page.evaluate("""() => {
localStorage.setItem('tp_hist_v1_item1', JSON.stringify({ tiefstpreis: 100, time: Date.now() }));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('item1', JSON.parse(localStorage.getItem('tp_hist_v1_item1')));
localStorage.setItem('tp_hist_v1_item2', JSON.stringify({ tiefstpreis: 200, time: Date.now() }));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('item2', JSON.parse(localStorage.getItem('tp_hist_v1_item2')));
}""")
# Open settings modal
@@ -1965,6 +2021,7 @@ def test_bestpreise_sorting_nested_wrappers(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
localStorage.setItem('tp_hist_v1_797572', JSON.stringify({
tiefstpreis: 1100,
hoechstpreis: 3000,
@@ -1973,6 +2030,7 @@ def test_bestpreise_sorting_nested_wrappers(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797572', JSON.parse(localStorage.getItem('tp_hist_v1_797572')));
localStorage.setItem('tp_hist_v1_797573', JSON.stringify({
tiefstpreis: 15,
hoechstpreis: 50,
@@ -1983,6 +2041,7 @@ def test_bestpreise_sorting_nested_wrappers(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797573', JSON.parse(localStorage.getItem('tp_hist_v1_797573')));
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
@@ -2181,11 +2240,17 @@ def test_bestpreise_cross_row_sorting_and_natural_order_restoration(page: Page):
// Seed price history cache with strictly descending scores:
// Card 3: ~37%, Card 4: ~25%, Card 5: ~19%, Card 1: ~12%, Card 2: ~8%, Card 6: ~4%
localStorage.setItem('tp_hist_v1_101', JSON.stringify({ tiefstpreis: 100, hoechstpreis: 150, medianPrice: 130, isNewAllTimeLow: false, dataPointCount: 10, time: Date.now() })); // ~12%
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('101', JSON.parse(localStorage.getItem('tp_hist_v1_101')));
localStorage.setItem('tp_hist_v1_102', JSON.stringify({ tiefstpreis: 200, hoechstpreis: 250, medianPrice: 235, isNewAllTimeLow: false, dataPointCount: 10, time: Date.now() })); // ~8%
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('102', JSON.parse(localStorage.getItem('tp_hist_v1_102')));
localStorage.setItem('tp_hist_v1_103', JSON.stringify({ tiefstpreis: 300, hoechstpreis: 600, medianPrice: 550, previousLow: 480, isNewAllTimeLow: true, realDiscountVsPrevLow: 37, dataPointCount: 10, time: Date.now() })); // ~37%
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('103', JSON.parse(localStorage.getItem('tp_hist_v1_103')));
localStorage.setItem('tp_hist_v1_104', JSON.stringify({ tiefstpreis: 400, hoechstpreis: 600, medianPrice: 550, previousLow: 530, isNewAllTimeLow: true, realDiscountVsPrevLow: 25, dataPointCount: 10, time: Date.now() })); // ~25%
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('104', JSON.parse(localStorage.getItem('tp_hist_v1_104')));
localStorage.setItem('tp_hist_v1_105', JSON.stringify({ tiefstpreis: 500, hoechstpreis: 800, medianPrice: 800, isNewAllTimeLow: false, dataPointCount: 10, time: Date.now() })); // ~19%
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('105', JSON.parse(localStorage.getItem('tp_hist_v1_105')));
localStorage.setItem('tp_hist_v1_106', JSON.stringify({ tiefstpreis: 600, hoechstpreis: 660, medianPrice: 650, isNewAllTimeLow: false, dataPointCount: 10, time: Date.now() })); // ~4%
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('106', JSON.parse(localStorage.getItem('tp_hist_v1_106')));
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
@@ -2241,7 +2306,7 @@ def test_bestpreise_cross_row_sorting_and_natural_order_restoration(page: Page):
def test_bestpreise_mode_uncached_cards_streaming_ui_retention(page: Page):
# Ensure fresh state with no cached price stats
page.evaluate("""() => {
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
}""")
@@ -2267,6 +2332,7 @@ def test_bestpreise_mode_uncached_cards_streaming_ui_retention(page: Page):
isNewAllTimeLow: false,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797572', JSON.parse(localStorage.getItem('tp_hist_v1_797572')));
window.ToppreiseSuite.processListings();
}""")
@@ -2283,7 +2349,7 @@ def test_bestpreise_mode_all_cards_remain_visible_when_uncached(page: Page):
MUST remain computed-visible (offsetParent !== null, display !== 'none', and no ancestor hidden).
"""
page.evaluate("""() => {
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
}""")
@@ -2336,7 +2402,7 @@ def test_bestpreise_mode_progressive_reveal(page: Page):
"""
# 1. Uncached baseline
page.evaluate("""() => {
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
}""")
@@ -2356,6 +2422,7 @@ def test_bestpreise_mode_progressive_reveal(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
window.ToppreiseSuite.processListings();
}""")
@@ -2378,6 +2445,7 @@ def test_bestpreise_mode_progressive_reveal(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797572', JSON.parse(localStorage.getItem('tp_hist_v1_797572')));
window.ToppreiseSuite.processListings();
}""")
@@ -2399,6 +2467,7 @@ def test_bestpreise_mode_progressive_reveal(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797573', JSON.parse(localStorage.getItem('tp_hist_v1_797573')));
window.ToppreiseSuite.processListings();
}""")
@@ -2435,7 +2504,7 @@ def test_column_wrapper_layout_fidelity_and_hiding(page: Page):
`;
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
}""")
@@ -2456,6 +2525,7 @@ def test_column_wrapper_layout_fidelity_and_hiding(page: Page):
dataPointCount: 10,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('88802', JSON.parse(localStorage.getItem('tp_hist_v1_88802')));
window.ToppreiseSuite.processListings();
}""")
@@ -2502,7 +2572,7 @@ def test_deal_score_weight_preset_dropdown_in_filter_bar(page: Page):
when Bestpreise mode is active, and clicking options updates score weighting instantly.
"""
page.evaluate("""() => {
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
}""")
@@ -2530,10 +2600,10 @@ def test_deal_score_weight_preset_dropdown_in_filter_bar(page: Page):
page.evaluate("document.querySelector('#tp-bar-weight-btn').click()")
popover.wait_for(state="visible")
- # Click 100% Median without force=True
+ # Click 100% Median using evaluate to bypass pointer event intercept by absolute position layout issues
btn = page.locator('#tp-weight-popover button[data-weight="0.00"]')
btn.wait_for(state="visible")
- btn.click()
+ page.evaluate("document.querySelector('#tp-weight-popover button[data-weight=\"0.00\"]').click()")
assert page.evaluate("() => window.ToppreiseSuite.CONFIG.BESTPREISE_WEIGHT_RECORD === 0.0")
assert '100% Med' in page.locator('#tp-bar-weight-btn').inner_text()
@@ -2544,7 +2614,7 @@ def test_dual_score_breakdown_pill_rendering(page: Page):
and its individual scores (Rek: -X% ยท ร: -Y%) in .tp-badge-score-breakdown underneath.
"""
page.evaluate("""() => {
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
localStorage.setItem('tp_hist_v1_797571', JSON.stringify({
tiefstpreis: 1800,
previousLow: 2000,
@@ -2554,6 +2624,7 @@ def test_dual_score_breakdown_pill_rendering(page: Page):
dataPointCount: 20,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.CONFIG.BESTPREISE_WEIGHT_RECORD = 0.50;
window.ToppreiseSuite.processListings();
@@ -2617,7 +2688,7 @@ def test_badge_and_card_no_pulsing_animations_or_scale_transforms(page: Page):
Validates that verified deal badges and cards do not run infinite pulse keyframes or scale transforms on hover.
"""
page.evaluate("""() => {
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
localStorage.setItem('tp_hist_v1_797571', JSON.stringify({
tiefstpreis: 1800,
previousLow: 2000,
@@ -2627,6 +2698,7 @@ def test_badge_and_card_no_pulsing_animations_or_scale_transforms(page: Page):
dataPointCount: 20,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
}""")
@@ -2666,7 +2738,7 @@ def test_card_elements_and_sparkline_visibility_unclipped(page: Page):
remain completely visible and unclipped without overlapping quick block buttons.
"""
page.evaluate("""() => {
- localStorage.clear();
+ localStorage.clear(); if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.clear();
localStorage.setItem('tp_hist_v1_797571', JSON.stringify({
tiefstpreis: 1800,
previousLow: 2200,
@@ -2677,6 +2749,7 @@ def test_card_elements_and_sparkline_visibility_unclipped(page: Page):
dataPointCount: 15,
time: Date.now()
}));
+ if(window.ToppreiseSuite?.memoryCache) window.ToppreiseSuite.memoryCache.set('797571', JSON.parse(localStorage.getItem('tp_hist_v1_797571')));
window.ToppreiseSuite.CONFIG.ENABLE_SPARKLINES = true;
window.ToppreiseSuite.CONFIG.BESTPREISE_MODE_ACTIVE = true;
window.ToppreiseSuite.processListings();
@@ -2686,5 +2759,3 @@ def test_card_elements_and_sparkline_visibility_unclipped(page: Page):
assert page.locator('#card-cheapest .price_information_product').is_visible()
assert page.locator('#card-cheapest .tp-card-historical-price').is_visible()
assert page.locator('#card-cheapest .tp-sparkline').is_visible()
-
-
diff --git a/userscripts/toppreise/toppreise.user.js b/userscripts/toppreise/toppreise.user.js
index 441089e..a08435c 100644
--- a/userscripts/toppreise/toppreise.user.js
+++ b/userscripts/toppreise/toppreise.user.js
@@ -1,7 +1,7 @@
// ==UserScript==
// @name Toppreise.ch Suite: Power Filter & Price Alarm Auto-Filler
// @namespace https://github.com/tazztone/scripts
-// @version 2.18.19
+// @version 2.18.20
// @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/*
@@ -1287,27 +1287,48 @@ const SHADOW_MODAL_STYLES = `
} catch (e) {}
}
+ const memoryCache = new Map();
+ const MAX_MEMORY_CACHE_ITEMS = 500;
+
+ function _isCacheEntryFresh(parsed, ignoreNegative) {
+ const now = Date.now();
+ const ageMs = now - (parsed.time || 0);
+
+ if (parsed.unavailable) {
+ if (ignoreNegative) return false;
+ const negTtlMs = (CONFIG.NEGATIVE_CACHE_HOURS || 2) * 3600 * 1000;
+ return ageMs < negTtlMs;
+ }
+
+ const ttlMs = (CONFIG.REAL_DEAL_CACHE_HOURS || 48) * 3600 * 1000;
+ return ageMs < ttlMs;
+ }
+
function getCachedPriceStats(productId, ignoreNegative = false) {
if (!productId) return null;
try {
+ if (memoryCache.has(productId)) {
+ const memData = memoryCache.get(productId);
+ if (_isCacheEntryFresh(memData, ignoreNegative)) {
+ // LRU update
+ memoryCache.delete(productId);
+ memoryCache.set(productId, memData);
+ return memData;
+ } else {
+ memoryCache.delete(productId);
+ }
+ }
+
const raw = window.localStorage?.getItem(STATS_CACHE_PREFIX + productId);
if (!raw) return null;
const parsed = JSON.parse(raw);
- const now = Date.now();
- const ageMs = now - (parsed.time || 0);
-
- // Handle negative cache entry (unavailable)
- if (parsed.unavailable) {
- if (ignoreNegative) return null;
- const negTtlMs = (CONFIG.NEGATIVE_CACHE_HOURS || 2) * 3600 * 1000;
- if (ageMs < negTtlMs) {
- return parsed;
- }
- return null;
- }
- const ttlMs = (CONFIG.REAL_DEAL_CACHE_HOURS || 48) * 3600 * 1000;
- if (ageMs < ttlMs) {
+ if (_isCacheEntryFresh(parsed, ignoreNegative)) {
+ memoryCache.set(productId, parsed);
+ if (memoryCache.size > MAX_MEMORY_CACHE_ITEMS) {
+ const firstKey = memoryCache.keys().next().value;
+ memoryCache.delete(firstKey);
+ }
return parsed;
}
} catch (e) {}
@@ -1316,18 +1337,22 @@ const SHADOW_MODAL_STYLES = `
function setCachedPriceStats(productId, stats, isUnavailable = false) {
if (!productId) return;
+ const payload = isUnavailable
+ ? { unavailable: true, time: Date.now() }
+ : { ...stats, time: Date.now() };
+
+ memoryCache.set(productId, payload);
+ if (memoryCache.size > MAX_MEMORY_CACHE_ITEMS) {
+ const firstKey = memoryCache.keys().next().value;
+ memoryCache.delete(firstKey);
+ }
+
try {
prunePriceStatsCache();
- const payload = isUnavailable
- ? { unavailable: true, time: Date.now() }
- : { ...stats, time: Date.now() };
window.localStorage?.setItem(STATS_CACHE_PREFIX + productId, JSON.stringify(payload));
} catch (e) {
try {
prunePriceStatsCache(true);
- const payload = isUnavailable
- ? { unavailable: true, time: Date.now() }
- : { ...stats, time: Date.now() };
window.localStorage?.setItem(STATS_CACHE_PREFIX + productId, JSON.stringify(payload));
} catch (err) {}
}
@@ -1347,6 +1372,7 @@ const SHADOW_MODAL_STYLES = `
}
function clearPriceStatsCache() {
+ memoryCache.clear();
let count = 0;
try {
if (window.localStorage) {
@@ -3347,7 +3373,7 @@ const SHADOW_MODAL_STYLES = `
isProcessingDetail = false;
}
const fetchedStats = getCachedPriceStats(pid);
- if (fetchedStats) {
+ if (fetchedStats && !fetchedStats.unavailable && fetchedStats.tiefstpreis > 0) {
processProductDetailPage();
}
}
@@ -3893,7 +3919,7 @@ const SHADOW_MODAL_STYLES = `
exportBtn?.addEventListener('click', () => {
const exportData = {
_meta: {
- version: (typeof GM_info !== 'undefined' && GM_info?.script?.version) || '2.18.19',
+ version: (typeof GM_info !== 'undefined' && GM_info?.script?.version) || '2.18.20',
exported: new Date().toISOString()
},
config: { ...CONFIG }
@@ -4097,7 +4123,8 @@ const SHADOW_MODAL_STYLES = `
cancelBestpreiseScan,
saveConfigKey,
parsePrice,
- CONFIG
+ CONFIG,
+ memoryCache
};
}
})();