diff --git a/extras/background.js b/extras/background.js
index c3085306..297a4c0d 100644
--- a/extras/background.js
+++ b/extras/background.js
@@ -1,49 +1,49 @@
chrome.runtime.onInstalled.addListener(() => { // this event is triggered when the extension is installed or reloaded
- chrome.tabs.create({ url: 'https://tools.scratchstatus.org/' }); // this is to open a webpage
- });
-
- chrome.tabs.onUpdated.addListener(function (tabId , info) {
+ chrome.tabs.create({
+ url: 'https://tools.scratchstatus.org/'
+ }); // this is to open a webpage
+});
+
+chrome.tabs.onUpdated.addListener(function(tabId, info) {
if (info.status === 'loading') {
- async function getCurrentTab() {
- var response = await fetch('/features/features.json')
- var data = await response.json()
- console.log(data)
- Object.keys(data).forEach(async function(el) {
- chrome.storage.sync.get("features", function (obj) {
- console.log(obj['features']);
- console.log(obj['features'])
- if (data[el]['default'] === true) {
- if (!obj['features'].includes(data[el]['file'])) {
- chrome.scripting.executeScript({
- target: { tabId: tabId },
- files: [`/features/${data[el]['file']}.js`]
- });
- }
- } else {
- if (obj['features'].includes(data[el]['file'])) {
- chrome.scripting.executeScript({
- target: { tabId: tabId },
- files: [`/features/${data[el]['file']}.js`]
- });
+ async function getCurrentTab() {
+ var response = await fetch('/features/features.json')
+ var data = await response.json()
+ console.log(data)
+ Object.keys(data).forEach(async function(el) {
+ chrome.storage.local.get(["features"], function(obj) {
+ console.log(obj['features']);
+ console.log(obj['features'])
+ if (data[el]['default'] === true) {
+ if (!obj['features'].includes(data[el]['file'])) {
+ chrome.tabs.executeScript({
+ file: `/features/${data[el]['file']}.js`
+ });
+ }
+ } else {
+ if (obj['features'].includes(data[el]['file'])) {
+ chrome.tabs.executeScript({
+ file: `/features/${data[el]['file']}.js`
+ });
+ }
+ }
+ });
+ })
+ var version = '2.6.0'
+ await chrome.storage.local.get(["version"], async function(obj) {
+ if (obj['version'] !== version) {
+ var tab = await chrome.tabs.get(tabId)
+ if (tab.url.includes('https://scratch.mit.edu')) {
+ chrome.storage.local.set({
+ "version": version
+ })
+ chrome.tabs.executeScript({
+ file: `/extras/new.js`
+ });
+ }
+ }
+ })
}
+ getCurrentTab()
}
- });
- })
- var version = '2.5.0'
- await chrome.storage.sync.get("version", async function (obj) {
- if (obj['version'] !== version) {
- var tab = await chrome.tabs.get(tabId)
- if (tab.url.includes('https://scratch.mit.edu')) {
- chrome.storage.sync.set({"version": version})
- chrome.scripting.executeScript({
- target: { tabId: tabId },
- files: [`/extras/new.js`]
- });
- }
- }
- })
- }
- getCurrentTab()
- }
- })
-
+})
diff --git a/extras/icon128.png b/extras/icon128.png
index 098fcd62..68de2caf 100644
Binary files a/extras/icon128.png and b/extras/icon128.png differ
diff --git a/extras/icon16.png b/extras/icon16.png
index ef902f4c..7fb276e4 100644
Binary files a/extras/icon16.png and b/extras/icon16.png differ
diff --git a/extras/icon48.png b/extras/icon48.png
index 098f14f9..2273d915 100644
Binary files a/extras/icon48.png and b/extras/icon48.png differ
diff --git a/extras/logo3.png b/extras/logo3.png
new file mode 100644
index 00000000..2e36a354
Binary files /dev/null and b/extras/logo3.png differ
diff --git a/extras/new.js b/extras/new.js
index 072cceb1..326b85e2 100644
--- a/extras/new.js
+++ b/extras/new.js
@@ -1,4 +1,4 @@
-createModal("What's New in ScratchTools v2.5", "We've put the settings into the extension popup! Now, just click on the extension icon and choose which features you want on or off! Take a look around at the new features! We even added back the modes from April Fool's Day!")
+createModal("What's New in ScratchTools v2.6", "This new version has made a lot of changes. First, it added a beta feature that hides likely generic projects from the trending page. It also added some significant UI updates to the settings popup to make it look much nicer.")
function createModal(title, description) {
var div = document.createElement('div')
div.className = 'ReactModalPortal ScratchToolsNew'
diff --git a/extras/popup.html b/extras/popup.html
index 55e074c3..f031cbd5 100644
--- a/extras/popup.html
+++ b/extras/popup.html
@@ -7,8 +7,7 @@
-
- ScratchTools
+
@@ -42,7 +41,7 @@ ScratchTools
}
.logo {
- width: 50px;
+ width: 80px;
}
a:hover, a:visited, a:link, a:active {
diff --git a/extras/popup.js b/extras/popup.js
index 8bb5a211..912766b1 100644
--- a/extras/popup.js
+++ b/extras/popup.js
@@ -12,8 +12,8 @@ async function doStuff() {
var description2 = document.createElement('p')
description2.textContent = description
var color = data['color']
- div.style.padding = '10px'
- div.style.margin = '5px'
+ div.style.padding = '5px'
+ div.style.margin = '0px'
div.style.borderRadius = '10px'
div.style.border = `2px solid ${color}`
div.appendChild(title2)
@@ -75,23 +75,25 @@ var abc = document.querySelector('center')
def.style.margin = '10px'
abc.appendChild(def)
}
-again()
+//again()
async function createFeature(name, description, id, credits, def) {
var div23 = document.createElement('div')
var item = div23
- item.style.margin = '15px'
- item.style.border = '1px solid black'
+ item.style.margin = '10px'
+ //item.style.border = '2px solid #8e9091'
item.style.padding = '5px'
- item.style.borderRadius = '5px'
+ item.style.borderRadius = '7px'
var h23 = document.createElement('h3')
h23.textContent = name
+h23.style.fontSize = '1.5em'
+h23.style.color = '#FF9F00'
var label23 = document.createElement('label')
label23.className = "switch"
var switch23 = document.createElement('input')
switch23.type = "checkbox"
switch23.id = id
-await chrome.storage.sync.get("features", async function (obj) {
+await chrome.storage.local.get("features", async function (obj) {
if (obj['features'] !== undefined) {
if (def === true) {
if (obj['features'].includes(switch23.id)) {
@@ -107,28 +109,28 @@ if (obj['features'].includes(switch23.id)) {
}
}
} else {
- await chrome.storage.sync.set({"features": "ok"})
+ await chrome.storage.local.set({"features": "ok"})
switch23.checked = false
}
});
console.log(getCookie('ST Features'))
switch23.addEventListener('click', async function() {
- await chrome.storage.sync.get("features", async function (obj) {
+ await chrome.storage.local.get("features", async function (obj) {
console.log(obj['features'])
if (obj['features'].includes(switch23.id)) {
console.log('false')
- await chrome.storage.sync.set({"features": obj['features'].replaceAll(switch23.id, '')})
- await chrome.storage.sync.set({"features": obj['features'].replaceAll(switch23.id, '')})
+ await chrome.storage.local.set({"features": obj['features'].replaceAll(switch23.id, '')})
+ await chrome.storage.local.set({"features": obj['features'].replaceAll(switch23.id, '')})
switch23.checked = false
} else {
console.log('true')
- await chrome.storage.sync.set({"features": obj['features']+switch23.id})
+ await chrome.storage.local.set({"features": obj['features']+switch23.id})
switch23.checked = true
}
})
})
- await chrome.storage.sync.get("features", function (obj) {
+ await chrome.storage.local.get("features", function (obj) {
console.log(obj['features'])
label23.appendChild(switch23)
var span23 = document.createElement('span')
@@ -138,10 +140,11 @@ div23.appendChild(h23)
div23.appendChild(document.createElement('br'))
var description2 = document.createElement('h3')
description2.style.marginTop = '-20px'
-description2.style.width = '200px'
+description2.style.width = '250px'
description2.textContent = description
var a = document.createElement('h3')
a.textContent = `Credits: ${credits.join(', ')}.`
+a.style.color = '#8e9091'
div23.appendChild(description2)
div23.appendChild(label23)
div23.appendChild(a)
diff --git a/extras/stsettings.css b/extras/stsettings.css
index 5af2ce8f..aba5aac9 100644
--- a/extras/stsettings.css
+++ b/extras/stsettings.css
@@ -2,6 +2,8 @@
body {
font-family: 'Space Grotesk', sans-serif;
+ background-color: #1b2126;
+ color: white;
}
.switch {
@@ -9,11 +11,22 @@ body {
display: inline-block;
width: 60px;
height: 34px;
+ margin: 0;
+ position: absolute;
+ top: 50%;
+ -ms-transform: translateY(-50%);
+ transform: translateY(-50%);
+ text-align: right;
+ right: 4%;
+ }
+
+ div {
+ position: relative;
}
h3 {
margin-top: 10px;
- padding: 10px;
+ padding: 3px;
}
/* Hide default HTML checkbox */
@@ -26,7 +39,7 @@ h3 {
.switch {
float: right;
- margin-top: -50px;
+ /* margin-top: -50px; */
}
/* The slider */
@@ -37,7 +50,7 @@ h3 {
left: 0;
right: 0;
bottom: 0;
- background-color: #ccc;
+ background-color: #262e3b;
-webkit-transition: .4s;
transition: .4s;
float: right;
@@ -57,12 +70,12 @@ h3 {
}
input:checked + .slider {
- background-color: #2196F3;
+ background-color: #FF9F00;
float: right;
}
input:focus + .slider {
- box-shadow: 0 0 1px #2196F3;
+ box-shadow: 0 0 1px #FF9F00;
float: right;
}
diff --git a/features/anti-generic.js b/features/anti-generic.js
new file mode 100644
index 00000000..232986ab
--- /dev/null
+++ b/features/anti-generic.js
@@ -0,0 +1,122 @@
+function cleanUp() {
+ var titles = []
+ document.querySelectorAll('div.thumbnail.project').forEach(function(el) {
+ var title = el.querySelector('div.thumbnail-title').firstChild.textContent.toLowerCase()
+ if (title.includes("part ")) {
+ console.log(title)
+ el.remove()
+ }
+ if (title.includes("#trending")) {
+ console.log(title)
+ el.remove()
+ }
+ if (title.includes("speedrun platformer")) {
+ console.log(title)
+ el.remove()
+ }
+if (title.includes("cave platformer")) {
+ console.log(title)
+ el.remove()
+ }
+if (title.includes("dark platformer")) {
+ console.log(title)
+ el.remove()
+ }
+if (title.includes("jungle platformer")) {
+ console.log(title)
+ el.remove()
+ }
+if (title.includes("platformer 1")) {
+ console.log(title)
+ el.remove()
+ }
+if (title.includes("platformer 2")) {
+ console.log(title)
+ el.remove()
+ }
+if (title.includes("platformer 3")) {
+ console.log(title)
+ el.remove()
+ }
+if (title.includes("dark") && title.includes("platformer")) {
+ console.log(title)
+ el.remove()
+}
+if (title.includes("generic") && title.includes("platformer")) {
+ console.log(title)
+ el.remove()
+}
+if (title.includes("jungle") && title.includes("platformer")) {
+ console.log(title)
+ el.remove()
+}
+if (title.includes("night") && title.includes("platformer")) {
+ console.log(title)
+ el.remove()
+}
+ if (countInstances(title, "#") > 3) {
+ console.log(title)
+ el.remove()
+ }
+ titles.forEach(function(el2) {
+ if (similarity(el2, title) > 0.5) {
+ if (el !== undefined && el !== null) {
+ console.log(title)
+ el.remove()
+ }
+ }
+ })
+ titles.push(title)
+ })
+
+ function countInstances(string, word) {
+ return string.split(word).length - 1;
+ }
+
+ function editDistance(s1, s2) {
+ s1 = s1.toLowerCase();
+ s2 = s2.toLowerCase();
+
+ var costs = new Array();
+ for (var i = 0; i <= s1.length; i++) {
+ var lastValue = i;
+ for (var j = 0; j <= s2.length; j++) {
+ if (i == 0)
+ costs[j] = j;
+ else {
+ if (j > 0) {
+ var newValue = costs[j - 1];
+ if (s1.charAt(i - 1) != s2.charAt(j - 1))
+ newValue = Math.min(Math.min(newValue, lastValue),
+ costs[j]) + 1;
+ costs[j - 1] = lastValue;
+ lastValue = newValue;
+ }
+ }
+ }
+ if (i > 0)
+ costs[s2.length] = lastValue;
+ }
+ return costs[s2.length];
+ }
+
+ function similarity(s1, s2) {
+ var longer = s1;
+ var shorter = s2;
+ if (s1.length < s2.length) {
+ longer = s2;
+ shorter = s1;
+ }
+ var longerLength = longer.length;
+ if (longerLength == 0) {
+ return 1.0;
+ }
+ return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
+ }
+ if (window.location.href.includes('https://scratch.mit.edu/explore/')) {
+ setTimeout(cleanUp, 200)
+ }
+}
+if (window.location.href.includes('https://scratch.mit.edu/explore/')) {
+ cleanUp()
+}
diff --git a/features/features.json b/features/features.json
index 5a41bdb8..71368e10 100644
--- a/features/features.json
+++ b/features/features.json
@@ -19,8 +19,15 @@
"urls": ["https://scratch.mit.edu/users/scratchfangs/", "https://scratch.mit.edu/users/jeffalo/", "https://scratch.mit.edu/users/rgantzos/"],
"file": "nfe-project-checker"
},
- {
- "title": "Advanced Search",
+ {
+ "title":"(Beta) Anti Generic",
+ "description":"On the explore and trending pages, this beta feature automatically hides repetitive projects, along with projects that it expects are generic. This includes projects with a lot of tags, common names, and project duplicates.",
+ "credits":["Bob the Potato wit Drip Jr.", "rgantzos"],
+ "urls":["https://scratch.mit.edu/users/JefferyTheSuperKat/", "https://scratch.mit.edu/users/rgantzos/"],
+ "file":"anti-generic"
+ },
+ {
+ "title": "(Beta) Advanced Search",
"description": "Replaces the basic search that Scratch uses with a much better and smarter search.",
"credits": ["rgantzos"],
"urls": ["https://scratch.mit.edu/users/rgantzos/"],
@@ -180,18 +187,18 @@
"urls": ["https://scratch.mit.edu/users/Scratchfangs", "https://scratch.mit.edu/users/rgantzos"],
"file": "fixed-box"
},
- {
- "title": "Follows You Message on Profiles",
- "description": "If the user whose profile you're visiting follows you, it will put a small message next to their username.",
- "credits": ["Bob the Potato with Drip", "TimMcCool"],
- "urls": ["https://scratch.mit.edu/users/JefferyTheSuperKat/", "https://scratch.mit.edu/users/TimMcCool/"],
- "file": "follows-you"
- },
{
"title": "Replace Scratch News with Recent Projects",
"description": "Replaces the Scratch News section on the home page with your recently shared projects.",
"credits": ["Scratchfangs", "rgantzos"],
"urls": ["https://scratch.mit.edu/users/scratchfangs/", "https://scratch.mit.edu/users/rgantzos/"],
"file":"my-recent-projects"
+ },
+ {
+ "title": "Focus Mode",
+ "description": "Removes the comments, studio and remix column, header, and footer on project pages.",
+ "credits": ["Scratchfangs"],
+ "urls": ["https://scratch.mit.edu/users/Scratchfangs"],
+ "file": "focus-mode"
}
]
diff --git a/features/focus-mode.js b/features/focus-mode.js
new file mode 100644
index 00000000..e92f7e10
--- /dev/null
+++ b/features/focus-mode.js
@@ -0,0 +1,21 @@
+if (window.location.href.includes("https://scratch.mit.edu/projects/")) {
+checkSubactions()
+function checkSubactions() {
+ if(document.querySelector('#view > div > div.inner > div:nth-child(3) > div.flex-row.subactions') === null) {
+ window.setTimeout(checkSubactions, 100)
+ } else {
+ focusMode()
+ }
+}
+function focusMode() {
+var btn = document.createElement('button')
+btn.className = 'button focusMode'
+btn.textContent = 'Focus Mode'
+btn.onclick = function() {
+ document.querySelector('#footer').remove()
+ document.querySelector('#navigation').remove()
+ document.querySelector("#view > div > div.project-lower-container").remove()
+}
+document.querySelector("#view > div > div.inner > div:nth-child(3) > div.flex-row.subactions").appendChild(btn)
+}
+}
diff --git a/features/searchable-dropdown.js b/features/searchable-dropdown.js
new file mode 100644
index 00000000..f5072091
--- /dev/null
+++ b/features/searchable-dropdown.js
@@ -0,0 +1,110 @@
+// ==UserScript==
+// @name Searchable Dropdowns for Scratch 3
+// @version 0.1.2
+// @namespace https://github.com/forkphorus/cat-plus
+// @match https://scratch.mit.edu/projects/*
+// @grant GM_addStyle
+// ==/UserScript==
+
+function callback(mutationList) {
+ for (const mutation of mutationList) {
+ if (mutation.type === 'childList') {
+ const newNodes = mutation.addedNodes;
+ for (const node of newNodes) {
+ if (node.classList && node.classList.contains('blocklyDropdownMenu')) {
+ addSearch();
+ break;
+ }
+ }
+ }
+ }
+}
+
+function addSearch() {
+ const el = document.createElement('input');
+ el.type = 'text';
+ el.addEventListener('input', search);
+ el.classList.add('u-dropdown-searchbar');
+ const container = getDropDownMenu();
+ container.insertBefore(el, container.firstChild);
+ el.focus();
+
+ for (const child of getItems()) {
+ child.dataset.visible = 'true';
+ }
+}
+
+function search(e) {
+ const value = e.target.value.toLowerCase();
+ for (const child of getItems()) {
+ const text = child.textContent.toLowerCase();
+ const contains = text.includes(value);
+ child.dataset.visible = contains.toString();
+ }
+}
+
+let cachedDropDownContentElement = null;
+function getDropDownContentElement() {
+ if (cachedDropDownContentElement) {
+ return cachedDropDownContentElement;
+ }
+ cachedDropDownContentElement = document.querySelector('.blocklyDropDownContent');
+ return cachedDropDownContentElement;
+}
+
+function getDropDownMenu() {
+ return getDropDownContentElement().querySelector('.blocklyDropdownMenu')
+}
+
+function getItems() {
+ const el = getDropDownMenu();
+ if (el) {
+ return Array.from(el.children).filter((child) => child.tagName !== 'INPUT');
+ }
+ return [];
+}
+
+const observer = new MutationObserver(callback);
+observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+});
+function GM_addStyle(style) {
+var el = document.createElement('style')
+el.innerHTML = style
+document.body.appendChild(el)
+}
+GM_addStyle(`
+.u-dropdown-searchbar {
+ /* seems to always fill the entire thing without making a horizontal scrollbar */
+ width: calc(100% - 20px);
+ /* based on styles for the title input */
+ color: white;
+ background-color: hsla(0, 100%, 100%, 0.25);
+ border: 1px dashed hsla(0, 0%, 0%, 0.15);
+ padding: .5rem;
+ outline: none;
+ transition: 0.25s ease-out;
+ font-size: 13px;
+ font-weight: bold;
+ border-radius: 4px;
+}
+.u-dropdown-searchbar:hover {
+ background-color: hsla(0, 100%, 100%, 0.5);
+}
+.u-dropdown-searchbar:focus {
+ background-color: white;
+ color: black;
+}
+
+[data-visible="false"] {
+ display: none;
+}
+
+/*.goog-menuitem-highlight {
+ background: transparent;
+}
+.goog-menuitem:hover {
+ background: rgba(0, 0, 0, 0.2);
+}*/
+`);
diff --git a/features/statistics.js b/features/statistics.js
index 8f4d22d1..99070c5e 100644
--- a/features/statistics.js
+++ b/features/statistics.js
@@ -5,9 +5,11 @@ el = document.querySelector('#tabs > li:nth-child(5)')
var clone = el.cloneNode(true);
document.querySelector('#tabs').appendChild(clone);
document.querySelector('#tabs > li:nth-child(6) > a').textContent = 'Statistics'
-document.querySelector('#tabs > li:nth-child(6)').className = 'last'
+document.querySelector('#tabs > li:nth-child(6)').className = 'last statistics'
document.querySelector('#tabs > li:nth-child(6)').dataTab = 'stats'
+ if (document.querySelector('li.statistics') === null) {
document.querySelector('#tabs > li:nth-child(6) > a').href = `https://scratchstats.com/${document.querySelector('#topnav > div > div > ul.account-nav.logged-in > li.logged-in-user.dropdown > div > ul > li:nth-child(1) > a').href.split('/users/')[1]}`
}
+}
setTimeout(() => { stuff() }, 50);
}
diff --git a/manifest.json b/manifest.json
index 9f3084ba..606f987c 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,26 +1,24 @@
{
- "name": "ScratchTools",
- "short_name": "ScratchTools",
- "manifest_version": 3,
- "version": "2.5.3",
- "description": "Great tools to make Scratching easier!",
- "author": "rgantzos",
- "background": {
- "service_worker": "/extras/background.js"
- },
- "permissions": [
- "scripting",
- "storage"
- ],
- "action": {
- "default_icon": "/extras/icon128.png",
- "default_popup": "/extras/popup.html",
- "default_title": "ScratchTools"
- },
- "icons": { "16": "/extras/icon16.png",
- "48": "/extras/icon48.png",
- "128": "/extras/icon128.png" },
- "host_permissions": [
- "https://scratch.mit.edu/"
- ]
- }
+ "manifest_version": 2,
+ "name": "ScratchTools",
+ "short_name": "ScratchTools",
+ "description": "Great tools to make Scratching easier!",
+ "version": "2.6.0",
+ "background": {
+ "scripts": ["/extras/background.js"],
+ "persistent": false
+ },
+ "permissions": [
+ "https://scratch.mit.edu/*",
+ "storage"
+ ],
+ "browser_action": {
+ "default_icon": "/extras/logo3.png",
+ "default_popup": "/extras/popup.html",
+ "default_title": "ScratchTools"
+ },
+ "icons": { "16": "/extras/icon16.png",
+ "48": "/extras/icon48.png",
+ "128": "/extras/icon128.png"
+ }
+}