diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 0000000..2792370 --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1 @@ +ko_fi: andriir diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd8c797 --- /dev/null +++ b/.gitignore @@ -0,0 +1,106 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +# dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port +package-lock.json +pnpm-lock.yaml diff --git a/README.md b/README.md index 31ba029..03f4060 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,37 @@ -# hunt-adblock -Detect adblocks +# Adblock Hunter 🔫 +This library enables you to determine whether a user is using an ad blocker or not. + +## Installation +```bash +$ npm install --save adblock-hunter +``` + +## Examples +```javascript +import { isAdblocking } from 'adblock-hunter' + +isAdblocking().then((adblocking) => { + if (adblocking) { + // an adblocker is present + } +}) + +// or + +const someFunction = async () => { + // some of your code here... + + const adblocking = await isAdblocking() + if (adblocking) { + // an adblocker is present + } +} +``` + +## API +### `isAdblocking` +`isAdblocking` is a function which makes a call to Google Ads URL and checks wheater the request succeeds (user has no adblock) or not (the adblock is present).\ +The returned value is `Promise`. + +## Donate +You can support the project by donating me at https://ko-fi.com/andriir diff --git a/dist/adblock-hunter.cjs.js b/dist/adblock-hunter.cjs.js new file mode 100644 index 0000000..af764a0 --- /dev/null +++ b/dist/adblock-hunter.cjs.js @@ -0,0 +1,85 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +var adURL = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'; +/** + * Check if AdBlocker is present in user's browser + * @return Promise + */ +var isAblocking = function () { return __awaiter(void 0, void 0, void 0, function () { + var enabled; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + enabled = false; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, fetch(adURL)]; + case 2: + _a.sent(); + return [3 /*break*/, 4]; + case 3: + _a.sent(); + enabled = true; + return [3 /*break*/, 4]; + case 4: return [2 /*return*/, enabled]; + } + }); +}); }; + +exports.isAblocking = isAblocking; diff --git a/dist/adblock-hunter.es5.js b/dist/adblock-hunter.es5.js new file mode 100644 index 0000000..4d9b563 --- /dev/null +++ b/dist/adblock-hunter.es5.js @@ -0,0 +1,81 @@ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +var adURL = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'; +/** + * Check if AdBlocker is present in user's browser + * @return Promise + */ +var isAblocking = function () { return __awaiter(void 0, void 0, void 0, function () { + var enabled; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + enabled = false; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, fetch(adURL)]; + case 2: + _a.sent(); + return [3 /*break*/, 4]; + case 3: + _a.sent(); + enabled = true; + return [3 /*break*/, 4]; + case 4: return [2 /*return*/, enabled]; + } + }); +}); }; + +export { isAblocking }; diff --git a/dist/adblock-hunter.js b/dist/adblock-hunter.js new file mode 100644 index 0000000..8eab0a9 --- /dev/null +++ b/dist/adblock-hunter.js @@ -0,0 +1 @@ +!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self)["adblock-hunter"]={})}(this,function(e){"use strict";function n(e,i,u,c){return new(u=u||Promise)(function(t,n){function o(e){try{a(c.next(e))}catch(e){n(e)}}function r(e){try{a(c.throw(e))}catch(e){n(e)}}function a(e){var n;e.done?t(e.value):((n=e.value)instanceof u?n:new u(function(e){e(n)})).then(o,r)}a((c=c.apply(e,i||[])).next())})}function t(o,r){var a,i,u,c={label:0,sent:function(){if(1&u[0])throw u[1];return u[1]},trys:[],ops:[]},e={next:n(0),throw:n(1),return:n(2)};return"function"==typeof Symbol&&(e[Symbol.iterator]=function(){return this}),e;function n(t){return function(e){var n=[t,e];if(a)throw new TypeError("Generator is already executing.");for(;c;)try{if(a=1,i&&(u=2&n[0]?i.return:n[0]?i.throw||((u=i.return)&&u.call(i),0):i.next)&&!(u=u.call(i,n[1])).done)return u;switch(i=0,(n=u?[2&n[0],u.value]:n)[0]){case 0:case 1:u=n;break;case 4:return c.label++,{value:n[1],done:!1};case 5:c.label++,i=n[1],n=[0];continue;case 7:n=c.ops.pop(),c.trys.pop();continue;default:if(!(u=0<(u=c.trys).length&&u[u.length-1])&&(6===n[0]||2===n[0])){c=0;continue}if(3===n[0]&&(!u||n[1]>u[0]&&n[1] + */ +declare const isAblocking: () => Promise; +export { isAblocking, }; diff --git a/dist/esnext/index.js b/dist/esnext/index.js new file mode 100644 index 0000000..7fa8ff8 --- /dev/null +++ b/dist/esnext/index.js @@ -0,0 +1,17 @@ +const adURL = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'; +/** + * Check if AdBlocker is present in user's browser + * @return Promise + */ +const isAblocking = async () => { + let enabled = false; + try { + await fetch(adURL); + } + catch (_) { + enabled = true; + } + return enabled; +}; +export { isAblocking, }; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/esnext/index.js.map b/dist/esnext/index.js.map new file mode 100644 index 0000000..a4b3ddf --- /dev/null +++ b/dist/esnext/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,KAAK,GAAG,gEAAgE,CAAA;AAE9E;;;GAGG;AACH,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAA;IAEnB,IAAI;QACF,MAAM,KAAK,CAAC,KAAK,CAAC,CAAA;KACnB;IAAC,OAAO,CAAC,EAAE;QACV,OAAO,GAAG,IAAI,CAAA;KACf;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED,OAAO,EACL,WAAW,GACZ,CAAA"} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2b5c098 --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "adblock-hunter", + "version": "1.0.0", + "description": "Detect adblock usage with ease", + "main": "dist/adblock-hunter.cjs.js", + "module": "dist/adblock-hunter.es5.js", + "browser": "dist/adblock-hunter.js", + "esnext": "dist/esnext/index.js", + "typings": "dist/esnext/index.d.ts", + "scripts": { + "prebuild": "rimraf dist", + "prepublish": "npm run build", + "build": "rollup -c && tsc -p tsconfig.esnext.json", + "start": "rollup -c -w", + "tsc": "tsc -p tsconfig.esnext.json" + }, + "funding": { + "type": "individual", + "url": "https://ko-fi.com/andriir" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Blaumaus/adblock-hunter.git" + }, + "author": "Andrii R. ", + "license": "MIT", + "bugs": { + "url": "https://github.com/Blaumaus/adblock-hunter/issues" + }, + "homepage": "https://github.com/Blaumaus/adblock-hunter", + "devDependencies": { + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-node-resolve": "^13.0.6", + "rimraf": "^3.0.2", + "rollup": "^2.61.1", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-sourcemaps": "^0.6.3", + "rollup-plugin-typescript2": "^0.30.0", + "rollup-plugin-uglify": "^6.0.4", + "tslib": "^2.3.1", + "typescript": "^4.5.3" + } +} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..005e5aa --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,28 @@ +import { nodeResolve } from '@rollup/plugin-node-resolve' +import commonjs from '@rollup/plugin-commonjs' +import sourceMaps from 'rollup-plugin-sourcemaps' +import typescript from 'rollup-plugin-typescript2' +import { uglify } from 'rollup-plugin-uglify' +import pkg from './package.json' + +export default [ + { + input: 'src/index.ts', + output: [ + { file: pkg.main, format: 'cjs' }, + { file: pkg.module, format: 'es' }, + ], + plugins: [ + typescript(), nodeResolve(), commonjs(), sourceMaps(), + ] + }, + { + input: 'src/index.ts', + output: [ + { file: pkg.browser, format: 'umd', name: 'adblock-hunter' }, + ], + plugins: [ + typescript(), nodeResolve(), commonjs(), uglify(), + ] + } +] diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..110ae56 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,21 @@ +const adURL = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js' + +/** + * Check if AdBlocker is present in user's browser + * @return Promise + */ +const isAblocking = async () => { + let enabled = false + + try { + await fetch(adURL) + } catch (_) { + enabled = true + } + + return enabled +} + +export { + isAblocking, +} diff --git a/tsconfig.esnext.json b/tsconfig.esnext.json new file mode 100644 index 0000000..901fb91 --- /dev/null +++ b/tsconfig.esnext.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "target": "es2020", + "module": "es2015", + "lib": ["dom"], + "strict": true, + "sourceMap": true, + "declaration": true, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "outDir": "dist/esnext", + "typeRoots": ["node_modules/@types"] + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3fe10f8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "target": "es5", + "module": "es2015", + "lib": ["es2015", "es2016", "es2017", "dom"], + "strict": true, + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "sourceMap": true, + "declaration": false, + "outDir": "dist/lib", + "typeRoots": ["node_modules/@types"] + }, + "include": ["src"] +}