-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d4ea1b3
Showing
7 changed files
with
260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
* | ||
!.gitignore | ||
!src**/** | ||
!contentScript.js | ||
!icon.png | ||
!manifest.json | ||
!popup.html | ||
!popup.js | ||
!README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# ao3-filter | ||
|
||
Simple little browser extension which allows you to filter works from Archive of Our Own's (AO3) search using regular expressions. | ||
|
||
## Installation | ||
|
||
Unfortunately, there is no simple way to install this since to release to an extension on Google Chrome or Mozilla Firefox a lot of information has to be released. | ||
|
||
So you'll have to install the extension via side loading it. | ||
|
||
For Chrome: | ||
|
||
1. Download the latest zip from the [releases page](https://github.com/zamu-flowerpot/ao3-filter/releases). | ||
2. Unpack the zip in some directory where the extension will live. | ||
3. In Chrome go to `chrome://extensions` and click on `Lock Unpacked`, navigate to where the zip was unpacked and hit select. | ||
4. Done! | ||
|
||
For Firefox: | ||
|
||
Unless you are running Firefox Nightly, you can't use this. Mozilla has taken a much harder stance on running unsigned extensions and since I'm not willing to submit it to their signing service, you're out of luck. | ||
|
||
If you *are* using Firefox Nightly: | ||
|
||
1. Download the latest zip from the [releases page](https://github.com/zamu-flowerpot/ao3-filter/releases). | ||
3. In Firefox Nightly go to `about:config`, search `xpinstall.signatures.required`, and set it to false. | ||
4. Once that is complete go to `about:addons', click on the gear in the top right underneath the search bar, and select `Install Add-on From File...`. | ||
5. Navigate to the directory where the zip file is located and select it. | ||
6. Done! | ||
|
||
## Usage | ||
|
||
The extension has one pane and no other configuration options. | ||
|
||
The pane has two buttons and one text area which houses the terms you want to filter out. | ||
|
||
The top button denotes whether the extension is on or off through a green checkmark or a red cross, respectively. | ||
|
||
The text area takes regular expressions to search *each* work on a search page for the pattern and if found hide the work. Each line in the text area is a seperate regular expression and all regular expresions match *case-insensitve*. | ||
|
||
The regex applies to the entire HTML of the work element, meaning that poorly constructed searches can lead to hiding all works. | ||
|
||
Finally after adding some patterns to match against, the bottom button saves and applies the search right away. | ||
|
||
## How it works | ||
|
||
This abuses regular expressions to either state whether a work is filtered or not. If it is filtered it sets the work to be hidden by toggling a CSS class which specifies `display: hidden;`. | ||
|
||
## Examples | ||
|
||
Filter works which contain the term hiatus, haitus, hiitus, or haatus. | ||
|
||
``` | ||
h[ai]{2}tus | ||
``` | ||
|
||
Filter works on just containing a term like `twin` | ||
|
||
``` | ||
twin | ||
``` | ||
|
||
Filter works that have Hermione Granger in a pairing with anyone that is not Harry Potter. This does use some specific knowledge that the H/Hr pairing is `Hermione Granger/Harry Potter` on AO3. | ||
|
||
``` | ||
hermione.granger\/(?!harry.potter)|\/hermione.granger | ||
``` | ||
|
||
## Bugs/Comments/Etc. | ||
|
||
Feel free to open an Issue if you discover a bug or weird edge case. If you just have a question or comment open up a discussion post. | ||
|
||
I generally don't see this breaking due to the code itself, but changes in the Browser Extension APIs and interfaces (ie. Manifest v2 vs v3). If it does and there isn't a fix, free free to push a pull request or just open an issue. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
function addStyle(styleString) { | ||
const style = document.createElement('style'); | ||
style.textContent = styleString; | ||
document.head.append(style); | ||
console.log("style added") | ||
} | ||
|
||
function hideWorksByRegex(selector='li.work') { | ||
function _hideWorksByRegex(pattern,elems) { | ||
if (pattern.length < 1) { | ||
return | ||
} | ||
let re = new RegExp(pattern, 'i'); | ||
elems = elems | ||
.filter(x=>x.innerHTML.match(re)); | ||
elems | ||
.map(x=>x.classList.toggle("ao3-filter-hidden")); | ||
console.log("pattern:", pattern ,"selector:", selector,"elems:", elems, "summary", elems.map( | ||
x=>{ | ||
return { | ||
"title": x.querySelector('div.header.module h4.heading').innerText.replace(/\s\s+/g, ' ').trim(), | ||
"summary": x.querySelector('blockquote.userstuff.summary').innerText.replace(/\s\s+/g,' ').trim(), | ||
} | ||
})); | ||
} | ||
|
||
chrome.storage.sync.get(["patterns", "active"], record=>{ | ||
console.log(record) | ||
let elems = Array.from(document.querySelectorAll(selector)); | ||
elems.map(x=>x.classList.remove('ao3-filter-hidden')); | ||
if (record.active && record.patterns) { | ||
_hideWorksByRegex(record.patterns.join("|"), elems); | ||
} | ||
}) | ||
} | ||
|
||
|
||
|
||
addStyle(` | ||
.ao3-filter-hidden { | ||
display: none !important; | ||
} | ||
`) | ||
hideWorksByRegex() | ||
|
||
chrome.runtime.onMessage.addListener( | ||
function(request, sender, sendResponse) { | ||
switch (request.settings_changed) { | ||
case 'saved': | ||
hideWorksByRegex(); | ||
break; | ||
case 'toggled': | ||
hideWorksByRegex(); | ||
break; | ||
default: | ||
()=>{} | ||
} | ||
} | ||
) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"manifest_version": 2, | ||
"name": "ao3-filter", | ||
"description": "filter ao3 works based on regular expressions", | ||
"version": "0.1", | ||
|
||
"permissions": ["storage", "activeTab"], | ||
"icons": { | ||
"19": "icon.png" | ||
}, | ||
"browser_action": { | ||
"default_icon": "icon.png", | ||
"default_title": "ao3-filter", | ||
"default_popup": "popup.html" | ||
}, | ||
"content_scripts": [ | ||
{ | ||
"matches": [ | ||
"https://archiveofourown.org/tags/*", | ||
"https://archiveofourown.org/works*" | ||
], | ||
"js": ["contentScript.js"], | ||
"all_frames": false | ||
} | ||
], | ||
"browser_specific_settings": { | ||
"gecko": { | ||
"id": "[email protected]", | ||
"strict_min_version": "53" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta http-equiv="content-type" content="text/html; charset=utf-8"> | ||
<title>ao3-filter</title> | ||
<style> | ||
body { | ||
font-family: san-serif; | ||
} | ||
div.content { | ||
display: grid; | ||
width: 20em; | ||
grid-template-columns: 1fr 1fr; | ||
grid-template-rows: auto 1fr auto; | ||
grid-gap: 3px; | ||
} | ||
h1 { | ||
grid-row: 1; | ||
grid-column: 1; | ||
} | ||
|
||
textarea#terms { | ||
grid-row: 2; | ||
grid-column: 1 / 3; | ||
} | ||
|
||
button#savebtn { | ||
grid-column: 1 /3; | ||
grid-row: 3; | ||
} | ||
|
||
button#toggle_activity { | ||
height: fit-content; | ||
align-self: center; | ||
margin: 10px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div class="content"> | ||
<h1>ao3-filter</h1> | ||
<textarea name="terms" id="terms" cols="30" rows="10"></textarea> | ||
<button id="savebtn" type="submit">Save</button> | ||
<button type="submit" id="toggle_activity">✅</button> | ||
</div> | ||
<script src="popup.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
|
||
const termElem = document.getElementById("terms"); | ||
const stateElem = document.getElementById("toggle_activity"); | ||
function loadPopup() { | ||
chrome.storage.sync.get(["patterns", "active"], record => { | ||
record.patterns = record.patterns || []; | ||
termElem.value = record.patterns.join("\n"); | ||
stateElem.innerText = record.active ? "✅": "❌"; | ||
}) | ||
} | ||
loadPopup() | ||
document.getElementById("savebtn").addEventListener("click",(_ev)=>{ | ||
let patterns = termElem.value; | ||
chrome.storage.sync.set( | ||
{ | ||
["patterns"]: patterns.split('\n').filter(x=>x!==""), | ||
}, | ||
(_res) => (_res) | ||
) | ||
|
||
chrome.tabs.query({active:true, currentWindow: true}, function(tabs) { | ||
chrome.tabs.sendMessage(tabs[0].id, {settings_changed: "saved"}) | ||
}) | ||
loadPopup() | ||
}) | ||
|
||
stateElem.addEventListener("click", (_ev)=>{ | ||
let state = stateElem.innerText; | ||
chrome.storage.sync.set( | ||
{ | ||
["active"]: state == "✅" ? false : true, | ||
}, | ||
(_res)=>_res | ||
) | ||
chrome.tabs.query({active:true, currentWindow: true}, function(tabs) { | ||
chrome.tabs.sendMessage(tabs[0].id, {settings_changed: "toggled"}) | ||
}) | ||
loadPopup() | ||
}) | ||
|