diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..436c448 --- /dev/null +++ b/.gitignore @@ -0,0 +1,134 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-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/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# 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 variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# 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 + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# Clear from any builds +**/*.exe +out.js \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..bbfe773 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +
Gif Validator preview
+ + +# 💀 GIF Validator +GIF Validator is a utility tool that checks your favorite gifs on Discord and identifies any that are no longer available. This ensures your gif collection remains up-to-date and clean from broken links. + +## ❗ Requirements +If you wish to use original JS files (for example if you don't trust the EXE file) you will need: +- [Node.js](https://nodejs.org/en/) [v21.6.1 or higher] +- [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) (or any other package manager like yarn/pnpm) + +## ⚙ Installation + +To install Gif Validator, follow these steps: + +1. Clone the repository to your local machine. +2. Navigate to the cloned directory. +3. Run `npm install` to install all the necessary dependencies. + +## ⌨ Usage + +To start using Gif Validator: + +1. Ensure you have set up your Discord API token in the configuration file. +2. Run `npm start` to execute the script. + +The script will validate your gifs and remove any that are no longer available leaving you with a clean collection! + +## 📖 How to Build + +❗ OFFICIAL SUPPORT IS AVAILABLE ONLY FOR WINDOWS +If you have any major Linux Distro (Like Ubuntu, Debian etc.), please make a pull request with needed dependencies, scripts and configuration files for build to work on them! + +Building is fairly simple, just use the following command: +```bash +npm run build-win +``` +...or open the `build.bat` file in the root of the repository. \ No newline at end of file diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..87e9492 --- /dev/null +++ b/build.bat @@ -0,0 +1,20 @@ +@echo off +WHERE node >nul 2>nul +if %ERRORLEVEL% NEQ 0 ( + echo You must install node.js to build this app! +) else ( + echo It is recommended to install signtool to remove corrupted signature warning! + echo https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ + + .\node_modules\.bin\esbuild index.js --bundle --platform=node --outfile=out.js + + node --experimental-sea-config sea-config.json + node -e "require('fs').copyFileSync(process.execPath, 'gif-validator.exe')" + + if NOT exist "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" ( echo Signtool not found. Ignoring... ) else ( "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" remove /s gif-validator.exe ) + + npx postject gif-validator.exe NODE_SEA_BLOB sea.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 + + if exist sea.blob ( del sea.blob ) + if exist out.js ( out.js ) +) \ No newline at end of file diff --git a/classes/GifClient.js b/classes/GifClient.js new file mode 100644 index 0000000..ddf0f9f --- /dev/null +++ b/classes/GifClient.js @@ -0,0 +1,85 @@ +const { Helper } = require("./Helper.js") +const { FrecencyUserSettings } = require("discord-protos") +const { Axios } = require("axios") + +/** Main client class for this project */ +export class GifClient { + constructor(token) { + if(!token) throw new Error("No token provided") + + this.axios = new Axios({ + headers: { + "Authorization": token, + "accept": "*/*", + "Content-Type": "application/json", + "x-discord-locale": "en-US", + "accept-language": "en-US;q=0.9", + "Referer": "https://discord.com/channels/@me", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.9034 Chrome/108.0.5359.215 Electron/22.3.26 Safari/537.36", + "x-discord-timezone": Intl.DateTimeFormat().resolvedOptions().timeZone, + "x-super-properties": "eyJvcyI6IldpbmRvd3MiLCJicm93c2VyIjoiRGlzY29yZCBDbGllbnQiLCJyZWxlYXNlX2NoYW5uZWwiOiJzdGFibGUiLCJjbGllbnRfdmVyc2lvbiI6IjEuMC45MDM0Iiwib3NfdmVyc2lvbiI6IjEwLjAuMTkwNDUiLCJvc19hcmNoIjoieDY0IiwiYXBwX2FyY2giOiJpYTMyIiwic3lzdGVtX2xvY2FsZSI6ImVuLVVTIiwiYnJvd3Nlcl91c2VyX2FnZW50IjoiTW96aWxsYS81LjAgKFdpbmRvd3MgTlQgMTAuMDsgV09XNjQpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIGRpc2NvcmQvMS4wLjkwMzQgQ2hyb21lLzEwOC4wLjUzNTkuMjE1IEVsZWN0cm9uLzIyLjMuMjYgU2FmYXJpLzUzNy4zNiIsImJyb3dzZXJfdmVyc2lvbiI6IjIyLjMuMjYiLCJjbGllbnRfYnVpbGRfbnVtYmVyIjoyNzEyMTYsIm5hdGl2ZV9idWlsZF9udW1iZXIiOjQ0MTQyLCJjbGllbnRfZXZlbnRfc291cmNlIjpudWxsfQ==" + }, + transformResponse: (data) => Helper.tryParseJSON(data, true), + transformRequest: (data) => JSON.stringify(data) + }) + } + + _handleError(response) { + const json = Helper.tryParseJSON(response); + if(json) { + if(json["message"]) { + if(json["message"] === "401: Unauthorized" && json["code"] === 0) throw new Error("Invalid token!") + if(!Helper.statusesOK.some(s => json["message"].startsWith(s))) throw new Error(json) + } + return true + } + return true + } + + /** + * Grabs list of gifs and returns them + * @returns {Promise<{[key: string]: import("discord-protos").FrecencyUserSettings_FavoriteGIF}>} Gifs + */ + async getGifs() { + const {data} = await this.axios.get(Helper.PROTO_URL(2)) + this._handleError(data) + + const {settings: encodedSettings} = data + const decodedSettings = FrecencyUserSettings.fromBase64(encodedSettings) + + return decodedSettings["favoriteGifs"]["gifs"] + } + + /** + * Validates gifs and removes unavailable ones. + * @param {{[key: string]: import("discord-protos").FrecencyUserSettings_FavoriteGIF}} gifs Gifs + * @returns {Promise<{[key: string]: import("discord-protos").FrecencyUserSettings_FavoriteGIF}>} Valid Gifs + */ + async validateGifs(gifs) { + let newGifs = {...gifs} + for (let key of Object.keys(gifs)) { + const resp = await this.axios.head(gifs[key].src) + if(!Helper.isOK(resp.status)) delete newGifs[key] + } + return newGifs + } + + /** + * Saves gifs and returns if it succedded + * @param {{[key: string]: import("discord-protos").FrecencyUserSettings_FavoriteGIF}} gifs Gifs to save + * @return {Promise} Was save successful? + */ + async saveGifs(gifs) { + const decodedSettings = { + favoriteGifs: { + gifs: gifs + } + } + const encodedSettings = FrecencyUserSettings.toBase64(decodedSettings); + + const {status, data} = await this.axios.patch(Helper.PROTO_URL(2), {settings: encodedSettings}) + this._handleError(data) + + return Helper.isOK(status) + } +} \ No newline at end of file diff --git a/classes/Helper.js b/classes/Helper.js new file mode 100644 index 0000000..708fa45 --- /dev/null +++ b/classes/Helper.js @@ -0,0 +1,35 @@ +/** Helper methods for project */ +export class Helper { + /** Status codes which are taken as OK */ + static statusesOK = [ + ...new Array(8).fill(0).map((_, i) => 200 + i), + 226 + ] + + /** + * Generates url for proto manipulation + * @param {1 | 2 | 3} proto_type Type of proto + * @returns {string} URL + */ + static PROTO_URL = (proto_type) => "https://discord.com/api/v9/users/@me/settings-proto/".concat(proto_type) + + /** + * Tries to parse a JSON string to object + * @param {string} maybeJson String that might be a JSON + * @param {boolean} shouldReturnBack Should function return string on error? + * @returns {object|null} Parsed object if valid JSON | null if invalid + */ + static tryParseJSON(maybeJson = "", shouldReturnBack = false){ + try {return JSON.parse(maybeJson)} + catch {return shouldReturnBack ? maybeJson : null} + } + + /** + * Checks if status code is an OK response (200-208 & 226) + * @param {number} status Status code + * @returns {boolean} Is OK? + */ + static isOK(status) { + return Helper.statusesOK.includes(status) + } +} \ No newline at end of file diff --git a/classes/RL.js b/classes/RL.js new file mode 100644 index 0000000..b4e4f98 --- /dev/null +++ b/classes/RL.js @@ -0,0 +1,36 @@ +const { createInterface } = require("readline") +const { stdin, stdout } = require("process") + +/** Class for prompting user in terminal */ +export class RL { + constructor() { + this.interface = createInterface(stdin, stdout) + } + + /** + * Prompts user + * @param {string} question Question for the readline function + * @param {boolean} require Is method accepting empty strings? + * @returns {Promise} Answer + */ + async readLine(question = "", require = false) { + const q = (q) => new Promise(resolve => this.interface.question(q, resolve)) + let a = "" + + if(require) while(a.trim().length === 0) a = await q(question) + else a = await q(question) + + return a + } + + /** + * Prompts user staticaally without need of new classes + * @param {string} question Question for the readline function + * @param {boolean} require Is method accepting empty strings? + * @returns {Promise} Answer + */ + static async readLine(question = "", require = false) { + const instance = new RL() + return instance.readLine(question, require) + } +} \ No newline at end of file diff --git a/clear.bat b/clear.bat new file mode 100644 index 0000000..911e4b0 --- /dev/null +++ b/clear.bat @@ -0,0 +1,5 @@ +@echo off + +if exist sea.blob ( del sea.blob ) +if exist out.js ( del out.js ) +if exist gif-validator.exe ( del gif-validator.exe ) \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..2885c76 --- /dev/null +++ b/index.js @@ -0,0 +1,22 @@ +const { GifClient } = require("./classes/GifClient.js"); +const { RL } = require("./classes/RL.js"); + +process.removeAllListeners('warning') + +RL.readLine("Provide your token here: ", true).then(async token => { + const client = new GifClient(token) + + console.log("Grabbing gifs...") + const gifs = await client.getGifs() + + console.log(`Validating ${Object.keys(gifs).length} gifs...`) + const validatedGifs = await client.validateGifs(gifs) + + console.log(`Got ${Object.keys(validatedGifs).length} valid gifs... saving them.`) + const result = await client.saveGifs(validatedGifs); + + if(result) console.log(`Successfully validated and saved ${Object.keys(validatedGifs).length} gifs!`) + else console.log("Something went wrong... maybe discord updated their servers. If so, this app WON'T work anymore.") + + setTimeout(process.exit, 5_000) // Delay before closing +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7deac4f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,528 @@ +{ + "name": "gif-validator", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gif-validator", + "version": "1.0.0", + "dependencies": { + "axios": "^1.6.7", + "discord-protos": "^1.0.5" + }, + "devDependencies": { + "esbuild": "0.20.1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.9.3.tgz", + "integrity": "sha512-nivzCpg/qYD0RX2OmHOahJALb8ndjGmUhNBcTJ0BbXoqKwCSM6vYA+vegzS3rhuaPgbyC7Ec8idlnizzUfIRuw==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/discord-protos": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/discord-protos/-/discord-protos-1.0.5.tgz", + "integrity": "sha512-924CFthTtgkwsjVp9tC6Pvj/C5b5HWQ68A6suiEz1Dkg+LqvVsvQAGgMhvYc/nXNcosqQIeBruSQBxv4wIxVvw==", + "dependencies": { + "@protobuf-ts/runtime": "^2.8.2" + } + }, + "node_modules/esbuild": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8ab4103 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "gif-validator", + "description": "gif-validator is a simple script allowing you to clear favorite gifs on Discord from ones that are not available.", + "version": "1.0.0", + "private": true, + "main": "index.js", + "scripts": { + "start": "node .", + "build-win": "build.bat", + "clear-win": "clear.bat" + }, + "dependencies": { + "axios": "^1.6.7", + "discord-protos": "^1.0.5" + }, + "devDependencies": { + "esbuild": "0.20.1" + } +} diff --git a/preview.gif b/preview.gif new file mode 100644 index 0000000..99442c4 Binary files /dev/null and b/preview.gif differ diff --git a/sea-config.json b/sea-config.json new file mode 100644 index 0000000..d38a9d6 --- /dev/null +++ b/sea-config.json @@ -0,0 +1,4 @@ +{ + "main": "out.js", + "output": "sea.blob" +} \ No newline at end of file