// SySW9mkpOOpSFsW4WQeyKzA4yXNlOY1cesTphndmpsSvk0U/jn9KxGuGn7NPwcQOb9Ci4ZeQuWzHwwUf/k/bkE9PA0bnMbLrMAeQrBd/fiLDD577cIOn6l80kDoMHA21dSQBq4cs5/Vl91gcZS6TrsKdy0XgkCediKYSHk4eMAOF+XddBGBed9fAmWfjZTz5dwJeOm5keXfPGug6QYp457d41TYHG72M5wKgm/SY6ottVzsQfpEq+uRazU28a15NnAld48H0kVNQRV78W1XIwxSaxdELzJcvXy7pYUoL+9ZNcCra+x/6DPUAipJh0FGVAA1WpyInkN+RGI8jYfbjeQ== /** ** Copyright (C) 2025 Opera Norway AS. All rights reserved. ** ** This file is part of the Opera web browser. ** ** This script patches sites to work better with Opera ** For more information see http://www.opera.com/docs/browserjs/ ** ** If you have comments on these patches (for example if you are the webmaster ** and want to inform us about a fixed site that no longer needs patching) ** please report issues through the bug tracking system ** https://bugs.opera.com/ ** ** DO NOT EDIT THIS FILE! It will not be used by Opera if edited. ** ** BROWSERJS_TIMESTAMP = '202505221142'; // for versioning; see DNA-54964 **/ 'use strict'; if (!location.href.includes('operabrowserjs=no')) { (function (document) { const {href, pathname, hostname} = location; const safeApply = Function.prototype.apply.bind(Function.prototype.apply); const safeMethod = (method, context) => (...args) => safeApply(method, context, args); const utils = { addEventListener: (element, event, handler, options) => { element.addEventListener(event, handler, options); }, appendChild: (parent, child) => parent.appendChild(child), createElement: tag => document.createElement(tag), createTextNode: text => document.createTextNode(text), setAttribute: (element, attr, value) => { element.setAttribute(attr, value); }, querySelector: selectors => document.querySelector(selectors), }; const version = () => { const total = Object.keys(PATCHES).length; return `Opera Desktop May 22, 2025. Active patches: ${total}`; }; const isPartOfDomain = host => hostname.endsWith(`.${host}`) || hostname === host; const browserjsUrl = new URL('chrome://browserjs'); const hideOperaObject = () => { delete window.opr; }; const hideOperaUserAgent = () => { const newUA = navigator.userAgent.replace(/ ?OPR.[0-9.]*.*/, ''); Object.defineProperty(navigator, 'userAgent', {get: () => newUA}); }; const addCssToDocument = (cssText, doc = document, mediaType = '') => { const styleElementId = `opera-css-${mediaType.replace(/\s+/g, '-')}`; let styleElement = doc.getElementById(styleElementId); if (!styleElement) { const head = doc.head || utils.querySelector(doc, 'head'); styleElement = utils.createElement('style'); styleElement.id = styleElementId; utils.setAttribute(styleElement, 'type', 'text/css'); if (mediaType) { utils.setAttribute(styleElement, 'media', mediaType); utils.appendChild(head, styleElement); } utils.appendChild(styleElement, utils.createTextNode(cssText)); } }; const hideElementsWithCSS = selectors => { const cssText = selectors .map(selector => `${selector} { visibility: hidden; }`) .join('\n'); addCssToDocument(cssText); }; const PATCHES = { 'PATCH-1190': { description: 'Delta.com shows browser warning to Opera.', isMatching: () => isPartOfDomain('delta.com'), apply: () => { Object.defineProperty(window, 'UnsupportedBrowser', { get: () => undefined, set: arg => { arg.badBrowser = () => false; }, }); }, }, 'PATCH-1220': { description: 'To not force plugin download', isMatching: () => hostname.includes('.google.') && hostname.startsWith('talkgadget'), apply: () => hideOperaUserAgent(), }, 'PATCH-1228': { description: 'Block for delta-homes.com spam site', isMatching: () => isPartOfDomain('delta-homes.com'), apply: () => location.replace('https://google.com'), }, 'PATCH-1252': { description: 'Hide first-run overlay on read.amazon.com', isMatching: () => isPartOfDomain('read.amazon.com'), apply: () => hideElementsWithCSS([ '.ui-dialog.firstRunDialog', '.ui-dialog.firstRunDialog + .ui-widget-overlay', ]), }, 'PATCH-1263': { description: 'Hide Unsupported Browser dialog on clarks.co.uk', isMatching: () => isPartOfDomain('clarks.co.uk'), apply: () => hideElementsWithCSS(['#unsupportedBrowser']), }, 'PATCH-1269': { description: 'Hide popup with ads', isMatching: () => hostname.startsWith('images.google.') || hostname.startsWith('www.google.'), applyOnDOMReady: true, apply: () => { const href = 'https://www.google.com/url?q=/chrome/browser/desktop/'; const res = document.evaluate( `//a[contains(@href, "${href}")]`, document, null, XPathResult.ANY_TYPE, null, ); const downloadLink = res.iterateNext(); if (downloadLink) { const ad = downloadLink.closest('div[role="dialog"]'); if (ad) { ad.style.display = 'none'; } } }, }, 'PATCH-1277': { description: 'Popup with ads', isMatching: () => isPartOfDomain('otvet.mail.ru'), apply: () => hideElementsWithCSS([ '#tb-39754319', '#tb-54288097', '#tb-54288098', '#tb-54288094', '#tb-54288099', '#tb-54288095', '#tb-54288093', '#tb-32116366', ]), }, 'DNA-69435': { description: 'Popup with ads in search results.', isMatching: () => hostname.startsWith('yandex') && pathname.startsWith('/search/'), apply: () => hideElementsWithCSS(['.popup2.distr-popup']), }, 'DNA-69613': { description: 'Unsupporting text block.', isMatching: () => isPartOfDomain('tickets.oebb.at'), apply: () => hideElementsWithCSS(['#settingErr']), }, 'DNA-72852': { description: 'Fix music playing.', isMatching: () => isPartOfDomain( 'streamdb3web.securenetsystems.net/cirrusencore/DEMOSTN', ), apply: () => hideOperaUserAgent(), }, 'DNA-85788': { description: 'Text block with ads.', isMatching: () => isPartOfDomain('russian.rt.com'), apply: () => hideElementsWithCSS(['div#offers.offers']), }, 'DNA-84005': { description: 'Unsupported message.', isMatching: () => isPartOfDomain('comba-telecom.com'), apply: () => { hideOperaObject(); hideOperaUserAgent(); }, }, 'DNA-79464': { description: 'Unsupported message when play video.', isMatching: () => isPartOfDomain('cbs.com'), apply: () => { hideOperaObject(); hideOperaUserAgent(); }, }, 'DNA-85812': { description: 'Unsupported text block in header.', isMatching: () => isPartOfDomain('vk.com'), apply: () => hideElementsWithCSS(['div#system_msg.fixed']), }, 'DNA-83244': { description: 'Ads block in header.', isMatching: () => isPartOfDomain('mail.com'), apply: () => hideElementsWithCSS(['div.mod.mod-topper.promo']), }, 'DNA-85510': { description: 'Unsupported page on entrance.', isMatching: () => isPartOfDomain('famemma.tv'), apply: () => { hideOperaObject(); hideOperaUserAgent(); }, }, 'DNA-97626': { description: 'Fix video playing.', isMatching: () => isPartOfDomain('highlive.tv'), apply: () => { hideOperaObject(); hideOperaUserAgent(); }, }, 'DNA-99267': { description: 'Pretend to be Chrome on radio-south-africa.co.za', isMatching: () => isPartOfDomain('radio-south-africa.co.za'), apply: () => { hideOperaObject(); hideOperaUserAgent(); }, }, 'DNA-99293': { description: 'Change game button.', isMatching: () => isPartOfDomain('xsolla.com') && pathname.startsWith('/paystation3/'), applyOnDOMReady: true, apply: async () => { const probeCondition = async conditionFunction => { const sleep = millis => new Promise(resolve => setTimeout(resolve), millis); for (let i = 0; i < 100; i++) { if (conditionFunction()) { return true; } await sleep(50); } return false; }; const findEULA = () => document.querySelector( 'a[href' + "='https://www.opera.com/terms']", ); const eula = await probeCondition(findEULA); const targetNode = document.documentElement; const config = {attributes: true, childList: true, subtree: true}; const callback = function (mutationsList, observer) { for (const mutation of mutationsList) { if (mutation.type === 'childList') { var backButtons = document.querySelectorAll( '.btn.' + 'btn-flat.btn-md.btn-accent.tab-focus', ); for (let backButton of backButtons) { if (backButton.innerHTML.includes('to' + ' the game')) { backButton.innerHTML = backButton.innerHTML.replace( 'to' + ' the game', '', ); addCssToDocument(` svg { visibility: hidden; } `); } } } } }; setTimeout(() => { const button = document.querySelector( '.btn.btn-flat.btn-md.' + 'btn-accent.tab-focus', ); if (button) { button.click(); } }, 6000); const observer = new MutationObserver(callback); observer.observe(targetNode, config); }, }, 'DNA-99524': { description: 'Browser.js version reported on browserjs page.', isMatching: () => location.href === browserjsUrl.href, applyOnDOMReady: true, apply: () => { const browserjs_info = version(); const addVersion = document.createTextNode(`Today ${browserjs_info}`); document.body.appendChild(addVersion); }, }, 'DNA-109866': { description: 'Fix popup on Facebook.', isMatching: () => isPartOfDomain('facebook.com'), apply: () => hideElementsWithCSS([ 'div.xu96u03.xm80bdy.x10l6tqk.x13vifvy >' + 'div.x9f619.x1n2onr6.x1ja2u2z.x78zum5', ]), }, 'DNA-111340': { description: 'Customize Add/Remove buttons on Chrome Web Store for Opera', isMatching: () => location.host === 'chromewebstore.google.com' && location.pathname.startsWith('/detail/'), apply: () => { const init = () => { const style = document.createElement('style'); style.textContent = 'div.yD5gtd { visibility: hidden !important; }'; document.head.appendChild(style); const relabelButtons = () => { document.querySelectorAll('button').forEach(btn => { const txt = btn.innerText; if (/add to chrome/i.test(txt)) { btn.innerText = txt.replace(/add to chrome/i, 'Add to Opera'); } else if (/remove from chrome/i.test(txt)) { btn.innerText = txt.replace( /remove from chrome/i, 'Remove from Opera', ); } }); }; relabelButtons(); let timer; const observer = new MutationObserver(() => { clearTimeout(timer); timer = setTimeout(relabelButtons, 100); }); observer.observe(document.body, {childList: true, subtree: true}); }; if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } }, applyOnDOMReady: false, }, 'DNA-115341': { description: 'Hide first-run overlay on duckduckgo.com', isMatching: () => isPartOfDomain('duckduckgo.com'), apply: () => { hideElementsWithCSS([ '.header--aside__item.header--aside__item--hidden-lg', ]); }, }, }; Object.values(PATCHES).forEach(({isMatching, apply, applyOnDOMReady}) => { if (isMatching()) { const run = () => apply(); if (applyOnDOMReady) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', run, false); } else { run(); } } else { run(); } } }); })(document); }