Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Romeo Additions
- // @namespace https://greasyfork.org/en/users/723211-ray/
- // @version 2.2
- // @description Allows to hide users, display their information on tiles, and enhances the Radar.
- // @description:de Ermöglicht das Verstecken von Benutzern, die Anzeige ihrer Details auf Kacheln, und verbessert den Radar.
- // @author -Ray-, Djamana
- // @include *://*.romeo.com/*
- // @grant GM_addStyle
- // @require https://code.jquery.com/git/jquery-git.slim.min.js
- // @_require https://code.jquery.com/jquery-3.6.0.slim.min.js
- // ==/UserScript==
- // ==== Dependencies ====
- /*! waitForKeyElements | https://gist.github.com/BrockA/2625891 */
- /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts,
- that detects and handles AJAXed content.
- Usage example:
- waitForKeyElements (
- "div.comments"
- , commentCallbackFunction
- );
- //--- Page-specific function to do what we want when the node is found.
- function commentCallbackFunction (jNode) {
- jNode.text ("This comment changed by waitForKeyElements().");
- }
- IMPORTANT: This function requires your script to have loaded jQuery.
- */
- function waitForKeyElements(
- selectorTxt, /* Required: The jQuery selector string that
- specifies the desired element(s).
- */
- actionFunction, /* Required: The code to run when elements are
- found. It is passed a jNode to the matched
- element.
- */
- bWaitOnce, /* Optional: If false, will continue to scan for
- new elements even after the first match is
- found.
- */
- iframeSelector /* Optional: If set, identifies the iframe to
- search.
- */
- ) {
- var targetNodes, btargetsFound;
- if (typeof iframeSelector == "undefined")
- targetNodes = $(selectorTxt);
- else
- targetNodes = $(iframeSelector).contents()
- .find(selectorTxt);
- if (targetNodes && targetNodes.length > 0) {
- btargetsFound = true;
- /*--- Found target node(s). Go through each and act if they
- are new.
- */
- targetNodes.each(function () {
- var jThis = $(this);
- var alreadyFound = jThis.data('alreadyFound') || false;
- if (!alreadyFound) {
- //--- Call the payload function.
- var cancelFound = actionFunction(jThis);
- if (cancelFound)
- btargetsFound = false;
- else
- jThis.data('alreadyFound', true);
- }
- });
- }
- else {
- btargetsFound = false;
- }
- //--- Get the timer-control variable for this selector.
- var controlObj = waitForKeyElements.controlObj || {};
- var controlKey = selectorTxt.replace(/[^\w]/g, "_");
- var timeControl = controlObj[controlKey];
- //--- Now set or clear the timer as appropriate.
- if (btargetsFound && bWaitOnce && timeControl) {
- //--- The only condition where we need to clear the timer.
- clearInterval(timeControl);
- delete controlObj[controlKey]
- }
- else {
- //--- Set a timer, if needed.
- if (!timeControl) {
- timeControl = setInterval(function () {
- waitForKeyElements(selectorTxt,
- actionFunction,
- bWaitOnce,
- iframeSelector
- );
- },
- 300
- );
- controlObj[controlKey] = timeControl;
- }
- }
- waitForKeyElements.controlObj = controlObj;
- }
- // ==== CSS ====
- GM_addStyle(`
- #visits > .layer__container--wider { width:unset; max-width:1227px; }
- div[class*='tile--loading--'] .tile__image { background-image:url(/assets/05c2dc53b86dcd7abdb1d8a50346876b.svg); }
- .tile__bar { position:absolute; bottom:0; right:0; visibility:hidden; }
- .tile__bar_action { background:rgba(0,0,0,0.4); backdrop-filter: blur(3px); display: inline-block; color:white; margin-left: 1px; padding: 0.25rem 0.45rem; }
- .tile__bar_action:hover { background-color:#00A3E4; }
- .tile__bar_action:active { background-color:#06648B; }
- .tile__link:hover .tile__bar { visibility:visible; }
- `);
- // ==== Script ====
- (function () {
- 'use strict';
- proxyXhr();
- })();
- // ---- Language ----
- const _strings = {
- "display": {
- "de": "Anzeige",
- "en": "Display"
- },
- "enhancedTiles": {
- "de": "Erweiterte Kacheln",
- "en": "Enhanced tiles"
- },
- "enhancedTilesDesc": {
- "de": "Zeige alle Benutzerdetails auf den Kacheln. Im Radar wird dies Benutzer als 'Plus'-Abonnenten mit großen Kacheln darstellen.",
- "en": "Shows all user details on tiles. The radar will claim users to be 'Plus' subscribers in large tiles."
- },
- "extensionTitle": {
- "en": "Romeo Additions"
- },
- "hiddenUsers": {
- "de": "Ausgeblendete Benutzer",
- "en": "Hidden users"
- },
- "hideUser": {
- "de": "Benutzer ausblenden",
- "en": "Hide user"
- },
- "maxAge": {
- "de": "Maximales Alter",
- "en": "Maximal age"
- },
- "minAge": {
- "de": "Minimales Alter",
- "en": "Minimal age"
- },
- "viewFullImage": {
- "de": "Bild vergrößern",
- "en": "View full image"
- },
- }
- function getString(key) {
- const lang = document.documentElement.getAttribute("lang") || "en";
- const translations = _strings[key];
- if (translations)
- return translations[lang] || translations["en"] || "%" + key + "%";
- return "%" + key + "%";
- }
- // ---- Settings ----
- const settingNs = "RA_SETTINGS:";
- function getEnhancedTiles() {
- return localStorage.getItem(settingNs + "enhancedTiles") == "true";
- }
- function getHiddenMaxAge() {
- return parseInt(localStorage.getItem(settingNs + "hiddenMaxAge")) || 99;
- }
- function getHiddenMinAge() {
- return parseInt(localStorage.getItem(settingNs + "hiddenMinAge")) || 18;
- }
- function getHiddenUsers() {
- return JSON.parse(localStorage.getItem(settingNs + "hiddenUsers")) || [];
- }
- function setEnhancedTiles(value) {
- localStorage.setItem(settingNs + "enhancedTiles", value);
- }
- function setHiddenMaxAge(value) {
- localStorage.setItem(settingNs + "hiddenMaxAge", value);
- }
- function setHiddenMinAge(value) {
- localStorage.setItem(settingNs + "hiddenMinAge", value);
- }
- function setUserHidden(username, hide) {
- let hiddenUsers = getHiddenUsers();
- if (hide) {
- if (hiddenUsers.length < hiddenUsers.push(username)) {
- hiddenUsers.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
- localStorage.setItem(settingNs + "hiddenUsers", JSON.stringify(hiddenUsers));
- }
- } else {
- const prevLength = hiddenUsers.length;
- hiddenUsers = hiddenUsers.filter(e => e != username);
- if (prevLength > hiddenUsers.length)
- localStorage.setItem(settingNs + "hiddenUsers", JSON.stringify(hiddenUsers));
- }
- }
- // ---- XHR ----
- function ReMaskDash(RE_WithDashes) {
- return RE_WithDashes
- .replaceAll("/","\\/")
- }
- function isApiRequest(url, verb) {
- // Request must start with "/api/v?/" or "/api/+/" followed by the given verb.
- //const matches = url.match(/\/api\/(v[0-9]|\+)\//);
- const matches = url.match(ReMaskDash("/api/(v[0-9]|\\+)/"));
- if (matches && matches.length)
- return url.startsWith(verb, matches[0].length);
- return false;
- }
- function filterUser(user, hiddenMaxAge, hiddenMinAge, hiddenNames) {
- return user.personal.age >= hiddenMinAge
- && user.personal.age <= hiddenMaxAge
- && !hiddenNames.includes(user.name)
- }
- function proxyXhr() {
- // Intercept XHR queries and replies by hooking the XHR open method.
- const realOpen = window.XMLHttpRequest.prototype.open;
- window.XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
- this.addEventListener("load", () => {
- //console.log("[RA] XHR reply: method=" + method + ", url=" + url);
- try {
- // Parse data.
- const isString = typeof this.response === "string";
- reply = isString ?
- JSON.parse(this.response) :
- this.response;
- // Modify interesting data.
- if ( isApiRequest(url, "notifications") ) {
- reply = xhrHideNotifications(reply);
- }
- if (
- isApiRequest(url, "profiles") ||
- isApiRequest(url, "visitors") ||
- isApiRequest(url, "visits")
- ) {
- reply = xhrRestorePlusVisit( reply );
- reply = xhrEnhanceUsers ( reply );
- }
- if ( isApiRequest(url, "session") ) {
- reply = xhrPoorMensPlus( reply );
- }
- // Write back possibly modified data.
- Object.defineProperty(this, "responseText", { writable: true });
- this.responseText = isString ? JSON.stringify(reply) : reply;
- } catch (e) {
- //console.log("[RA] XHR handler failed: " + e)
- }
- });
- // Forward to client.
- return realOpen.apply(this, arguments);
- }
- }
- function xhrHideNotifications(reply) {
- // Remove manually hidden users.
- const hiddenMaxAge = getHiddenMaxAge();
- const hiddenMinAge = getHiddenMinAge();
- const hiddenNames = getHiddenUsers();
- return reply.filter(x => filterUser(x.partner, hiddenMaxAge, hiddenMinAge, hiddenNames));
- }
- function xhrEnhanceUsers(reply) {
- // Remove manually hidden users.
- const enhancedTiles = getEnhancedTiles();
- const hiddenMaxAge = getHiddenMaxAge();
- const hiddenMinAge = getHiddenMinAge();
- const hiddenNames = getHiddenUsers();
- let newItems = [];
- for (let item of reply.items) {
- if (filterUser(item, hiddenMaxAge, hiddenMinAge, hiddenNames)) {
- // Show as "large tiles" to display user details everywhere.
- if (enhancedTiles)
- item.display.large_tile = true;
- newItems.push(item);
- }
- }
- reply.items = newItems;
- return reply;
- }
- function xhrPoorMensPlus(reply) {
- // Cosmetic patch #1
- if (!reply.is_plus) {
- reply.is_plus = true
- reply.is_free_plus = true // maybe not needed
- reply.payment_group = "PLUS"
- }
- // Cosmetic patch #2
- if (reply.inferface) {
- reply.show_plus_badge = true // maybe not needed
- reply.show_ads = false // maybe not needed
- }
- // Cosmetic patch #3
- if (reply.show_plus_badge) {
- reply.show_plus_badge = true // maybe not needed
- }
- return reply;
- }
- function xhrRestorePlusVisit(reply) {
- // Restore PLUS-visible visitors.
- reply.items_limited = 0;
- return reply;
- }
- // ---- Tile UI ----
- waitForKeyElements(
- "a.tile__link, " +
- "div.js-profiles a.listresult, " +
- "div.js-wrapper a.tile__link > div.tile__image, " +
- "#visits a.listresult", jNode => {
- // Determine tile properties.
- const tile = jNode.parent(".tile");
- const tileLink = tile.children(".tile__link").first();
- if (!tileLink) // ignore placeholders
- return;
- // Add full headline as tooltip.
- const tileInfo = tileLink.children(".tile__info").first();
- const tileHeadline = tileInfo.children(".tile__headline").first();
- tileHeadline.attr("title", tileHeadline.text());
- // Add action bar.
- const tileImage = tileLink.children(".tile__image").first();
- const username = tileImage.attr("aria-label");
- const tileBar = $("<div class='tile__bar'></div>").appendTo(tileLink);
- addShowImageAction(tileBar, tileImage);
- addHideUserAction(tileBar, tile, username);
- });
- function addShowImageAction(tileBar, tileImage) {
- const style = tileImage.attr("style");
- if (!style)
- return;
- const url = style.substring(style.lastIndexOf("/") + 1, style.lastIndexOf(")"));
- if (url.endsWith(".svg")) // ignore "no photo" placeholders
- return;
- const origUrl = "/img/usr/original/0x0/" + url;
- $("<a class='tile__bar_action' href='" + origUrl + "' title='" + getString("viewFullImage") + "'><span class='icon icon-picture'></a>")
- .on("click", e => {
- e.preventDefault();
- window.open(origUrl, "_blank");
- })
- .appendTo(tileBar);
- }
- function addHideUserAction(tileBar, tile, username) {
- $("<a class='tile__bar_action' href='#' title='" + getString("hideUser") + "'><span class='icon icon-hide-visit'></a>")
- .on("click", e => {
- e.preventDefault();
- setUserHidden(username, true);
- tile.css("display", "none");
- })
- .appendTo(tileBar);
- }
- // ---- Settings UI ----
- waitForKeyElements("li.js-settings > div.accordion > ul", jNode => {
- let itemClass = jNode.find("a").attr("class");
- $("<li><div><a class='" + itemClass + "'>" + getString("extensionTitle") + "</a></div></li>")
- .on("click", e => {
- // Force open the setting pane and clear any existing contents.
- $("#offcanvas-nav > .js-layer-content").addClass("is-open");
- const pane = $(".js-side-content");
- pane.empty();
- // Add pane and list.
- pane.append(`
- <div class='layout layout--vertical layout--consume'>
- <div class='layout-item layout-item--consume layout layout--vertical'>
- <div class='layout-item settings__navigation p l-hidden-sm'>
- <div class='js-title typo-section-navigation'>` + getString("extensionTitle") + `</div>
- </div>
- <div class='layout-item layout-item--consume'>
- <div class='js-content js-scrollable fit scrollable'>
- <div class="p">
- <div class="settings__key">
- <div class="layout layout--v-center">
- <div class="layout-item [ 6/12--sm ]">
- <span>` + getString("enhancedTiles") + `</span>
- </div>
- <div class="layout-item [ 6/12--sm ]">
- <div class="js-toggle-show-headlines pull-right">
- <div>
- <span class="ui-toggle ui-toggle--default ui-toggle--right">
- <input class="ui-toggle__input" type="checkbox" id="ra_enhancedTiles">
- <label class="ui-toggle__label" for="ra_enhancedTiles" style="touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></label>
- </span>
- </div>
- </div>
- </div>
- </div>
- <div>
- <div class="settings__description">` + getString("enhancedTilesDesc") + `</div>
- </div>
- </div>
- <div class="settings__key">
- <div>
- <span>` + getString("hiddenUsers") + `</span>
- </div>
- <div class="separator separator--alt separator--narrow [ mb ] "></div>
- <div class="settings__key">
- <div class="layout layout--v-center">
- <div class="layout-item [ 6/12--sm ]">
- <span>` + getString("minAge") + `</span>
- </div>
- <div class="layout-item [ 6/12--sm ]">
- <input class="input input--block" id="ra_hiddenMinAge" type="number" min="18" max="99"/>
- </div>
- </div>
- </div>
- <div class="settings__key">
- <div class="layout layout--v-center">
- <div class="layout-item [ 6/12--sm ]">
- <span>` + getString("maxAge") + `</span>
- </div>
- <div class="layout-item [ 6/12--sm ]">
- <input class="input input--block" id="ra_hiddenMaxAge" type="number" min="18" max="99"/>
- </div>
- </div>
- </div>
- <div class="settings__key">
- <div class="js-grid-stats-selector">
- <div>
- <ul class="js-list tags-list tags-list--centered" id="ra_hiddenUsers"/>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>`);
- // Handle enhanced user tiles.
- let inEnhancedTiles = $("#ra_enhancedTiles");
- inEnhancedTiles.prop("checked", getEnhancedTiles());
- inEnhancedTiles.on("change", e => {
- setEnhancedTiles(e.target.checked);
- });
- // Handle hidden age.
- let minAge = getHiddenMinAge();
- let maxAge = getHiddenMaxAge();
- let inMinAge = $("#ra_hiddenMinAge");
- let inMaxAge = $("#ra_hiddenMaxAge");
- inMinAge.val(minAge);
- inMaxAge.val(maxAge);
- inMinAge.on("change", e => {
- minAge = parseInt(e.target.value);
- setHiddenMinAge(minAge);
- if (minAge > maxAge) {
- maxAge = minAge;
- setHiddenMaxAge(maxAge);
- inMaxAge.val(maxAge);
- }
- });
- inMaxAge.on("change", e => {
- maxAge = parseInt(e.target.value);
- setHiddenMaxAge(maxAge);
- if (maxAge < minAge) {
- minAge = maxAge;
- setHiddenMinAge(minAge);
- inMinAge.val(minAge);
- }
- });
- // Handle hidden user list.
- const ul = $("#ra_hiddenUsers");
- for (const item of getHiddenUsers()) {
- const li = $("<li class='tags-list__item'/>").appendTo(ul);
- $("<a class='js-tag ui-tag ui-tag--removable ui-tag--selected' href='#'><span class='ui-tag__label'>" + item + "</span></a>")
- .on("click", e => {
- setUserHidden(e.target.innerHTML, false);
- $(e.target).closest(".tags-list__item").css("display", "none");
- })
- .appendTo(li);
- };
- })
- .appendTo(jNode);
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement