Microsoft Store Regional Price Checker

Compare game prices across Iceland, Ireland, Turkey and United States

Size

8.8 KB

Version

1.1.2

Created

Oct 26, 2025

Updated

about 1 month ago

1// ==UserScript==
2// @name		Microsoft Store Regional Price Checker
3// @description		Compare game prices across Iceland, Ireland, Turkey and United States
4// @version		1.1.2
5// @match		https://*.apps.microsoft.com/*
6// @icon		https://apps.microsoft.com/favicon.ico
7// @grant		GM.xmlhttpRequest
8// ==/UserScript==
9(function() {
10    'use strict';
11
12    // Regional configurations
13    const REGIONS = [
14        { name: 'Iceland', code: 'is', language: 'is-is' },
15        { name: 'Ireland', code: 'IE', language: 'en-ie' },
16        { name: 'Turkey', code: 'tr', language: 'tr-tr' },
17        { name: 'United States', code: 'us', language: 'en-us' }
18    ];
19
20    // Extract product ID from URL
21    function getProductId() {
22        const match = window.location.pathname.match(/\/detail\/([^/?]+)/);
23        return match ? match[1] : null;
24    }
25
26    // Fetch price for a specific region
27    async function fetchRegionalPrice(productId, region) {
28        const url = `https://apps.microsoft.com/detail/${productId}?hl=${region.language}&gl=${region.code}`;
29        
30        console.log(`Fetching price for ${region.name} from: ${url}`);
31        
32        return new Promise((resolve) => {
33            GM.xmlhttpRequest({
34                method: 'GET',
35                url: url,
36                onload: function(response) {
37                    try {
38                        const parser = new DOMParser();
39                        const doc = parser.parseFromString(response.responseText, 'text/html');
40                        
41                        let price = 'Not found';
42                        
43                        // Try to find price in span with aria-label containing "Purchase"
44                        const purchaseSpan = doc.querySelector('span[aria-label*="Purchase"]');
45                        if (purchaseSpan) {
46                            price = purchaseSpan.textContent.trim();
47                            console.log(`Found price in purchase span for ${region.name}: ${price}`);
48                            resolve({ region: region.name, price: price });
49                            return;
50                        }
51                        
52                        // Try to find sale price in span with class "current-price"
53                        const salePriceSpan = doc.querySelector('span.current-price');
54                        if (salePriceSpan) {
55                            price = salePriceSpan.textContent.trim();
56                            console.log(`Found sale price for ${region.name}: ${price}`);
57                            resolve({ region: region.name, price: price });
58                            return;
59                        }
60                        
61                        // Try to find price in meta tags
62                        const priceMetaTag = doc.querySelector('meta[property="product:price:amount"]') ||
63                                           doc.querySelector('meta[name="price"]');
64                        if (priceMetaTag) {
65                            const amount = priceMetaTag.getAttribute('content');
66                            const currencyTag = doc.querySelector('meta[property="product:price:currency"]');
67                            const currency = currencyTag ? currencyTag.getAttribute('content') : '';
68                            price = currency + amount;
69                            console.log(`Found price in meta tag for ${region.name}: ${price}`);
70                            resolve({ region: region.name, price: price });
71                            return;
72                        }
73                        
74                        // Search for price patterns in the entire HTML text
75                        const bodyText = doc.body.textContent;
76                        
77                        // Try different currency patterns
78                        const patterns = [
79                            /€\s*[\d,]+\.?\d*/g,  // Euro
80                            /\$\s*[\d,]+\.?\d*/g,  // Dollar
81                            /£\s*[\d,]+\.?\d*/g,  // Pound
82                            /₺\s*[\d,]+\.?\d*/g,  // Turkish Lira
83                            /kr\s*[\d,]+\.?\d*/gi, // Krona
84                            /[\d,]+\.?\d*\s*/g,   // Euro after number
85                            /[\d,]+\.?\d*\s*\$/g,  // Dollar after number
86                            /[\d,]+\.?\d*\s*kr/gi  // Krona after number
87                        ];
88                        
89                        for (const pattern of patterns) {
90                            const matches = bodyText.match(pattern);
91                            if (matches && matches.length > 0) {
92                                // Get the first reasonable price (not 0 or very small)
93                                for (const match of matches) {
94                                    const numValue = parseFloat(match.replace(/[^\d.]/g, ''));
95                                    if (numValue > 1) {
96                                        price = match.trim();
97                                        console.log(`Found price for ${region.name}: ${price}`);
98                                        break;
99                                    }
100                                }
101                                if (price !== 'Not found') break;
102                            }
103                        }
104                        
105                        // If still not found, look for "Free" text
106                        if (price === 'Not found' && /\bfree\b/i.test(bodyText)) {
107                            price = 'Free';
108                        }
109                        
110                        console.log(`Final price for ${region.name}: ${price}`);
111                        resolve({ region: region.name, price: price });
112                    } catch (error) {
113                        console.error(`Error parsing price for ${region.name}:`, error);
114                        resolve({ region: region.name, price: 'Error' });
115                    }
116                },
117                onerror: function(error) {
118                    console.error(`Failed to fetch price for ${region.name}:`, error);
119                    resolve({ region: region.name, price: 'Failed to load' });
120                }
121            });
122        });
123    }
124
125    // Create and style the price comparison box
126    function createPriceBox() {
127        const box = document.createElement('div');
128        box.id = 'regional-price-box';
129        box.innerHTML = `
130            <div style="font-weight: bold; margin-bottom: 10px; font-size: 16px; color: #0067b8;">
131                Regional Prices
132            </div>
133            <div id="price-list" style="font-size: 14px;">
134                <div style="color: #666;">Loading prices...</div>
135            </div>
136        `;
137        
138        box.style.cssText = `
139            position: fixed;
140            top: 100px;
141            right: 20px;
142            background: white;
143            border: 2px solid #0067b8;
144            border-radius: 8px;
145            padding: 20px;
146            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
147            z-index: 10000;
148            min-width: 280px;
149            max-width: 350px;
150            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
151        `;
152        
153        document.body.appendChild(box);
154        return box;
155    }
156
157    // Update the price list in the box
158    function updatePriceList(prices) {
159        const priceList = document.getElementById('price-list');
160        if (!priceList) return;
161        
162        priceList.innerHTML = prices.map(item => `
163            <div style="display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #e0e0e0;">
164                <span style="font-weight: 500; color: #333;">${item.region}:</span>
165                <span style="color: #0067b8; font-weight: bold;">${item.price}</span>
166            </div>
167        `).join('');
168    }
169
170    // Main initialization function
171    async function init() {
172        console.log('Microsoft Store Regional Price Checker initialized');
173        
174        const productId = getProductId();
175        if (!productId) {
176            console.log('No product ID found in URL');
177            return;
178        }
179        
180        console.log('Product ID:', productId);
181        
182        // Wait for page to be fully loaded
183        if (document.readyState === 'loading') {
184            await new Promise(resolve => {
185                document.addEventListener('DOMContentLoaded', resolve);
186            });
187        }
188        
189        // Create the price box
190        const priceBox = createPriceBox();
191        
192        // Fetch prices for all regions
193        const pricePromises = REGIONS.map(region => fetchRegionalPrice(productId, region));
194        const prices = await Promise.all(pricePromises);
195        
196        // Update the display
197        updatePriceList(prices);
198    }
199
200    // Start the extension
201    if (document.readyState === 'loading') {
202        document.addEventListener('DOMContentLoaded', init);
203    } else {
204        init();
205    }
206})();
Microsoft Store Regional Price Checker | Robomonkey