├── LICENSE ├── README.md └── CS-RIN-RU-ENHANCED-external.user.js /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![Icon of CS.RIN.RU](https://i.ibb.co/zXtW7WD/csrinfavicon32.png) CS RIN RU Enhanced (external) 2 | ![License](https://img.shields.io/badge/License-UNLICENSE-red) ![Release](https://img.shields.io/github/v/release/Altansar69/CS.RIN.RU-Enhanced-external) ![OS](https://img.shields.io/badge/OS-Windows%2FmacOS%2FLinux-green) 3 | 4 | Extension of [CS RIN RU Enhanced mod](https://github.com/SubZeroPL/cs-rin-ru-enhanced-mod) (to be used in conjunction with) for everything concerning the forum, but act on external pages (Steam, SteamDB etc...) and not on the forum itself. 5 | 6 | Official forum topic: https://cs.rin.ru/forum/viewtopic.php?f=14&t=75717 7 | 8 | ## 🔧 Features 9 | - On a game's [Steam](https://store.steampowered.com) page, a button has been added to take you to the game's cs.rin page. 10 | - On a game's [Steam](https://store.steampowered.com) page, its tags (cs.rin) are displayed in its title ([CRACKED] [UNCRACKED] etc...). 11 | - On a game's [SteamDB](https://steamdb.info) page, a button has been added to take you to the game's cs.rin page. 12 | - On a game's [SteamDB](https://steamdb.info) page, its tags (cs.rin) are displayed in its title ([CRACKED] [UNCRACKED] etc...). 13 | - On a game's [GG.Deals](https://gg.deals) page, a button has been added to take you to the game's cs.rin page (works only for base game, not for special editions/bundles/packs etc.). 14 | 15 | ## 🧑‍🤝‍🧑 Other related projects 16 | - [CS RIN RU Enhanced mod](https://github.com/SubZeroPL/cs-rin-ru-enhanced-mod) - Main project 17 | 18 | ## 📅 TODO (planned features): 19 | see: [issues](https://github.com/Altansar69/CS.RIN.RU-Enhanced-external/issues) 20 | 21 | ## 🔨 Installation: 22 | 1) Download a script extension like [Violentmonkey](https://violentmonkey.github.io/) or [Tampermonkey](https://www.tampermonkey.net/). 23 | 2) Simply click on [this link](https://raw.githubusercontent.com/Altansar69/CS.RIN.RU-Enhanced-external/master/CS-RIN-RU-ENHANCED-external.user.js) and a pop-up window should appear asking you if you wish to install the extension. 24 | 25 | **Notes:** The script supports automatic updates, which means you don't have to download it again each time it's updated. 26 | 27 | *Developed & tested with [Violentmonkey](https://violentmonkey.github.io/) and [Tampermonkey](https://www.tampermonkey.net/) on [Firefox](https://www.mozilla.org/) and Chromium ([Brave](https://brave.com/)).* 28 | 29 | ## 🔢 Versioning 30 | This project is following semantic versioning schema. 31 | 32 | ## 🤝 Credits 33 | - [Altansar69](https://github.com/Altansar69) - Has created the project 34 | - [Reddiepoint](https://github.com/Reddiepoint) - Project co-creator 35 | - [SubZeroPL](https://github.com/SubZeroPL) - Project co-creator 36 | 37 | ## 📄 License 38 | This software is under the Unlicense, terms of which are available in [UNLICENSE.txt](UNLICENSE.txt]) 39 | -------------------------------------------------------------------------------- /CS-RIN-RU-ENHANCED-external.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name CS.RIN.RU Enhanced (External) 3 | // @name:fr CS.RIN.RU Amélioré (Externe) 4 | // @name:pt CS.RIN.RU Melhorado (Externo) 5 | // @name:tr Genişletilmiş CS.RIN.RU (Ek) 6 | // @namespace https://github.com/Altansar69/CS.RIN.RU-Enhanced-external 7 | // @version 1.1.12 8 | // @description Everything that concerns CS.RIN.RU - Steam Underground Community but does not act on the site. 9 | // @description:fr Tout ce qui concerne CS.RIN.RU - Steam Underground Community mais qui n'agit pas sur le site. 10 | // @description:pt Tudo o que diz respeito ao CS.RIN.RU - Steam Underground Community mas não age no site. 11 | // @description:tr CS.RIN.RU sitesini ilgilendiren her şey - Steam Underground Topluluğu ancak sitede faaliyet göstermemektedir. 12 | // @author CS.RIN.RU community 13 | // @match *://store.steampowered.com/app/* 14 | // @match *://steamdb.info/app/* 15 | // @match *://www.pcgamingwiki.com/wiki/* 16 | // @match *://gg.deals/game/* 17 | // @icon https://i.ibb.co/p1k6cq6/image.png 18 | // @grant GM_xmlhttpRequest 19 | // @homepageURL https://github.com/Altansar69/CS.RIN.RU-Enhanced-external 20 | // @supportURL https://cs.rin.ru/forum/viewtopic.php?f=14&t=75717 21 | // @updateURL https://raw.githubusercontent.com/Altansar69/CS.RIN.RU-Enhanced-external/master/CS-RIN-RU-ENHANCED-external.user.js 22 | // @downloadURL https://raw.githubusercontent.com/Altansar69/CS.RIN.RU-Enhanced-external/master/CS-RIN-RU-ENHANCED-external.user.js 23 | // ==/UserScript== 24 | 25 | const RIN_IMAGE = "data:image/png;base64,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"; 26 | const RIN_LABEL = "View on CS.RIN.RU"; 27 | 28 | let defaultTag; 29 | //defaultTag = "Cracked (by default)" 30 | 31 | console.log("CS.RIN.RU Enhanced (External) script started"); 32 | 33 | function addRinLinkToSteam() { 34 | if (!document.location.origin.match("store.steampowered.com")) return; 35 | 36 | const page = "steam" 37 | const rinButton = addRinButton(page); 38 | 39 | const dlcPage = document.querySelector("div.game_area_bubble.game_area_dlc_bubble"); 40 | const pageUrl = dlcPage?.querySelector("div > p > a")?.href ?? document.location.pathname; 41 | 42 | const appName = document.querySelector("#appHubAppName").textContent; 43 | const appId = getAppIdFromUrl(pageUrl); 44 | if (!appId) return; 45 | const developer = encodeURIComponent(document.querySelector("#developers_list").firstElementChild.textContent); 46 | updatePage(appId, appName, developer, rinButton, page); 47 | } 48 | 49 | addRinLinkToSteam(); 50 | 51 | function addRinLinkToSteamDB() { 52 | if (!document.location.origin.match("steamdb.info")) return; 53 | 54 | const page = "steamdb" 55 | const rinButton = addRinButton(page); 56 | 57 | const appName = document.querySelector("h1").textContent; 58 | const firstEntry = document.querySelector('.span3'); 59 | const appId = firstEntry.nextElementSibling.textContent; 60 | const developer = encodeURIComponent(firstEntry.parentElement 61 | .nextElementSibling.nextElementSibling 62 | .firstElementChild.nextElementSibling.textContent.replace(/\n/g, "")) 63 | updatePage(appId, appName, developer, rinButton, page) 64 | } 65 | 66 | addRinLinkToSteamDB(); 67 | 68 | function addRinLinkToPCGW() { 69 | if (!document.location.origin.match("pcgamingwiki.com")) return; 70 | 71 | const page = "PCGW" 72 | const rinButton = addRinButton(page); 73 | 74 | const pageUrl = document.querySelector('.infobox-steamdb > a').getAttribute("href"); 75 | const appName = document.querySelector("h1").textContent; 76 | const appId = getAppIdFromUrl(pageUrl); 77 | if (!appId) return; 78 | const developer = encodeURIComponent(document.querySelector(".template-infobox-info").textContent); 79 | updatePage(appId, appName, developer, rinButton, page); 80 | } 81 | 82 | addRinLinkToPCGW(); 83 | 84 | function addRinLinkToGGDeals() { 85 | if (!document.location.origin.match("gg.deals")) return; 86 | 87 | const gameName = document.querySelector("li[itemprop='itemListElement']:last-child").innerText.trim(); 88 | const developerItem = Array.from(document.querySelectorAll("div.game-info-details-section.text-details")).filter((v) => { 89 | return v.innerText.includes('Developer') 90 | })[0]; 91 | const developer = developerItem.querySelector("p").innerText; 92 | const ggUrl = document.querySelector("a.game-link-widget").href; 93 | 94 | const rinButton = addRinButton("ggdeals"); 95 | rinButton.href = "https://cs.rin.ru/forum"; 96 | 97 | GM_xmlhttpRequest({ 98 | method: "GET", 99 | url: ggUrl, 100 | onerror: function (error) { 101 | console.log(error); 102 | }, 103 | onload: function (response) { 104 | const appId = getAppIdFromUrl(response.finalUrl); 105 | if (!appId) return; 106 | updatePage(appId, gameName, developer, rinButton, "ggdeals"); 107 | } 108 | }); 109 | } 110 | 111 | addRinLinkToGGDeals(); 112 | 113 | function addRinButton(page) { 114 | let rinButton = document.createElement("a"); 115 | const spanElement = document.createElement("span"); 116 | const imgElement = document.createElement("img"); 117 | imgElement.className = "ico16"; 118 | imgElement.setAttribute("src", RIN_IMAGE); 119 | spanElement.appendChild(imgElement); 120 | 121 | // Add spacing 122 | if (page === "steam") { 123 | rinButton.className = "btnv6_blue_hoverfade btn_medium"; 124 | rinButton.style.marginRight = "0.28em" 125 | spanElement.dataset.tooltipText = RIN_LABEL; 126 | } 127 | 128 | // Add text for RIN button on SteamDB 129 | if (page === "steamdb") { 130 | rinButton.className = "btn tooltipped tooltipped-n"; 131 | rinButton.ariaLabel = RIN_LABEL; 132 | imgElement.style.height = "16px"; 133 | imgElement.style.width = "16px"; 134 | spanElement.append(" CS.RIN.RU"); 135 | } 136 | 137 | // Make sure the button has the same size as the other buttons 138 | if (page === "PCGW") { 139 | rinButton.className = "svg-icon template-infobox-icon"; 140 | rinButton.title = RIN_LABEL; 141 | } 142 | 143 | // Add button without image 144 | if (page === "ggdeals") { 145 | imgElement.style.height = "0px"; // No image 146 | imgElement.style.width = "0px"; 147 | rinButton.title = RIN_LABEL; 148 | rinButton.className = "game-link-widget"; 149 | rinButton.style.left = "130px" // Offset the button to the left so it does not overlap with the existing one 150 | spanElement.append("View on CS.RIN.RU"); 151 | spanElement.className = "game-header-store-link badge badge-big"; 152 | } 153 | 154 | rinButton.append(spanElement); 155 | 156 | const siteSelectors = { 157 | "steam": () => document.querySelector('.apphub_OtherSiteInfo').firstElementChild, 158 | "steamdb": () => document.querySelectorAll('.app-links')[1].firstElementChild, 159 | "PCGW": () => document.querySelectorAll('.template-infobox-icons')[0].firstElementChild, 160 | "ggdeals": () => document.querySelector("a.game-link-widget") // Button will be added to the right of the existing button 161 | }; 162 | const otherSiteInfo = (siteSelectors[page] || (() => null))(); 163 | // otherSiteInfo.insertBefore(rinButton, otherSiteInfo.firstChild); 164 | otherSiteInfo.insertAdjacentElement("beforebegin", rinButton); 165 | 166 | return rinButton; 167 | } 168 | 169 | function updatePage(appId, appName, developer, rinButton, page) { 170 | getRinTopic(appId, appName, developer, function (url, tags) { 171 | // Adds the cs.rin topic "href" attribute to the button 172 | addRinUrl(rinButton, url); 173 | addRinTags(tags, page); 174 | }); 175 | } 176 | 177 | function getRinTopic(appId, appName, developer, callback) { 178 | const rinSearchUrl = `https://cs.rin.ru/forum/search.php?keywords=${appId}&fid%5B%5D=10&sr=topics&sf=firstpost`; 179 | console.log(rinSearchUrl); 180 | console.log("Trying..."); 181 | GM_xmlhttpRequest({ 182 | method: "GET", url: rinSearchUrl, 183 | onerror: function (error) { 184 | console.log(error) 185 | }, 186 | onload: function (response) { 187 | const doc = new DOMParser().parseFromString(response.responseText, "text/html"); 188 | const topicSelectors = doc.querySelectorAll(".titles:not(:first-child), .topictitle"); 189 | const securityCheck = doc.querySelector("p"); // "Security check, please wait..." text element if it exists 190 | if (topicSelectors.length > 1) { 191 | getRinTopicAdvanced(appId, appName, developer, callback); 192 | } else if (securityCheck && securityCheck.textContent.includes("Security check")) { 193 | retryAttempts = maxRetryAttempts; // Fail immediately 194 | processResponse(appName, response.responseText, rinSearchUrl, callback, function () { 195 | getRinTopic(appId, "", developer, callback); // Returns search link immediately 196 | }); 197 | } else { 198 | processResponse(appName, response.responseText, rinSearchUrl, callback, function () { 199 | getRinTopic(appId, "", developer, callback); // Retry getRinTopic if search fails 200 | }); 201 | } 202 | } 203 | }); 204 | } 205 | 206 | function getRinTopicAdvanced(appId, appName, developer, callback) { 207 | const rinSearchUrl = `https://cs.rin.ru/forum/search.php?keywords=${appId}+${developer}&fid%5B%5D=10&sr=topics&sf=firstpost`; 208 | console.log(rinSearchUrl); 209 | GM_xmlhttpRequest({ 210 | method: "GET", url: rinSearchUrl, 211 | onerror: function (error) { 212 | console.log(error) 213 | }, 214 | onload: function (response) { 215 | processResponse(appName, response.responseText, rinSearchUrl, callback, function () { 216 | getRinTopicAdvanced(appId, appName, developer, callback); // Retry getRinTopicAdvanced if search fails 217 | }); 218 | } 219 | }); 220 | } 221 | 222 | let retryScheduled = false; // Flag to track if a retry is scheduled 223 | let retryAttempts = 0; // Counter for retry attempts 224 | const maxRetryAttempts = 1; // Maximum number of retry attempts 225 | function processResponse(appName, responseText, url, callback, retryFunction) { 226 | if (retryScheduled) return; // If a retry is scheduled, don't do anything 227 | 228 | if (retryAttempts >= maxRetryAttempts) { 229 | console.log("Max retry attempts reached"); 230 | callback(url, []); // Redirect to search page 231 | return; 232 | } 233 | retryAttempts++; 234 | 235 | const doc = new DOMParser().parseFromString(responseText, "text/html"); 236 | 237 | // Check if search was successful 238 | const checkElement = doc.querySelector("#wrapcentre > form > table.tablebg > tbody > tr:nth-child(1) > th:nth-child(1)"); 239 | if (!checkElement) { 240 | if (retryFunction) { 241 | retryScheduled = true; // Set the flag to true to block further retries 242 | setTimeout(() => { 243 | retryScheduled = false; // Reset the flag when the retry function is called 244 | retryFunction(); // Call the retryFunction, whichever function called this function 245 | }, 2000); 246 | } 247 | return; 248 | } 249 | 250 | // Get all topics 251 | const topics = doc.querySelectorAll(".titles:not(:first-child), .topictitle"); 252 | let topicSelector = null; 253 | for (let potentialTopic of topics) { 254 | if (potentialTopic.textContent.includes(appName)) { 255 | topicSelector = potentialTopic; 256 | break; 257 | } 258 | } 259 | // Default to first topic 260 | if (!topicSelector) { 261 | topicSelector = doc.querySelector(".titles:not(:first-child), .topictitle"); 262 | } 263 | 264 | const rinURL = topicSelector ? topicSelector.getAttribute("href") : "posting.php?mode=post&f=10"; 265 | const redirectUrl = "https://cs.rin.ru/forum/" + rinURL.split("&hilit")[0]; 266 | const tags = topicSelector ? topicSelector.text.match(/(? document.getElementById("appHubAppName"), 288 | "steamdb": () => document.querySelector('[itemprop="name"]'), 289 | "PCGW": () => document.getElementsByClassName("article-title")[0], 290 | "ggdeals": () => document.querySelector("div.game-heading h1") 291 | }; 292 | 293 | // const titleElem = (tagFunctions[page] || (() => null))(tags); 294 | const titleLocation = (titleLocations[page] || (() => null))(); 295 | const titleElem = appendRinTags(tags, titleLocation); 296 | 297 | // Add colours to the tags 298 | const bracketRegex = /[\[\]]/g; 299 | 300 | let newContent = titleElem.textContent; 301 | 302 | tags.forEach(tag => { 303 | const color = colorize(tag, titleElem); 304 | const tagSpan = `[${tag.replace(bracketRegex, "")}]`; 305 | newContent = newContent.replace(tag, tagSpan); 306 | }); 307 | 308 | titleElem.innerHTML = newContent; 309 | } 310 | 311 | function hexToRgb(hex) { 312 | return [parseInt(hex.substring(0, 2), 16), parseInt(hex.substring(2, 4), 16), parseInt(hex.substring(4, 6), 16)]; 313 | } 314 | 315 | function colorize(str, parentElem) { 316 | let lstr = str.toLowerCase(); 317 | let hash = 0; 318 | for (let i = 0; i < lstr.length; i++) { 319 | hash = lstr.charCodeAt(i) + ((hash << 5) - hash); 320 | } 321 | let color = Math.floor(Math.abs((Math.sin(hash) * 10000) % 1 * 16777216)).toString(16); 322 | let rgb = hexToRgb(color); 323 | 324 | while (!getComputedStyle(parentElem).getPropertyValue("background-color").match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)) { 325 | parentElem = parentElem.parentElement; 326 | } 327 | let bgColour = getComputedStyle(parentElem).getPropertyValue("background-color"); 328 | let matches = bgColour.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); 329 | const bgRgb = [parseInt(matches[1]), parseInt(matches[2]), parseInt(matches[3])]; 330 | 331 | while (Math.abs(rgb[0] + rgb[1] + rgb[2] - (bgRgb[0] + bgRgb[1] + bgRgb[2])) < 300) { 332 | hash = (hash << 5) - hash; 333 | color = Math.floor(Math.abs((Math.sin(hash) * 10000) % 1 * 16777216)).toString(16); 334 | rgb = hexToRgb(color); 335 | } 336 | 337 | return '#' + color.padStart(6, '0'); 338 | } 339 | 340 | /** 341 | * Returns AppId parsed from Url passed as an argument 342 | * @param {string} url 343 | * @returns AppId 344 | */ 345 | function getAppIdFromUrl(url) { 346 | const regex = /\/app\/(\d+)\//; 347 | const matches = url.match(regex); 348 | if (matches == null || matches[1] == null) { 349 | console.log(`Error getting AppId from URL ${url}`); 350 | return; 351 | } 352 | return matches[1]; 353 | } 354 | --------------------------------------------------------------------------------