您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A simple helper to make GOG.com's grid-view catalogue listings more scannable during a sale
- // ==UserScript==
- // @name GOG.com - Sale Helper
- // @version 2
- // @namespace ssokolow.com
- // @description A simple helper to make GOG.com's grid-view catalogue listings more scannable during a sale
- //
- // @compatible firefox Tested under Greasemonkey 4 and ViolentMonkey
- // @compatible chrome Tested under TamperMonkey
- //
- // @include https://www.gog.com/games?*
- //
- // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
- // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
- //
- // @grant GM_registerMenuCommand
- // @grant GM.registerMenuCommand
- //
- // @grant GM_getValue
- // @grant GM_setValue
- // NOTE: GM_config doesn't currently support GM4 APIs, so allowing the GM4
- // versions of these isn't helpful and could result in users losing
- // access to their settings if GM_config suddenly starts supporting
- // them without transparently migrating data from its localStorage
- // fallback.
- // ==/UserScript==
- /* jshint esversion: 6 */
- var fieldDefs = {
- 'discount_min': {
- 'section': 'Minimum Discount Percentage',
- 'label': 'Minimum',
- 'labelPos': 'left',
- 'type': 'number',
- 'min': 0,
- 'max': 99,
- 'default': 50,
- 'tail': '%',
- },
- 'discount_preferred': {
- 'label': 'Preferred',
- 'type': 'number',
- 'min': 0,
- 'max': 99,
- 'default': 75,
- 'tail': '%',
- },
- 'discount_preferred_fgcolor': {
- 'label': 'Foreground',
- 'type': 'color',
- 'default': '#ffffff',
- },
- 'discount_preferred_bgcolor': {
- 'label': 'Background',
- 'type': 'color',
- 'default': '#00aa00',
- },
- 'discount_rare': {
- 'label': 'Rare Bargain',
- 'type': 'number',
- 'min': 0,
- 'max': 99,
- 'default': 76,
- 'tail': '%',
- },
- 'discount_rare_fgcolor': {
- 'label': 'Foreground',
- 'type': 'color',
- 'default': '#ffffff',
- },
- 'discount_rare_bgcolor': {
- 'label': 'Background',
- 'type': 'color',
- 'default': '#ff0000',
- },
- 'price_max': {
- 'section': 'Maximum Price',
- 'label': 'Maximum',
- 'labelPos': 'left',
- 'type': 'number',
- 'min': '0',
- 'step': '0.01',
- 'default': '15.00',
- },
- 'price_low': {
- 'label': 'Preferred',
- 'type': 'number',
- 'min': '0',
- 'step': '0.01',
- 'default': '5.00',
- },
- 'price_low_fgcolor': {
- 'label': 'Foreground',
- 'type': 'color',
- 'default': '#ffffff',
- },
- 'price_low_bgcolor': {
- 'label': 'Background',
- 'type': 'color',
- 'default': '#00aa00',
- },
- 'price_impulse': {
- 'label': 'Impulse Buys',
- 'type': 'number',
- 'min': '0',
- 'step': '0.01',
- 'default': '2.00',
- },
- 'price_impulse_fgcolor': {
- 'label': 'Foreground',
- 'type': 'color',
- 'default': '#ffffff',
- },
- 'price_impulse_bgcolor': {
- 'label': 'Background',
- 'type': 'color',
- 'default': '#ff0000',
- },
- 'hide_owned': {
- 'section': 'Other Filters',
- 'label': 'Hide entries marked "In Library"',
- 'labelPos': 'left',
- 'type': 'checkbox',
- 'default': true,
- },
- 'hide_title_regex': {
- 'label': 'Hide entries with titles matching:',
- 'labelPos': 'left',
- 'type': 'text',
- 'size': 35,
- 'default': "(Upgrade|[ ]OST|Soundtrack|Artbook)$",
- },
- };
- function remove_tile(mutation_event) {
- mutation_event.target.closest(".product-tile").remove();
- }
- let observer = new MutationObserver(function (mutations) {
- mutations.forEach(function (mut) {
- if (mut.type == "attributes" && mut.attributeName == "class" &&
- mut.target.classList.contains("product-tile__labels--in-library")) {
- // Hide entries that are already owned
- remove_tile(mut);
- } else if (mut.type == "childList" && mut.target.classList.contains("product-tile__discount")) {
- // Hide entries that are below the minimum discount
- // and highlight ones with abnormally high discounts
- let discount = mut.target.innerText;
- let discount_parsed = Number.parseInt(discount.substring(1, discount.length - 1));
- if (discount_parsed < GM_config.get('discount_min')) {
- remove_tile(mut);
- } else if (discount_parsed >= GM_config.get('discount_rare')) {
- mut.target.style.color = GM_config.get('discount_rare_fgcolor');
- mut.target.style.backgroundColor = GM_config.get('discount_rare_bgcolor');
- } else if (discount_parsed >= GM_config.get('discount_preferred')) {
- mut.target.style.color = GM_config.get('discount_preferred_fgcolor');
- mut.target.style.backgroundColor = GM_config.get('discount_preferred_bgcolor');
- }
- } else if (mut.type == "childList" && mut.target.classList.contains("product-tile__prices")) {
- // Hide entries that are over the maximum price
- // and highlight ones at or below the preferred price
- let discounted = mut.target.querySelector(".product-tile__price-discounted");
- let price = Number.parseFloat(discounted.innerText);
- if (price > GM_config.get('price_max')) {
- remove_tile(mut);
- } else if (price <= GM_config.get('price_impulse')) {
- discounted.style.color = GM_config.get('price_impulse_fgcolor');
- discounted.style.backgroundColor = GM_config.get('price_impulse_bgcolor');
- } else if (price <= GM_config.get('price_low')) {
- discounted.style.color = GM_config.get('price_low_fgcolor');
- discounted.style.backgroundColor = GM_config.get('price_low_bgcolor');
- }
- discounted.style.padding = '2px';
- discounted.style.borderRadius = '2px';
- } else if (mut.type == "childList" && mut.target.classList.contains("product-tile__title")) {
- let regex_str = GM_config.get('hide_title_regex');
- if (regex_str && regex_str.trim() && RegExp(regex_str).test(mut.target.innerText)) {
- remove_tile(mut);
- }
- }
- });
- });
- let frame = document.createElement('div');
- document.body.append(frame);
- GM_config.init({
- id: 'sale_filter_GM_config',
- title: "Sale Helper Settings",
- fields: fieldDefs,
- css: ('#sale_filter_GM_config ' + [
- // Match GOG.com styling more closely
- "{ box-shadow: 0 0 15px rgba(0,0,0,.15),0 1px 3px rgba(0,0,0,.15); " +
- " background: #ccc; color: #212121; border: 0 !important; " +
- " height: auto !important; width: auto !important; margin: auto; padding: 1ex !important; }",
- " * { font-family: Lato GOG,Lato GOG Latin,sans-serif; }",
- ".config_header, .section_header { font-weight: 700; margin: 1ex 0 -1ex; }",
- ".section_header { color: #212121; background-color: inherit; border-width: 0 0 1px 0; " +
- " font-size: 16px; border-bottom: 1px solid #bfbfbf; " +
- " margin: 1em 1em 1ex 1em; text-align: left !important; " +
- " clear: both; }",
- " .title_underline { display: inline-block; border-bottom: 1px solid #212121; padding: 5px 0; }",
- ".field_label { display: inline-block; min-width: 9em; text-align: right; }",
- ".field_label, .field_tail { font-size: 12px; }",
- ".field_tail { margin-left: 0.5ex; font-weight: 700; }",
- ".config_var { float: left; margin-right: 1ex; }",
- ".reset { margin-right: 12px; }",
- "button, input, .field_tail { vertical-align: middle; }",
- "input[type='checkbox'] { margin: 0 0.5ex 0 2.5ex; }",
- "input[type='number'] { width: 5em; }",
- "input[type='color'] { box-sizing: content-box; height: 1.1em; width: 2em; }",
- "#sale_filter_GM_config_field_discount_min, #sale_filter_GM_config_field_discount_preferred, " +
- " #sale_filter_GM_config_field_discount_rare { width: 4em !important; }",
- "#sale_filter_GM_config_buttons_holder { padding-top: 1ex; }",
- "#sale_filter_GM_config_hide_title_regex_var, #sale_filter_GM_config_hide_owned_var " +
- " { margin-left: 3ex !important; }",
- "#sale_filter_GM_config_field_hide_owned { margin-left: 1ex; }",
- "#sale_filter_GM_config_discount_min_var, #sale_filter_GM_config_discount_preferred_var, " +
- " #sale_filter_GM_config_discount_rare_var, #sale_filter_GM_config_price_impulse_var, " +
- " #sale_filter_GM_config_price_low_var, #sale_filter_GM_config_price_max_var, " +
- " #sale_filter_GM_config_hide_title_regex_var, #sale_filter_GM_config_buttons_holder " +
- " { clear: left; }",
- ].join('\n#sale_filter_GM_config ')),
- events: {
- open: function(doc) {
- this.frame.querySelectorAll('.section_header').forEach(function(node) {
- let inner = document.createElement('div');
- inner.classList.add("title_underline");
- inner.innerText = node.innerText;
- node.firstChild.replaceWith(inner);
- });
- },
- },
- types: {
- 'color': {
- default: '#ffffff',
- toNode: function(configId) {
- var field = this.settings,
- id = this.id,
- value = this.value,
- create = this.create,
- retNode = create('div', { className: 'config_var',
- id: configId + '_' + id + '_var',
- title: field.title || '' });
- // Create the field lable
- retNode.appendChild(create('label', {
- innerHTML: field.label,
- id: configId + '_' + id + '_field_label',
- for: configId + '_field_' + id,
- className: 'field_label'
- }));
- // Actually create and append the input element
- retNode.appendChild(create('input', {
- id: configId + '_field_' + id,
- type: 'color',
- value: value ? value : this['default'],
- }));
- return retNode;
- },
- toValue: function() {
- if (this.wrapper) {
- return this.wrapper.getElementsByTagName('input')[0].value;
- }
- },
- reset: function() {
- if (this.wrapper) {
- this.wrapper.getElementsByTagName('input')[0].value = this['default'];
- }
- }
- },
- 'number': {
- default: '0',
- toNode: function() {
- console.log(this);
- var field = this.settings,
- id = this.id,
- value = this.value,
- create = this.create,
- configId = this.configId,
- retNode = create('div', { className: 'config_var',
- id: configId + '_' + id + '_var',
- title: field.title || '' });
- // Create the field label
- retNode.appendChild(create('label', {
- innerHTML: field.label,
- id: configId + '_' + id + '_field_label',
- for: configId + '_field_' + id,
- className: 'field_label'
- }));
- let params = {
- id: configId + '_field_' + id,
- type: 'number',
- value: value ? value : this['default'],
- };
- if (field.min || field.min === 0) { params.min = field.min; }
- if (field.max || field.max === 0) { params.max = field.max; }
- if (field.step) { params.step = field.step; }
- // Actually create and append the input element
- retNode.appendChild(create('input', params));
- if (field.tail) {
- retNode.appendChild(create('span', {
- innerHTML: field.tail ,
- className: 'field_tail',
- }));
- }
- return retNode;
- },
- toValue: function() {
- if (this.wrapper) {
- let val = Number(this.wrapper.getElementsByTagName('input')[0].value);
- if (isNaN(val)) { return null; }
- return val;
- }
- },
- reset: function() {
- if (this.wrapper) {
- this.wrapper.getElementsByTagName('input')[0].value = this['default'];
- }
- }
- }
- },
- frame: frame,
- });
- GM.registerMenuCommand("Configure Sale Helper...",
- function() { GM_config.open(); }, 'C');
- let catalog = document.querySelector(".catalog__wrapper");
- observer.observe(catalog, { attributes: GM_config.get('hide_owned'), childList: true, subtree: true });