// ==UserScript== // @name Wii Shop Style Enhancer (Tampermonkey - With BGM) // @namespace http://tampermonkey.net/ // @version 0.1 // @description Applies Wii Shop Channel aesthetics and functionality, including BGM. // @author Thom // @match *://*/* // Or more specific URLs where you want it to run // @grant GM_setValue // @grant GM_getValue // @grant GM_log // @grant GM_getResourceURL // @resource SND_SE01 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/1.wav // @resource SND_SE02 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/2.wav // @resource SND_SE03 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/3.wav // @resource SND_SE04 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/4.wav // @resource SND_SE05 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/5.wav // @resource SND_SE06 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/6.wav // @resource SND_SE07 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/7.wav // @resource SND_SE08 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/8.wav // @resource SND_SE09 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/9.wav // @resource SND_SE10 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/10.wav // @resource SND_SE11 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/11.wav // @resource SND_SE12 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/12.wav // @resource SND_SE13 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/13.wav // @resource SND_SE14 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/14.wav // @resource SND_SE15 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/15.wav // @resource SND_SE16 https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/16.wav // @resource BGM_WII_SHOP https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/audio/bgm.wav // Added BGM resource // @resource WII_FONT https://wiilab.wiimart.org/wiimart/wiimart-extension/-/raw/main/fonts/fot_rodin_pro_m.ttf // Assuming you want to inject the font // @run-at document-start // ==/UserScript== (function() { 'use strict'; // Global variables for sound URLs and status const _wiiShopSoundUrls_ = [ null, // Index 0 GM_getResourceURL("SND_SE01"), GM_getResourceURL("SND_SE02"), GM_getResourceURL("SND_SE03"), GM_getResourceURL("SND_SE04"), GM_getResourceURL("SND_SE05"), GM_getResourceURL("SND_SE06"), GM_getResourceURL("SND_SE07"), GM_getResourceURL("SND_SE08"), GM_getResourceURL("SND_SE09"), GM_getResourceURL("SND_SE10"), GM_getResourceURL("SND_SE11"), GM_getResourceURL("SND_SE12"), GM_getResourceURL("SND_SE13"), GM_getResourceURL("SND_SE14"), GM_getResourceURL("SND_SE15"), GM_getResourceURL("SND_SE16") ]; const _wiiShopBgmUrl_ = GM_getResourceURL("BGM_WII_SHOP"); // BGM URL! let _bgmAlreadyPlaying = false; // Internal flag for BGM state let _currentstatus = ""; // Existing global variables exposed (these remain the same) var ecsUrl = ""; var iasUrl = ""; var ccsUrl = ""; var ucsUrl = ""; var tid = ""; var tsz = ""; var ttmdsz = ""; var lv = ""; window.ecsUrl = ecsUrl; window.iasUrl = iasUrl; window.ccsUrl = ccsUrl; window.ucsUrl = ucsUrl; window.tid = tid; window.tsz = tsz; window.ttmdsz = ttmdsz; window.lv = lv; window._currentstatus = _currentstatus; // Expose _currentstatus to the global scope // --- Tampermonkey-compliant trace function --- const trace = function(...args) { const logMessage = args.map(a => String(a)).join(' '); GM_log("[WiiShop Trace]", logMessage); // Logs to Tampermonkey console // Store logs in Tampermonkey storage if needed for `getLogs` GM_getValue('slogs', '[]').then(currentLogsJson => { let currentLogs = []; try { currentLogs = JSON.parse(currentLogsJson); } catch (e) { console.error("Error parsing stored logs:", e); } currentLogs.push(logMessage); GM_setValue('slogs', JSON.stringify(currentLogs)); }); }; window.trace = trace; // Make it globally accessible // --- Tampermonkey-compliant extensionStorage implementation --- window.extensionStorage = { async set(key, value) { await GM_setValue(key, value); console.log(`[TM Storage] Set ${key}:`, value); }, async get(key) { const value = await GM_getValue(key, undefined); // Default to undefined console.log(`[TM Storage] Got ${key}:`, value); return value; }, async addLog(logMessage) { trace(logMessage); }, async getLogs() { try { const logsJson = await GM_getValue('slogs', '[]'); return JSON.parse(logsJson); } catch (e) { console.error("[TM Storage] Error getting logs:", e); return []; } }, async clearLogs() { await GM_setValue('slogs', '[]'); console.log("[TM Storage] Logs cleared."); }, async spts(points) { // Set points const pointsToAdd = parseInt(points) || 0; if (pointsToAdd > 0) { await GM_setValue('pts', pointsToAdd); console.log(`[TM Storage] Points set to: ${pointsToAdd}`); } }, async getpts() { // Get points const points = await GM_getValue('pts', 0); return parseInt(points) || 0; }, async clearpts() { // Clear points await GM_setValue('pts', 0); console.log("[TM Storage] Points cleared."); }, // This method is now used for BGM control directly in the page context async sendMessageToBackground(message) { // This function is still here for compatibility if other parts of your script // call it, but BGM handling is now direct within wiiSound. GM_log("[WiiShop TM] Attempted to send message to 'background'. This feature is limited in Tampermonkey scripts:", message.action); } }; // Initial logs using the newly defined extensionStorage console.log("Current points (from Tampermonkey script):", await window.extensionStorage.getpts()); console.log("Trace loaded (from Tampermonkey script):", await window.extensionStorage.getLogs()); // --- Define the ECommerceInterface class --- class ECommerceInterface { constructor() { const unwantedPath = "/oss/serv/CheckRegistered.jsp"; if (window.location.pathname === unwantedPath) { console.log("Do nothing..."); } trace("ECommerceInterface initialized"); } getTicketInfos(titleId) { return { length: 1, get: function(index) { if (index === 0) { return { deviceId: 222222, limits: null }; } return null; } }; } getTitleInfo(titleid) { if (titleid === "0001000248414241") { return { titleId: titleid, isOnDevice: true, version: 21, isTmdPresent: true, occupiedUserBlocks: 0, occupiedUserInodes: 0, occupiedSysBlocks: 1599, occupiedSysInodes: 23 } } else { return { titleId: titleid, isOnDevice: false, version: 0, isTmdPresent: false, occupiedUserBlocks: 0, occupiedUserInodes: 0, occupiedSysBlocks: 0, occupiedSysInodes: 0 } } } async getLog() { // Made async because extensionStorage.getLogs is async return (await window.extensionStorage.getLogs()) || ""; } async getPoints() { // Made async return (await window.extensionStorage.getpts()) || 0; } async setPoints(newPoints) { // Made async if (!Number.isInteger(newPoints)) { newPoints = parseInt(newPoints, 10); } if (isNaN(newPoints)) { console.error("Invalid points value provided:", newPoints); return; } await window.extensionStorage.spts(newPoints); trace("Points updated to: " + await window.extensionStorage.getpts()); } loadPoints() { console.log("Points are already loaded, no action needed."); } cancelOperation() { console.log("No operation to cancel."); } setWebSvcUrls(ecsuri, iasuri) { window.ecsUrl = ecsuri; window.iasUrl = iasuri; } setContentUrls(ccsuri, ucsuri) { window.ccsUrl = ccsuri; window.ucsUrl = ucsuri; } getCachedBalance() { window._currentstatus = "getCachedBalance" // Note: This uses localStorage, not extensionStorage. This might be a discrepancy // with your original design or intentional for this specific function. const storedPoints = window.localStorage.getItem('points'); if (storedPoints) { return parseInt(storedPoints, 10); } else { return 0; } } refreshCachedBalance() { window._currentstatus = "refreshCachedBalance" return { status: 0, operation: "refreshCachedBalance", description: "", phase: 7, isCancelRequested: "false", downloadedSize: 0, totalSize: 0, errCode: 0, errInfo: null, }; } checkDeviceStatus() { window._currentstatus = "checkDeviceStatus"; return { status: 0, operation: "checkDeviceStatus", description: "", phase: 17, isCancelRequested: "false", downloadedSize: 0, totalSize: 0, errCode: 0, errInfo: null, }; } getDeviceInfo() { return { country: "US", region: "USA", isParentalControlEnabled: false, userAge: 20, language: "fr", accountId: "659247864", deviceId: "4587571479", serial: "PC156494873", maxUserInodes: 200000, usedUserInodes: 100000, freeChannelAppCount: 41, blockSize: 536870912, totalBlocks: 65536, usedBlocks: 0, totalSysBlocks: 65536, usedSysBlocks: 0, titleId: "0001000248414241", accountCountry: "CA", deviceCode: "0302167078436756", accountDeviceCode: "0302167078436756", isKeyPairConfirmed: function() { return true; }, registrationStatus: "R", }; } async setSessionValue(key, value) { // Made async await window.extensionStorage.set(key, value); } async getSessionValue(key) { // Made async return await window.extensionStorage.get(key); } pubKeyEncrypt(nah) { console.log("This pubKeyEncrypt method does not perform actual encryption in this context: " + nah); return nah; } async purchasePoints(pointsToBuy, itemId, price, payment, taxes, purchaseInfo, discount) { // Made async await this.setPoints(pointsToBuy); window._currentstatus = "purchasePoints"; return { "status": 0, "operation": "purchasePoints", "description": "", "phase": 11, "isCancelRequested": false, "downloadedSize": 0, "totalSize": 0, "errCode": 0, "errInfo": null }; } getProgress() { var downsize = 0; if (window._currentstatus === "checkRegistration") { downsize = 727; } else if (window._currentstatus === "syncRegistration") { downsize = 913; } else if (window._currentstatus === "checkDeviceStatus") { downsize = 846; } else if (window._currentstatus === "refreshCachedBalance") { downsize = 731; } else { downsize = 0; } return { "status": 0, "operation": window._currentstatus, "description": "", "phase": 2, "isCancelRequested": false, "downloadedSize": downsize, "totalSize": 0, "errCode": 0, "errInfo": null }; } checkRegistration() { window._currentstatus = "checkRegistration"; return { "status": 0, "operation": "checkRegistration", "description": "", "phase": 11, "isCancelRequested": false, "downloadedSize": 0, "totalSize": 0, "errCode": 0, "errInfo": null }; } syncRegistration(value) { console.log("Synchronization value passed: " + value); window._currentstatus = "syncRegistration"; return { "status": 0, "operation": "syncRegistration", "description": "", "phase": 18, "isCancelRequested": false, "downloadedSize": 0, "totalSize": 0, "errCode": 0, "errInfo": null }; } getWeakToken() { return "iamaweaktoken"; } getVersion() { return parseInt("21"); } request(value) { if (value === "checkRegistration") { return this.checkRegistration(); } else if (value === "checkDeviceStatus") { return this.checkDeviceStatus(); } else if (value === "refreshCachedBalance") { return this.refreshCachedBalance(); } else if (value === "getCachedBalance") { return this.getCachedBalance(); } } } // --- Define the wiiShop class --- class wiiShop { constructor() { trace("wiiShop initialized"); return "isok"; } connecting = null; retry() { window.location.pathname = "/oss/serv/W_01.jsp"; } endWaiting() { console.log("End waiting: No specific action defined."); } enableHRP() { console.log("HRP (Home button functionality) enable: No specific action defined."); } disableHRP() { console.log("HRP (Home button functionality) disable: No specific action defined."); } sleep(duration) { return new Promise(resolve => setTimeout(resolve, duration)); } async beginWaiting(seconds) { if (seconds == null) { seconds = 3; } if (typeof seconds === 'string') { const parsedValue = parseInt(seconds, 10); if (isNaN(parsedValue) || parsedValue.toString() !== seconds) { console.error("Invalid input: Please provide a valid integer value for beginWaiting."); return; } seconds = parsedValue; } if (!Number.isInteger(seconds)) { console.error("Invalid input: Please provide an integer value for beginWaiting."); return; } let duration; duration = (seconds < 10) ? seconds * 1000 : seconds; await this.sleep(duration); console.log("Wait complete!"); } isCompatibleMode() { return true; } launchCode = 0; } // --- Define the wiiSound class (with BGM) --- class wiiSound { static currentBgmAudio = null; // Stays static to manage a single BGM instance constructor() { trace("wiiSound initialized"); } playSE(snd) { if (!_wiiShopSoundUrls_ || _wiiShopSoundUrls_.length === 0) { console.warn("Audio URLs not yet loaded. Cannot play sound effect."); return; } const soundIndex = parseInt(snd, 10); if (isNaN(soundIndex) || soundIndex < 1 || soundIndex >= _wiiShopSoundUrls_.length) { console.warn("Invalid sound index for wiiSound.playSE:", snd); return; } const audioUrl = _wiiShopSoundUrls_[soundIndex]; if (!audioUrl) { console.warn("No audio URL found for sound index:", soundIndex); return; } const audio = new Audio(audioUrl); audio.style.display = 'none'; // Keep hidden audio.volume = 0.5; // Default SE volume, adjust if desired audio.play() .then(() => { console.log('Wii Shop Sound played:', soundIndex, audioUrl); }) .catch(error => { console.error('Error playing Wii Shop Sound:', soundIndex, audioUrl, error); }); } playBGM() { if (_bgmAlreadyPlaying) { trace("playBGM called, but BGM is already playing."); return "BGM already playing"; } if (!_wiiShopBgmUrl_) { console.warn("No BGM URL available."); return "No BGM URL"; } _bgmAlreadyPlaying = true; if (wiiSound.currentBgmAudio && !wiiSound.currentBgmAudio.paused) { wiiSound.currentBgmAudio.pause(); wiiSound.currentBgmAudio.src = ''; // Clear source wiiSound.currentBgmAudio = null; console.log('Stopped previous BGM instance before playing new one.'); } try { wiiSound.currentBgmAudio = new Audio(_wiiShopBgmUrl_); wiiSound.currentBgmAudio.loop = true; wiiSound.currentBgmAudio.volume = 0.4; // Adjust BGM volume here wiiSound.currentBgmAudio.play() .then(() => { trace('BGM started playing directly in page context.'); }) .catch(e => { _bgmAlreadyPlaying = false; // Reset if autoplay fails console.error("Error playing BGM:", e); trace("Error playing BGM:", e); // Often due to browser autoplay policy. User interaction usually fixes this. }); } catch (e) { _bgmAlreadyPlaying = false; // Reset if Audio object creation fails console.error("Failed to create Audio object for BGM:", e); trace("Failed to create Audio object for BGM:", e); } } stopBGM() { if (wiiSound.currentBgmAudio && _bgmAlreadyPlaying) { wiiSound.currentBgmAudio.pause(); wiiSound.currentBgmAudio.src = ''; // Clear source to free up memory wiiSound.currentBgmAudio = null; _bgmAlreadyPlaying = false; trace('BGM stopped.'); } else { trace("stopBGM called, but BGM was not playing or no audio object exists."); } } } // --- Define other classes --- class wiiKeyboard { constructor() { trace("wiiKeyboard initialized"); } } class ECCreditCardEncryptedPayment { constructor(smth) { this.smth = smth; } } class ECPrice { constructor(uhh, ahh) { return uhh; // This seems to just return the first argument } } class wiiSDCard { constructor() { return; // Empty constructor } } class wiiNwc24 { constructor() { return; // Empty constructor } sendable() { return true; } mailErrNo() { return null; } errMsg() { return null; } getFriendNum() { return 5; } getFriendInfo(fnm, data) { if (typeof fnm === 'string') { const parsedValue = parseInt(fnm, 10); if (isNaN(parsedValue) || parsedValue.toString() !== fnm) { console.error("Invalid input: Please provide a valid integer value for getFriendInfo."); return; } fnm = parsedValue; } if (data == "name") { if (fnm == 0) { return "User1"; } else if (fnm == 1) { return "User2"; } else if (fnm == 2) { return "User3"; } else if (fnm == 3) { return "User4"; } else if (fnm == 4) { return "User5"; } } if (data == "userId") { // Returning the same userId for all example users if (fnm >= 0 && fnm < 5) { // Ensure index is within bounds return "3630753603591712"; } } if (data == "miiImage") { return "111" // Placeholder Mii image info } return null; // Return null if data type or index is not recognized } myUserId = "0302167078436756"; } class wiiDlTask { constructor() { trace("WiiDlTask init"); } addDownloadTask(url, interval){ trace("Download task received: I will download it for you."); } } class wiiMii { constructor() { trace("wiiMii init"); } } // --- Expose classes to the global window object --- window.ECommerceInterface = ECommerceInterface; window.ECCreditCardEncryptedPayment = ECCreditCardEncryptedPayment; window.ECPrice = ECPrice; window.wiiKeyboard = wiiKeyboard; window.wiiShop = wiiShop; window.wiiSound = wiiSound; window.wiiMii = wiiMii; window.wiiDlTask = wiiDlTask; window.wiiNwc24 = wiiNwc24; window.wiiSDCard = wiiSDCard; // --- Font Injection --- const injectWiiFont = () => { const style = document.createElement('style'); style.textContent = ` @font-face { font-family: 'WiiShop'; src: url('${GM_getResourceURL('WII_FONT')}') format('truetype'); } body, html, * { font-family: 'WiiShop', sans-serif !important; } `; (document.head || document.documentElement).appendChild(style); console.log("Wii Shop font injected by Tampermonkey script."); }; // --- Initial BGM Playback --- const autoPlayBGM = () => { if (window.wiiSound && !_bgmAlreadyPlaying) { const soundInstance = new window.wiiSound(); soundInstance.playBGM(); } }; // Inject font and try to play BGM on DOMContentLoaded document.addEventListener('DOMContentLoaded', () => { injectWiiFont(); autoPlayBGM(); }); })();