Skip to content

Commit 6d87373

Browse files
authored
Initial commit
1 parent f2c4481 commit 6d87373

File tree

5 files changed

+154
-0
lines changed

5 files changed

+154
-0
lines changed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Watermark Remover
2+
3+
Watermark Remover is a Chrome extension that removes hidden watermark characters from copied text on web pages.
4+
5+
## Features
6+
7+
- Intercepts clipboard operations (`navigator.clipboard.writeText`, `navigator.clipboard.write`) and `document.execCommand('copy')`
8+
- Removes watermark characters: U+200B, U+200C, U+200D, U+2060, U+FEFF, U+202F, U+00A0
9+
10+
## Installation
11+
12+
1. Clone or download the repository to a local directory.
13+
2. Open Chrome and navigate to `chrome://extensions`.
14+
3. Enable **Developer mode**.
15+
4. Click **Load unpacked** and select the extension directory.
16+
17+
## Configuration
18+
19+
- **manifest.json**
20+
- `content_scripts.matches`: URL patterns for injection
21+
- `content_scripts.run_at`: set to `document_start` to override clipboard APIs early
22+
- `web_accessible_resources`: include `inject.js` for page injection
23+
- Permissions: `scripting`, and host permissions for target domains
24+
25+
## Project Structure
26+
27+
```
28+
text-watermark-remover/
29+
├── content.js # Injects inject.js into page context
30+
├── icon.png # Chrome extension icon
31+
├── inject.js # Overrides clipboard APIs
32+
├── manifest.json # Extension metadata and permissions
33+
└── README.md # Project documentation
34+
```
35+
36+
## Development
37+
38+
- Modify `inject.js` or `content.js` as needed.
39+
- Reload the extension in `chrome://extensions`.
40+
- Reload target web pages to apply changes.

content.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const script = document.createElement("script");
2+
script.src = chrome.runtime.getURL("inject.js");
3+
script.onload = () => script.remove();
4+
(document.head || document.documentElement).appendChild(script);

icon.png

1.96 KB
Loading

inject.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
(() => {
2+
const watermarkChars = [
3+
"\u200B",
4+
"\u200C",
5+
"\u200D",
6+
"\u2060",
7+
"\uFEFF",
8+
"\u202F",
9+
"\u00A0",
10+
];
11+
12+
const cleanse = (text) =>
13+
watermarkChars.reduce((t, ch) => t.split(ch).join(" "), text);
14+
15+
// sol 1
16+
if (navigator.clipboard?.writeText) {
17+
const origWriteText = navigator.clipboard.writeText.bind(
18+
navigator.clipboard
19+
);
20+
navigator.clipboard.writeText = async (data) => {
21+
const cleaned = cleanse(data);
22+
console.log(`Text watermarks removed.`);
23+
return origWriteText(cleaned);
24+
};
25+
}
26+
27+
// sol 2
28+
if (navigator.clipboard?.write) {
29+
const origWrite = navigator.clipboard.write.bind(navigator.clipboard);
30+
navigator.clipboard.write = async (items) => {
31+
const newItems = await Promise.all(
32+
items.map(async (item) => {
33+
const blobs = {};
34+
for (const type of item.types) {
35+
const blob = await item.getType(type);
36+
if (type === "text/plain") {
37+
const text = await blob.text();
38+
const cleaned = cleanse(text);
39+
console.log(`Text watermarks removed.`);
40+
blobs[type] = new Blob([cleaned], { type });
41+
} else blobs[type] = blob;
42+
}
43+
return new ClipboardItem(blobs);
44+
})
45+
);
46+
return origWrite(newItems);
47+
};
48+
}
49+
50+
// sol 3
51+
{
52+
const origExec = Document.prototype.execCommand;
53+
Document.prototype.execCommand = (cmd, ...args) => {
54+
if (cmd.toLowerCase() === "copy") {
55+
const sel = window.getSelection().toString();
56+
const cleaned = cleanse(sel);
57+
const ta = document.createElement("textarea");
58+
ta.value = cleaned;
59+
ta.style.position = "fixed";
60+
ta.style.opacity = "0";
61+
document.body.appendChild(ta);
62+
ta.select();
63+
const result = origExec.call(this, "copy", ...args);
64+
document.body.removeChild(ta);
65+
console.log(`Text watermarks removed.`);
66+
return result;
67+
}
68+
return origExec.call(this, cmd, ...args);
69+
};
70+
}
71+
72+
// sol 4
73+
document.addEventListener(
74+
"copy",
75+
(e) => {
76+
const sel = window.getSelection().toString();
77+
const cleaned = cleanse(sel);
78+
e.clipboardData.setData("text/plain", cleaned);
79+
e.clipboardData.setData("text/html", cleaned);
80+
e.preventDefault();
81+
console.log(`Text watermarks removed.`);
82+
},
83+
true
84+
);
85+
86+
console.log("[T.W.R.] Injected all content scripts!");
87+
})();

manifest.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"manifest_version": 3,
3+
"name": "Watermark Remover",
4+
"version": "1.0",
5+
"permissions": ["scripting"],
6+
"host_permissions": ["<all_urls>"],
7+
"action": {
8+
"default_icon": "icon.png"
9+
},
10+
"content_scripts": [
11+
{
12+
"matches": ["<all_urls>"],
13+
"js": ["content.js"],
14+
"run_at": "document_start"
15+
}
16+
],
17+
"web_accessible_resources": [
18+
{
19+
"resources": ["inject.js"],
20+
"matches": ["<all_urls>"]
21+
}
22+
]
23+
}

0 commit comments

Comments
 (0)