├── index.js ├── scripts ├── router.js ├── bumble_responses_text.js └── okcupid_responses_text.js ├── README.md ├── manifest.json ├── LICENSE ├── .gitignore └── packed.js /index.js: -------------------------------------------------------------------------------- 1 | injectScript('packed.js'); 2 | 3 | function injectScript(scriptName) { 4 | return new Promise(function () { 5 | const s = document.createElement('script'); 6 | s.src = chrome.runtime.getURL(scriptName); 7 | (document.head || document.documentElement).appendChild(s); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /scripts/router.js: -------------------------------------------------------------------------------- 1 | const start = async () => { 2 | const url = new URL(location.href); 3 | if (url.host.includes('okcupid.com')) { 4 | okcupid_init_response_hook(); 5 | } else if (url.host.includes('bumble.com')) { 6 | bumble_init_response_hook(); 7 | } 8 | }; 9 | 10 | console.log('Dating-Plus loaded successfully!'); 11 | start(); 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dating-Plus 2 | 3 | ## Features for okcupid: 4 | 5 | | Feature | Availability | 6 | |:------------------------------------------:|:------------:| 7 | | Indication if the current person liked you | ✔ | 8 | | Disable blur of liked you images | ✔ | 9 | 10 | ## Features for bumble: 11 | 12 | | Feature | Availability | 13 | |:------------------------------------------:|:------------:| 14 | | Indication if the current person liked you | ✔ | 15 | 16 | ## Installing from GitHub 17 | 18 | 1. To install the extension, download the latest release as a zip file or clone the repository. 19 | 2. Go to `chrome://extensions/`. 20 | 3. Enable developer mode. 21 | 4. Add it to Chrome using the 'Load unpacked extension' option. 22 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dating-Plus", 3 | "version": "1.0.0", 4 | "description": "", 5 | "permissions": [ 6 | "storage", 7 | "activeTab", 8 | "webNavigation", 9 | "tabs" 10 | ], 11 | "content_scripts": [ 12 | { 13 | "matches": [ 14 | "https://www.okcupid.com/*", 15 | "https://*.bumble.com/*" 16 | ], 17 | "js": [ 18 | "./index.js" 19 | ], 20 | "run_at": "document_end" 21 | } 22 | ], 23 | "host_permissions": [ 24 | "https://www.okcupid.com/", 25 | "https://*.bumble.com/*" 26 | ], 27 | "manifest_version": 3, 28 | "web_accessible_resources": [ 29 | { 30 | "resources": [ 31 | "packed.js" 32 | ], 33 | "matches": [ 34 | "https://www.okcupid.com/*", 35 | "https://*.bumble.com/*" 36 | ] 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Alon Schwartzblat & Yan Osher Cohen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /scripts/bumble_responses_text.js: -------------------------------------------------------------------------------- 1 | let current_match_index = 0; 2 | 3 | const bumble_init_response_hook = () => { 4 | const matches_handler = (data) => { 5 | current_matches = data.body[0].client_encounters.results; 6 | console.log(current_matches); 7 | return data; 8 | }; 9 | 10 | 11 | const match_handler = () => { 12 | const match = current_matches[current_match_index]; 13 | if (!match?.user?.their_vote || match.user.their_vote === 1) { 14 | console.log(`${match.user.name} haven't voted yet`); 15 | return; 16 | } 17 | const is_match = match.user.their_vote === 2; 18 | 19 | try { 20 | const v_icon = document.getElementsByClassName('encounters-action tooltip-activator encounters-action--like')[0]; 21 | v_icon.childNodes[0].childNodes[0].childNodes[0].childNodes[0].setAttribute('fill', is_match ? 'green' : 'red') 22 | } catch (e) { 23 | console.log(e); 24 | } 25 | }; 26 | 27 | const parse_clone = JSON.parse; 28 | 29 | JSON.parse = function (string) { 30 | if (string.includes('badoo.bma.ClientVoteResponse')) { 31 | current_match_index++; 32 | console.log(`current_match_index: ${current_match_index}`); 33 | match_handler(); 34 | } 35 | let ret = parse_clone(string); 36 | 37 | if (ret?.body?.[0]?.client_encounters?.results) { 38 | current_match_index = 0 39 | ret = matches_handler(ret); 40 | match_handler(); 41 | return ret; 42 | } 43 | return ret; 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /scripts/okcupid_responses_text.js: -------------------------------------------------------------------------------- 1 | let current_matches = []; 2 | 3 | 4 | const okcupid_init_response_hook = () => { 5 | 6 | setInterval(() => { 7 | const elements = document.getElementsByClassName('usercard-placeholder-thumb'); 8 | for (const element of elements) { 9 | element.className = 'usercard-placeholder'; 10 | } 11 | for (const paywall of document.getElementsByClassName('likes-you-paywall-explainer-cta')) { 12 | paywall.remove(); 13 | } 14 | }, 100); 15 | 16 | const matches_handler = (data) => { 17 | current_matches = data.data.me.matches; 18 | return JSON.stringify(data); 19 | }; 20 | 21 | 22 | const match_handler = (user_id) => { 23 | const match = current_matches.some(match => match.user.id === user_id); 24 | if (!match?.targetVote || match.targetVote === 'NONE') { 25 | console.log(`${user_id} haven't voted yet`); 26 | return; 27 | } 28 | const like_and_pass_buttons = document.getElementsByClassName('dt-action-buttons-button-text'); 29 | const like_button = like_and_pass_buttons[1]; 30 | like_button.textContent = match.targetVote === 'LIKE' ? 'MATCH' : 'NOPE'; 31 | }; 32 | 33 | const who_liked_you_handler = (data) => { 34 | data.data.me.likes.data.map((like) => { 35 | like.primaryImageBlurred = like.primaryImage; 36 | }); 37 | return JSON.stringify(data); 38 | }; 39 | 40 | const text_clone = Response.prototype.text; 41 | 42 | Response.prototype.text = async function () { 43 | const text = await text_clone.call(this); 44 | if (!this.url.includes('graphql')) { 45 | return text; 46 | } 47 | const data = JSON.parse(text); 48 | if (data?.data?.me?.matches) { 49 | return matches_handler(data); 50 | } 51 | if (data?.data?.me?.match?.user?.id) { 52 | match_handler(data.data.me.match.user.id); 53 | } 54 | if (data?.data?.me?.likes) { 55 | return who_liked_you_handler(data); 56 | } 57 | return JSON.stringify(data); 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | 106 | # Docusaurus cache and generated files 107 | .docusaurus 108 | 109 | # Serverless directories 110 | .serverless/ 111 | 112 | # FuseBox cache 113 | .fusebox/ 114 | 115 | # DynamoDB Local files 116 | .dynamodb/ 117 | 118 | # TernJS port file 119 | .tern-port 120 | 121 | # Stores VSCode versions used for testing VSCode extensions 122 | .vscode-test 123 | 124 | # yarn v2 125 | .yarn/cache 126 | .yarn/unplugged 127 | .yarn/build-state.yml 128 | .yarn/install-state.gz 129 | .pnp.* 130 | .idea 131 | /Gruntfile.js 132 | /package.json 133 | /package-lock.json 134 | -------------------------------------------------------------------------------- /packed.js: -------------------------------------------------------------------------------- 1 | const main = () => { 2 | let current_matches = []; 3 | 4 | 5 | const okcupid_init_response_hook = () => { 6 | 7 | setInterval(() => { 8 | const elements = document.getElementsByClassName('usercard-placeholder-thumb'); 9 | for (const element of elements) { 10 | element.className = 'usercard-placeholder'; 11 | } 12 | for (const paywall of document.getElementsByClassName('likes-you-paywall-explainer-cta')) { 13 | paywall.remove(); 14 | } 15 | }, 100); 16 | 17 | const matches_handler = (data) => { 18 | current_matches = data.data.me.matches; 19 | return JSON.stringify(data); 20 | }; 21 | 22 | 23 | const match_handler = (user_id) => { 24 | const match = current_matches.some(match => match.user.id === user_id); 25 | if (!match?.targetVote || match.targetVote === 'NONE') { 26 | console.log(`${user_id} haven't voted yet`); 27 | return; 28 | } 29 | const like_and_pass_buttons = document.getElementsByClassName('dt-action-buttons-button-text'); 30 | const like_button = like_and_pass_buttons[1]; 31 | like_button.textContent = match.targetVote === 'LIKE' ? 'MATCH' : 'NOPE'; 32 | }; 33 | 34 | const who_liked_you_handler = (data) => { 35 | data.data.me.likes.data.map((like) => { 36 | like.primaryImageBlurred = like.primaryImage; 37 | }); 38 | return JSON.stringify(data); 39 | }; 40 | 41 | const text_clone = Response.prototype.text; 42 | 43 | Response.prototype.text = async function () { 44 | const text = await text_clone.call(this); 45 | if (!this.url.includes('graphql')) { 46 | return text; 47 | } 48 | const data = JSON.parse(text); 49 | if (data?.data?.me?.matches) { 50 | return matches_handler(data); 51 | } 52 | if (data?.data?.me?.match?.user?.id) { 53 | match_handler(data.data.me.match.user.id); 54 | } 55 | if (data?.data?.me?.likes) { 56 | return who_liked_you_handler(data); 57 | } 58 | return JSON.stringify(data); 59 | }; 60 | } 61 | 62 | 63 | let current_match_index = 0; 64 | 65 | const bumble_init_response_hook = () => { 66 | const matches_handler = (data) => { 67 | current_matches = data.body[0].client_encounters.results; 68 | console.log(current_matches); 69 | return data; 70 | }; 71 | 72 | 73 | const match_handler = () => { 74 | const match = current_matches[current_match_index]; 75 | if (!match?.user?.their_vote || match.user.their_vote === 1) { 76 | console.log(`${match.user.name} haven't voted yet`); 77 | return; 78 | } 79 | const is_match = match.user.their_vote === 2; 80 | 81 | try { 82 | const v_icon = document.getElementsByClassName('encounters-action tooltip-activator encounters-action--like')[0]; 83 | v_icon.childNodes[0].childNodes[0].childNodes[0].childNodes[0].setAttribute('fill', is_match ? 'green' : 'red') 84 | } catch (e) { 85 | console.log(e); 86 | } 87 | }; 88 | 89 | const parse_clone = JSON.parse; 90 | 91 | JSON.parse = function (string) { 92 | if (string.includes('badoo.bma.ClientVoteResponse')) { 93 | current_match_index++; 94 | console.log(`current_match_index: ${current_match_index}`); 95 | match_handler(); 96 | } 97 | let ret = parse_clone(string); 98 | 99 | if (ret?.body?.[0]?.client_encounters?.results) { 100 | current_match_index = 0 101 | ret = matches_handler(ret); 102 | match_handler(); 103 | return ret; 104 | } 105 | return ret; 106 | }; 107 | } 108 | 109 | 110 | const start = async () => { 111 | const url = new URL(location.href); 112 | if (url.host.includes('okcupid.com')) { 113 | okcupid_init_response_hook(); 114 | } else if (url.host.includes('bumble.com')) { 115 | bumble_init_response_hook(); 116 | } 117 | }; 118 | 119 | console.log('Dating-Plus loaded successfully!'); 120 | start(); 121 | 122 | }; 123 | main(); --------------------------------------------------------------------------------