├── config.json ├── Makefile ├── LICENSE ├── package.json ├── .gitignore ├── index.js └── README.md /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "", 3 | "server": "", 4 | "log_channel": "" 5 | } 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | REPORTER = spec 2 | 3 | all: jshint test 4 | 5 | test: 6 | @NODE_ENV=test ./node_modules/.bin/mocha --recursive --reporter $(REPORTER) --timeout 3000 7 | 8 | jshint: 9 | jshint lib examples test index.js 10 | 11 | tests: test 12 | 13 | tap: 14 | @NODE_ENV=test ./node_modules/.bin/mocha -R tap > results.tap 15 | 16 | unit: 17 | @NODE_ENV=test ./node_modules/.bin/mocha --recursive -R xunit > results.xml --timeout 3000 18 | 19 | skel: 20 | mkdir examples lib test 21 | touch index.js 22 | npm install mocha chai --save-dev 23 | 24 | .PHONY: test tap unit jshint skel -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2018, Ottomated 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emoji-thief", 3 | "version": "1.0.0", 4 | "description": "Monitors clipboard for Discord emoji and adds them to a private server", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/ottomated/emoji-thief.git" 12 | }, 13 | "keywords": [ 14 | "discord.js", 15 | "discord", 16 | "emoji" 17 | ], 18 | "author": "Ottomated", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/ottomated/emoji-thief/issues" 22 | }, 23 | "homepage": "https://github.com/ottomated/emoji-thief#readme", 24 | "dependencies": { 25 | "clipboard-monitor": "^1.0.2", 26 | "copy-paste": "^1.3.0", 27 | "discord.js": "github:discordjs/discord.js", 28 | "gifsicle": "^3.0.4", 29 | "tmp": "0.0.33" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/node 2 | 3 | const clipMonit = require('clipboard-monitor'); 4 | const Discord = require("discord.js"); 5 | const tmp = require('tmp'); 6 | const http = require('https'); 7 | const fs = require('fs'); 8 | const cp = require('copy-paste'); 9 | const {spawn, execFile} = require('child_process'); 10 | const gifsicle = require('gifsicle'); 11 | const config = require('./config.json'); 12 | var monitor = clipMonit(500); 13 | 14 | var lastClip = ''; 15 | 16 | discord_log = (text) => { 17 | console.log(text); 18 | logchan.send('`' + text + '`'); 19 | }; 20 | 21 | 22 | monitor.on('copy', function (data) { 23 | if(!server) 24 | return; 25 | let re = /^https:\/\/cdn\.discordapp\.com\/emojis\/[0-9]{18}\.(?:png|gif|jpg)/; 26 | if(!re.test(data)) { 27 | lastClip = data; 28 | return; 29 | } else { 30 | cp.copy(lastClip); 31 | } 32 | writeImageToTempFile(re.exec(data)[0], (file) => { 33 | discord_log('Write: ' + file); 34 | 35 | var child = spawn('yad', ['--center', '--on-top', '--image-on-top', '--image', file, '--title', 'Emoji Stolen', '--text', 'Enter Emoji Name:', '--entry']); 36 | var stdout = '', 37 | stderr = ''; 38 | child.stdout.on('data', function(data) { 39 | stdout += data.toString(); 40 | }); 41 | 42 | child.stderr.on('data', function(data) { 43 | stderr += data.toString(); 44 | }); 45 | 46 | child.on('exit', function(code) { 47 | if(!(/^[A-z_]+$/).test(stdout.trim())) { 48 | fs.unlink(file, () => discord_log('Delete: ' + file)); 49 | return; 50 | } 51 | newEmoji(file, stdout.trim()); 52 | }); 53 | }); 54 | }); 55 | 56 | 57 | const client = new Discord.Client(); 58 | 59 | var server = null; 60 | var logchan = null; 61 | client.on('ready', () => { 62 | console.log(`Logged in as ${client.user.tag}`); 63 | server = client.guilds.get(config.server); 64 | logchan = server.channels.get(config.log_channel); 65 | }); 66 | 67 | 68 | client.login(config.token); 69 | 70 | function newEmoji(path, name) { 71 | server.emojis.create(path, name) 72 | .then(emoji => { 73 | discord_log('Upload: ' + emoji.id); 74 | logchan.send(`<@194259969359478784> Stole emoji: <${emoji.animated ? 'a' : ''}:${emoji.name}:${emoji.id}> `); 75 | fs.unlink(path, () => discord_log('Delete: ' + path)); 76 | }) 77 | .catch(err => { 78 | if(err.message.indexOf('256') > -1) { 79 | 80 | var scaled = tmp.tmpNameSync(); 81 | execFile(gifsicle, ['--scale', '0.5', '-o', scaled, path], err => { 82 | discord_log('Scale: ' + scaled); 83 | fs.unlink(path, () => discord_log('Delete: ' + path)); 84 | newEmoji(scaled, name); 85 | }); 86 | } else { 87 | console.error(err); 88 | } 89 | }); 90 | } 91 | 92 | function writeImageToTempFile(url, cb) { 93 | var tmpobj = tmp.tmpNameSync() + url.substring(url.length - 4); 94 | var s = fs.createWriteStream(tmpobj); 95 | var request = http.get(url, function(response) { 96 | discord_log('Download: ' + url); 97 | response.pipe(s); 98 | cb(tmpobj); 99 | }); 100 | } 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Emoji Thief 2 | > Monitors the keyboard for Discord emoji URLs, and uses a bot to upload them to a private server. 3 | 4 | Discord Nitro allows users to use custom emoji globally, across servers. But what do you do when you see someone else use their own emoji? Now you don't have to ask them for an invite! 5 | Simply right-click on the emoji, press "Copy Link", and Emoji Thief will do the rest! 6 | 7 | ![](https://i.imgur.com/8Y2O4sI.png) 8 | 9 | ## Prerequisites 10 | 11 | #### Linux: 12 | 13 | - [yad](https://sourceforge.net/projects/yad-dialog/) 14 | ```sh 15 | # Arch Linux 16 | yaourt -S yad 17 | 18 | # Ubuntu 19 | sudo apt-add-repository ppa:webupd8team/y-ppa-manager 20 | sudo apt-get update 21 | sudo apt-get install yad 22 | ``` 23 | 24 | - [Node.js](https://nodejs.org) v9.5.0 25 | 26 | ```sh 27 | # Arch Linux 28 | pacman -S nodejs npm 29 | 30 | # Ubuntu 31 | curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash - 32 | sudo apt-get install -y nodejs 33 | ``` 34 | 35 | 36 | 37 | ## Installation 38 | 39 | #### Linux: 40 | 41 | ```sh 42 | git clone https://github.com/ottomated/emoji-thief.git 43 | cd emoji-thief 44 | npm install 45 | ``` 46 | 47 | ## Config Setup 48 | 49 | To actually use this script, you need to make: 50 | 51 | - A new Discord server for the emoji to be uploaded to 52 | - Optional: An extra channel in that server for the bot to write its logs to 53 | - A Discord Bot 54 | 55 | Server creation and channel creation are relatively easy, so I'm not going to go over that. In the `config.json` file, enter the server and channel IDs in their respective fields. 56 | 57 | To create the bot: 58 | 1. go to 59 | 2. "New App" 60 | 3. Fill out the name as "Emoji Thief" (or whatever you'd like) 61 | 4. Upload an image for the icon: I suggest [this](https://i.imgur.com/JMJGUhV.png) 62 | 5. "Create App" 63 | 6. Scroll down, "Create a Bot User" 64 | 7. Click to reveal the token and copy it to the "token" field in `config.json` 65 | 8. Scroll up, find your client ID 66 | 9. Visit this URL, replacing the zeros with your real client ID: 67 | [https://discordapp.com/api/oauth2/authorize?client_id=**000000000000000000**&permissions=8&scope=bot](https://discordapp.com/api/oauth2/authorize?client_id=000000000000000000&permissions=8&scope=bot) 68 | 10. Add the bot to the server you created earlier. 69 | 70 | ## Running the Script 71 | 72 | Once you've filled out the `config.json`, navigate to the folder in your terminal and run `npm start`. Feel free to set this up as a startup script. 73 | 74 | ## Meta 75 | 76 | Website: [ottomated.pw](https://ottomated.pw) 77 | 78 | Distributed under the ISC license. See ``LICENSE`` for more information. 79 | 80 | [https://github.com/ottomated/](https://github.com/ottomated/) 81 | 82 | ## Contributing 83 | 84 | 1. Fork it () 85 | 2. Create your feature branch (`git checkout -b feature/fooBar`) 86 | 3. Commit your changes (`git commit -am 'Add some fooBar'`) 87 | 4. Push to the branch (`git push origin feature/fooBar`) 88 | 5. Create a new Pull Request 89 | 90 | ## ToDo 91 | 92 | - Multi-Platform support 93 | - Better error handling 94 | - Scaling of multiple image types 95 | 96 | --------------------------------------------------------------------------------