├── .prettierrc ├── .gitignore ├── images └── icon_128.png ├── README.md ├── .eslintrc.js ├── package.json ├── LICENSE ├── src ├── manifest.json └── inject │ └── inject.ts └── tsconfig.json /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | mocks/ 4 | 5 | .vscode/ 6 | 7 | dist.zip -------------------------------------------------------------------------------- /images/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MercadoTrack/extension-local/HEAD/images/icon_128.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

MercadoTrack

2 | 3 |

logo

4 | 5 |

6 | downloads 7 |

8 | 9 | _Extensión de Chromium para seguir productos en MercadoLibre Argentina y visualizar sus precios a lo largo del tiempo_ 10 | 11 |

Instalala directo de la Chrome webstore

12 | 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | }, 6 | extends: [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "plugin:react/recommended", 10 | "prettier", 11 | ], 12 | overrides: [ 13 | { 14 | env: { 15 | node: true, 16 | }, 17 | files: [".eslintrc.{js,cjs}"], 18 | parserOptions: { 19 | sourceType: "script", 20 | }, 21 | }, 22 | ], 23 | parser: "@typescript-eslint/parser", 24 | parserOptions: { 25 | ecmaVersion: "latest", 26 | sourceType: "module", 27 | }, 28 | plugins: ["@typescript-eslint", "react"], 29 | rules: { 30 | indent: ["error", 2], 31 | "linebreak-style": ["error", "unix"], 32 | quotes: ["error", "double"], 33 | semi: ["error", "always"], 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mercadotrack", 3 | "version": "0.6.0", 4 | "description": "MercadoTrack", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "sh ./build.sh", 8 | "zip": "cd ./dist && zip -r ../dist.zip .", 9 | "prepare": "npm run build && npm run zip" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/MercadoTrack/extension-local.git" 14 | }, 15 | "author": "Guillermo Maiolo", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/MercadoTrack/extension-local/issues" 19 | }, 20 | "homepage": "https://mercadotrack.com", 21 | "devDependencies": { 22 | "@types/chrome": "^0.0.251", 23 | "@typescript-eslint/eslint-plugin": "^6.11.0", 24 | "@typescript-eslint/parser": "^6.11.0", 25 | "eslint": "^8.53.0", 26 | "eslint-config-prettier": "^9.0.0", 27 | "eslint-plugin-react": "^7.33.2", 28 | "prettier": "^3.1.0", 29 | "typescript": "^5.2.2" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Guillermo Maiolo 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 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "author": "Guillermo Maiolo", 4 | "name": "MercadoTrack", 5 | "description": "Seguí los artículos de MercadoLibre y mirá las variaciones en sus precios a lo largo del tiempo", 6 | "version": "0.9.0", 7 | "permissions": [], 8 | "icons": { 9 | "128": "images/icon_128.png" 10 | }, 11 | "action": { 12 | "default_title": "MercadoTrack" 13 | }, 14 | "content_scripts": [ 15 | { 16 | "type": "module", 17 | "js": ["/inject/inject.js"], 18 | "runAt": "document_idle", 19 | "matches": [ 20 | "*://*.mercadolibre.com.ar/*", 21 | "*://*.mercadolibre.com.ve/*", 22 | "*://*.mercadolibre.com.bo/*", 23 | "*://*.mercadolibre.cl/*", 24 | "*://*.mercadolibre.com.co/*", 25 | "*://*.mercadolibre.co.cr/*", 26 | "*://*.mercadolibre.com.do/*", 27 | "*://*.mercadolibre.com.ec/*", 28 | "*://*.mercadolibre.com.gt/*", 29 | "*://*.mercadolibre.com.hn/*", 30 | "*://*.mercadolibre.com.mx/*", 31 | "*://*.mercadolibre.com.ni/*", 32 | "*://*.mercadolibre.com.pa/*", 33 | "*://*.mercadolibre.com.py/*", 34 | "*://*.mercadolibre.com.pe/*", 35 | "*://*.mercadolibre.com.sv/*", 36 | "*://*.mercadolibre.com.uy/*", 37 | "*://*.mercadolivre.com.br/*", 38 | "*://*.mercadolivre.pt/*" 39 | ] 40 | } 41 | ], 42 | "host_permissions": [ 43 | "*://*.mercadolibre.com.ar/*", 44 | "*://*.mercadolibre.com.ve/*", 45 | "*://*.mercadolibre.com.bo/*", 46 | "*://*.mercadolibre.cl/*", 47 | "*://*.mercadolibre.com.co/*", 48 | "*://*.mercadolibre.co.cr/*", 49 | "*://*.mercadolibre.com.do/*", 50 | "*://*.mercadolibre.com.ec/*", 51 | "*://*.mercadolibre.com.gt/*", 52 | "*://*.mercadolibre.com.hn/*", 53 | "*://*.mercadolibre.com.mx/*", 54 | "*://*.mercadolibre.com.ni/*", 55 | "*://*.mercadolibre.com.pa/*", 56 | "*://*.mercadolibre.com.py/*", 57 | "*://*.mercadolibre.com.pe/*", 58 | "*://*.mercadolibre.com.sv/*", 59 | "*://*.mercadolibre.com.uy/*", 60 | "*://*.mercadolivre.com.br/*", 61 | "*://*.mercadolivre.pt/*" 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /src/inject/inject.ts: -------------------------------------------------------------------------------- 1 | function getIdFromUrl(url: string) { 2 | const [rawId] = url.match(/(M[A-Z]{2}-\d+)/g) || []; 3 | const id = rawId && rawId.replace("-", ""); 4 | 5 | if (id) { 6 | return id; 7 | } 8 | 9 | const [match] = url.match(/\/p\/(M[A-Z]{2}\d+)/g) || []; 10 | const pid = match?.replace("/p/", ""); 11 | 12 | return pid; 13 | } 14 | 15 | function getMainContainer() { 16 | const rootApp = document.getElementById("root-app"); 17 | 18 | if (!rootApp) { 19 | console.error( 20 | "[MercadoTrack] La extensión no puede funcionar debido a un cambio de diseño por parte del equipo de MercadoLibre.\nPor favor contactate con los desarrolladores a través de un issue en GitHub: https://github.com/GMaiolo/mercado-track/issues", 21 | ); 22 | } 23 | 24 | return rootApp; 25 | } 26 | 27 | function htmlToElement(html: string) { 28 | const template = document.createElement("template"); 29 | html = html.trim(); // Never trust an incoming string! 30 | template.innerHTML = html; 31 | return template.content.firstChild; 32 | } 33 | 34 | const run = async () => { 35 | console.log("MT Running"); 36 | 37 | const elementId = "mercadotrack-container"; 38 | 39 | const mercadotrackId = getIdFromUrl(window.location.pathname); 40 | 41 | const res = await fetch( 42 | `https://mercadotrack.com/api/articulos/track/${mercadotrackId}`, 43 | ).catch(() => {}); 44 | 45 | if (!res || res.status !== 200) { 46 | return; 47 | } 48 | 49 | setTimeout(() => { 50 | if (document.getElementById(elementId)) { 51 | return; 52 | } 53 | 54 | const href = `https://mercadotrack.com/articulo/${mercadotrackId}`; 55 | 56 | const $trackBtn = htmlToElement( 57 | ` 58 |
59 | 66 | Ver en MercadoTrack 67 | MercadoTrack Logo 72 | 73 |
74 | `, 75 | ); 76 | 77 | const mainContainer = getMainContainer(); 78 | 79 | if (!mainContainer || !$trackBtn) { 80 | return; 81 | } 82 | 83 | mainContainer.prepend($trackBtn); 84 | }, 2000); 85 | }; 86 | 87 | run(); 88 | 89 | // Also run when the url changes 90 | window.addEventListener("popstate", run); 91 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2020" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "ES2020" /* Specify what module code is generated. */, 29 | "rootDir": "./src" /* Specify the root folder within your source files. */, 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | "sourceMap": true /* Create source map files for emitted JavaScript files. */, 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | "outDir": "./dist" /* Specify an output folder for all emitted files. */, 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 83 | 84 | /* Type Checking */ 85 | "strict": true /* Enable all strict type-checking options. */, 86 | 87 | /* Completeness */ 88 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 89 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 90 | } 91 | } 92 | --------------------------------------------------------------------------------