├── .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 | 
4 |
5 |
6 |
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 |
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 |
--------------------------------------------------------------------------------