From 118427c41b6a4f1a70d8bf60f31ef6e2b6c8254c Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Tue, 14 Apr 2026 16:54:25 -0700 Subject: [PATCH 1/2] build: oxc.rs --- .oxfmtrc.json | 9 + .oxlintrc.json | 5 + .prettierrc | 6 - categories.js | 2 +- index.json | 3442 +++++----------------------- lib/app-categories.js | 2 +- lib/apps-with-github-repos.js | 14 +- lib/broken-links.js | 66 +- lib/grandfathered-descriptions.js | 2 +- lib/grandfathered-links.js | 2 +- lib/grandfathered-small-icons.js | 2 +- lib/is-url.js | 12 +- lib/old-electron-apps.js | 72 +- lib/raw-app-list.js | 24 +- meta/categories.json | 2 +- meta/dates.json | 2 +- package.json | 23 +- readme.md | 7 +- script/categories.js | 44 +- script/clean.js | 20 +- script/dates.js | 24 +- script/find-broken-links.js | 26 +- script/pack.js | 45 +- script/remove-broken-links.js | 52 +- script/remove-disabled-apps.js | 24 +- script/remove-old-electron-apps.js | 54 +- script/resize.js | 62 +- script/ymlupdate.js | 144 +- test/human-data.js | 253 +- test/machine-data.js | 121 +- wizard.js | 84 +- yarn.lock | 427 +++- 32 files changed, 1500 insertions(+), 3574 deletions(-) create mode 100644 .oxfmtrc.json create mode 100644 .oxlintrc.json delete mode 100644 .prettierrc diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 00000000000..059e88fd022 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,9 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "trailingComma": "all", + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "sortPackageJson": false, + "ignorePatterns": ["*.md", "*.yml", "*.yaml"] +} diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 00000000000..18e46d35d64 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,5 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["eslint", "unicorn", "oxc", "import"], + "categories": { "correctness": "warn" } +} diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 5eb7e293cc3..00000000000 --- a/.prettierrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "singleQuote": true, - "trailingComma": "es5", - "semi": false, - "proseWrap": "always" -} diff --git a/categories.js b/categories.js index b9bbcf0f0e0..b90a788a073 100644 --- a/categories.js +++ b/categories.js @@ -1 +1 @@ -module.exports = require('./meta/categories.json') +module.exports = require('./meta/categories.json'); diff --git a/index.json b/index.json index 3ebeb3dad6f..0b4dc63c124 100644 --- a/index.json +++ b/index.json @@ -5,9 +5,7 @@ "description": "A universal clipboard managing app that makes it easy to access your clipboard from anywhere on any device", "website": "http://1clipboard.io", "repository": "https://github.com/wiziple/1clipboard", - "keywords": [ - "clipboard" - ], + "keywords": ["clipboard"], "category": "Utilities", "icon": "1clipboard-icon.png", "icon32": "1clipboard-icon-32.png", @@ -21,11 +19,7 @@ "name": "1Password", "description": "The easiest way to store and use strong passwords. Log in to sites and fill forms securely with a single click.", "website": "https://www.1password.com", - "keywords": [ - "Password manager", - "Security", - "Privacy" - ], + "keywords": ["Password manager", "Security", "Privacy"], "category": "Utilities", "icon": "1password-icon.png", "icon32": "1password-icon-32.png", @@ -39,13 +33,8 @@ "name": "5EClient", "description": "5EPlay CSGO Client", "website": "https://www.5eplay.com/", - "keywords": [ - "CSGO", - "PUG" - ], - "locales": [ - "zh_CN" - ], + "keywords": ["CSGO", "PUG"], + "locales": ["zh_CN"], "category": "Games", "icon": "5eclient-icon.png", "icon32": "5eclient-icon-32.png", @@ -84,13 +73,7 @@ "website": "https://install.advancedrestclient.com", "category": "Developer Tools", "repository": "https://github.com/advanced-rest-client/arc-electron", - "keywords": [ - "REST", - "REST client", - "HTTP", - "request", - "developer" - ], + "keywords": ["REST", "REST client", "HTTP", "request", "developer"], "license": "Apache-2.0", "icon": "advanced-rest-client-icon.png", "icon32": "advanced-rest-client-icon-32.png", @@ -167,10 +150,7 @@ "agora", "e-learning" ], - "locales": [ - "en-US", - "zh-CN" - ], + "locales": ["en-US", "zh-CN"], "license": "MIT", "icon": "agora-flat-icon.png", "icon32": "agora-flat-icon-32.png", @@ -184,9 +164,7 @@ "name": "Aipo.com", "description": "Communication tool to optimize the connection between people", "website": "https://www.aipo.com/", - "locales": [ - "ja" - ], + "locales": ["ja"], "category": "Business", "icon": "aipo-com-icon.png", "icon32": "aipo-com-icon-32.png", @@ -223,25 +201,12 @@ "website": "https://altair.sirmuel.design/", "category": "Developer Tools", "repository": "https://github.com/imolorhe/altair", - "keywords": [ - "graphql", - "graphql-ide", - "graphql-client", - "opensource" - ], + "keywords": ["graphql", "graphql-ide", "graphql-client", "opensource"], "license": "MIT", "homebrewCaskName": "altair-graphql-client", "snapcraftName": "altair", "youtube_video_url": "https://www.youtube.com/watch?v=zTFYOo4uD-M", - "locales": [ - "en-US", - "fr-FR", - "es-ES", - "cs-CZ", - "de-DE", - "pt-BR", - "zh-CN" - ], + "locales": ["en-US", "fr-FR", "es-ES", "cs-CZ", "de-DE", "pt-BR", "zh-CN"], "icon": "altair-icon.png", "icon32": "altair-icon-32.png", "icon64": "altair-icon-64.png", @@ -279,12 +244,7 @@ "description": "Faster, better and more stable redis desktop manager, compatible with Linux, windows, mac.", "category": "Developer Tools", "repository": "https://github.com/qishibo/AnotherRedisDesktopManager", - "keywords": [ - "redis-desktop-manager", - "redis-client", - "redis-desktop", - "redis-gui" - ], + "keywords": ["redis-desktop-manager", "redis-client", "redis-desktop", "redis-gui"], "license": "MIT", "icon": "anotherredisdesktopmanager-icon.png", "icon32": "anotherredisdesktopmanager-icon-32.png", @@ -300,16 +260,7 @@ "website": "https://antares-sql.app", "category": "Developer Tools", "repository": "https://github.com/antares-sql/antares", - "keywords": [ - "sql client", - "databases", - "sql", - "mysql", - "mariadb", - "linux", - "windows", - "mac" - ], + "keywords": ["sql client", "databases", "sql", "mysql", "mariadb", "linux", "windows", "mac"], "license": "MIT", "icon": "antares-icon.png", "icon32": "antares-icon-32.png", @@ -323,10 +274,7 @@ "name": "Asana", "description": "Keep remote and distributed teams, and your entire organization, focused on their goals, projects, and tasks with Asana.", "website": "https://asana.com/", - "keywords": [ - "project management", - "collaboration" - ], + "keywords": ["project management", "collaboration"], "category": "Productivity", "icon": "asana-icon.png", "icon32": "asana-icon-32.png", @@ -342,10 +290,7 @@ "website": "https://www.assessmentdisaggregation.org/", "category": "Education", "repository": "https://github.com/tazzben/Assessment-Disaggregation.git", - "keywords": [ - "Disaggregation", - "Value-added learning scores" - ], + "keywords": ["Disaggregation", "Value-added learning scores"], "license": "MIT", "icon": "assessment-disaggregation-icon.png", "icon32": "assessment-disaggregation-icon-32.png", @@ -360,9 +305,7 @@ "description": "The all-in-one image resizer.", "website": "https://assetizr.com", "category": "Graphics & Design", - "locales": [ - "en" - ], + "locales": ["en"], "keywords": [ "design", "image", @@ -413,12 +356,7 @@ "website": "https://www.barklarm.com/", "category": "Developer Tools", "repository": "https://github.com/kanekotic/barklarm", - "keywords": [ - "build", - "observability", - "CI", - "CD" - ], + "keywords": ["build", "observability", "CI", "CD"], "license": "Apache License 2.0", "youtube_video_url": "https://www.youtube.com/watch?v=lJhVdrje63w", "icon": "barklarm-icon.png", @@ -433,10 +371,7 @@ "name": "Bdash", "description": "Simple business intelligence application.", "repository": "https://github.com/bdash-app/bdash", - "keywords": [ - "SQL", - "visualization" - ], + "keywords": ["SQL", "visualization"], "license": "MIT", "category": "Developer Tools", "icon": "bdash-icon.png", @@ -453,14 +388,7 @@ "website": "https://beakerbrowser.com", "repository": "https://github.com/beakerbrowser/beaker", "homebrewCaskName": "beaker-browser", - "keywords": [ - "browser", - "p2p", - "dat", - "decentralization", - "hosting", - "privacy" - ], + "keywords": ["browser", "p2p", "dat", "decentralization", "hosting", "privacy"], "category": "Productivity", "icon": "beaker-browser-icon.png", "icon32": "beaker-browser-icon-32.png", @@ -477,16 +405,7 @@ "category": "Developer Tools", "repository": "https://github.com/beekeeper-studio/beekeeper-studio", "snapcraftName": "beekeeper-studio", - "keywords": [ - "sql", - "mysql", - "postgres", - "sql-server", - "sqlite", - "linux", - "mac", - "windows" - ], + "keywords": ["sql", "mysql", "postgres", "sql-server", "sqlite", "linux", "mac", "windows"], "license": "MIT", "icon": "beekeeper-studio-icon.png", "icon32": "beekeeper-studio-icon-32.png", @@ -502,10 +421,7 @@ "website": "https://bibisco.com/", "category": "Books", "repository": "https://github.com/andreafeccomandi/bibisco/", - "keywords": [ - "novel writing software", - "character development software" - ], + "keywords": ["novel writing software", "character development software"], "license": "GNU GPL v3", "locales": [ "en-US", @@ -538,13 +454,7 @@ "description": "Browser where your favorite apps won't get buried in tabs.", "website": "https://eatbiscuit.com/", "category": "Productivity", - "keywords": [ - "browser", - "mac", - "windows", - "tab", - "web" - ], + "keywords": ["browser", "mac", "windows", "tab", "web"], "icon": "biscuit-icon.png", "icon32": "biscuit-icon-32.png", "icon64": "biscuit-icon-64.png", @@ -558,10 +468,7 @@ "description": "A modern 3D model editor for cube-based models", "website": "https://blockbench.net/", "repository": "https://github.com/JannisX11/blockbench", - "keywords": [ - "modeling", - "minecraft" - ], + "keywords": ["modeling", "minecraft"], "license": "MIT", "category": "Graphics & Design", "goodColorOnWhite": "#282c34", @@ -579,15 +486,7 @@ "description": " control CPU turbo boost and the settings of the cpu speed on Linux.", "category": "Utilities", "repository": "https://github.com/nbebaw/boostchanger", - "keywords": [ - "cpu", - "settings", - "turbo", - "boost", - "linux", - "system", - "battery" - ], + "keywords": ["cpu", "settings", "turbo", "boost", "linux", "system", "battery"], "license": "MIT", "icon": "boost-changer-icon.png", "icon32": "boost-changer-icon-32.png", @@ -602,15 +501,7 @@ "description": "Powerful desktop app for creating responsive websites using the Bootstrap framework.", "website": "https://bootstrapstudio.io/", "category": "Developer Tools", - "keywords": [ - "bootstrap", - "css", - "sass", - "js", - "ide", - "editor", - "builder" - ], + "keywords": ["bootstrap", "css", "sass", "js", "ide", "editor", "builder"], "icon": "bootstrap-studio-icon.png", "icon32": "bootstrap-studio-icon-32.png", "icon64": "bootstrap-studio-icon-64.png", @@ -637,10 +528,7 @@ "e-commerce", "POS" ], - "locales": [ - "en", - "ko" - ], + "locales": ["en", "ko"], "icon": "boxhero-icon.png", "icon32": "boxhero-icon-32.png", "icon64": "boxhero-icon-64.png", @@ -655,14 +543,7 @@ "category": "Graphics & Design", "website": "https://boxy-svg.com", "snapcraftName": "boxy-svg", - "keywords": [ - "svg", - "vector", - "editor", - "graphics", - "design", - "images" - ], + "keywords": ["svg", "vector", "editor", "graphics", "design", "images"], "icon": "boxy-svg-icon.png", "icon32": "boxy-svg-icon-32.png", "icon64": "boxy-svg-icon-64.png", @@ -677,12 +558,7 @@ "website": "https://www.brimsecurity.com", "category": "Utilities", "repository": "https://github.com/brimsec/brim", - "keywords": [ - "zeek", - "pcap", - "wireshark", - "logs" - ], + "keywords": ["zeek", "pcap", "wireshark", "logs"], "license": "BSD-3-Clause License", "youtube_video_url": "https://youtu.be/InT-7WZ5Y2Y", "icon": "brim-icon.png", @@ -725,12 +601,7 @@ "name": "Browserosaurus", "description": "Browser prompter for macOS.", "repository": "https://github.com/will-stone/browserosaurus", - "keywords": [ - "productivity", - "development", - "utility", - "macos" - ], + "keywords": ["productivity", "development", "utility", "macos"], "category": "Utilities", "license": "MIT", "icon": "browserosaurus-icon.png", @@ -745,16 +616,9 @@ "name": "Buckets", "description": "Beautiful, private budgeting.", "website": "https://www.budgetwithbuckets.com", - "keywords": [ - "budgeting", - "finance" - ], + "keywords": ["budgeting", "finance"], "category": "Finance", - "locales": [ - "pt", - "en", - "es" - ], + "locales": ["pt", "en", "es"], "icon": "buckets-icon.png", "icon32": "buckets-icon-32.png", "icon64": "buckets-icon-64.png", @@ -792,14 +656,7 @@ "website": "https://buttercup.pw", "repository": "https://github.com/buttercup/buttercup-desktop", "license": "MIT", - "keywords": [ - "encrypt", - "encryption", - "password", - "security", - "privacy", - "login" - ], + "keywords": ["encrypt", "encryption", "password", "security", "privacy", "login"], "category": "Productivity", "icon": "buttercup-icon.png", "icon32": "buttercup-icon-32.png", @@ -813,12 +670,7 @@ "name": "Cacher", "description": "Cloud-based, team-enabled code snippet manager with Gists sync.", "website": "https://www.cacher.io/", - "keywords": [ - "snippets", - "programming", - "coding", - "gists" - ], + "keywords": ["snippets", "programming", "coding", "gists"], "category": "Developer Tools", "snapcraftName": "cacher", "icon": "cacher-icon.png", @@ -861,14 +713,7 @@ "website": "https://camunda.com/products/modeler/", "category": "Developer Tools", "repository": "https://github.com/camunda/camunda-modeler/", - "keywords": [ - "bpmn", - "dmn", - "modeling", - "modeler", - "diagram", - "business process" - ], + "keywords": ["bpmn", "dmn", "modeling", "modeler", "diagram", "business process"], "license": "MIT", "icon": "camunda-modeler-icon.png", "icon32": "camunda-modeler-icon-32.png", @@ -915,16 +760,7 @@ "freight", "transport" ], - "locales": [ - "en-US", - "ru", - "lt", - "pl", - "lv", - "es", - "pt", - "ua" - ], + "locales": ["en-US", "ru", "lt", "pl", "lv", "es", "pt", "ua"], "icon": "cargo-messenger-icon.png", "icon32": "cargo-messenger-icon-32.png", "icon64": "cargo-messenger-icon-64.png", @@ -937,14 +773,7 @@ "name": "CashNotify", "description": "Monitor your Stripe accounts from your menu bar.", "website": "https://cashnotify.com", - "keywords": [ - "stripe", - "mac", - "menubar", - "payments", - "alerts", - "notifications" - ], + "keywords": ["stripe", "mac", "menubar", "payments", "alerts", "notifications"], "category": "Utilities", "icon": "cashnotify-icon.png", "icon32": "cashnotify-icon-32.png", @@ -959,9 +788,7 @@ "description": "Desktop build status notifications", "website": "https://catlight.io", "homebrewCaskName": "catlight", - "keywords": [ - "build" - ], + "keywords": ["build"], "category": "Developer Tools", "icon": "catlight-icon.png", "icon32": "catlight-icon-32.png", @@ -975,11 +802,7 @@ "name": "CBETA Reader 2 (Unofficial)", "description": "CBETA Reader 2 is a Buddhist text reader app. It gets Buddhist text data from CBETA APIs.", "repository": "https://github.com/MrMYHuang/cbetar2", - "keywords": [ - "CBETA", - "Buddhist", - "Tripitaka" - ], + "keywords": ["CBETA", "Buddhist", "Tripitaka"], "category": "Books", "license": "MIT", "icon": "cbetar2-icon.png", @@ -1042,11 +865,7 @@ "description": "Save history of all information you copy and use them whenever with a solitary snap.", "category": "Productivity", "repository": "https://github.com/AkashRajpurohit/clipper", - "keywords": [ - "clipboard", - "clipboard-history", - "clipboard-manager" - ], + "keywords": ["clipboard", "clipboard-history", "clipboard-manager"], "license": "MIT", "icon": "clipper-icon.png", "icon32": "clipper-icon-32.png", @@ -1061,9 +880,7 @@ "description": "Clipboard Tool", "category": "Utilities", "repository": "https://github.com/monsterkodi/clippo", - "keywords": [ - "clipboard" - ], + "keywords": ["clipboard"], "license": "Unlicense", "icon": "clippo-icon.png", "icon32": "clippo-icon-32.png", @@ -1077,13 +894,7 @@ "name": "cliptext", "description": "A simple clipboard manager for macOS.", "repository": "https://github.com/aaabhilash97/cliptext", - "keywords": [ - "clipboard", - "native", - "osx", - "mac", - "clipboard manager" - ], + "keywords": ["clipboard", "native", "osx", "mac", "clipboard manager"], "category": "Utilities", "icon": "cliptext-icon.png", "icon32": "cliptext-icon-32.png", @@ -1098,15 +909,8 @@ "description": "Time tracking for small and medium-sized companies.", "website": "https://www.clockodo.com/", "category": "Productivity", - "keywords": [ - "Time tracking", - "Work time", - "Project reports" - ], - "locales": [ - "en-US", - "de-DE" - ], + "keywords": ["Time tracking", "Work time", "Project reports"], + "locales": ["en-US", "de-DE"], "icon": "clockodo-icon.png", "icon32": "clockodo-icon-32.png", "icon64": "clockodo-icon-64.png", @@ -1144,9 +948,7 @@ "description": "Game development tools", "website": "https://www.cocos.com/en/creator", "repository": "https://github.com/cocos-creator/engine", - "keywords": [ - "games" - ], + "keywords": ["games"], "category": "Games", "icon": "cocos-creator-icon.png", "icon32": "cocos-creator-icon-32.png", @@ -1186,9 +988,7 @@ "name": "Colibri", "description": "Modern browser without tabs", "website": "https://colibri.opqr.co", - "keywords": [ - "browser" - ], + "keywords": ["browser"], "category": "Productivity", "icon": "colibri-icon.png", "icon32": "colibri-icon-32.png", @@ -1202,13 +1002,7 @@ "name": "Collectie", "description": "Your personal galaxy of inspiration", "website": "https://getcollectie.com/", - "keywords": [ - "collection", - "inspiration", - "database", - "design", - "Productivity" - ], + "keywords": ["collection", "inspiration", "database", "design", "Productivity"], "category": "Productivity", "icon": "collectie-icon.png", "icon32": "collectie-icon-32.png", @@ -1284,14 +1078,7 @@ "description": "Cross-platform tool to read & query JSON aka CLEF log files created by Serilog.", "category": "Developer Tools", "repository": "https://github.com/warrenbuckley/Compact-Log-Format-Viewer", - "keywords": [ - "logviewer", - "logs", - "log viewer", - "clef", - "compact log event format", - "serilog" - ], + "keywords": ["logviewer", "logs", "log viewer", "clef", "compact log event format", "serilog"], "icon": "compact-log-viewer-icon.png", "icon32": "compact-log-viewer-icon-32.png", "icon64": "compact-log-viewer-icon-64.png", @@ -1305,10 +1092,7 @@ "description": "Mini browser to pin on top of any other desktop app.", "category": "Entertainment", "repository": "https://github.com/brunurd/companion", - "keywords": [ - "browser", - "client" - ], + "keywords": ["browser", "client"], "license": "MIT", "icon": "companion-icon.png", "icon32": "companion-icon-32.png", @@ -1322,12 +1106,7 @@ "name": "Composercat", "description": "Graphical User Interface for the Composer package manager (PHP)", "website": "https://getcomposercat.com", - "keywords": [ - "php", - "composer", - "programming", - "productivity" - ], + "keywords": ["php", "composer", "programming", "productivity"], "category": "Developer Tools", "license": "COMMERCIAL", "icon": "composercat-icon.png", @@ -1368,13 +1147,7 @@ "name": "Container PS", "description": "This little app help you to manage your Docker containers", "repository": "https://github.com/Toinane/container-ps", - "keywords": [ - "docker", - "containers", - "ps", - "list", - "management" - ], + "keywords": ["docker", "containers", "ps", "list", "management"], "license": "MIT", "category": "Developer Tools", "icon": "container-ps-icon.png", @@ -1390,11 +1163,7 @@ "description": "File Synchronisation for Cozy Cloud on Desktop and Laptop", "website": "https://cozy.io/", "repository": "https://github.com/cozy-labs/cozy-desktop", - "keywords": [ - "productivity", - "synchronization", - "files" - ], + "keywords": ["productivity", "synchronization", "files"], "license": "AGPLv3", "category": "Productivity", "icon": "cozy-desktop-icon.png", @@ -1411,18 +1180,9 @@ "website": "https://cryptoarm.ru/cryptoarm-gost/", "category": "Productivity", "repository": "https://github.com/TrustedRu/CryptoARMGOST", - "keywords": [ - "crypto", - "gost", - "signature", - "encryption", - "typescript", - "react" - ], + "keywords": ["crypto", "gost", "signature", "encryption", "typescript", "react"], "license": "Apache License 2.0 / Proprietary", - "locales": [ - "ru-RU" - ], + "locales": ["ru-RU"], "icon": "cryptoarm-gost-icon.png", "icon32": "cryptoarm-gost-icon-32.png", "icon64": "cryptoarm-gost-icon-64.png", @@ -1464,9 +1224,7 @@ "description": "App that lets you track your Counter-Strike: Global Offensive matches and stats.", "category": "Games", "repository": "https://github.com/davidaf3/csgo-tracker", - "keywords": [ - "CSGO" - ], + "keywords": ["CSGO"], "license": "MIT", "icon": "csgo-tracker-icon.png", "icon32": "csgo-tracker-icon-32.png", @@ -1481,10 +1239,7 @@ "description": "Professional Crypto Trading Terminal. √ Locally Deployed With Strong Encryption. √ Trade Multiple Account In One Place. √ Best-In-Class Algorithms. √ Asset Management.", "website": "https://www.cyberx.com/?utm_source=electron", "category": "Finance", - "locales": [ - "en-US", - "zh-CN" - ], + "locales": ["en-US", "zh-CN"], "keywords": [ "trading", "crypto trading", @@ -1540,12 +1295,7 @@ "description": "Programmer themed adventure RPG.", "website": "https://thedangercrew.com", "category": "Games", - "keywords": [ - "danger", - "crew", - "game", - "rpg" - ], + "keywords": ["danger", "crew", "game", "rpg"], "youtube_video_url": "https://www.youtube.com/watch?v=ej1OAujypd8", "icon": "danger-crew-icon.png", "icon32": "danger-crew-icon-32.png", @@ -1560,11 +1310,7 @@ "description": "A fluid, dark themed native desktop UI for JIRA.", "website": "https://github.com/Yamazaki93/DarkJ-Release", "category": "Productivity", - "keywords": [ - "jira", - "angular", - "dark-theme" - ], + "keywords": ["jira", "angular", "dark-theme"], "icon": "darkj-icon.png", "icon32": "darkj-icon-32.png", "icon64": "darkj-icon-64.png", @@ -1578,11 +1324,7 @@ "description": "Organize and manage all your files inside one application.", "website": "https://dashy.futureglobe.de/", "category": "Productivity", - "keywords": [ - "filemanager", - "shortcutmanager", - "manager" - ], + "keywords": ["filemanager", "shortcutmanager", "manager"], "icon": "dashy-icon.png", "icon32": "dashy-icon-32.png", "icon64": "dashy-icon-64.png", @@ -1655,14 +1397,7 @@ "name": "Data Pixels Playground", "description": "Create Pixel Art Programmatically", "repository": "https://github.com/gmattie/Data-Pixels", - "keywords": [ - "art", - "developer tools", - "image", - "pixel", - "programming", - "web development" - ], + "keywords": ["art", "developer tools", "image", "pixel", "programming", "web development"], "category": "Developer Tools", "icon": "data-pixels-playground-icon.png", "icon32": "data-pixels-playground-icon-32.png", @@ -1676,9 +1411,7 @@ "name": "Datazenit", "description": "Modern database administration tool", "website": "https://datazenit.com", - "keywords": [ - "database" - ], + "keywords": ["database"], "category": "Developer Tools", "icon": "datazenit-icon.png", "icon32": "datazenit-icon-32.png", @@ -1694,13 +1427,7 @@ "website": "https://felipeleivav.github.io/dbcloner-app/", "category": "Developer Tools", "repository": "https://github.com/felipeleivav/dbcloner-app", - "keywords": [ - "docker", - "database", - "postgresql", - "developer-tool", - "clone-database" - ], + "keywords": ["docker", "database", "postgresql", "developer-tool", "clone-database"], "icon": "dbcloner-icon.png", "icon32": "dbcloner-icon-32.png", "icon64": "dbcloner-icon-64.png", @@ -1742,11 +1469,7 @@ "description": "Simple cross-platform PostgreSQL client", "website": "http://dbglass.web-pal.com", "repository": "https://github.com/web-pal/DBGlass", - "keywords": [ - "postgresql", - "sql", - "database" - ], + "keywords": ["postgresql", "sql", "database"], "license": "MIT", "category": "Developer Tools", "icon": "dbglass-icon.png", @@ -1762,10 +1485,7 @@ "description": "Debug in-production Electron based app.", "category": "Developer Tools", "repository": "https://github.com/bytedance/debugtron", - "keywords": [ - "debug", - "debugging-tool" - ], + "keywords": ["debug", "debugging-tool"], "license": "MIT", "icon": "debugtron-icon.png", "icon32": "debugtron-icon-32.png", @@ -1781,12 +1501,7 @@ "website": "https://rivafarabi.github.io/deckboard", "repository": "https://github.com/rivafarabi/deckboard", "category": "Productivity", - "keywords": [ - "shortcut", - "macro", - "remote", - "deck" - ], + "keywords": ["shortcut", "macro", "remote", "deck"], "icon": "deckboard-icon.png", "icon32": "deckboard-icon-32.png", "icon64": "deckboard-icon-64.png", @@ -1800,10 +1515,7 @@ "description": "Deck editor for the yu-gi-oh trading card game.", "website": "https://theotterlord.github.io/deckmaster", "repository": "https://github.com/TheOtterlord/deckmaster", - "keywords": [ - "yu-gi-oh", - "deck-building" - ], + "keywords": ["yu-gi-oh", "deck-building"], "license": "MIT", "category": "Games", "icon": "deckmaster-icon.png", @@ -1832,11 +1544,7 @@ "description": "A modern, fast, beautiful note taking app", "category": "Productivity", "repository": "https://github.com/abahmed/Deer", - "keywords": [ - "note-taking", - "note-app", - "notes" - ], + "keywords": ["note-taking", "note-app", "notes"], "license": "MIT", "icon": "deer-icon.png", "icon32": "deer-icon-32.png", @@ -1850,12 +1558,7 @@ "name": "Demio", "description": "A Webinar Platform Built for Inbound Marketing and Sales", "website": "https://demio.com/", - "keywords": [ - "webinar", - "marketing", - "b2b", - "live streaming" - ], + "keywords": ["webinar", "marketing", "b2b", "live streaming"], "category": "Business", "icon": "demio-icon.png", "icon32": "demio-icon-32.png", @@ -1870,14 +1573,7 @@ "description": "Seamless Presentation tool to help sales and marketing crush remote sales.", "website": "https://demoflow.io", "category": "Business", - "keywords": [ - "presentations", - "demos", - "sales", - "marketing", - "remote", - "teams" - ], + "keywords": ["presentations", "demos", "sales", "marketing", "remote", "teams"], "youtube_video_url": "https://www.youtube.com/watch?v=YzCaUmp6AwE", "icon": "demoflow-icon.png", "icon32": "demoflow-icon-32.png", @@ -1921,13 +1617,7 @@ "website": "https://goo.gl/tVdhAB", "category": "Education", "repository": "https://github.com/bryht/Dict", - "keywords": [ - "study", - "dictionary", - "english", - "dict", - "translate" - ], + "keywords": ["study", "dictionary", "english", "dict", "translate"], "icon": "dict-icon.png", "icon32": "dict-icon-32.png", "icon64": "dict-icon-64.png", @@ -1942,13 +1632,7 @@ "website": "https://diffuse.sh", "category": "Music", "repository": "https://github.com/icidasset/diffuse", - "keywords": [ - "music library", - "music player", - "cloud", - "decentralized", - "distributed" - ], + "keywords": ["music library", "music player", "cloud", "decentralized", "distributed"], "license": "MIT", "icon": "diffuse-icon.png", "icon32": "diffuse-icon-32.png", @@ -1962,10 +1646,7 @@ "name": "DigiExam", "description": "Digital assessments platform.", "website": "https://www.digiexam.com", - "keywords": [ - "education", - "assessments" - ], + "keywords": ["education", "assessments"], "category": "Education", "icon": "digiexam-icon.png", "icon32": "digiexam-icon-32.png", @@ -1979,9 +1660,7 @@ "name": "Discord", "description": "The easiest way to talk over voice, video, and text. Talk, chat, hang out, and stay close with your friends and communities.", "website": "https://discord.com/", - "keywords": [ - "chat" - ], + "keywords": ["chat"], "category": "Social", "icon": "discord-icon.png", "icon32": "discord-icon-32.png", @@ -1996,11 +1675,7 @@ "description": "Cross platform desktop application that supports brightness adjustment for integrated laptop monitor as well as external monitors and dark mode toggle supporting Windows and MacOSX at the moment. Adjustment brightness will be quicker and does not require tinkering with the external monitor controls.", "website": "https://synle.github.io/display-dj/", "repository": "https://github.com/synle/display-dj", - "keywords": [ - "display", - "brightness", - "darkmode" - ], + "keywords": ["display", "brightness", "darkmode"], "license": "MIT", "category": "Utilities", "icon": "display-dj-icon.png", @@ -2016,10 +1691,7 @@ "description": "Cross platform clipboard manager inspired by Ditto for windows.", "category": "Productivity", "repository": "https://github.com/RubinderS/DittoPlusPlus/", - "keywords": [ - "clipboard", - "clipboard-manager" - ], + "keywords": ["clipboard", "clipboard-manager"], "license": "MIT", "icon": "ditto-icon.png", "icon32": "ditto-icon-32.png", @@ -2058,12 +1730,7 @@ "description": "Extendable application which can install multiple packages with one click.", "category": "Developer Tools", "repository": "https://github.com/como65416/DnToolContainer", - "keywords": [ - "extendable", - "format", - "editor", - "encryption" - ], + "keywords": ["extendable", "format", "editor", "encryption"], "license": "MIT", "icon": "dn-tool-container-icon.png", "icon32": "dn-tool-container-icon-32.png", @@ -2091,12 +1758,7 @@ "description": "Multi-pane terminal emulator.", "website": "https://domterm.org/", "repository": "https://github.com/PerBothner/DomTerm", - "keywords": [ - "terminal", - "html", - "css", - "js" - ], + "keywords": ["terminal", "html", "css", "js"], "license": "MIT", "category": "Developer Tools", "icon": "domterm-icon.png", @@ -2113,15 +1775,7 @@ "website": "https://www.digimezzo.com", "category": "Music", "repository": "https://github.com/digimezzo/dopamine", - "keywords": [ - "music", - "audio", - "player", - "organize", - "simple", - "pretty", - "elegant" - ], + "keywords": ["music", "audio", "player", "organize", "simple", "pretty", "elegant"], "license": "GNU General Public License v3.0", "icon": "dopamine-icon.png", "icon32": "dopamine-icon-32.png", @@ -2136,11 +1790,7 @@ "description": "A simple vector illustration tool, that works by adding control points and drawing different line-types between them.", "website": "https://hundredrabbits.itch.io/dotgrid", "repository": "https://hundredrabbits.itch.io/dotgrid", - "keywords": [ - "illustration", - "design", - "vector" - ], + "keywords": ["illustration", "design", "vector"], "category": "Graphics & Design", "icon": "dotgrid-icon.png", "icon32": "dotgrid-icon-32.png", @@ -2213,11 +1863,7 @@ "website": "https://aveek-saha.github.io/", "repository": "https://github.com/Aveek-Saha/MusicPlayer", "category": "Music", - "keywords": [ - "music", - "audio", - "mp3" - ], + "keywords": ["music", "audio", "mp3"], "icon": "dusk-player-icon.png", "icon32": "dusk-player-icon-32.png", "icon64": "dusk-player-icon-64.png", @@ -2247,15 +1893,7 @@ "screen-recorder" ], "category": "Productivity", - "locales": [ - "zh", - "en", - "ar", - "eo", - "es", - "fr", - "ru" - ], + "locales": ["zh", "en", "ar", "eo", "es", "fr", "ru"], "icon": "e-search-icon.png", "icon32": "e-search-icon-32.png", "icon64": "e-search-icon-64.png", @@ -2268,15 +1906,7 @@ "name": "Eagle", "description": "Organizing Ideas Has Never Been Easier", "website": "https://eagle.cool/", - "keywords": [ - "Inspiration", - "Design", - "Sketch", - "Screenshot", - "Mac", - "Windows", - "Productivity" - ], + "keywords": ["Inspiration", "Design", "Sketch", "Screenshot", "Mac", "Windows", "Productivity"], "category": "Productivity", "icon": "eagle-icon.png", "icon32": "eagle-icon-32.png", @@ -2291,11 +1921,7 @@ "description": "Pomodoro Timer with Force to Rest.", "category": "Productivity", "repository": "https://github.com/surajrathod/eagluet", - "keywords": [ - "pomodoro", - "timer", - "stopwatch" - ], + "keywords": ["pomodoro", "timer", "stopwatch"], "license": "MIT", "icon": "eagluet-icon.png", "icon32": "eagluet-icon-32.png", @@ -2311,15 +1937,7 @@ "website": "https://www.ericbt.com/ebtcalc_electron", "category": "Utilities", "repository": "https://github.com/EricTerrell/EBTCalc", - "keywords": [ - "rpn", - "calculator", - "programmable", - "Javascript", - "windows", - "linux", - "osx" - ], + "keywords": ["rpn", "calculator", "programmable", "Javascript", "windows", "linux", "osx"], "license": "GPL3", "icon": "ebtcalc-icon.png", "icon32": "ebtcalc-icon-32.png", @@ -2335,10 +1953,7 @@ "website": "https://afractal.github.io/echo-app", "category": "Music", "repository": "https://github.com/afractal/echo-app", - "keywords": [ - "echo", - "text-to-speech" - ], + "keywords": ["echo", "text-to-speech"], "license": "Proprietary", "goodColorOnWhite": "#343e40", "goodColorOnBlack": "#fafbfc", @@ -2356,12 +1971,7 @@ "description": "Cross-platform calculator", "category": "Finance", "repository": "https://github.com/elcalc/elcalc", - "keywords": [ - "calculator", - "math", - "arithmetic", - "calculation" - ], + "keywords": ["calculator", "math", "arithmetic", "calculation"], "license": "MIT", "icon": "elcalc-icon.png", "icon32": "elcalc-icon-32.png", @@ -2376,12 +1986,7 @@ "description": "An Electron remote client app for uTorrent server", "homebrewCaskName": "electorrent", "repository": "https://github.com/Tympanix/Electorrent", - "keywords": [ - "utorrent", - "remote", - "client", - "magnet" - ], + "keywords": ["utorrent", "remote", "client", "magnet"], "license": "GPLv3", "category": "Utilities", "icon": "electorrent-icon.png", @@ -2398,16 +2003,7 @@ "website": "https://garrylachman.github.io/ElectroCRUD/", "category": "Developer Tools", "repository": "https://github.com/garrylachman/ElectroCRUD", - "keywords": [ - "database", - "crud", - "db", - "mysql", - "mariadb", - "sql", - "postgres", - "developers" - ], + "keywords": ["database", "crud", "db", "mysql", "mariadb", "sql", "postgres", "developers"], "license": "MIT", "icon": "electrocrud-icon.png", "icon32": "electrocrud-icon-32.png", @@ -2422,11 +2018,7 @@ "description": "Simple clipboard manager inspired by ditto.", "category": "Productivity", "repository": "https://github.com/HeyitSaif/Clippy.git", - "keywords": [ - "clibboard", - "clippy", - "ditto" - ], + "keywords": ["clibboard", "clippy", "ditto"], "icon": "electron-clippy-icon.png", "icon32": "electron-clippy-icon-32.png", "icon64": "electron-clippy-icon-64.png", @@ -2440,9 +2032,7 @@ "description": "Generate ICO and ICNS files for your desktop apps.", "repository": "https://github.com/sprout2000/elephicon", "category": "Developer Tools", - "locales": [ - "en-US" - ], + "locales": ["en-US"], "icon": "elephicon-icon.png", "icon32": "elephicon-icon-32.png", "icon64": "elephicon-icon-64.png", @@ -2479,12 +2069,7 @@ "description": "Open-source messaging solution for anyone.", "category": "Social", "repository": "https://github.com/bluethefoxofficial/CreativePublicMessenger", - "keywords": [ - "messaging", - "instant messaging", - "enclica", - "social" - ], + "keywords": ["messaging", "instant messaging", "enclica", "social"], "icon": "enclina-messenger-icon.png", "icon32": "enclina-messenger-icon-32.png", "icon64": "enclina-messenger-icon-64.png", @@ -2499,14 +2084,7 @@ "website": "https://kunalnagar.in/blog/encryptor-encrypt-decrypt-files-passphrase/", "repository": "https://github.com/kunalnagar/encrypt0r", "license": "MIT", - "keywords": [ - "encrypt", - "decrypt", - "passphrase", - "encrypt0r", - "cryptography", - "nodejs" - ], + "keywords": ["encrypt", "decrypt", "passphrase", "encrypt0r", "cryptography", "nodejs"], "category": "Utilities", "icon": "encrypt0r-icon.png", "icon32": "encrypt0r-icon-32.png", @@ -2521,15 +2099,7 @@ "description": "It is a framework, built using a framework, for you! It can make it much easier for new developers to develop and build more modern apps.", "category": "Developer Tools", "repository": "https://github.com/EnderAdel/EnderFramework", - "keywords": [ - "framework", - "store", - "studio", - "installer", - "gaming", - "apps", - "enderapps" - ], + "keywords": ["framework", "store", "studio", "installer", "gaming", "apps", "enderapps"], "icon": "enderframework-icon.png", "icon32": "enderframework-icon-32.png", "icon64": "enderframework-icon-64.png", @@ -2545,9 +2115,7 @@ "snapcraftName": "erin", "category": "Utilities", "repository": "https://github.com/losbiw/erin", - "keywords": [ - "wallpaper" - ], + "keywords": ["wallpaper"], "license": "MIT", "icon": "erin-icon.png", "icon32": "erin-icon-32.png", @@ -2563,19 +2131,10 @@ "website": "https://etcdmanager.io", "category": "Developer Tools", "repository": "https://github.com/icellmobilsoft/etcdmanager.git", - "keywords": [ - "etcd", - "etcd3", - "gui", - "client", - "admin" - ], + "keywords": ["etcd", "etcd3", "gui", "client", "admin"], "license": "MIT", "npmPackageName": "etcd-manager", - "locales": [ - "hu-HU", - "en-US" - ], + "locales": ["hu-HU", "en-US"], "icon": "etcd-manager-icon.png", "icon32": "etcd-manager-icon-32.png", "icon64": "etcd-manager-icon-64.png", @@ -2589,11 +2148,7 @@ "description": "Flash OS images to SD cards & USB drives, safely and easily.", "website": "https://etcher.balena.io/", "repository": "https://github.com/resin-io/etcher", - "keywords": [ - "hardware", - "developer tools", - "IoT" - ], + "keywords": ["hardware", "developer tools", "IoT"], "license": "Apache 2.0", "category": "Developer Tools", "icon": "etcher-icon.png", @@ -2609,12 +2164,7 @@ "description": "Task management (to-do) app for Linux, Windows and Mac. Privacy-focused, powerful, free.", "website": "https://everdo.net", "category": "Productivity", - "keywords": [ - "todo", - "gtd", - "productivity", - "getting things done" - ], + "keywords": ["todo", "gtd", "productivity", "getting things done"], "icon": "everdo-icon.png", "icon32": "everdo-icon-32.png", "icon64": "everdo-icon-64.png", @@ -2627,10 +2177,7 @@ "name": "EVE Trade", "description": "The EVE Online trading tool that lets you discover what to trade between stations and regions. This tool enables making ISK through hauling or station trading.", "website": "https://evetrade.space", - "keywords": [ - "eve_online", - "video_games" - ], + "keywords": ["eve_online", "video_games"], "category": "Games", "icon": "evetrade-icon.png", "icon32": "evetrade-icon-32.png", @@ -2671,13 +2218,7 @@ "website": "https://exifcleaner.com", "category": "Photo & Video", "repository": "https://github.com/szTheory/exifcleaner", - "keywords": [ - "exif", - "image", - "metadata", - "privacy", - "open source" - ], + "keywords": ["exif", "image", "metadata", "privacy", "open source"], "license": "MIT", "icon": "exifcleaner-icon.png", "icon32": "exifcleaner-icon-32.png", @@ -2704,13 +2245,7 @@ "name": "ExpressLRS Configurator", "description": "App to build & flash ExpressLRS firmware.", "repository": "https://github.com/ExpressLRS/ExpressLRS-Configurator", - "keywords": [ - "firmware", - "embedded", - "drones", - "radio", - "utilities" - ], + "keywords": ["firmware", "embedded", "drones", "radio", "utilities"], "category": "Utilities", "license": "GPLv3", "youtube_video_url": "https://www.youtube.com/watch?v=wBUamLm51XQ", @@ -2727,10 +2262,7 @@ "description": "Swiss army chainsaw of terminal emulators", "website": "http://extraterm.org", "repository": "https://github.com/sedwards2009/extraterm", - "keywords": [ - "terminal", - "typescript" - ], + "keywords": ["terminal", "typescript"], "license": "MIT", "category": "Developer Tools", "icon": "extraterm-icon.png", @@ -2746,14 +2278,7 @@ "description": "Offline application that comes at you all day long and curates your own web favorites.", "website": "https://xizon.github.io/F-Curator-Official-Website/", "repository": "https://github.com/xizon/F-Curator/tree/main/package", - "keywords": [ - "curator", - "curation", - "efficiency", - "web favorites", - "bookmark", - "collection" - ], + "keywords": ["curator", "curation", "efficiency", "web favorites", "bookmark", "collection"], "license": "MIT", "npmPackageName": "f-curator", "category": "Productivity", @@ -2772,15 +2297,7 @@ "website": "https://fairdataihub.org/fairshare", "category": "Science & Medicine", "repository": "https://github.com/fairdataihub/FAIRshare", - "keywords": [ - "fair", - "metadata", - "curation", - "sharing", - "windows", - "macos", - "ubuntu" - ], + "keywords": ["fair", "metadata", "curation", "sharing", "windows", "macos", "ubuntu"], "license": "MIT", "icon": "fairshare-icon.png", "icon32": "fairshare-icon-32.png", @@ -2794,13 +2311,8 @@ "name": "fangyuanjian", "description": "a collaboration and messaging app for small-to-medium sized businesses.", "website": "http://bzsns.cn/", - "keywords": [ - "messaging", - "collaboration" - ], - "locales": [ - "zh-CN" - ], + "keywords": ["messaging", "collaboration"], + "locales": ["zh-CN"], "category": "Social", "icon": "fangyuanjian-icon.png", "icon32": "fangyuanjian-icon-32.png", @@ -2816,16 +2328,8 @@ "website": "https://getfenet.re", "category": "Productivity", "youtube_video_url": "https://www.youtube.com/watch?v=mOuQyzbHzO4&list=PL2jvDJe7CN0oi6nscDlWFZehvaIsE7OWh", - "locales": [ - "fr-FR" - ], - "keywords": [ - "picture in picture", - "productivity", - "tool", - "video", - "player" - ], + "locales": ["fr-FR"], + "keywords": ["picture in picture", "productivity", "tool", "video", "player"], "icon": "fenetre-icon.png", "icon32": "fenetre-icon-32.png", "icon64": "fenetre-icon-64.png", @@ -2840,12 +2344,7 @@ "website": "https://fifo.snaildos.com", "category": "Productivity", "repository": "https://github.com/snaildos/Fifo-Browser", - "keywords": [ - "Browser", - "Privacy", - "Secure", - "React" - ], + "keywords": ["Browser", "Privacy", "Secure", "React"], "icon": "fifo-icon.png", "icon32": "fifo-icon-32.png", "icon64": "fifo-icon-64.png", @@ -2859,16 +2358,7 @@ "description": "Build better products as a team. Design, prototype, and gather feedback all in one place with Figma.", "website": "https://www.figma.com/", "homebrewCaskName": "figma", - "keywords": [ - "graphics", - "images", - "editor", - "svg", - "sketch", - "vector", - "ui", - "ux" - ], + "keywords": ["graphics", "images", "editor", "svg", "sketch", "vector", "ui", "ux"], "category": "Graphics & Design", "icon": "figma-icon.png", "icon32": "figma-icon-32.png", @@ -2883,10 +2373,7 @@ "description": "Modern, tiling file manager with unlimited panes.", "website": "https://www.fileside.app", "category": "Utilities", - "keywords": [ - "file-manager", - "file-browser" - ], + "keywords": ["file-manager", "file-browser"], "youtube_video_url": "https://www.youtube.com/watch?v=48SU-0P-VfY", "icon": "fileside-icon.png", "icon32": "fileside-icon-32.png", @@ -2901,12 +2388,7 @@ "description": "Generates a running clock counting down to the second of one's death.", "category": "Productivity", "repository": "https://github.com/hunterphillips/countdown", - "keywords": [ - "desktop", - "angularJS", - "cross-platform", - "productivity" - ], + "keywords": ["desktop", "angularJS", "cross-platform", "productivity"], "icon": "final-countdown-icon.png", "icon32": "final-countdown-icon-32.png", "icon64": "final-countdown-icon-64.png", @@ -2946,13 +2428,8 @@ "website": "https://ff.1zilc.top", "category": "Finance", "repository": "https://github.com/1zilc/fishing-funds", - "keywords": [ - "funds", - "menubar" - ], - "locales": [ - "zh-CN" - ], + "keywords": ["funds", "menubar"], + "locales": ["zh-CN"], "license": "GPL-3.0", "icon": "fishing-funds-icon.png", "icon32": "fishing-funds-icon-32.png", @@ -2977,9 +2454,7 @@ "smart-diary", "utility" ], - "locales": [ - "en-US" - ], + "locales": ["en-US"], "license": "MIT", "icon": "flawesome-icon.png", "icon32": "flawesome-icon-32.png", @@ -2997,15 +2472,7 @@ "license": "MIT", "category": "Music", "youtube_video_url": "https://youtu.be/tjInHlpOK38", - "keywords": [ - "music", - "player", - "vue", - "youtube", - "download", - "deezer", - "spotify" - ], + "keywords": ["music", "player", "vue", "youtube", "download", "deezer", "spotify"], "goodColorOnWhite": "#3469C1", "goodColorOnBlack": "#4175CC", "icon": "flbmusic-icon.png", @@ -3063,9 +2530,7 @@ "name": "Flow", "description": "Simple Project Management Software For Teams", "website": "https://www.getflow.com/solutions/startups", - "keywords": [ - "Productivity" - ], + "keywords": ["Productivity"], "category": "Productivity", "icon": "flow-icon.png", "icon32": "flow-icon-32.png", @@ -3081,16 +2546,9 @@ "website": "https://hyliu.me/fluent-reader/", "repository": "https://github.com/yang991178/fluent-reader", "license": "BSD", - "keywords": [ - "rss", - "rss reader", - "news aggregator" - ], + "keywords": ["rss", "rss reader", "news aggregator"], "category": "News", - "locales": [ - "zh-CN", - "en-US" - ], + "locales": ["zh-CN", "en-US"], "icon": "fluent-reader-icon.png", "icon32": "fluent-reader-icon-32.png", "icon64": "fluent-reader-icon-64.png", @@ -3104,15 +2562,7 @@ "description": "MacOS menu bar todo app built with React and Redux. It goals is to help you do deep work.", "category": "Productivity", "repository": "https://github.com/RStankov/FocusedTask", - "keywords": [ - "react", - "redux", - "todo", - "bookmarks", - "task manager", - "notes", - "menubar" - ], + "keywords": ["react", "redux", "todo", "bookmarks", "task manager", "notes", "menubar"], "license": "MIT", "youtube_video_url": "https://www.youtube.com/watch?v=Vp2ASWq-S04", "icon": "focused-task-icon.png", @@ -3128,13 +2578,7 @@ "description": "Lightning fast, beautiful and free font manager for designers", "website": "https://fontba.se/", "category": "Graphics & Design", - "keywords": [ - "fonts", - "typography", - "type", - "design", - "graphics" - ], + "keywords": ["fonts", "typography", "type", "design", "graphics"], "license": "Dominik Levitsky Studio", "icon": "fontbase-icon.png", "icon32": "fontbase-icon-32.png", @@ -3148,11 +2592,7 @@ "name": "Forestpin Analytics", "description": "Financial data analytics tool for businesses", "website": "http://forestpin.com/analytics", - "keywords": [ - "analytics", - "data", - "finance" - ], + "keywords": ["analytics", "data", "finance"], "category": "Finance", "icon": "forestpin-analytics-icon.png", "icon32": "forestpin-analytics-icon-32.png", @@ -3264,11 +2704,7 @@ "name": "Franz", "description": "Messaging app / former emperor of Austria, combining chat and messaging services into one application", "website": "https://meetfranz.com/", - "keywords": [ - "messaging", - "chat", - "productivity" - ], + "keywords": ["messaging", "chat", "productivity"], "category": "Productivity", "icon": "franz-icon.png", "icon32": "franz-icon-32.png", @@ -3282,10 +2718,7 @@ "name": "Freeter", "description": "The smartest way to work on your projects", "website": "https://freeter.io", - "keywords": [ - "productivity", - "organizer" - ], + "keywords": ["productivity", "organizer"], "category": "Productivity", "icon": "freeter-icon.png", "icon32": "freeter-icon-32.png", @@ -3299,9 +2732,7 @@ "name": "Friends", "description": "Peer to peer chat", "website": "https://moose-team.github.io/friends", - "keywords": [ - "chat" - ], + "keywords": ["chat"], "category": "Social", "icon": "friends-icon.png", "icon32": "friends-icon-32.png", @@ -3329,10 +2760,7 @@ "name": "Galeri", "description": "A perpetual artwork streaming app", "website": "https://www.galeri.io", - "keywords": [ - "art", - "painting" - ], + "keywords": ["art", "painting"], "category": "Photo & Video", "icon": "galeri-icon.png", "icon32": "galeri-icon-32.png", @@ -3348,9 +2776,7 @@ "website": "https://angrykoala.github.io/gaucho/", "repository": "https://github.com/angrykoala/gaucho", "license": "GPL-3.0", - "keywords": [ - "launcher" - ], + "keywords": ["launcher"], "category": "Utilities", "icon": "gaucho-icon.png", "icon32": "gaucho-icon-32.png", @@ -3394,13 +2820,7 @@ "description": "TIL writing tool for programmer", "category": "Productivity", "repository": "https://github.com/seokju-na/geeks-diary", - "keywords": [ - "Markdown", - "Note App", - "Code", - "Programmer", - "TIL" - ], + "keywords": ["Markdown", "Note App", "Code", "Programmer", "TIL"], "license": "MIT", "icon": "geeks-diary-icon.png", "icon32": "geeks-diary-icon-32.png", @@ -3416,13 +2836,7 @@ "website": "https://virejdasani.github.io/Geniemoji/", "category": "Utilities", "repository": "https://github.com/virejdasani/Geniemoji", - "keywords": [ - "Geniemoji", - "Emoji", - "search-emoji", - "rocket", - "Emogenie" - ], + "keywords": ["Geniemoji", "Emoji", "search-emoji", "rocket", "Emogenie"], "license": "MIT", "youtube_video_url": "https://youtu.be/0I18p8e1Z5Y", "icon": "geniemoji-icon.png", @@ -3439,11 +2853,7 @@ "website": "https://geppetto.js.org/", "category": "Graphics & Design", "repository": "https://github.com/matthijsgroen/geppetto", - "keywords": [ - "Animation", - "WebGL", - "Game Development" - ], + "keywords": ["Animation", "WebGL", "Game Development"], "license": "MIT", "icon": "geppetto-icon.png", "icon32": "geppetto-icon-32.png", @@ -3468,9 +2878,7 @@ "strichliste", "vereine" ], - "locales": [ - "de-DE" - ], + "locales": ["de-DE"], "icon": "getraenkeliste-icon.png", "icon32": "getraenkeliste-icon-32.png", "icon64": "getraenkeliste-icon-64.png", @@ -3484,12 +2892,7 @@ "description": "The easiest way to backup all your github repositories with just a few clicks.", "website": "https://gibu.futureglobe.de/", "category": "Developer Tools", - "keywords": [ - "gihuba", - "tool", - "backup", - "github" - ], + "keywords": ["gihuba", "tool", "backup", "github"], "icon": "gibu-icon.png", "icon32": "gibu-icon-32.png", "icon64": "gibu-icon-64.png", @@ -3502,13 +2905,7 @@ "name": "Git-it", "description": "Desktop App for learning Git and GitHub.", "repository": "https://github.com/Git-it-App/git-it-electron", - "keywords": [ - "Git", - "GitHub", - "tutorial", - "guide", - "learn" - ], + "keywords": ["Git", "GitHub", "tutorial", "guide", "learn"], "license": "BSD-2-Clause", "category": "Education", "icon": "git-it-icon.png", @@ -3523,13 +2920,7 @@ "name": "GitBook", "description": "Editor for a modern publishing toolchain based on Git", "website": "https://www.gitbook.com/?utm_source=electron&utm_medium=logo", - "keywords": [ - "writing", - "editor", - "documentation", - "git", - "gitbook" - ], + "keywords": ["writing", "editor", "documentation", "git", "gitbook"], "category": "Productivity", "icon": "gitbook-icon.png", "icon32": "gitbook-icon-32.png", @@ -3544,13 +2935,7 @@ "description": "Hoard git repositories with ease", "repository": "https://github.com/beepboopbangbang/githoard", "category": "Productivity", - "keywords": [ - "git", - "code", - "developer", - "tool", - "productivity" - ], + "keywords": ["git", "code", "developer", "tool", "productivity"], "license": "MIT", "icon": "githoard-icon.png", "icon32": "githoard-icon-32.png", @@ -3594,13 +2979,7 @@ "website": "https://www.gitify.io/", "repository": "https://github.com/manosim/gitify", "homebrewCaskName": "gitify", - "keywords": [ - "Github", - "notifications", - "developer", - "tool", - "productivity" - ], + "keywords": ["Github", "notifications", "developer", "tool", "productivity"], "license": "MIT", "category": "Productivity", "icon": "gitify-icon.png", @@ -3615,11 +2994,7 @@ "name": "GitKraken", "description": "The downright luxurious Git client for Windows, Mac and Linux", "website": "https://www.gitkraken.com/", - "keywords": [ - "git", - "programming", - "productivity" - ], + "keywords": ["git", "programming", "productivity"], "category": "Productivity", "icon": "gitkraken-icon.png", "icon32": "gitkraken-icon-32.png", @@ -3633,12 +3008,7 @@ "name": "Gitscout", "description": "A beautiful and optimized GitHub Issues experience for macOS", "website": "https://gitscout.com", - "keywords": [ - "github", - "mac", - "git", - "developer tools" - ], + "keywords": ["github", "mac", "git", "developer tools"], "category": "Developer Tools", "icon": "gitscout-icon.png", "icon32": "gitscout-icon-32.png", @@ -3653,15 +3023,7 @@ "description": "Unified Communications as a service", "website": "https://gluppi.com/download/", "category": "Social", - "keywords": [ - "telephony", - "videoconference", - "pbx", - "chat", - "video", - "cloud", - "storage" - ], + "keywords": ["telephony", "videoconference", "pbx", "chat", "video", "cloud", "storage"], "license": "Commercial", "icon": "gluppi-icon.png", "icon32": "gluppi-icon-32.png", @@ -3675,11 +3037,7 @@ "name": "Glyphr Studio", "description": "Free font design tool for hobbyists.", "repository": "https://github.com/glyphr-studio/Glyphr-Studio-Desktop", - "keywords": [ - "font", - "design", - "utility" - ], + "keywords": ["font", "design", "utility"], "category": "Utilities", "icon": "glyphr-studio-icon.png", "icon32": "glyphr-studio-icon-32.png", @@ -3717,10 +3075,7 @@ "category": "Social", "repository": "https://github.com/ankurk91/google-chat-electron", "snapcraftName": "google-chat-electron", - "keywords": [ - "google-hangouts", - "hangouts-chat" - ], + "keywords": ["google-hangouts", "hangouts-chat"], "license": "MIT", "icon": "google-chat-electron-icon.png", "icon32": "google-chat-electron-icon-32.png", @@ -3734,11 +3089,7 @@ "name": "GramTools", "description": "collection of dev tools.", "website": "https://ritoyantools.github.io/", - "keywords": [ - "developer tools", - "json format", - "differ" - ], + "keywords": ["developer tools", "json format", "differ"], "license": "MIT", "category": "Developer Tools", "icon": "gram-tools-icon.png", @@ -3754,14 +3105,7 @@ "description": "A GUI for editing and testing GraphQL queries and mutations", "website": "https://github.com/skevy/graphiql-app", "category": "Developer Tools", - "keywords": [ - "GraphQL", - "data", - "databases", - "GitHub", - "API", - "development" - ], + "keywords": ["GraphQL", "data", "databases", "GitHub", "API", "development"], "license": "MIT", "icon": "graphiql-icon.png", "icon32": "graphiql-icon-32.png", @@ -3776,15 +3120,7 @@ "description": " GraphQL IDE for better development workflows", "category": "Developer Tools", "repository": "https://github.com/graphql/graphql-playground", - "keywords": [ - "GraphQL", - "data", - "database", - "IDE", - "editor", - "developer", - "API" - ], + "keywords": ["GraphQL", "data", "database", "IDE", "editor", "developer", "API"], "license": "MIT", "icon": "graphql-playground-icon.png", "icon32": "graphql-playground-icon-32.png", @@ -3839,11 +3175,7 @@ "website": "https://graviton.netlify.app/", "category": "Developer Tools", "repository": "https://github.com/Graviton-Code-Editor/Graviton-App", - "keywords": [ - "code", - "editor", - "minimalist" - ], + "keywords": ["code", "editor", "minimalist"], "license": "MIT", "snapcraftName": "graviton", "icon": "graviton-editor-icon.png", @@ -3859,11 +3191,7 @@ "description": "App to play with hash.", "category": "Developer Tools", "repository": "https://github.com/MrAnyx/HashTag", - "keywords": [ - "Hash", - "Security", - "Development" - ], + "keywords": ["Hash", "Security", "Development"], "icon": "hashtag-icon.png", "icon32": "hashtag-icon-32.png", "icon64": "hashtag-icon-64.png", @@ -3876,11 +3204,7 @@ "name": "HBBatchBeast", "description": "A GUI application for Handbrake on Windows, macOS and Linux with an emphasis on batch conversion (including recursive folder scans and folder watching). Can also perform a basic scan for corrupt videos.", "repository": "https://github.com/HaveAGitGat/HBBatchBeast", - "keywords": [ - "conversion", - "transcoding", - "videos" - ], + "keywords": ["conversion", "transcoding", "videos"], "category": "Utilities", "icon": "hbbatchbeast-icon.png", "icon32": "hbbatchbeast-icon-32.png", @@ -3894,10 +3218,7 @@ "name": "Headset", "description": "Discover, collect and listen to music from YouTube", "website": "https://headsetapp.co/", - "keywords": [ - "Music", - "YouTube" - ], + "keywords": ["Music", "YouTube"], "category": "Music", "icon": "headset-icon.png", "icon32": "headset-icon-32.png", @@ -3912,13 +3233,7 @@ "description": "Your mac's battery doctor", "website": "https://pablopunk.github.io/healthi-app/", "repository": "https://github.com/pablopunk/healthi-app", - "keywords": [ - "battery", - "mac", - "doctor", - "health", - "util" - ], + "keywords": ["battery", "mac", "doctor", "health", "util"], "license": "MIT", "category": "Utilities", "icon": "healthi-icon.png", @@ -3934,21 +3249,8 @@ "description": "Amazing Watch Parties.", "website": "https://hearo.live/", "category": "Entertainment", - "keywords": [ - "watch party", - "video", - "talk", - "chat", - "social" - ], - "locales": [ - "en", - "de", - "ms-MY", - "pt-BR", - "es-419", - "tr" - ], + "keywords": ["watch party", "video", "talk", "chat", "social"], + "locales": ["en", "de", "ms-MY", "pt-BR", "es-419", "tr"], "icon": "hearo-icon.png", "icon32": "hearo-icon-32.png", "icon64": "hearo-icon-64.png", @@ -3962,12 +3264,7 @@ "description": "Custom Launcher for Modded Minecraft.", "repository": "https://github.com/dscalzi/HeliosLauncher", "category": "Games", - "keywords": [ - "minecraft", - "minecraft launcher", - "forge", - "liteloader" - ], + "keywords": ["minecraft", "minecraft launcher", "forge", "liteloader"], "icon": "helioslauncher-icon.png", "icon32": "helioslauncher-icon-32.png", "icon64": "helioslauncher-icon-64.png", @@ -4001,9 +3298,7 @@ "name": "Hive", "description": "Home for busy teams", "website": "https://hive.com", - "keywords": [ - "Productivity" - ], + "keywords": ["Productivity"], "category": "Productivity", "icon": "hive-icon.png", "icon32": "hive-icon-32.png", @@ -4018,13 +3313,7 @@ "description": "Elegant RSS reader.", "category": "News", "repository": "https://github.com/Saul-Mirone/homura", - "keywords": [ - "rss", - "rss-reader", - "typescript", - "react", - "redux" - ], + "keywords": ["rss", "rss-reader", "typescript", "react", "redux"], "license": "MIT", "icon": "homura-icon.png", "icon32": "homura-icon-32.png", @@ -4039,19 +3328,9 @@ "description": "Yet another music player 音乐播放器.", "category": "Music", "repository": "https://github.com/kevinjobs/Horen", - "keywords": [ - "player", - "music", - "howler", - "howl", - "pure", - "foobar2k", - "foobar2000" - ], + "keywords": ["player", "music", "howler", "howl", "pure", "foobar2k", "foobar2000"], "license": "Apache-2.0", - "locales": [ - "zh-CN" - ], + "locales": ["zh-CN"], "icon": "horen-icon.png", "icon32": "horen-icon-32.png", "icon64": "horen-icon-64.png", @@ -4065,15 +3344,7 @@ "description": "The Browser for ADHD minds that think in Trails®, not Tabs. Browse naturally, follow tangents and connections without losing your original thread.", "website": "https://browser.horse", "category": "Productivity", - "keywords": [ - "browser", - "productivity", - "tabs", - "trails", - "adhd", - "neurodiversity", - "research" - ], + "keywords": ["browser", "productivity", "tabs", "trails", "adhd", "neurodiversity", "research"], "icon": "horse-browser-icon.png", "icon32": "horse-browser-icon-32.png", "icon64": "horse-browser-icon-64.png", @@ -4086,9 +3357,7 @@ "name": "Hoster", "description": "Hosts configuration tools", "website": "https://houfeng.net/hoster", - "locales": [ - "zh-cn" - ], + "locales": ["zh-cn"], "keywords": [ "hosts", "hoster", @@ -4114,9 +3383,7 @@ "name": "Hozz", "description": "A better way to manage your hosts", "website": "https://ppoffice.github.io/Hozz", - "keywords": [ - "hosts" - ], + "keywords": ["hosts"], "category": "Developer Tools", "icon": "hozz-icon.png", "icon32": "hozz-icon-32.png", @@ -4158,14 +3425,7 @@ "name": "HTTPS Checker", "description": "Scan a website for HTTPS mixed content issues", "website": "https://httpschecker.net/guides/https-checker", - "keywords": [ - "https", - "ssl", - "tls", - "migration", - "checker", - "mixed-content" - ], + "keywords": ["https", "ssl", "tls", "migration", "checker", "mixed-content"], "category": "Developer Tools", "icon": "https-checker-icon.png", "icon32": "https-checker-icon-32.png", @@ -4181,12 +3441,7 @@ "website": "https://hyper.is", "repository": "https://github.com/vercel/hyper", "homebrewCaskName": "hyper", - "keywords": [ - "terminal", - "html", - "css", - "js" - ], + "keywords": ["terminal", "html", "css", "js"], "license": "MIT", "goodColorOnWhite": "#000", "goodColorOnBlack": "#FFF", @@ -4213,9 +3468,7 @@ "translation tool" ], "license": "MIT", - "locales": [ - "en-US" - ], + "locales": ["en-US"], "icon": "i18n-manager-icon.png", "icon32": "i18n-manager-icon-32.png", "icon64": "i18n-manager-icon-64.png", @@ -4228,11 +3481,7 @@ "name": "i5sing", "description": "A simple music client for 5sing.kugou.com", "repository": "https://github.com/i5sing/i5SING", - "keywords": [ - "5sing", - "music client", - "kugou" - ], + "keywords": ["5sing", "music client", "kugou"], "category": "Music", "icon": "i5sing-icon.png", "icon32": "i5sing-icon-32.png", @@ -4247,13 +3496,7 @@ "description": "Free cross-platform and fast SVG icon organizer for designers and teams. Available for macOS and Windows.", "website": "https://iconset.io", "category": "Graphics & Design", - "keywords": [ - "SVG Organizer", - "Free", - "Mac App", - "Windows App", - "Organizer" - ], + "keywords": ["SVG Organizer", "Free", "Mac App", "Windows App", "Organizer"], "icon": "iconset-icon.png", "icon32": "iconset-icon-32.png", "icon64": "iconset-icon-64.png", @@ -4266,12 +3509,7 @@ "name": "Illyriad", "description": "4X Grand Strategy MMO Game", "website": "https://store.steampowered.com/app/559310", - "keywords": [ - "games", - "steam", - "grand strategy", - "mmo" - ], + "keywords": ["games", "steam", "grand strategy", "mmo"], "category": "Games", "icon": "illyriad-icon.png", "icon32": "illyriad-icon-32.png", @@ -4337,11 +3575,7 @@ "name": "Imagine", "description": "Image optimizer", "repository": "https://github.com/meowtec/Imagine", - "keywords": [ - "image compress", - "png", - "jpg" - ], + "keywords": ["image compress", "png", "jpg"], "category": "Photo & Video", "icon": "imagine-icon.png", "icon32": "imagine-icon-32.png", @@ -4357,11 +3591,7 @@ "website": "https://denysdovhan.com/inboxer", "category": "Social", "repository": "https://github.com/denysdovhan/inboxer", - "keywords": [ - "mail", - "gmail", - "inbox" - ], + "keywords": ["mail", "gmail", "inbox"], "license": "MIT", "icon": "inboxer-icon.png", "icon32": "inboxer-icon-32.png", @@ -4376,13 +3606,7 @@ "description": "LaTeX and WYSIWYG editor with productivity hacks.", "category": "Productivity", "repository": "https://github.com/fetacore/Infinitex", - "keywords": [ - "react", - "latex", - "material-ui", - "uglifyjs", - "libgen" - ], + "keywords": ["react", "latex", "material-ui", "uglifyjs", "libgen"], "license": "GPL-3.0", "icon": "infinitex-icon.png", "icon32": "infinitex-icon-32.png", @@ -4398,13 +3622,8 @@ "website": "https://infiniticlips.com/", "category": "Utilities", "repository": "https://github.com/azure06/infiniti-clips.git", - "keywords": [ - "clipboard", - "notes" - ], - "locales": [ - "en-US" - ], + "keywords": ["clipboard", "notes"], + "locales": ["en-US"], "icon": "infiniti-clips-icon.png", "icon32": "infiniti-clips-icon-32.png", "icon64": "infiniti-clips-icon-64.png", @@ -4417,11 +3636,7 @@ "name": "Infinity", "description": "An easy way to make presentation.", "website": "https://ycosxapp.github.io", - "keywords": [ - "presentation", - "design", - "react" - ], + "keywords": ["presentation", "design", "react"], "category": "Productivity", "icon": "infinity-icon.png", "icon32": "infinity-icon-32.png", @@ -4435,13 +3650,7 @@ "name": "Inkdrop", "description": "Markdown note-taking app that syncs, with 100+ plugins", "website": "https://www.inkdrop.app/", - "keywords": [ - "text", - "programming", - "notebook", - "extensible", - "markdown" - ], + "keywords": ["text", "programming", "notebook", "extensible", "markdown"], "category": "Productivity", "snapcraftName": "inkdrop", "youtube_video_url": "https://www.youtube.com/watch?v=O_hyFYdkxkQ", @@ -4458,13 +3667,7 @@ "description": "REST API Client", "website": "https://insomnia.rest/", "repository": "https://github.com/getinsomnia/insomnia", - "keywords": [ - "REST Client", - "HTTP", - "API", - "developer tools", - "GraphQL" - ], + "keywords": ["REST Client", "HTTP", "API", "developer tools", "GraphQL"], "license": "MIT", "category": "Developer Tools", "homebrewCaskName": "insomnia", @@ -4520,13 +3723,7 @@ "description": "Explore a galaxy of ideas", "website": "https://intumind.github.io/", "category": "Utilities", - "keywords": [ - "Organize", - "Writing", - "Ideas", - "Share", - "Social" - ], + "keywords": ["Organize", "Writing", "Ideas", "Share", "Social"], "licence": "Commercial", "icon": "intu-mind-icon.png", "icon32": "intu-mind-icon-32.png", @@ -4543,12 +3740,7 @@ "category": "Finance", "repository": "https://github.com/invizi/invizi/", "youtube_video_url": "https://www.youtube.com/watch?v=nJ6OPCZb1zs", - "keywords": [ - "private cryptocurrency tracker", - "privacy", - "crypto portfolio", - "bitcoin" - ], + "keywords": ["private cryptocurrency tracker", "privacy", "crypto portfolio", "bitcoin"], "license": "GPLv3", "icon": "invizi-icon.png", "icon32": "invizi-icon-32.png", @@ -4563,13 +3755,7 @@ "description": "Desktop app which provide you IONIC CLI in UI.", "category": "Developer Tools", "repository": "https://github.com/shivang-pokar/ioui", - "keywords": [ - "ioui", - "ionic", - "cordova", - "hybridapp", - "phonegap" - ], + "keywords": ["ioui", "ionic", "cordova", "hybridapp", "phonegap"], "license": "MIT", "icon": "ioui-icon.png", "icon32": "ioui-icon-32.png", @@ -4604,20 +3790,10 @@ "description": "Video player for IPTV playlists.", "category": "Photo & Video", "repository": "https://github.com/4gray/iptvnator", - "keywords": [ - "iptv", - "video", - "player", - "m3u", - "internet", - "opensource", - "tv" - ], + "keywords": ["iptv", "video", "player", "m3u", "internet", "opensource", "tv"], "license": "MIT", "snapcraftName": "iptvnator", - "locales": [ - "en-US" - ], + "locales": ["en-US"], "icon": "iptvnator-icon.png", "icon32": "iptvnator-icon-32.png", "icon64": "iptvnator-icon-64.png", @@ -4630,10 +3806,7 @@ "name": "Istrolid", "description": "Fleet Design Strategy Game", "website": "https://www.istrolid.com/", - "keywords": [ - "games", - "strategy" - ], + "keywords": ["games", "strategy"], "category": "Games", "icon": "istrolid-icon.png", "icon32": "istrolid-icon-32.png", @@ -4648,9 +3821,7 @@ "description": "The best way to play your itch.io games", "website": "https://itch.io/app", "repository": "https://github.com/itchio/itch", - "keywords": [ - "games" - ], + "keywords": ["games"], "license": "MIT", "category": "Games", "icon": "itch-icon.png", @@ -4682,10 +3853,7 @@ "website": "https://www.jamovi.org", "category": "Productivity", "repository": "https://github.com/jamovi/jamovi", - "keywords": [ - "spreadsheet", - "statistics" - ], + "keywords": ["spreadsheet", "statistics"], "license": "AGPL3", "icon": "jamovi-icon.png", "icon32": "jamovi-icon-32.png", @@ -4699,10 +3867,7 @@ "name": "JANDI", "description": "Team Communication for Businesses", "website": "https://www.jandi.com", - "keywords": [ - "messenger", - "collaboration" - ], + "keywords": ["messenger", "collaboration"], "category": "Social", "icon": "jandi-icon.png", "icon32": "jandi-icon-32.png", @@ -4717,12 +3882,7 @@ "description": "Japanese Kanji to Katakana.", "category": "Productivity", "repository": "https://github.com/styunan/japankana", - "keywords": [ - "japanhr", - "Japanese", - "Kanji", - "Katakana" - ], + "keywords": ["japanhr", "Japanese", "Kanji", "Katakana"], "license": "MIT", "icon": "janpankana-icon.png", "icon32": "janpankana-icon-32.png", @@ -4762,14 +3922,7 @@ "category": "Productivity", "repository": "https://github.com/laurent22/joplin", "homebrewCaskName": "joplin", - "keywords": [ - "note", - "to-do", - "onedrive", - "synchronisation", - "evernote", - "enex" - ], + "keywords": ["note", "to-do", "onedrive", "synchronisation", "evernote", "enex"], "license": "MIT", "locales": [ "cs-CZ", @@ -4823,13 +3976,7 @@ "name": "Jukeboks", "description": "Fast viewer", "repository": "https://github.com/hirohisa/Jukeboks", - "keywords": [ - "viewer", - "player", - "image", - "movie", - "video" - ], + "keywords": ["viewer", "player", "image", "movie", "video"], "license": "ISC", "category": "Photo & Video", "icon": "jukeboks-icon.png", @@ -4846,13 +3993,7 @@ "website": "https://www.kahla.app/", "category": "Social", "repository": "https://github.com/AiursoftWeb/Kahla.App", - "keywords": [ - "chat", - "messaging", - "secure", - "business", - "end-to-end" - ], + "keywords": ["chat", "messaging", "secure", "business", "end-to-end"], "license": "MIT", "icon": "kahla-icon.png", "icon32": "kahla-icon-32.png", @@ -4867,14 +4008,8 @@ "description": "Cool tool for browsing pictures in Mac OS.", "category": "Photo & Video", "repository": "https://github.com/newham/kankan", - "keywords": [ - "picture", - "photo" - ], - "locales": [ - "zh-CN", - "en" - ], + "keywords": ["picture", "photo"], + "locales": ["zh-CN", "en"], "license": "GPL", "icon": "kankan-icon.png", "icon32": "kankan-icon-32.png", @@ -4889,13 +4024,7 @@ "description": "An open-source screen recorder built with web technology", "website": "https://getkap.co", "repository": "https://github.com/wulkano/kap", - "keywords": [ - "kap", - "screen", - "capture", - "record", - "video" - ], + "keywords": ["kap", "screen", "capture", "record", "video"], "license": "MIT", "category": "Photo & Video", "icon": "kap-icon.png", @@ -4911,14 +4040,7 @@ "description": "Free and open-source CAT tool for linguists.", "website": "https://kaplan.pro", "repository": "https://github.com/kaplanPRO/kaplan-desktop", - "keywords": [ - "cat", - "translation", - "l10n", - "localization", - "i18n", - "internationalization" - ], + "keywords": ["cat", "translation", "l10n", "localization", "i18n", "internationalization"], "license": "MIT", "category": "Productivity", "icon": "kaplan-desktop-icon.png", @@ -4934,9 +4056,7 @@ "description": "Application Launcher", "category": "Utilities", "repository": "https://github.com/monsterkodi/kappo", - "keywords": [ - "launcher" - ], + "keywords": ["launcher"], "license": "Unlicense", "icon": "kappo-icon.png", "icon32": "kappo-icon-32.png", @@ -4952,15 +4072,8 @@ "website": "https://mugen.karaokes.moe/en", "license": "MIT", "repository": "https://gitlab.com/karaokemugen/karaokemugen-app", - "keywords": [ - "karaoke", - "video", - "mpv" - ], - "locales": [ - "en-US", - "fr-FR" - ], + "keywords": ["karaoke", "video", "mpv"], + "locales": ["en-US", "fr-FR"], "category": "Entertainment", "icon": "karaokemugen-icon.png", "icon32": "karaokemugen-icon-32.png", @@ -4974,12 +4087,7 @@ "name": "Katana", "description": "Open-source screenshot utility that lives in your menubar", "repository": "https://github.com/bluegill/katana", - "keywords": [ - "screenshot", - "cloud", - "share", - "upload" - ], + "keywords": ["screenshot", "cloud", "share", "upload"], "category": "Utilities", "icon": "katana-icon.png", "icon32": "katana-icon-32.png", @@ -5068,12 +4176,7 @@ "name": "KeeWeb", "description": "Free cross-platform password manager compatible with KeePass", "website": "https://keeweb.info", - "keywords": [ - "password manager", - "keepass", - "kdbx", - "security" - ], + "keywords": ["password manager", "keepass", "kdbx", "security"], "category": "Utilities", "license": "MIT", "repository": "https://github.com/keeweb/keeweb", @@ -5119,12 +4222,7 @@ "description": "Organize, practice, and look up keyboard shortcuts.", "website": "https://keycombiner.com/", "repository": "https://github.com/tkainrad/keycombiner", - "keywords": [ - "keyboard", - "shortcuts", - "productivity", - "snippets" - ], + "keywords": ["keyboard", "shortcuts", "productivity", "snippets"], "category": "Utilities", "icon": "keycombiner-icon.png", "icon32": "keycombiner-icon-32.png", @@ -5140,12 +4238,7 @@ "website": "https://kinesis-ci.com", "category": "Business", "repository": "https://github.com/Kinesis-CI/education-and-innovation", - "keywords": [ - "tableau", - "business intelligence", - "testing", - "continuous integration" - ], + "keywords": ["tableau", "business intelligence", "testing", "continuous integration"], "icon": "kinesis-ci-icon.png", "icon32": "kinesis-ci-icon-32.png", "icon64": "kinesis-ci-icon-64.png", @@ -5158,9 +4251,7 @@ "name": "Kitematic", "description": "Run containers through a simple, yet powerful graphical user interface", "website": "https://kitematic.com", - "keywords": [ - "docker" - ], + "keywords": ["docker"], "category": "Developer Tools", "icon": "kitematic-icon.png", "icon32": "kitematic-icon-32.png", @@ -5176,14 +4267,7 @@ "website": "https://www.digimezzo.com", "category": "Productivity", "repository": "https://github.com/digimezzo/knowte-electron", - "keywords": [ - "note", - "notes", - "text", - "organize", - "search", - "quick" - ], + "keywords": ["note", "notes", "text", "organize", "search", "quick"], "license": "GNU General Public License v3.0", "icon": "knowte-icon.png", "icon32": "knowte-icon-32.png", @@ -5197,12 +4281,7 @@ "name": "Kobiton", "description": "A powerful platform that lets you create the perfect test cloud to meet the demands of your mobile teams.", "website": "https://kobiton.com", - "keywords": [ - "testing", - "mobile labs", - "mobile app testing", - "real device testing" - ], + "keywords": ["testing", "mobile labs", "mobile app testing", "real device testing"], "category": "Developer Tools", "icon": "kobiton-icon.png", "icon32": "kobiton-icon-32.png", @@ -5218,12 +4297,7 @@ "website": "https://prsh9.github.io/kubectl-dashboard/", "category": "Developer Tools", "repository": "https://github.com/prsh9/KubeCtl-Dashboard", - "keywords": [ - "kubernetes", - "developer-tools", - "kubectl", - "kubernetes-dashboard" - ], + "keywords": ["kubernetes", "developer-tools", "kubectl", "kubernetes-dashboard"], "license": "MPL-2.0", "icon": "kube-dev-dashboard-icon.png", "icon32": "kube-dev-dashboard-icon-32.png", @@ -5240,13 +4314,7 @@ "category": "Developer Tools", "repository": "https://github.com/pixel-point/kube-forwarder", "homebrewCaskName": "kube-forwarder", - "keywords": [ - "kubectl", - "kubernetes", - "devops", - "k8s", - "port-forwarding" - ], + "keywords": ["kubectl", "kubernetes", "devops", "k8s", "port-forwarding"], "license": "MIT", "icon": "kube-forwarder-icon.png", "icon32": "kube-forwarder-icon-32.png", @@ -5262,13 +4330,7 @@ "website": "https://laradumps.dev", "category": "Developer Tools", "repository": "https://github.com/laradumps/app", - "keywords": [ - "laravel", - "debug", - "php", - "tool", - "livewire" - ], + "keywords": ["laravel", "debug", "php", "tool", "livewire"], "license": "MIT", "icon": "laradumps-icon.png", "icon32": "laradumps-icon-32.png", @@ -5284,11 +4346,7 @@ "website": "https://tmdh.github.io/laravel-kit", "repository": "https://github.com/tmdh/laravel-kit", "homebrewCaskName": "laravel-kit", - "keywords": [ - "laravel", - "kit", - "php" - ], + "keywords": ["laravel", "kit", "php"], "category": "Developer Tools", "icon": "laravel-kit-icon.png", "icon32": "laravel-kit-icon-32.png", @@ -5314,9 +4372,7 @@ "continuous integration", "ci" ], - "locales": [ - "en-US" - ], + "locales": ["en-US"], "icon": "last-hit-icon.png", "icon32": "last-hit-icon-32.png", "icon64": "last-hit-icon-64.png", @@ -5330,10 +4386,7 @@ "description": "Friendly IRC client.", "website": "https://github.com/brandly/Lax", "category": "Social", - "keywords": [ - "chat", - "irc" - ], + "keywords": ["chat", "irc"], "license": "MIT", "icon": "lax-icon.png", "icon32": "lax-icon-32.png", @@ -5348,15 +4401,7 @@ "description": "Software to create aliases for commands, applications to type in cmd.", "website": "https://github.com/ngudbhav/lazyType", "category": "Utilities", - "keywords": [ - "desktop", - "windows", - "utility", - "alias", - "lazy", - "type", - "lazyType" - ], + "keywords": ["desktop", "windows", "utility", "alias", "lazy", "type", "lazyType"], "license": "MIT", "icon": "lazytype-icon.png", "icon32": "lazytype-icon-32.png", @@ -5371,12 +4416,7 @@ "description": "LBRY is a free, open, and community-run digital marketplace. You own your data. You control the network. Indeed, you are the network. Hollywood films, college lessons, amazing streamers and more are on the first media network ruled by you.", "website": "https://lbry.com", "repository": "https://github.com/lbryio/lbry-desktop", - "keywords": [ - "Decentralized", - "LBRY", - "P2P Network", - "Digital Content Platform" - ], + "keywords": ["Decentralized", "LBRY", "P2P Network", "Digital Content Platform"], "license": "MIT", "category": "Entertainment", "icon": "lbry-desktop-icon.png", @@ -5392,16 +4432,8 @@ "description": "Secure image viewer for minimalists.", "repository": "https://github.com/sprout2000/leafview", "license": "MIT", - "keywords": [ - "image", - "viewer", - "pan", - "wheelzoom" - ], - "locales": [ - "en", - "ja-JP" - ], + "keywords": ["image", "viewer", "pan", "wheelzoom"], + "locales": ["en", "ja-JP"], "category": "Photo & Video", "icon": "leafview-icon.png", "icon32": "leafview-icon-32.png", @@ -5416,12 +4448,7 @@ "description": "player for interactive fiction, or text adventure games.", "category": "Games", "repository": "https://github.com/erkyrath/lectrote", - "keywords": [ - "interactive fiction", - "books", - "games", - "RPG" - ], + "keywords": ["interactive fiction", "books", "games", "RPG"], "license": "MIT license", "icon": "lectrote-icon.png", "icon32": "lectrote-icon-32.png", @@ -5436,12 +4463,7 @@ "description": "A distractionless writing tool with auto-complete, a synonyms dictionary, writing statistics, markup-based navigation and a speed-reader.", "website": "https://hundredrabbits.itch.io/left", "repository": "https://hundredrabbits.itch.io/left", - "keywords": [ - "writing", - "text", - "edit", - "markup" - ], + "keywords": ["writing", "text", "edit", "markup"], "category": "Utilities", "icon": "left-icon.png", "icon32": "left-icon-32.png", @@ -5480,9 +4502,7 @@ "name": "Light Table", "description": "The next generation code editor", "website": "http://www.lighttable.com", - "keywords": [ - "code" - ], + "keywords": ["code"], "category": "Developer Tools", "icon": "light-table-icon.png", "icon32": "light-table-icon-32.png", @@ -5498,11 +4518,7 @@ "website": "https://sachinchoolur.github.io/lightgallery-desktop/", "homebrewCaskName": "lightgallery", "repository": "https://github.com/sachinchoolur/lightgallery-desktop", - "keywords": [ - "image", - "photo", - "gallery" - ], + "keywords": ["image", "photo", "gallery"], "license": "MIT", "category": "Photo & Video", "icon": "lightgallery-icon.png", @@ -5518,9 +4534,7 @@ "description": "Open-source web debugging proxy.", "repository": "https://github.com/alibaba/lightproxy", "category": "Developer Tools", - "keywords": [ - "proxy" - ], + "keywords": ["proxy"], "icon": "lightproxy-icon.png", "icon32": "lightproxy-icon-32.png", "icon64": "lightproxy-icon-64.png", @@ -5535,14 +4549,7 @@ "website": "https://uselinked.com/", "category": "Utilities", "repository": "https://github.com/lostdesign/linked", - "keywords": [ - "journal", - "ideas", - "calendar", - "notes", - "diary", - "editor" - ], + "keywords": ["journal", "ideas", "calendar", "notes", "diary", "editor"], "license": "GPL-3.0", "icon": "linked-icon.png", "icon32": "linked-icon-32.png", @@ -5557,12 +4564,7 @@ "description": "Lisk graphical user interface for desktop", "website": "https://lisk.com", "repository": "https://github.com/LiskHQ/lisk-hub", - "keywords": [ - "blockchain", - "cryptocurrency", - "wallet", - "token" - ], + "keywords": ["blockchain", "cryptocurrency", "wallet", "token"], "category": "Finance", "icon": "lisk-hub-icon.png", "icon32": "lisk-hub-icon-32.png", @@ -5578,12 +4580,7 @@ "website": "https://localbyflywheel.com", "category": "Developer Tools", "repository": "https://github.com/getflywheel/local-components", - "keywords": [ - "wordpress", - "flywheel", - "wp-cli", - "wpengine" - ], + "keywords": ["wordpress", "flywheel", "wp-cli", "wpengine"], "youtube_video_url": "https://www.youtube.com/watch?v=M238QnTcnXE", "icon": "local-by-flywheel-icon.png", "icon32": "local-by-flywheel-icon-32.png", @@ -5598,11 +4595,7 @@ "description": "This is simple tool for creating mock API locally.", "category": "Developer Tools", "repository": "https://github.com/jayakumarreddy/Local-Mock-Server/", - "keywords": [ - "mock-api-server", - "front-end", - "api-design" - ], + "keywords": ["mock-api-server", "front-end", "api-design"], "license": "MIT", "icon": "local-mock-server-icon.png", "icon32": "local-mock-server-icon-32.png", @@ -5639,12 +4632,7 @@ "website": "https://logsnag.com", "category": "Developer Tools", "repository": "https://github.com/LogSnag/LogSnag", - "keywords": [ - "notification", - "event", - "logging", - "api" - ], + "keywords": ["notification", "event", "logging", "api"], "icon": "logsnag-icon.png", "icon32": "logsnag-icon-32.png", "icon64": "logsnag-icon-64.png", @@ -5658,13 +4646,7 @@ "description": "Record your screen, share your thoughts, and get things done faster with async video.", "website": "https://www.loom.com", "category": "Developer Tools", - "keywords": [ - "screen recording", - "video", - "communication", - "development", - "4k" - ], + "keywords": ["screen recording", "video", "communication", "development", "4k"], "icon": "loom-icon.png", "icon32": "loom-icon-32.png", "icon64": "loom-icon-64.png", @@ -5677,9 +4659,7 @@ "name": "LosslessCut", "description": "GUI tool for lossless trimming / cutting of videos using ffmpeg", "license": "MIT", - "keywords": [ - "videos" - ], + "keywords": ["videos"], "category": "Photo & Video", "repository": "https://github.com/mifi/lossless-cut", "icon": "losslesscut-icon.png", @@ -5696,16 +4676,7 @@ "website": "https://jisco.me/lot", "category": "Utilities", "repository": "https://github.com/Jisco/LotOfThings", - "keywords": [ - "things", - "organize", - "search", - "find", - "custom", - "stuff", - "manage", - "reminder" - ], + "keywords": ["things", "organize", "search", "find", "custom", "stuff", "manage", "reminder"], "icon": "lot-lot-of-things-icon.png", "icon32": "lot-lot-of-things-icon-32.png", "icon64": "lot-lot-of-things-icon-64.png", @@ -5719,10 +4690,7 @@ "description": "Customizable file manager.", "website": "https://lsdeer.vercel.app/", "repository": "https://github.com/AlexanderPershin/lsdeer", - "keywords": [ - "file", - "file management" - ], + "keywords": ["file", "file management"], "category": "Utilities", "icon": "lsdeer-icon.png", "icon32": "lsdeer-icon-32.png", @@ -5759,12 +4727,7 @@ "name": "MagicCap", "description": "A image capture suite for Mac and Linux.", "repository": "https://github.com/MagicCap/MagicCap", - "keywords": [ - "screenshot", - "upload", - "productivity", - "capture" - ], + "keywords": ["screenshot", "upload", "productivity", "capture"], "category": "Productivity", "icon": "magiccap-icon.png", "icon32": "magiccap-icon-32.png", @@ -5780,13 +4743,7 @@ "website": "https://getmailspring.com/", "category": "Productivity", "repository": "https://github.com/Foundry376/Mailspring", - "keywords": [ - "email", - "mail", - "messaging", - "imap", - "gmail" - ], + "keywords": ["email", "mail", "messaging", "imap", "gmail"], "license": "GPL-3.0", "icon": "mailspring-icon.png", "icon32": "mailspring-icon-32.png", @@ -5802,13 +4759,7 @@ "website": "https://manyver.se", "category": "Social", "repository": "https://gitlab.com/staltz/manyverse", - "keywords": [ - "ssb", - "scuttlebutt", - "decentralized", - "p2p", - "cryptography" - ], + "keywords": ["ssb", "scuttlebutt", "decentralized", "p2p", "cryptography"], "license": "MPL-2.0", "icon": "manyverse-icon.png", "icon32": "manyverse-icon-32.png", @@ -5822,11 +4773,7 @@ "name": "Markdown C3", "description": "A Markdown Editor and Previewer built with Construct 3 and ElectronJs", "repository": "https://github.com/el3um4s/markdown-c3/blob/master/README.md", - "keywords": [ - "markdwown", - "construct3", - "showdownjs" - ], + "keywords": ["markdwown", "construct3", "showdownjs"], "category": "Productivity", "license": "MIT", "icon": "markdown-c3-icon.png", @@ -5842,16 +4789,7 @@ "description": "This is a minimal Markdown Editor desktop app based on Electron.", "website": "https://markdownify.js.org", "repository": "https://github.com/amitmerchant1990/electron-markdownify", - "keywords": [ - "markdown", - "plain", - "node", - "minimal", - "editor", - "preview", - "html", - "desktop" - ], + "keywords": ["markdown", "plain", "node", "minimal", "editor", "preview", "html", "desktop"], "category": "Productivity", "icon": "markdownify-icon.png", "icon32": "markdownify-icon-32.png", @@ -5864,12 +4802,7 @@ "slug": "marktext", "name": "MarkText", "description": "A realtime preview MarkDown Editor", - "keywords": [ - "markdown", - "performance", - "efficiency", - "eidtor" - ], + "keywords": ["markdown", "performance", "efficiency", "eidtor"], "category": "Productivity", "license": "MIT", "repository": "https://github.com/marktext/marktext", @@ -5886,13 +4819,7 @@ "description": "Open source code snippets manager for developers.", "website": "https://masscode.io", "repository": "https://github.com/antonreshetov/massCode", - "keywords": [ - "productivity", - "snippet", - "markdown", - "note", - "code" - ], + "keywords": ["productivity", "snippet", "markdown", "note", "code"], "license": "AGPLv3", "category": "Productivity", "icon": "masscode-icon.png", @@ -5990,9 +4917,7 @@ "video" ], "category": "Productivity", - "locales": [ - "en-EN" - ], + "locales": ["en-EN"], "icon": "media-dupes-icon.png", "icon32": "media-dupes-icon-32.png", "icon64": "media-dupes-icon-64.png", @@ -6057,18 +4982,10 @@ "repository": "https://github.com/feugy/melodie", "license": "MIT", "category": "Music", - "keywords": [ - "music", - "player", - "svelte", - "rxjs", - "desktop" - ], + "keywords": ["music", "player", "svelte", "rxjs", "desktop"], "goodColorOnWhite": "#2e3141", "goodColorOnBlack": "#ffffff", - "locales": [ - "fr-FR" - ], + "locales": ["fr-FR"], "icon": "melodie-icon.png", "icon32": "melodie-icon-32.png", "icon64": "melodie-icon-64.png", @@ -6083,11 +5000,7 @@ "category": "Developer Tools", "repository": "https://github.com/codecentric/merge-request-notifier", "homebrewCaskName": "merge-request-notifier", - "keywords": [ - "gitlab", - "merge-request", - "pull-request" - ], + "keywords": ["gitlab", "merge-request", "pull-request"], "license": "MIT", "icon": "merge-request-notifier-icon.png", "icon32": "merge-request-notifier-icon-32.png", @@ -6128,11 +5041,7 @@ "description": "Highly perfomant, easy to use, minimalistic digital metronome desktop app.", "website": "https://afractal.github.io/metronome-app", "category": "Music", - "keywords": [ - "metronome", - "timer", - "practice" - ], + "keywords": ["metronome", "timer", "practice"], "license": "Proprietary", "goodColorOnWhite": "#343e40", "goodColorOnBlack": "#fafbfc", @@ -6150,9 +5059,7 @@ "description": "Platform that combines workplace chat, meetings, notes, and attachments.", "website": "https://products.office.com/en-us/microsoft-teams/group-chat-software", "license": "Proprietary", - "keywords": [ - "teams" - ], + "keywords": ["teams"], "category": "Business", "icon": "microsoft-teams-icon.png", "icon32": "microsoft-teams-icon-32.png", @@ -6166,9 +5073,7 @@ "name": "Microstockr", "description": "Microstock photography made easy", "website": "https://microstockr.com/", - "keywords": [ - "photography" - ], + "keywords": ["photography"], "category": "Photo & Video", "icon": "microstockr-icon.png", "icon32": "microstockr-icon-32.png", @@ -6183,10 +5088,7 @@ "description": "A smarter web browser", "website": "https://minbrowser.org/", "repository": "https://github.com/minbrowser/min", - "keywords": [ - "browser", - "privacy" - ], + "keywords": ["browser", "privacy"], "license": "Apache 2.0", "category": "Productivity", "icon": "min-icon.png", @@ -6202,14 +5104,7 @@ "description": "Draw effective mind maps in a few minutes.", "website": "https://mindmapp.cedoor.dev/", "repository": "https://github.com/Mindmapp/mindmapp", - "keywords": [ - "map", - "mind", - "mindmapp", - "organization", - "memorise", - "productivity" - ], + "keywords": ["map", "mind", "mindmapp", "organization", "memorise", "productivity"], "license": "MIT", "category": "Productivity", "icon": "mindmapp-icon.png", @@ -6226,26 +5121,9 @@ "website": "https://minidiary.app", "category": "Lifestyle", "repository": "https://github.com/samuelmeuli/mini-diary", - "keywords": [ - "mini", - "diary", - "journal", - "text", - "editor" - ], + "keywords": ["mini", "diary", "journal", "text", "editor"], "license": "MIT", - "locales": [ - "de", - "el", - "en", - "es", - "fr", - "is", - "pt", - "tr", - "uk", - "zh" - ], + "locales": ["de", "el", "en", "es", "fr", "is", "pt", "tr", "uk", "zh"], "icon": "mini-diary-icon.png", "icon32": "mini-diary-icon-32.png", "icon64": "mini-diary-icon-64.png", @@ -6312,10 +5190,7 @@ "name": "Mixmax", "description": "See every action on your emails in real-time. Compose anywhere.", "website": "https://mixmax.com/download", - "keywords": [ - "email", - "analytics" - ], + "keywords": ["email", "analytics"], "category": "Productivity", "icon": "mixmax-icon.png", "icon32": "mixmax-icon-32.png", @@ -6330,10 +5205,7 @@ "description": "Desktop wrapper around mjml language", "website": "https://mjmlio.github.io/mjml-app/", "repository": "https://github.com/mjmlio/mjml-app", - "keywords": [ - "mjml", - "email" - ], + "keywords": ["mjml", "email"], "category": "Productivity", "icon": "mjml-app-icon.png", "icon32": "mjml-app-icon-32.png", @@ -6349,12 +5221,7 @@ "youtube_video_url": "https://www.youtube.com/watch?v=76MBKJrMEn0", "website": "https://www.mobilelocker.com/", "category": "Business", - "keywords": [ - "sales", - "sales enablement", - "CRM", - "marketing" - ], + "keywords": ["sales", "sales enablement", "CRM", "marketing"], "icon": "mobile-locker-icon.png", "icon32": "mobile-locker-icon-32.png", "icon64": "mobile-locker-icon-64.png", @@ -6369,11 +5236,7 @@ "website": "https://mobirise.com/", "repository": "https://github.com/Mobirise/Mobirise", "category": "Developer Tools", - "keywords": [ - "website builder", - "free website builder", - "free bootstrap builder" - ], + "keywords": ["website builder", "free website builder", "free bootstrap builder"], "icon": "mobirise-icon.png", "icon32": "mobirise-icon-32.png", "icon64": "mobirise-icon-64.png", @@ -6388,13 +5251,7 @@ "website": "https://mockoon.com", "category": "Developer Tools", "repository": "https://github.com/255kb/mockoon", - "keywords": [ - "api", - "rest", - "server", - "mock", - "mocking" - ], + "keywords": ["api", "rest", "server", "mock", "mocking"], "icon": "mockoon-icon.png", "icon32": "mockoon-icon-32.png", "icon64": "mockoon-icon-64.png", @@ -6410,12 +5267,7 @@ "website": "https://moderndeck.org/", "repository": "https://github.com/dangeredwolf/ModernDeck", "license": "MIT", - "keywords": [ - "moderndeck", - "tweetdeck", - "twitter", - "tweet" - ], + "keywords": ["moderndeck", "tweetdeck", "twitter", "tweet"], "locales": [ "bg", "cs", @@ -6475,13 +5327,7 @@ "name": "MongoDB Compass", "description": "The MongoDB GUI", "website": "https://mongodb.com/compass", - "keywords": [ - "mongodb", - "database", - "gui", - "admin", - "management" - ], + "keywords": ["mongodb", "database", "gui", "admin", "management"], "category": "Developer Tools", "icon": "mongodb-compass-icon.png", "icon32": "mongodb-compass-icon-32.png", @@ -6495,14 +5341,7 @@ "name": "Mongomix", "description": "Simple MongoDB GUI Shell.", "website": "https://mongomix.sigma-solutions.fr", - "keywords": [ - "mongodb", - "database", - "gui", - "management", - "editor", - "browser" - ], + "keywords": ["mongodb", "database", "gui", "management", "editor", "browser"], "category": "Productivity", "license": "Freeware (see https://mongomix.sigma-solutions.fr/license.txt)", "icon": "mongomix-icon.png", @@ -6521,12 +5360,7 @@ "license": "MIT", "repository": "https://github.com/kubeshop/monokle", "youtube_video_url": "https://www.youtube.com/watch?v=9c80qj9NkQk&t=3s", - "keywords": [ - "Kubernetes", - "Helm", - "Kustomize", - "Validation" - ], + "keywords": ["Kubernetes", "Helm", "Kustomize", "Validation"], "icon": "monokle-icon.png", "icon32": "monokle-icon-32.png", "icon64": "monokle-icon-64.png", @@ -6564,13 +5398,7 @@ "website": "https://moosync.app", "category": "Music", "repository": "https://github.com/Moosync/Moosync", - "keywords": [ - "music", - "musicplayer", - "themes", - "customizable", - "extension" - ], + "keywords": ["music", "musicplayer", "themes", "customizable", "extension"], "license": "GPL-3.0", "icon": "moosync-icon.png", "icon32": "moosync-icon-32.png", @@ -6639,13 +5467,7 @@ "description": "Music Streaming Server", "website": "https://mstream.io/", "repository": "https://github.com/IrosTheBeggar/mStream", - "keywords": [ - "music", - "streaming", - "server", - "audio", - "selfhosted" - ], + "keywords": ["music", "streaming", "server", "audio", "selfhosted"], "license": "GPL-3.0", "category": "Music", "icon": "mstream-icon.png", @@ -6686,10 +5508,7 @@ "name": "Multiple File Manager", "description": "Modify your multiple files. Available for Windows, Linux, and macOS", "repository": "https://github.com/dhanyn10/multiple-file-manager", - "keywords": [ - "file", - "file management" - ], + "keywords": ["file", "file management"], "license": "MIT", "category": "Utilities", "icon": "multiple-file-manager-icon.png", @@ -6705,14 +5524,7 @@ "description": "Organize multiple apps in tabs!", "category": "Productivity", "repository": "https://github.com/sentialx/multrin", - "keywords": [ - "windows", - "organizer", - "tabs", - "material", - "typescript", - "react" - ], + "keywords": ["windows", "organizer", "tabs", "material", "typescript", "react"], "license": "MIT", "icon": "multrin-icon.png", "icon32": "multrin-icon-32.png", @@ -6727,11 +5539,7 @@ "description": "A simple, clean and cross-platform music player", "website": "https://museeks.io/", "repository": "https://github.com/martpie/museeks", - "keywords": [ - "music", - "audio", - "music player" - ], + "keywords": ["music", "audio", "music player"], "license": "MIT", "category": "Music", "icon": "museeks-icon.png", @@ -6747,14 +5555,7 @@ "description": "Open-Source Audio Player that supports a variety of formats", "website": "https://aveek-saha.github.io/", "repository": "https://github.com/Aveek-Saha/MusicPlayer", - "keywords": [ - "audio", - "music", - "song", - "album", - "mp3", - "audiophile" - ], + "keywords": ["audio", "music", "song", "album", "mp3", "audiophile"], "category": "Music", "icon": "music-player-icon.png", "icon32": "music-player-icon-32.png", @@ -6769,10 +5570,7 @@ "description": "a lottery software based on Electron and Angular", "website": "https://gitee.com/gemron/myLottery/blob/master/README.md", "repository": "https://gitee.com/gemron/myLottery", - "keywords": [ - "lottery", - "Angular" - ], + "keywords": ["lottery", "Angular"], "license": "MIT", "category": "Entertainment", "icon": "mylottery-icon.png", @@ -6787,10 +5585,7 @@ "name": "MyTools", "description": "Set of tools for developers.", "repository": "https://github.com/hiql/mytools-desktop", - "keywords": [ - "utility", - "tools" - ], + "keywords": ["utility", "tools"], "category": "Developer Tools", "license": "MIT", "icon": "mytools-icon.png", @@ -6866,13 +5661,7 @@ "name": "NetworkAssembler", "description": "GUI for creating neural networks.", "repository": "https://github.com/kir486680/Network-Assembler", - "keywords": [ - "deep-learning", - "keras", - "machine-learning", - "tensorflow", - "pytorch" - ], + "keywords": ["deep-learning", "keras", "machine-learning", "tensorflow", "pytorch"], "category": "Productivity", "icon": "network-assembler-icon.png", "icon32": "network-assembler-icon-32.png", @@ -6887,10 +5676,7 @@ "description": "Calculate with neumorphism UI and enjoy.", "category": "Utilities", "repository": "https://github.com/moh3n9595/neu-calculator", - "keywords": [ - "neumorphism", - "calculator" - ], + "keywords": ["neumorphism", "calculator"], "license": "MIT", "icon": "neucalculator-icon.png", "icon32": "neucalculator-icon-32.png", @@ -6930,15 +5716,7 @@ "repository": "https://github.com/nimblenote/nimblenote", "snapcraftName": "nimblenote", "category": "Productivity", - "keywords": [ - "notes", - "note taking", - "todo", - "markdown", - "react", - "tasks", - "keyboard" - ], + "keywords": ["notes", "note taking", "todo", "markdown", "react", "tasks", "keyboard"], "icon": "nimblenote-icon.png", "icon32": "nimblenote-icon-32.png", "icon64": "nimblenote-icon-64.png", @@ -6952,13 +5730,7 @@ "description": "SVG icon manager with multi-color editing.", "website": "https://norde.io", "category": "Graphics & Design", - "keywords": [ - "SVG", - "Icons", - "Design", - "Development", - "Productivity" - ], + "keywords": ["SVG", "Icons", "Design", "Development", "Productivity"], "icon": "norde-source-icon.png", "icon32": "norde-source-icon-32.png", "icon64": "norde-source-icon-64.png", @@ -6972,14 +5744,7 @@ "description": "RSS Feed Reader created with love and determination of progression in a pioneer world of digital media.", "website": "https://northreader.futureglobe.de/", "category": "News", - "keywords": [ - "reader", - "feed reader", - "rss reader", - "news reader", - "reading", - "news" - ], + "keywords": ["reader", "feed reader", "rss reader", "news reader", "reading", "news"], "icon": "northreader-icon.png", "icon32": "northreader-icon-32.png", "icon64": "northreader-icon-64.png", @@ -7021,15 +5786,7 @@ "description": "The Markdown-based note-taking app that doesn't suck.", "website": "https://notable.app", "repository": "https://github.com/notable/notable", - "keywords": [ - "notes", - "markdown", - "note taking", - "cross-platform", - "linux", - "mac", - "windows" - ], + "keywords": ["notes", "markdown", "note taking", "cross-platform", "linux", "mac", "windows"], "category": "Productivity", "icon": "notable-icon.png", "icon32": "notable-icon-32.png", @@ -7068,15 +5825,7 @@ "description": "A new editor that blends notes, tasks, wikis in one app.", "website": "https://www.notion.so/", "category": "Productivity", - "keywords": [ - "notes", - "tasks", - "wikis", - "kanban", - "spreadsheet", - "database", - "collaboration" - ], + "keywords": ["notes", "tasks", "wikis", "kanban", "spreadsheet", "database", "collaboration"], "icon": "notion-icon.png", "icon32": "notion-icon-32.png", "icon64": "notion-icon-64.png", @@ -7090,12 +5839,7 @@ "description": "Interactive literate coding notebook", "website": "https://nteract.io/", "repository": "https://github.com/nteract/nteract", - "keywords": [ - "jupyter", - "notebook", - "nteract", - "data" - ], + "keywords": ["jupyter", "notebook", "nteract", "data"], "license": "BSD-3-Clause", "category": "Productivity", "icon": "nteract-icon.png", @@ -7111,14 +5855,7 @@ "description": "Multiplatform music player that streams from multiple sources", "website": "https://nuclearplayer.com/", "repository": "https://github.com/nukeop/nuclear", - "keywords": [ - "music", - "player", - "stream", - "Youtube", - "last.fm", - "desktop" - ], + "keywords": ["music", "player", "stream", "Youtube", "last.fm", "desktop"], "license": "GPL-3.0", "category": "Music", "icon": "nuclear-icon.png", @@ -7133,9 +5870,7 @@ "name": "Nuclide", "description": "A unified developer experience for web and mobile development", "website": "https://nuclide.io/", - "keywords": [ - "developer" - ], + "keywords": ["developer"], "category": "Developer Tools", "icon": "nuclide-icon.png", "icon32": "nuclide-icon-32.png", @@ -7171,11 +5906,7 @@ "name": "Obsidian", "description": "Knowledge base that works on local Markdown files.", "website": "https://obsidian.md/", - "keywords": [ - "markdown", - "productivity", - "knowledge base" - ], + "keywords": ["markdown", "productivity", "knowledge base"], "category": "Productivity", "icon": "obsidian-icon.png", "icon32": "obsidian-icon-32.png", @@ -7189,13 +5920,7 @@ "name": "ODrive", "description": "Unofficial Google Drive app.", "repository": "https://github.com/liberodark/ODrive", - "keywords": [ - "google", - "drive", - "cloud", - "sync", - "google drive" - ], + "keywords": ["google", "drive", "cloud", "sync", "google drive"], "license": "GPL v3", "category": "Productivity", "icon": "odrive-icon.png", @@ -7211,9 +5936,7 @@ "description": "Web browser build for users who want a different experience.", "website": "https://ohhaibrowser.com", "repository": "https://github.com/OhHaiBrowser/Browser/", - "keywords": [ - "browser" - ], + "keywords": ["browser"], "category": "Productivity", "icon": "ohhai-browser-icon.png", "icon32": "ohhai-browser-icon-32.png", @@ -7227,10 +5950,7 @@ "name": "One Copy", "description": "Save all information and paste them whenever you need them.", "website": "https://github.com/HiroshiFuu/onecopy-electron", - "keywords": [ - "clipboard", - "password-manager" - ], + "keywords": ["clipboard", "password-manager"], "category": "Utilities", "icon": "onecopy-icon.png", "icon32": "onecopy-icon-32.png", @@ -7244,18 +5964,9 @@ "name": "OOMOL Studio", "description": "Makes it easy to connect code snippets and API services through intuitive visual interactions.", "website": "https://oomol.com/", - "keywords": [ - "developer", - "developer tools", - "workflow", - "ide", - "editor" - ], + "keywords": ["developer", "developer tools", "workflow", "ide", "editor"], "category": "Utilities", - "locales": [ - "en-US", - "zh-CN" - ], + "locales": ["en-US", "zh-CN"], "icon": "oomol-studio-icon.png", "icon32": "oomol-studio-icon-32.png", "icon64": "oomol-studio-icon-64.png", @@ -7269,12 +5980,7 @@ "description": "A multi-platform log viewer built with Electron and styled with Material Design", "category": "Developer Tools", "repository": "https://github.com/tmoreno/open-log-viewer", - "keywords": [ - "log", - "viewer", - "tail", - "vue" - ], + "keywords": ["log", "viewer", "tail", "vue"], "license": "GPL-3.0", "icon": "open-log-viewer-icon.png", "icon32": "open-log-viewer-icon-32.png", @@ -7288,12 +5994,7 @@ "name": "Open Stage Control", "description": "Libre and modular OSC / MIDI control surface", "website": "https://openstagecontrol.ammd.net", - "keywords": [ - "music", - "controller", - "osc", - "midi" - ], + "keywords": ["music", "controller", "osc", "midi"], "category": "Music", "license": "GNU/GPLv3", "goodColorOnBlack": "#52a8ff", @@ -7312,21 +6013,10 @@ "description": "Comic and manga reader.", "repository": "https://github.com/ollm/OpenComic", "snapcraftName": "opencomic", - "keywords": [ - "comic", - "manga", - "cbr", - "cbz", - "cb7" - ], + "keywords": ["comic", "manga", "cbr", "cbz", "cb7"], "license": "GPL-3.0", "category": "Books", - "locales": [ - "en", - "es", - "en-US", - "es-ES" - ], + "locales": ["en", "es", "en-US", "es-ES"], "icon": "opencomic-icon.png", "icon32": "opencomic-icon-32.png", "icon64": "opencomic-icon-64.png", @@ -7340,11 +6030,7 @@ "description": "Translate text directly from your menubar.", "website": "https://4gray.github.io/oversetter/", "repository": "https://github.com/4gray/oversetter", - "keywords": [ - "translator", - "menubar", - "language" - ], + "keywords": ["translator", "menubar", "language"], "license": "MIT", "category": "Utilities", "icon": "oversetter-icon.png", @@ -7360,10 +6046,7 @@ "description": "A Linux compatible version of OneNote.", "repository": "https://github.com/patrikx3/onenote", "website": "https://www.corifeus.com/onenote", - "keywords": [ - "onenote", - "linux" - ], + "keywords": ["onenote", "linux"], "license": "MIT", "category": "Productivity", "icon": "p3x-onenote-icon.png", @@ -7379,15 +6062,7 @@ "description": "A very functional handy database GUI and works in your pocket on the responsive web or as a desktop app.", "repository": "https://github.com/patrikx3/redis-ui", "website": "https://www.corifeus.com/redis-ui", - "keywords": [ - "redis", - "ui", - "admin", - "gui", - "dark", - "theme", - "internationalization" - ], + "keywords": ["redis", "ui", "admin", "gui", "dark", "theme", "internationalization"], "license": "MIT", "category": "Developer Tools", "icon": "p3x-redis-ui-icon.png", @@ -7402,12 +6077,7 @@ "name": "PamFax", "description": "A cross-platform app for sending and receiving faxes", "website": "https://www.pamfax.biz", - "keywords": [ - "fax", - "productivity", - "communication", - "utility" - ], + "keywords": ["fax", "productivity", "communication", "utility"], "category": "Productivity", "icon": "pamfax-icon.png", "icon32": "pamfax-icon-32.png", @@ -7422,14 +6092,7 @@ "description": "Markdown editor with pandoc integration and preview.", "website": "https://panwriter.com", "repository": "https://github.com/mb21/panwriter", - "keywords": [ - "markdown", - "pandoc", - "cross-platform", - "linux", - "mac", - "windows" - ], + "keywords": ["markdown", "pandoc", "cross-platform", "linux", "mac", "windows"], "category": "Productivity", "icon": "panwriter-icon.png", "icon32": "panwriter-icon-32.png", @@ -7444,13 +6107,7 @@ "description": "A new paper management tool.", "category": "Education", "repository": "https://github.com/fuzihaofzh/PaperArxiv", - "keywords": [ - "Research", - "Paper Management", - "Markdown", - "LaTeX", - "Mermaid" - ], + "keywords": ["Research", "Paper Management", "Markdown", "LaTeX", "Mermaid"], "icon": "paperarxiv-icon.png", "icon32": "paperarxiv-icon-32.png", "icon64": "paperarxiv-icon-64.png", @@ -7464,11 +6121,7 @@ "description": "An App which converts your minecraft .schematic files into blueprints for papercraft", "category": "Games", "repository": "https://github.com/FlorianFe/PaperCubes", - "keywords": [ - "minecraft", - "printing", - "papercraft" - ], + "keywords": ["minecraft", "printing", "papercraft"], "icon": "papercubes-icon.png", "icon32": "papercubes-icon-32.png", "icon64": "papercubes-icon-64.png", @@ -7481,12 +6134,7 @@ "name": "Papyrus", "description": "Unofficial Dropbox Paper app", "repository": "https://github.com/morkro/papyrus", - "keywords": [ - "dropbox", - "paper", - "notes", - "file sharing" - ], + "keywords": ["dropbox", "paper", "notes", "file sharing"], "license": "MIT", "category": "Productivity", "icon": "papyrus-icon.png", @@ -7502,19 +6150,9 @@ "description": "Extendable notepad calculator for the 21st Century.", "website": "https://parsify.app", "category": "Utilities", - "keywords": [ - "calculator", - "notepad", - "soulver", - "numi", - "calca" - ], + "keywords": ["calculator", "notepad", "soulver", "numi", "calca"], "homebrewCaskName": "parsify", - "locales": [ - "en-US", - "pl-PL", - "ua-UA" - ], + "locales": ["en-US", "pl-PL", "ua-UA"], "icon": "parsify-desktop-icon.png", "icon32": "parsify-desktop-icon-32.png", "icon64": "parsify-desktop-icon-64.png", @@ -7527,9 +6165,7 @@ "name": "Particle Dev", "description": "A professional IDE for Particle", "website": "https://www.particle.io/dev", - "keywords": [ - "IDE" - ], + "keywords": ["IDE"], "category": "Developer Tools", "icon": "particle-dev-icon.png", "icon32": "particle-dev-icon-32.png", @@ -7544,12 +6180,7 @@ "description": "Simple and secure password manager.", "website": "https://passky.org", "repository": "https://github.com/Rabbit-Company/Passky-Desktop", - "keywords": [ - "passky", - "password", - "passwords", - "manager" - ], + "keywords": ["passky", "password", "passwords", "manager"], "license": "GPL-3.0", "snapcraftName": "passky", "category": "Utilities", @@ -7639,12 +6270,7 @@ "description": "Share your files with peer-to-peer technology, simply.", "category": "Utilities", "repository": "https://github.com/connor-davis/peershare", - "keywords": [ - "p2p", - "hypercore", - "hyperswarm", - "filesharing" - ], + "keywords": ["p2p", "hypercore", "hyperswarm", "filesharing"], "license": "GPL-3.0", "icon": "peershare-icon.png", "icon32": "peershare-icon-32.png", @@ -7659,14 +6285,7 @@ "description": "A free and open-source tool for making diagrams and GUI prototyping", "website": "https://pencil.evolus.vn/", "repository": "https://github.com/evolus/pencil", - "keywords": [ - "prototyping", - "ui", - "mockup", - "design", - "drawing", - "sketch" - ], + "keywords": ["prototyping", "ui", "mockup", "design", "drawing", "sketch"], "license": "GPL 2", "category": "Productivity", "icon": "pencil-icon.png", @@ -7718,13 +6337,7 @@ "category": "Productivity", "homebrewCaskName": "pennywise", "license": "MIT", - "keywords": [ - "pennywise", - "floating window", - "video player", - "browser", - "multitasking" - ], + "keywords": ["pennywise", "floating window", "video player", "browser", "multitasking"], "icon": "pennywise-icon.png", "icon32": "pennywise-icon-32.png", "icon64": "pennywise-icon-64.png", @@ -7737,12 +6350,7 @@ "name": "Petal", "description": "Douban.FM Client With Extra - - -", "repository": "https://github.com/ilime/Petal", - "keywords": [ - "Douban.FM", - "Douban", - "FM", - "Music Desktop Player" - ], + "keywords": ["Douban.FM", "Douban", "FM", "Music Desktop Player"], "license": "MIT", "category": "Music", "icon": "petal-icon.png", @@ -7802,10 +6410,7 @@ "slug": "photoscreensaver", "name": "PhotoScreenSaver", "description": "Windows screen saver that displays a photo slideshow", - "keywords": [ - "screensaver", - "photography" - ], + "keywords": ["screensaver", "photography"], "license": "MIT", "category": "Photo & Video", "repository": "https://github.com/RandScullard/photo-screen-saver", @@ -7822,9 +6427,7 @@ "description": "App to crop images.", "category": "Photo & Video", "repository": "https://github.com/ujw0l/pic-crop", - "keywords": [ - "Image crop" - ], + "keywords": ["Image crop"], "license": "MIT", "icon": "pic-crop-icon.png", "icon32": "pic-crop-icon-32.png", @@ -7839,14 +6442,7 @@ "description": "Digital image organizer powered by the web.", "website": "https://picturama.github.io/", "repository": "https://github.com/picturama/picturama", - "keywords": [ - "image", - "photo", - "photography", - "gallery", - "editing", - "photo-manager" - ], + "keywords": ["image", "photo", "photography", "gallery", "editing", "photo-manager"], "license": "MIT", "category": "Photo & Video", "goodColorOnWhite": "#37474f", @@ -7865,11 +6461,7 @@ "website": "https://ozankaraali.com/PiTV/", "category": "Entertainment", "repository": "https://github.com/ozankaraali/PiTV", - "keywords": [ - "iptv", - "stb", - "player" - ], + "keywords": ["iptv", "stb", "player"], "license": "MIT", "icon": "pitv-icon.png", "icon32": "pitv-icon-32.png", @@ -7882,11 +6474,7 @@ "slug": "playback", "name": "Playback", "description": "Experimental video player", - "keywords": [ - "video", - "player", - "audio" - ], + "keywords": ["video", "player", "audio"], "category": "Photo & Video", "repository": "https://github.com/mafintosh/playback", "icon": "playback-icon.png", @@ -7900,12 +6488,7 @@ "slug": "playcode", "name": "PlayCode", "description": "Desktop client for Playcode Online Javascript Editor", - "keywords": [ - "playcode", - "editor", - "developer tools", - "mac" - ], + "keywords": ["playcode", "editor", "developer tools", "mac"], "license": "GPL-v3", "category": "Developer Tools", "repository": "https://github.com/playcode/playcode-desktop", @@ -7922,12 +6505,7 @@ "description": "Podcast client to listen to all you favorite podcasts.", "repository": "https://github.com/MrChuckomo/poddycast", "category": "Entertainment", - "keywords": [ - "podcast", - "feed", - "rss", - "itunes" - ], + "keywords": ["podcast", "feed", "rss", "itunes"], "icon": "poddycast-app-icon.png", "icon32": "poddycast-app-icon-32.png", "icon64": "poddycast-app-icon-64.png", @@ -7941,11 +6519,7 @@ "description": "A browser for web-based game kantai-collection", "website": "https://poi.moe", "repository": "https://github.com/poooi/poi", - "keywords": [ - "kantai-collection", - "kancolle", - "games" - ], + "keywords": ["kantai-collection", "kancolle", "games"], "license": "MIT", "category": "Games", "icon": "poi-icon.png", @@ -7960,14 +6534,7 @@ "name": "Polypane", "description": "The browser for building great web experiences.", "website": "https://polypane.app", - "keywords": [ - "browser", - "frontend", - "development", - "responsive", - "design", - "testing" - ], + "keywords": ["browser", "frontend", "development", "responsive", "design", "testing"], "category": "Developer Tools", "icon": "polypane-icon.png", "icon32": "polypane-icon-32.png", @@ -8012,15 +6579,7 @@ "name": "Postbird", "description": "PostgreSQL GUI client", "repository": "https://github.com/Paxa/postbird", - "keywords": [ - "postgresql", - "postgres", - "sql", - "database", - "developer", - "heroku", - "csv" - ], + "keywords": ["postgresql", "postgres", "sql", "database", "developer", "heroku", "csv"], "category": "Developer Tools", "license": "MIT", "icon": "postbird-icon.png", @@ -8035,9 +6594,7 @@ "name": "Postman", "description": "API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.", "website": "https://www.getpostman.com/", - "keywords": [ - "developer" - ], + "keywords": ["developer"], "category": "Developer Tools", "icon": "postman-icon.png", "icon32": "postman-icon-32.png", @@ -8053,13 +6610,7 @@ "website": "https://premid.app/", "category": "Utilities", "repository": "https://github.com/PreMiD/PreMiD", - "keywords": [ - "Discord", - "Rich Presence", - "Website", - "Service", - "integration" - ], + "keywords": ["Discord", "Rich Presence", "Website", "Service", "integration"], "license": "MPL 2.0", "locales": [ "ar", @@ -8095,12 +6646,7 @@ "slug": "preserver", "name": "Preserver", "description": "Notes organizer", - "keywords": [ - "notes", - "keep", - "record", - "data" - ], + "keywords": ["notes", "keep", "record", "data"], "category": "Productivity", "repository": "https://github.com/hsbalar/Preserver", "icon": "preserver-icon.png", @@ -8115,9 +6661,7 @@ "name": "Presets.io", "description": "Easy preset management for Adobe Lightroom", "website": "https://presets.io", - "keywords": [ - "photo" - ], + "keywords": ["photo"], "category": "Photo & Video", "icon": "presets-io-icon.png", "icon32": "presets-io-icon-32.png", @@ -8133,13 +6677,7 @@ "website": "https://prettyearth.evertdespiegeleer.com/", "repository": "https://github.com/evertdespiegeleer/PrettyEarth", "category": "Utilities", - "keywords": [ - "mac", - "wallpaper", - "earthview", - "satellite", - "images" - ], + "keywords": ["mac", "wallpaper", "earthview", "satellite", "images"], "icon": "prettyearth-icon.png", "icon32": "prettyearth-icon-32.png", "icon64": "prettyearth-icon-64.png", @@ -8201,11 +6739,7 @@ "name": "primitive.nextgen", "description": "Tool to redraw images using shapes (triangles, rectangles ...)", "repository": "https://github.com/cielito-lindo-productions/primitive.nextgen", - "keywords": [ - "image", - "redraw", - "Tool" - ], + "keywords": ["image", "redraw", "Tool"], "license": "MIT", "category": "Photo & Video", "icon": "primitive-nextgen-icon.png", @@ -8220,14 +6754,8 @@ "name": "ProDoctor Medicamentos", "description": "Look up medicines, read their information leaflets and find alternatives.", "website": "https://prodoctor.net/medicamentos", - "keywords": [ - "ProDoctor Software", - "Drugs Information Leaflet", - "Medicine" - ], - "locales": [ - "pt-BR" - ], + "keywords": ["ProDoctor Software", "Drugs Information Leaflet", "Medicine"], + "locales": ["pt-BR"], "category": "Science & Medicine", "icon": "prodoctor-medicamentos-icon.png", "icon32": "prodoctor-medicamentos-icon-32.png", @@ -8241,9 +6769,7 @@ "name": "Proposales", "description": "Create, deliver and monitor business proposals online", "website": "https://www.proposales.com/", - "keywords": [ - "business" - ], + "keywords": ["business"], "category": "Business", "icon": "proposales-icon.png", "icon32": "proposales-icon-32.png", @@ -8290,10 +6816,7 @@ "description": "API client for protobuf over http.", "category": "Developer Tools", "repository": "https://github.com/spluxx/protoman", - "keywords": [ - "protocol-buffers", - "api-client" - ], + "keywords": ["protocol-buffers", "api-client"], "license": "MIT", "icon": "protoman-icon.png", "icon32": "protoman-icon-32.png", @@ -8327,11 +6850,7 @@ "name": "Pullp", "description": "Dashboard for monitoring pull requests and reviews across your Github repos.", "repository": "https://github.com/rkclark/pullp", - "keywords": [ - "dashboard", - "github", - "developer" - ], + "keywords": ["dashboard", "github", "developer"], "license": "MIT", "category": "Developer Tools", "icon": "pullp-icon.png", @@ -8360,9 +6879,7 @@ "license": "MIT", "snapcraftName": "puppetry", "youtube_video_url": "https://www.youtube.com/watch?v=4DLnak6qU68", - "locales": [ - "en-US" - ], + "locales": ["en-US"], "icon": "puppetry-icon.png", "icon32": "puppetry-icon-32.png", "icon64": "puppetry-icon-64.png", @@ -8375,13 +6892,7 @@ "name": "Putler", "description": "Meaningful e-commerce analytics for online businesses", "website": "https://putler.com", - "keywords": [ - "analytics", - "reporting", - "e-commerce", - "business", - "growth" - ], + "keywords": ["analytics", "reporting", "e-commerce", "business", "growth"], "category": "Business", "goodColorOnWhite": "#6016e9", "icon": "putler-icon.png", @@ -8423,15 +6934,7 @@ "description": "Quran reader that combines the time-tested mushaf with digital convenience.", "website": "https://qawl.navedislam.com", "repository": "https://github.com/sufone/qawl", - "keywords": [ - "islam", - "quran", - "religion", - "faith", - "mushaf", - "book", - "muslim" - ], + "keywords": ["islam", "quran", "religion", "faith", "mushaf", "book", "muslim"], "category": "Education", "youtube_video_url": "https://www.youtube.com/watch?v=EWtOurhTzqo", "icon": "qawl-icon.png", @@ -8447,12 +6950,7 @@ "description": "Minimal app that creates QR codes.", "category": "Utilities", "repository": "https://github.com/deep5050/qikQR", - "keywords": [ - "qr", - "qrcodes", - "qrcode", - "qr-code" - ], + "keywords": ["qr", "qrcodes", "qrcode", "qr-code"], "license": "MIT", "icon": "qikqr-icon.png", "icon32": "qikqr-icon-32.png", @@ -8465,9 +6963,7 @@ "slug": "quail", "name": "Quail", "description": "Unofficial esa.io app", - "keywords": [ - "productivity" - ], + "keywords": ["productivity"], "category": "Productivity", "repository": "https://github.com/1000ch/quail", "icon": "quail-icon.png", @@ -8484,11 +6980,7 @@ "website": "https://quarkjs.io", "repository": "https://github.com/Nishkalkashyap/Quark-electron", "category": "Developer Tools", - "keywords": [ - "quark", - "serialport", - "prototyping" - ], + "keywords": ["quark", "serialport", "prototyping"], "icon": "quark-icon.png", "icon32": "quark-icon-32.png", "icon64": "quark-icon-64.png", @@ -8503,16 +6995,7 @@ "website": "https://quba-viewer.org/", "category": "Business", "repository": "https://github.com/ZUGFeRD/quba-viewer", - "keywords": [ - "invoice", - "viewer", - "order", - "PDF", - "XML", - "Factur-X", - "ZUGFeRD", - "XRechnung" - ], + "keywords": ["invoice", "viewer", "order", "PDF", "XML", "Factur-X", "ZUGFeRD", "XRechnung"], "license": "Apache Public License 2.0", "icon": "quba-e-invoice-viewer-icon.png", "icon32": "quba-e-invoice-viewer-icon-32.png", @@ -8527,11 +7010,7 @@ "description": "Desktop app for QuickBooks Online.", "website": "https://quickbooks.intuit.com/desktop/", "category": "Business", - "keywords": [ - "business", - "accounting", - "invoicing" - ], + "keywords": ["business", "accounting", "invoicing"], "icon": "quickbooks-icon.png", "icon32": "quickbooks-icon-32.png", "icon64": "quickbooks-icon-64.png", @@ -8545,16 +7024,7 @@ "description": "Todo list r2e-todoworks, which can create sticky notes with emoji status.", "category": "Productivity", "repository": "https://github.com/tuantvk/r2e-todoworks", - "keywords": [ - "todos", - "tasks", - "lists", - "todo", - "reminders", - "checklist", - "note", - "timemanage" - ], + "keywords": ["todos", "tasks", "lists", "todo", "reminders", "checklist", "note", "timemanage"], "license": "MIT", "icon": "r2e-todoworks-icon.png", "icon32": "r2e-todoworks-icon-32.png", @@ -8584,9 +7054,7 @@ "Windows", "Win" ], - "locales": [ - "en_US" - ], + "locales": ["en_US"], "category": "Utilities", "icon": "r6rc-icon.png", "icon32": "r6rc-icon-32.png", @@ -8637,9 +7105,7 @@ ], "license": "PRIVATE", "category": "Music", - "locales": [ - "fr-FR" - ], + "locales": ["fr-FR"], "icon": "radio5050-icon.png", "icon32": "radio5050-icon-32.png", "icon64": "radio5050-icon-64.png", @@ -8655,9 +7121,7 @@ "category": "Utilities", "repository": "https://github.com/HarshKhandeparkar/rainbow-board", "snapcraftName": "rainbow-board", - "keywords": [ - "whiteboard" - ], + "keywords": ["whiteboard"], "license": "MIT", "icon": "rainbow-board-icon.png", "icon32": "rainbow-board-icon-32.png", @@ -8703,14 +7167,7 @@ "description": "Simple RSS Reader for desktop without any distraction.", "repository": "https://github.com/hello-efficiency-inc/raven-reader", "license": "MIT", - "keywords": [ - "reader", - "feed reader", - "rss reader", - "news reader", - "reading", - "news" - ], + "keywords": ["reader", "feed reader", "rss reader", "news reader", "reading", "news"], "category": "News", "icon": "raven-reader-icon.png", "icon32": "raven-reader-icon-32.png", @@ -8725,10 +7182,7 @@ "description": "Simple RSS feed based podcast player", "category": "Entertainment", "repository": "https://github.com/SolarFloss/Reach-Podcast-Player", - "keywords": [ - "Podcast", - "MP3" - ], + "keywords": ["Podcast", "MP3"], "license": "GPL-3.0", "icon": "reach-podcast-player-icon.png", "icon32": "reach-podcast-player-icon-32.png", @@ -8743,17 +7197,9 @@ "description": "Simple & Fast File Manager for Windows, Mac & Linux.", "category": "Utilities", "repository": "https://github.com/warpdesign/react-explorer", - "keywords": [ - "file", - "explorer", - "react", - "blueprintjs", - "typescript" - ], + "keywords": ["file", "explorer", "react", "blueprintjs", "typescript"], "license": "MIT", - "locales": [ - "fr-FR" - ], + "locales": ["fr-FR"], "icon": "react-explorer-icon.png", "icon32": "react-explorer-icon-32.png", "icon64": "react-explorer-icon-64.png", @@ -8791,17 +7237,8 @@ "website": "https://murgatt.github.io/recode-converter/", "category": "Photo & Video", "repository": "https://github.com/murgatt/recode-converter", - "keywords": [ - "converter", - "audio converter", - "video converter", - "audio codec", - "ffmpeg" - ], - "locales": [ - "en-US", - "fr-FR" - ], + "keywords": ["converter", "audio converter", "video converter", "audio codec", "ffmpeg"], + "locales": ["en-US", "fr-FR"], "license": "MIT", "goodColorOnWhite": "#6246ea", "goodColorOnBlack": "#7f5af0", @@ -8878,9 +7315,7 @@ "description": "Display MacOS battery remaining time in your menubar.", "website": "https://github.com/funkyremi/macos-battery-remaining-menubar", "category": "Productivity", - "keywords": [ - "battery time menubar remaining macos" - ], + "keywords": ["battery time menubar remaining macos"], "icon": "remaining-time-icon.png", "icon32": "remaining-time-icon-32.png", "icon64": "remaining-time-icon-64.png", @@ -8893,9 +7328,7 @@ "name": "Remember", "description": "Business card management", "website": "https://rememberapp.co.kr", - "keywords": [ - "Business" - ], + "keywords": ["Business"], "category": "Business", "icon": "remember-icon.png", "icon32": "remember-icon-32.png", @@ -8909,14 +7342,7 @@ "name": "Remind", "description": "Send quick, simple messages to any device—for free.", "website": "https://www.remind.com/", - "keywords": [ - "school", - "messaging", - "communications", - "teacher", - "parent", - "student" - ], + "keywords": ["school", "messaging", "communications", "teacher", "parent", "student"], "category": "Social", "icon": "remind-icon.png", "icon32": "remind-icon-32.png", @@ -8931,11 +7357,7 @@ "description": "Simple and fast Remote Desktop for Windows, Mac & Linux.", "website": "https://remsupp.com", "category": "Business", - "keywords": [ - "remote desktop", - "remote access", - "unattended access" - ], + "keywords": ["remote desktop", "remote access", "unattended access"], "icon": "remsupp-icon.png", "icon32": "remsupp-icon-32.png", "icon64": "remsupp-icon-64.png", @@ -8952,15 +7374,7 @@ "repository": "https://github.com/MartinBarker/RenderTune", "snapcraftName": "rendertune", "youtube_video_url": "https://www.youtube.com/watch?v=LVnacPxquT4", - "keywords": [ - "ffmpeg", - "video", - "render", - "music", - "album", - "combine", - "concat" - ], + "keywords": ["ffmpeg", "video", "render", "music", "album", "combine", "concat"], "license": "MIT", "icon": "rendertune-icon.png", "icon32": "rendertune-icon-32.png", @@ -8974,12 +7388,7 @@ "name": "ReqView", "description": "Simple yet powerful software and system requirements management tool.", "website": "https://www.reqview.com", - "keywords": [ - "project management tool", - "office application", - "productivity", - "editor" - ], + "keywords": ["project management tool", "office application", "productivity", "editor"], "category": "Productivity", "icon": "reqview-icon.png", "icon32": "reqview-icon-32.png", @@ -8997,13 +7406,7 @@ "repository": "https://github.com/responsively-org/responsively-app", "homebrewCaskName": "responsively", "youtube_video_url": "https://youtu.be/rZgPPte9m4k", - "keywords": [ - "UI/UX", - "Responsive", - "Design", - "Browser", - "Testing" - ], + "keywords": ["UI/UX", "Responsive", "Design", "Browser", "Testing"], "icon": "responsively-icon.png", "icon32": "responsively-icon-32.png", "icon64": "responsively-icon-64.png", @@ -9018,13 +7421,7 @@ "website": "https://virejdasani.github.io/Responsivize/", "category": "Developer Tools", "repository": "https://github.com/virejdasani/Responsivize", - "keywords": [ - "Responsivize", - "Responsive", - "web-tool", - "Responsive-websites", - "Responsively" - ], + "keywords": ["Responsivize", "Responsive", "web-tool", "Responsive-websites", "Responsively"], "license": "MIT", "youtube_video_url": "https://www.youtube.com/watch?v=KqGJQ24jhkY", "icon": "responsivize-icon.png", @@ -9039,14 +7436,7 @@ "name": "Reversee", "description": "Reverse Proxy Web Debugger", "website": "https://www.reversee.ninja/", - "keywords": [ - "reverse proxy", - "web debugger", - "javascript", - "developer", - "software", - "network" - ], + "keywords": ["reverse proxy", "web debugger", "javascript", "developer", "software", "network"], "category": "Developer Tools", "icon": "reversee-icon.png", "icon32": "reversee-icon-32.png", @@ -9060,9 +7450,7 @@ "name": "RIDE", "description": "Remote IDE for Dyalog APL.", "repository": "https://github.com/Dyalog/ride", - "keywords": [ - "apl" - ], + "keywords": ["apl"], "license": "MIT", "category": "Developer Tools", "icon": "ride-icon.png", @@ -9193,13 +7581,7 @@ "website": "https://runjs.app", "homebrewCaskName": "runjs", "category": "Developer Tools", - "keywords": [ - "javascript", - "nodejs", - "typescript", - "development", - "web" - ], + "keywords": ["javascript", "nodejs", "typescript", "development", "web"], "icon": "runjs-icon.png", "icon32": "runjs-icon-32.png", "icon64": "runjs-icon-64.png", @@ -9213,12 +7595,7 @@ "description": "Unofficial JioSaavn desktop client, based on the official JioSaavn web app. Built with Electron.", "category": "Music", "repository": "https://github.com/arkokoley/saadhn", - "keywords": [ - "music", - "desktop", - "saavn", - "jiosaavn" - ], + "keywords": ["music", "desktop", "saavn", "jiosaavn"], "icon": "saadhn-icon.png", "icon32": "saadhn-icon-32.png", "icon64": "saadhn-icon-64.png", @@ -9232,13 +7609,7 @@ "description": "Simple, useful timetable application.", "category": "Education", "repository": "https://github.com/KDani-99/school_timetable", - "keywords": [ - "School", - "Timetable", - "Management", - "Time", - "Desktop" - ], + "keywords": ["School", "Timetable", "Management", "Time", "Desktop"], "icon": "school-timetable-icon.png", "icon32": "school-timetable-icon-32.png", "icon64": "school-timetable-icon-64.png", @@ -9252,11 +7623,7 @@ "description": "A converter from markdown to html", "website": "https://github.com/yasumichi/seapig/blob/master/README.md", "repository": "https://github.com/yasumichi/seapig", - "keywords": [ - "markdown", - "editor", - "html" - ], + "keywords": ["markdown", "editor", "html"], "license": "MIT", "category": "Productivity", "icon": "seapig-icon.png", @@ -9271,12 +7638,7 @@ "name": "Sejda PDF Desktop", "description": "Pleasant and productive PDF software that you'll love to use", "website": "https://www.sejda.com/desktop", - "keywords": [ - "PDF", - "document", - "editor", - "productivity" - ], + "keywords": ["PDF", "document", "editor", "productivity"], "category": "Productivity", "icon": "sejda-pdf-desktop-icon.png", "icon32": "sejda-pdf-desktop-icon-32.png", @@ -9290,12 +7652,7 @@ "name": "Sencha Architect", "description": "The Ext JS visual app builder for developing cross-platform HTML5 applications on desktop and mobile devices.", "website": "https://www.sencha.com/products/architect/", - "keywords": [ - "web development", - "programming", - "productivity", - "app builder" - ], + "keywords": ["web development", "programming", "productivity", "app builder"], "category": "Productivity", "icon": "sencha-architect-icon.png", "icon32": "sencha-architect-icon-32.png", @@ -9309,12 +7666,7 @@ "name": "Sencha Inspector", "description": "Debugging tool for troubleshooting and improving performance of Ext JS and Sencha Touch applications.", "website": "https://www.sencha.com/products/inspector/", - "keywords": [ - "web development", - "programming", - "productivity", - "debugging" - ], + "keywords": ["web development", "programming", "productivity", "debugging"], "category": "Productivity", "icon": "sencha-inspector-icon.png", "icon32": "sencha-inspector-icon-32.png", @@ -9328,12 +7680,7 @@ "name": "Sencha Test", "description": "Testing Ext JS and Sencha Touch apps with Jasmine", "website": "https://www.sencha.com/products/test/", - "keywords": [ - "web development", - "programming", - "productivity", - "editor" - ], + "keywords": ["web development", "programming", "productivity", "editor"], "category": "Productivity", "icon": "sencha-test-icon.png", "icon32": "sencha-test-icon-32.png", @@ -9347,12 +7694,7 @@ "name": "Sencha Themer", "description": "Theming tool to rapidly style Ext JS applications by creating custom themes using graphical tools – without writing code.", "website": "https://www.sencha.com/products/themer/", - "keywords": [ - "web development", - "programming", - "productivity", - "theming" - ], + "keywords": ["web development", "programming", "productivity", "theming"], "category": "Productivity", "icon": "sencha-themer-icon.png", "icon32": "sencha-themer-icon-32.png", @@ -9368,15 +7710,7 @@ "website": "https://seobrowse.com/?rel=electron", "category": "Productivity", "repository": "https://github.com/seobrowse/serp/", - "keywords": [ - "browser", - "seo", - "vpn", - "local", - "search engine", - "testing", - "screenshot" - ], + "keywords": ["browser", "seo", "vpn", "local", "search engine", "testing", "screenshot"], "icon": "seobrowse-icon.png", "icon32": "seobrowse-icon-32.png", "icon64": "seobrowse-icon-64.png", @@ -9418,11 +7752,7 @@ "description": "MacOS tray app to control Sonos speakers ecosystem.", "website": "https://github.com/dbilgili/Ses", "category": "Music", - "keywords": [ - "sonos", - "tray", - "controller" - ], + "keywords": ["sonos", "tray", "controller"], "license": "GNU", "icon": "ses-icon.png", "icon32": "ses-icon-32.png", @@ -9463,10 +7793,7 @@ "name": "shadowsocks-electron", "description": "Shadowsocks GUI application made for Ubuntu/Mac users.", "category": "Utilities", - "locales": [ - "zh-CN", - "en-US" - ], + "locales": ["zh-CN", "en-US"], "repository": "https://github.com/nojsja/shadowsocks-electron", "keywords": [ "shadowsocks-electron", @@ -9488,11 +7815,7 @@ "name": "Shapespark", "description": "Create WebGL virtual tours from 3D models.", "website": "https://www.shapespark.com", - "keywords": [ - "WebGL", - "3D", - "rendering" - ], + "keywords": ["WebGL", "3D", "rendering"], "category": "Photo & Video", "icon": "shapespark-icon.png", "icon32": "shapespark-icon-32.png", @@ -9507,9 +7830,7 @@ "description": "Multi-chat for streamers", "website": "https://sheep.chat", "license": "Freeware", - "keywords": [ - "chat" - ], + "keywords": ["chat"], "category": "Social", "icon": "sheepchat-icon.png", "icon32": "sheepchat-icon-32.png", @@ -9523,9 +7844,7 @@ "name": "Shift", "description": "Switch between multiple Gmail, Calendar and Drive accounts with ease.", "website": "https://shift.com", - "keywords": [ - "utility" - ], + "keywords": ["utility"], "category": "Utilities", "icon": "shift-icon.png", "icon32": "shift-icon-32.png", @@ -9540,20 +7859,10 @@ "description": "The fastest way to access to your favorite applications.", "category": "Utilities", "repository": "https://github.com/ShuttleBrowser/Shuttle", - "keywords": [ - "utility", - "browser", - "social", - "network" - ], + "keywords": ["utility", "browser", "social", "network"], "license": "NPOSL 3.0", "goodColorOnWhite": "#d31854", - "locales": [ - "fr-FR", - "en-US", - "en-EN", - "de-DE" - ], + "locales": ["fr-FR", "en-US", "en-EN", "de-DE"], "icon": "shuttle-icon.png", "icon32": "shuttle-icon-32.png", "icon64": "shuttle-icon-64.png", @@ -9567,14 +7876,7 @@ "description": "Say \"hello\" to a different messaging experience. An unexpected focus on privacy, combined with all of the features you expect.", "website": "https://signal.org", "repository": "https://github.com/signalapp/Signal-Desktop", - "keywords": [ - "communication", - "privacy", - "security", - "messenger", - "messaging", - "p2p" - ], + "keywords": ["communication", "privacy", "security", "messenger", "messaging", "p2p"], "category": "Social", "license": "AGPL-3.0-only", "icon": "signal-icon.png", @@ -9626,11 +7928,7 @@ "description": "Simple and useful application to find and download icons for your projects", "website": "https://simpico.futureglobe.de/", "category": "Developer Tools", - "keywords": [ - "iconfinder", - "tool", - "trayapp" - ], + "keywords": ["iconfinder", "tool", "trayapp"], "icon": "simpico-icon.png", "icon32": "simpico-icon-32.png", "icon64": "simpico-icon-64.png", @@ -9644,12 +7942,7 @@ "description": "This application is a basic function of file finder.", "category": "Utilities", "repository": "https://github.com/seniya/electron-finder-normal", - "keywords": [ - "finder", - "file-finder", - "file-explorer", - "file-browser" - ], + "keywords": ["finder", "file-finder", "file-explorer", "file-browser"], "license": "MIT", "icon": "simple-finder-icon.png", "icon32": "simple-finder-icon-32.png", @@ -9665,12 +7958,7 @@ "website": "https://mifi.github.io/SimpleInstaBot/", "category": "Social", "repository": "https://github.com/mifi/SimpleInstaBot", - "keywords": [ - "instagram", - "bot", - "socialmedia", - "followers" - ], + "keywords": ["instagram", "bot", "socialmedia", "followers"], "icon": "simpleinstabot-icon.png", "icon32": "simpleinstabot-icon-32.png", "icon64": "simpleinstabot-icon-64.png", @@ -9685,11 +7973,7 @@ "website": "https://simplenote.com", "repository": "https://github.com/Automattic/simplenote-electron", "homebrewCaskName": "simplenote", - "keywords": [ - "notes", - "utility", - "sync" - ], + "keywords": ["notes", "utility", "sync"], "license": "GPLv2", "category": "Productivity", "icon": "simplenote-icon.png", @@ -9705,12 +7989,7 @@ "description": "The browser for developers and designers.", "website": "https://sizzy.co", "category": "Developer Tools", - "keywords": [ - "browser", - "responsive", - "design", - "testing" - ], + "keywords": ["browser", "responsive", "design", "testing"], "icon": "sizzy-icon.png", "icon32": "sizzy-icon-32.png", "icon64": "sizzy-icon-64.png", @@ -9747,15 +8026,7 @@ "description": "New way to communicate with your team. It’s faster, better organized, and more secure than email.", "website": "https://slack.com", "homebrewCaskName": "slack", - "keywords": [ - "messaging", - "chat", - "p2p", - "video", - "voip", - "phone", - "community" - ], + "keywords": ["messaging", "chat", "p2p", "video", "voip", "phone", "community"], "category": "Business", "icon": "slack-icon.png", "icon32": "slack-icon-32.png", @@ -9799,13 +8070,7 @@ ], "category": "Productivity", "license": "MIT", - "locales": [ - "de-DE", - "en-GB", - "fr-FR", - "es-ES", - "it-IT" - ], + "locales": ["de-DE", "en-GB", "fr-FR", "es-ES", "it-IT"], "icon": "sleek-icon.png", "icon32": "sleek-icon-32.png", "icon64": "sleek-icon-64.png", @@ -9845,11 +8110,7 @@ "website": "https://snaildos.com/snailfm", "category": "Music", "repository": "https://github.com/snaildos/SnailFM-Application", - "keywords": [ - "music", - "NCS", - "simple" - ], + "keywords": ["music", "NCS", "simple"], "icon": "snailfm-icon.png", "icon32": "snailfm-icon-32.png", "icon64": "snailfm-icon-64.png", @@ -9863,11 +8124,7 @@ "description": "Customizable snippet manager made for developers and people who work with code", "website": "https://snipaway.futureglobe.de/", "category": "Productivity", - "keywords": [ - "snippetmanager", - "snippet", - "manager" - ], + "keywords": ["snippetmanager", "snippet", "manager"], "icon": "snipaway-icon.png", "icon32": "snipaway-icon-32.png", "icon64": "snipaway-icon-64.png", @@ -9904,21 +8161,10 @@ "description": "A snippet management app for developers", "website": "https://zerox-dg.github.io/SnippetStoreWeb/", "repository": "https://github.com/ZeroX-DG/SnippetStore", - "keywords": [ - "code", - "snippet", - "store", - "copy", - "tool", - "developer", - "productivity" - ], + "keywords": ["code", "snippet", "store", "copy", "tool", "developer", "productivity"], "license": "GPL", "category": "Developer Tools", - "locales": [ - "en-US", - "vi-VN" - ], + "locales": ["en-US", "vi-VN"], "icon": "snippetstore-icon.png", "icon32": "snippetstore-icon-32.png", "icon64": "snippetstore-icon-64.png", @@ -9931,15 +8177,9 @@ "name": "SnowyOwl", "description": "Manage your dataset with ease", "website": "https://snowyowl.app", - "keywords": [ - "dataset manager", - "reference manager" - ], + "keywords": ["dataset manager", "reference manager"], "category": "Productivity", - "locales": [ - "en-US", - "zh-CN" - ], + "locales": ["en-US", "zh-CN"], "icon": "snowyowl-icon.png", "icon32": "snowyowl-icon-32.png", "icon64": "snowyowl-icon-64.png", @@ -9952,18 +8192,10 @@ "name": "Social Amnesia", "description": "Delete reddit/twitter history automatically, save the stuff you like.", "repository": "https://github.com/Nick-Gottschlich/Social-Amnesia", - "keywords": [ - "reddit", - "twitter", - "social", - "social media", - "privacy" - ], + "keywords": ["reddit", "twitter", "social", "social media", "privacy"], "license": "GPL-3.0", "category": "Productivity", - "locales": [ - "en-US" - ], + "locales": ["en-US"], "icon": "social-amnesia-icon.png", "icon32": "social-amnesia-icon-32.png", "icon64": "social-amnesia-icon-64.png", @@ -9977,14 +8209,7 @@ "description": "Organise all your socials into just one app.", "website": "https://getsocially.app", "repository": "https://github.com/JackHumphries9/Socially", - "keywords": [ - "socially", - "productivity", - "utilities", - "social media", - "instagram", - "facebook" - ], + "keywords": ["socially", "productivity", "utilities", "social media", "instagram", "facebook"], "license": "GNU General Public License v3.0", "category": "Social", "icon": "socially-icon.png", @@ -10000,11 +8225,7 @@ "description": "Software to customize your status discord.", "website": "https://github.com/TaiStudio/Sofia", "category": "Games", - "keywords": [ - "discord", - "software", - "presence" - ], + "keywords": ["discord", "software", "presence"], "icon": "sofia-icon.png", "icon32": "sofia-icon-32.png", "icon64": "sofia-icon-64.png", @@ -10042,11 +8263,7 @@ "description": "Cross-platform sample browser with several innovative features, such as similarity-based audio search and automatic sound categorization.", "website": "https://www.sononym.net", "category": "Productivity", - "keywords": [ - "music", - "productivity", - "utilities" - ], + "keywords": ["music", "productivity", "utilities"], "icon": "sononym-icon.png", "icon32": "sononym-icon-32.png", "icon64": "sononym-icon-64.png", @@ -10060,12 +8277,7 @@ "description": "Simple soundboard desktop app (like EXP Soundboard).", "category": "Utilities", "repository": "https://github.com/Glecun/soundboard", - "keywords": [ - "soundboard", - "sound", - "exp", - "myinstants" - ], + "keywords": ["soundboard", "sound", "exp", "myinstants"], "icon": "soundboard-icon.png", "icon32": "soundboard-icon-32.png", "icon64": "soundboard-icon-64.png", @@ -10079,11 +8291,7 @@ "description": "Unofficial desktop client for Soundcloud.", "website": "https://soundnode.github.io/soundnode-website/", "repository": "https://github.com/Soundnode/soundnode-app", - "keywords": [ - "music", - "sound", - "soundcloud" - ], + "keywords": ["music", "sound", "soundcloud"], "license": "GNU GENERAL PUBLIC LICENSE Version 3", "category": "Music", "icon": "soundnode-icon.png", @@ -10111,12 +8319,7 @@ "name": "SparkChess", "description": "Play chess against the computer or challenge your friends in multiplayer", "website": "https://www.sparkchess.com", - "keywords": [ - "chess", - "game", - "multiplayer", - "learn" - ], + "keywords": ["chess", "game", "multiplayer", "learn"], "category": "Games", "icon": "sparkchess-icon.png", "icon32": "sparkchess-icon-32.png", @@ -10130,10 +8333,7 @@ "name": "Splice", "description": "Platform for music production offering access to millions of the best royalty-free samples, loops, and presets.", "website": "https://splice.com/", - "keywords": [ - "music", - "audio" - ], + "keywords": ["music", "audio"], "category": "Music", "icon": "splice-icon.png", "icon32": "splice-icon-32.png", @@ -10147,13 +8347,7 @@ "name": "SportFX Studio", "description": "Sports Graphics Editor for Photos and Videos", "website": "https://scorestream.com/sportfx", - "keywords": [ - "scoreboards", - "schedules", - "high school", - "customizable", - "templates" - ], + "keywords": ["scoreboards", "schedules", "high school", "customizable", "templates"], "category": "Photo & Video", "icon": "sportfx-studio-icon.png", "icon32": "sportfx-studio-icon-32.png", @@ -10167,12 +8361,7 @@ "name": "SpotSpot", "description": "Spotify mini-player for macOS.", "repository": "https://github.com/will-stone/SpotSpot", - "keywords": [ - "spotify", - "macos", - "audio", - "music" - ], + "keywords": ["spotify", "macos", "audio", "music"], "license": "MIT", "category": "Music", "icon": "spotspot-icon.png", @@ -10187,9 +8376,7 @@ "name": "Spreaker Studio", "description": "Create and discover podcasts", "website": "https://www.spreaker.com/podcast-recording-software", - "keywords": [ - "podcasts" - ], + "keywords": ["podcasts"], "category": "News", "icon": "spreaker-studio-icon.png", "icon32": "spreaker-studio-icon-32.png", @@ -10204,12 +8391,7 @@ "description": "A simple and lightweight SQL client desktop with cross database and platform support", "website": "https://sqlectron.github.io", "repository": "https://github.com/sqlectron/sqlectron-gui", - "keywords": [ - "sql", - "mysql", - "postgres", - "mssql" - ], + "keywords": ["sql", "mysql", "postgres", "mssql"], "license": "MIT", "category": "Developer Tools", "icon": "sqlectron-icon.png", @@ -10225,16 +8407,7 @@ "description": "Simple UI client for most SQL Engines. It is compatible with Windows, Mac, Ubuntu / Debian and Redhat. It supports most dialects of RMBDs like MySQL, Microsoft SQL Server, Postgres, SQLite and has limited supports for Cassandra, MongoDB and Redis.", "website": "https://synle.github.io/sqlui-native/", "repository": "https://github.com/synle/sqlui-native", - "keywords": [ - "mysql", - "sql", - "sqlite", - "postgresql", - "mssql", - "redis", - "cassandra", - "mongodb" - ], + "keywords": ["mysql", "sql", "sqlite", "postgresql", "mssql", "redis", "cassandra", "mongodb"], "license": "MIT", "category": "Developer Tools", "icon": "sqlui-native-icon.png", @@ -10275,14 +8448,7 @@ "description": "Your personal To Do and Project Manager.", "website": "https://stacks.rocks", "category": "Productivity", - "keywords": [ - "task", - "task manager", - "project", - "project management", - "stacks", - "kanban" - ], + "keywords": ["task", "task manager", "project", "project management", "stacks", "kanban"], "icon": "stacks-icon.png", "icon32": "stacks-icon-32.png", "icon64": "stacks-icon-64.png", @@ -10295,12 +8461,7 @@ "name": "STAMP", "description": "Move tracks and playlists across various streaming services", "website": "https://freeyourmusic.com/", - "keywords": [ - "music", - "spotify", - "apple music", - "google play music" - ], + "keywords": ["music", "spotify", "apple music", "google play music"], "category": "Music", "icon": "stamp-icon.png", "icon32": "stamp-icon-32.png", @@ -10340,11 +8501,7 @@ "description": "A desktop application which can be used in Scrum teams to initiate the daily Scrum meeting.", "website": "https://mokkapps.de", "repository": "https://github.com/Mokkapps/scrum-daily-standup-picker", - "keywords": [ - "Scrum", - "Standup", - "Picker" - ], + "keywords": ["Scrum", "Standup", "Picker"], "category": "Utilities", "icon": "standup-picker-icon.png", "icon32": "standup-picker-icon-32.png", @@ -10359,9 +8516,7 @@ "description": "Unifies all your web apps in one neat & productive interface.", "website": "https://getstation.com/", "category": "Productivity", - "keywords": [ - "browser" - ], + "keywords": ["browser"], "icon": "station-icon.png", "icon32": "station-icon-32.png", "icon64": "station-icon-64.png", @@ -10374,9 +8529,7 @@ "name": "stay-hydrated", "description": "Reminder to drink water.", "category": "Utilities", - "keywords": [ - "water" - ], + "keywords": ["water"], "repository": "https://github.com/QuentinGruber/stay-hydrated", "license": "MIT", "icon": "stay-hydrated-icon.png", @@ -10391,9 +8544,7 @@ "name": "SteelSeries Engine 3", "description": "A unified platform that supports nearly all your SteelSeries gear", "website": "https://steelseries.com/engine", - "keywords": [ - "Games" - ], + "keywords": ["Games"], "category": "Games", "icon": "steelseries-engine-3-icon.png", "icon32": "steelseries-engine-3-icon-32.png", @@ -10434,13 +8585,7 @@ "description": "Laravel tinker snippets keeper.", "website": "https://itzik.co", "repository": "https://github.com/PatentLobster/stinker", - "keywords": [ - "laravel", - "tinker", - "php", - "snippets", - "ide" - ], + "keywords": ["laravel", "tinker", "php", "snippets", "ide"], "category": "Developer Tools", "icon": "stinker-icon.png", "icon32": "stinker-icon-32.png", @@ -10455,15 +8600,7 @@ "description": "Notification and insights app for stock markets.", "category": "Finance", "repository": "https://github.com/jainsamyak/Stockifier", - "keywords": [ - "stock", - "notifier", - "prediction", - "forecast", - "insights", - "equity", - "analysis" - ], + "keywords": ["stock", "notifier", "prediction", "forecast", "insights", "equity", "analysis"], "license": "MIT", "icon": "stockifier-icon.png", "icon32": "stockifier-icon-32.png", @@ -10476,10 +8613,7 @@ "slug": "stopawu", "name": "Stopawu", "description": "Easily disable automatic Windows updates.", - "keywords": [ - "windows", - "update" - ], + "keywords": ["windows", "update"], "repository": "https://github.com/tariibaba/stopawu", "category": "Utilities", "icon": "stopawu-icon.png", @@ -10494,9 +8628,7 @@ "name": "StopLight", "description": "Mock, document, and test your way to API nirvana", "website": "https://stoplight.io", - "keywords": [ - "API" - ], + "keywords": ["API"], "category": "Developer Tools", "icon": "stoplight-icon.png", "icon32": "stoplight-icon-32.png", @@ -10511,12 +8643,7 @@ "description": "The Light/Responsive Inventory Management System.", "repository": "https://github.com/IndomaximTechId/storaji", "category": "Business", - "keywords": [ - "inventory", - "management", - "service", - "system" - ], + "keywords": ["inventory", "management", "service", "system"], "license": "MIT License", "icon": "storaji-icon.png", "icon32": "storaji-icon-32.png", @@ -10532,13 +8659,7 @@ "website": "https://snaildos.com/streambop", "category": "Music", "repository": "https://github.com/snaildos/StreamBop", - "keywords": [ - "Utility", - "Streaming", - "Helper", - "NCS", - "OBS Addon" - ], + "keywords": ["Utility", "Streaming", "Helper", "NCS", "OBS Addon"], "icon": "streambop-icon.png", "icon32": "streambop-icon-32.png", "icon64": "streambop-icon-64.png", @@ -10553,11 +8674,7 @@ "website": "https://streamlabs.com/streamlabs-obs", "category": "Photo & Video", "repository": "https://github.com/stream-labs/streamlabs-obs", - "keywords": [ - "livestreaming", - "streaming", - "streamlabs" - ], + "keywords": ["livestreaming", "streaming", "streamlabs"], "license": "GPLv3", "goodColorOnWhite": "#17242D", "goodColorOnBlack": "#32C3A2", @@ -10574,9 +8691,7 @@ "name": "Street View Download 360", "description": "App for downloading 360° Street View images", "website": "https://svd360.istreetview.com", - "keywords": [ - "images" - ], + "keywords": ["images"], "category": "Photo & Video", "icon": "streetviewdownload360-icon.png", "icon32": "streetviewdownload360-icon-32.png", @@ -10603,9 +8718,7 @@ "新片场", "字幕" ], - "locales": [ - "zh-CN" - ], + "locales": ["zh-CN"], "icon": "studiotrans-icon.png", "icon32": "studiotrans-icon-32.png", "icon64": "studiotrans-icon-64.png", @@ -10619,11 +8732,7 @@ "description": "Flashcards from Markdown.", "category": "Productivity", "repository": "https://github.com/jotron/StudyMD", - "keywords": [ - "flashcards", - "react-app", - "markdown" - ], + "keywords": ["flashcards", "react-app", "markdown"], "license": "MIT", "icon": "studymd-icon.png", "icon32": "studymd-icon-32.png", @@ -10637,11 +8746,7 @@ "name": "Subordination", "description": "A desktop app for translating and editing subtitles", "repository": "https://github.com/sunabozu/subordination", - "keywords": [ - "subtitles", - "translation", - "editor" - ], + "keywords": ["subtitles", "translation", "editor"], "category": "Productivity", "icon": "subordination-icon.png", "icon32": "subordination-icon-32.png", @@ -10680,13 +8785,7 @@ "description": "To Do List / Time Tracker with Jira Integration. Makes you super productive! ", "website": "https://super-productivity.com/", "repository": "https://github.com/johannesjo/super-productivity", - "keywords": [ - "todo", - "time tracker", - "jira", - "task management", - "productivity" - ], + "keywords": ["todo", "time tracker", "jira", "task management", "productivity"], "license": "MIT", "category": "Productivity", "icon": "super-productivity-icon.png", @@ -10701,9 +8800,7 @@ "name": "Superpowers — HTML5 2D+3D game maker", "description": "2D+3D game making for indies. Free and open source, finally", "website": "http://superpowers-html5.com/", - "keywords": [ - "games" - ], + "keywords": ["games"], "category": "Games", "icon": "superpowers-html5-2d-3d-game-maker-icon.png", "icon32": "superpowers-html5-2d-3d-game-maker-icon-32.png", @@ -10717,12 +8814,7 @@ "name": "Svgsus", "description": "Organize, clean and transform your SVGs", "website": "http://www.svgs.us", - "keywords": [ - "icon", - "svg", - "tool", - "productivity" - ], + "keywords": ["icon", "svg", "tool", "productivity"], "category": "Productivity", "icon": "svgsus-icon.png", "icon32": "svgsus-icon-32.png", @@ -10784,11 +8876,7 @@ "website": "https://ahkohd.github.io/switch-desktop", "category": "Productivity", "repository": "https://github.com/ahkohd/switch-desktop", - "keywords": [ - "window", - "manager", - "crossplatform" - ], + "keywords": ["window", "manager", "crossplatform"], "license": "GPL v3", "youtube_video_url": "https://youtu.be/cysVHi-pcxU", "icon": "switch-icon.png", @@ -10804,9 +8892,7 @@ "description": "Manage and switch your hosts files.", "website": "https://swh.app", "repository": "https://github.com/oldj/SwitchHosts", - "keywords": [ - "developer tools" - ], + "keywords": ["developer tools"], "license": "Apache-2.0", "category": "Developer Tools", "icon": "switchhosts-icon.png", @@ -10855,21 +8941,9 @@ "website": "https://syngdict.com/", "category": "Education", "repository": "https://github.com/sotch-pr35mac/syng", - "keywords": [ - "chinese", - "dictionary", - "hanzi", - "language", - "education", - "words", - "translation" - ], + "keywords": ["chinese", "dictionary", "hanzi", "language", "education", "words", "translation"], "license": "GPLv3", - "locales": [ - "en-US", - "zh-CN", - "zh-TW" - ], + "locales": ["en-US", "zh-CN", "zh-TW"], "icon": "syng-icon.png", "icon32": "syng-icon-32.png", "icon64": "syng-icon-64.png", @@ -10883,13 +8957,7 @@ "description": "IDE for designing JavaScript applications driven by the model", "website": "https://designfirst.io/systemdesigner/", "repository": "https://github.com/design-first/system-designer", - "keywords": [ - "uml", - "model", - "system", - "IDE", - "OSGI" - ], + "keywords": ["uml", "model", "system", "IDE", "OSGI"], "license": "Apache-2.0", "category": "Developer Tools", "icon": "system-designer-icon.png", @@ -10905,20 +8973,8 @@ "description": "Simple, beautiful desktop timetable app to manage your school schedule.", "category": "Education", "repository": "https://github.com/natixco/tabby", - "locales": [ - "en", - "hu", - "de", - "es-AR" - ], - "keywords": [ - "school", - "timetable", - "management", - "time", - "schedule", - "learning" - ], + "locales": ["en", "hu", "de", "es-AR"], + "keywords": ["school", "timetable", "management", "time", "schedule", "learning"], "icon": "tabby-icon.png", "icon32": "tabby-icon-32.png", "icon64": "tabby-icon-64.png", @@ -10932,14 +8988,7 @@ "description": "Terminal for a more modern age.", "website": "https://tabby.sh", "repository": "https://github.com/Eugeny/tabby", - "keywords": [ - "terminal", - "shell", - "tty", - "ssh", - "serial", - "terminal-emulator" - ], + "keywords": ["terminal", "shell", "tty", "ssh", "serial", "terminal-emulator"], "license": "MIT", "category": "Developer Tools", "icon": "tabby-terminal-icon.png", @@ -10954,13 +9003,7 @@ "name": "TagFlow", "description": "Cross-platform file manager with clever tags", "website": "https://www.tagflow.ch/", - "keywords": [ - "tags", - "file manager", - "file sharing", - "productivity", - "cross-platform" - ], + "keywords": ["tags", "file manager", "file sharing", "productivity", "cross-platform"], "category": "Productivity", "icon": "tagflow-icon.png", "icon32": "tagflow-icon-32.png", @@ -10976,12 +9019,7 @@ "website": "https://www.tagspaces.org/", "repository": "https://github.com/tagspaces/tagspaces", "license": "AGPL3", - "keywords": [ - "notetaking", - "organization", - "tagging", - "productivity" - ], + "keywords": ["notetaking", "organization", "tagging", "productivity"], "category": "Utilities", "icon": "tagspaces-icon.png", "icon32": "tagspaces-icon-32.png", @@ -11010,11 +9048,7 @@ "label" ], "license": "GPL-3.0", - "locales": [ - "en-US", - "fr-FR", - "es-ES" - ], + "locales": ["en-US", "fr-FR", "es-ES"], "icon": "tagstoo-icon.png", "icon32": "tagstoo-icon-32.png", "icon64": "tagstoo-icon-64.png", @@ -11030,14 +9064,7 @@ "repository": "https://github.com/mountainash/taskana", "category": "Productivity", "license": "MIT", - "keywords": [ - "Asana", - "wrapper", - "tasks", - "tickets", - "productivity", - "tracking" - ], + "keywords": ["Asana", "wrapper", "tasks", "tickets", "productivity", "tracking"], "icon": "taskana-icon.png", "icon32": "taskana-icon-32.png", "icon64": "taskana-icon-64.png", @@ -11050,16 +9077,8 @@ "name": "TEA Ebook", "description": "Application TEA Ebook pour Mac / Windows / Linux", "website": "https://app.tea-ebook.com", - "keywords": [ - "ebook", - "Reader", - "epub", - "PDF" - ], - "locales": [ - "fr", - "en" - ], + "keywords": ["ebook", "Reader", "epub", "PDF"], + "locales": ["fr", "en"], "category": "Books", "icon": "tea-ebook-icon.png", "icon32": "tea-ebook-icon-32.png", @@ -11074,12 +9093,7 @@ "description": "Bible study app.", "website": "https://teleios.bible", "category": "Education", - "keywords": [ - "bible", - "study", - "Jesus", - "God" - ], + "keywords": ["bible", "study", "Jesus", "God"], "icon": "teleios-bible-icon.png", "icon32": "teleios-bible-icon-32.png", "icon64": "teleios-bible-icon-64.png", @@ -11094,15 +9108,7 @@ "website": "https://tenhands.app", "category": "Utilities", "repository": "https://github.com/saisandeepvaddi/ten-hands", - "keywords": [ - "terminal", - "command-line", - "tasks", - "tools", - "organize", - "nodejs", - "react" - ], + "keywords": ["terminal", "command-line", "tasks", "tools", "organize", "nodejs", "react"], "license": "MIT", "icon": "ten-hands-icon.png", "icon32": "ten-hands-icon-32.png", @@ -11117,11 +9123,7 @@ "description": "A simple static webserver, in an app.", "website": "https://teseve.github.io/", "repository": "https://github.com/teseve/teseve", - "keywords": [ - "static", - "server", - "testing" - ], + "keywords": ["static", "server", "testing"], "license": "Public Domain", "category": "Developer Tools", "icon": "teseve-icon.png", @@ -11136,11 +9138,7 @@ "name": "Tess", "description": "Hackable, simple, rapid and beautiful terminal app for the new era of technology.", "repository": "https://github.com/SquitchYT/Tess/", - "keywords": [ - "tess", - "terminal", - "terminal-emulator" - ], + "keywords": ["tess", "terminal", "terminal-emulator"], "license": "MIT", "category": "Utilities", "icon": "tess-icon.png", @@ -11184,13 +9182,7 @@ "name": "Testrec", "description": "Record, playback and export protractor tests in seconds", "website": "https://testrec.com", - "keywords": [ - "protractor", - "tests", - "tool", - "frontend", - "development" - ], + "keywords": ["protractor", "tests", "tool", "frontend", "development"], "category": "Developer Tools", "icon": "testrec-icon.png", "icon32": "testrec-icon-32.png", @@ -11204,13 +9196,7 @@ "name": "texpaste", "description": "Live TeX rendering.", "repository": "https://github.com/jonasmusall/texpaste", - "keywords": [ - "TeX", - "LaTeX", - "math", - "formula", - "clipboard" - ], + "keywords": ["TeX", "LaTeX", "math", "formula", "clipboard"], "license": "GPL-3.0", "category": "Science & Medicine", "goodColorOnWhite": "#000000", @@ -11228,10 +9214,7 @@ "name": "The Poker Timer", "description": "Best tournament clock", "website": "https://www.thepokertimer.com/", - "keywords": [ - "tournament", - "timer" - ], + "keywords": ["tournament", "timer"], "category": "Games", "icon": "the-poker-timer-icon.png", "icon32": "the-poker-timer-icon-32.png", @@ -11246,12 +9229,7 @@ "description": "Bootstrap theme builder.", "category": "Developer Tools", "repository": "https://github.com/wurde/themebuilder", - "keywords": [ - "bootstrap", - "css", - "design", - "styles" - ], + "keywords": ["bootstrap", "css", "design", "styles"], "license": "MIT", "icon": "themebuilder-icon.png", "icon32": "themebuilder-icon-32.png", @@ -11266,13 +9244,7 @@ "description": "Browse your PC remotely from any web browser.", "category": "Developer Tools", "repository": "https://github.com/supunlakmal/thismypc", - "keywords": [ - "remote pc", - "remote access", - "open source", - "experimental", - "full stack" - ], + "keywords": ["remote pc", "remote access", "open source", "experimental", "full stack"], "license": "MIT", "icon": "thismypc-icon.png", "icon32": "thismypc-icon-32.png", @@ -11288,14 +9260,7 @@ "website": "https://www.edrlab.org/software/thorium-reader/", "category": "Books", "repository": "https://github.com/edrlab/thorium-reader/", - "keywords": [ - "epub", - "pdf", - "daisy", - "ebooks", - "reader", - "lcp" - ], + "keywords": ["epub", "pdf", "daisy", "ebooks", "reader", "lcp"], "license": "BSD-3", "icon": "thorium-reader-icon.png", "icon32": "thorium-reader-icon-32.png", @@ -11310,10 +9275,7 @@ "description": "Unofficial desktop client for Threema.", "category": "Social", "repository": "https://github.com/GeekCornerGH/Threema-For-Desktop", - "keywords": [ - "threema", - "desktop" - ], + "keywords": ["threema", "desktop"], "license": "MIT", "sceenshots": [ { @@ -11334,11 +9296,7 @@ "name": "TIDAL", "description": "The first global music streaming service with high fidelity sound, hi-def video quality, along with expertly curated playlists and original content.", "website": "https://www.tidal.com", - "keywords": [ - "music", - "streaming", - "videos" - ], + "keywords": ["music", "streaming", "videos"], "category": "Music", "icon": "tidal-icon.png", "icon32": "tidal-icon-32.png", @@ -11381,12 +9339,7 @@ "description": "Beautiful and elegant podcast client.", "repository": "https://github.com/paologiua/tilde", "category": "Entertainment", - "keywords": [ - "podcast", - "feed", - "rss", - "itunes" - ], + "keywords": ["podcast", "feed", "rss", "itunes"], "icon": "tilde-icon.png", "icon32": "tilde-icon-32.png", "icon64": "tilde-icon-64.png", @@ -11399,10 +9352,7 @@ "name": "Tiliq", "description": "The next generation of professional business email", "website": "https://tiliq.com", - "keywords": [ - "email", - "productivity" - ], + "keywords": ["email", "productivity"], "category": "Productivity", "icon": "tiliq-icon.png", "icon32": "tiliq-icon-32.png", @@ -11463,10 +9413,7 @@ "time tracking tools", "time tracking device" ], - "locales": [ - "en-US", - "de-DE" - ], + "locales": ["en-US", "de-DE"], "icon": "timebuzzer-icon.png", "icon32": "timebuzzer-icon-32.png", "icon64": "timebuzzer-icon-64.png", @@ -11480,13 +9427,7 @@ "description": "InfuxDB query editor and administrator UI", "website": "https://timeseriesadmin.github.io", "repository": "https://github.com/timeseriesadmin/timeseriesadmin", - "keywords": [ - "influxdb", - "influx", - "admin", - "ui", - "webui" - ], + "keywords": ["influxdb", "influx", "admin", "ui", "webui"], "license": "MIT", "npmPackageName": "timeseriesadmin", "category": "Developer Tools", @@ -11528,13 +9469,7 @@ "website": "https://to-do-tasks-lists.web.app", "category": "Productivity", "repository": "https://github.com/luapp/ToDo", - "keywords": [ - "todo", - "tasks", - "list", - "react", - "webapp" - ], + "keywords": ["todo", "tasks", "list", "react", "webapp"], "license": "gpl-3.0", "icon": "todo-icon.png", "icon32": "todo-icon-32.png", @@ -11549,14 +9484,7 @@ "description": "A meter-based to-do list.", "website": "https://cassidoo.github.io/todometer/", "repository": "https://github.com/cassidoo/todometer/", - "keywords": [ - "todometer", - "to-do list", - "todo", - "Productivity", - "task", - "focus" - ], + "keywords": ["todometer", "to-do list", "todo", "Productivity", "task", "focus"], "category": "Productivity", "icon": "todometer-icon.png", "icon32": "todometer-icon-32.png", @@ -11569,9 +9497,7 @@ "slug": "tofino", "name": "Tofino", "description": "Experimental web browser from Mozilla", - "keywords": [ - "browser" - ], + "keywords": ["browser"], "category": "Productivity", "repository": "https://github.com/mozilla/tofino", "icon": "tofino-icon.png", @@ -11583,18 +9509,10 @@ }, { "slug": "tonfotos", - "name": "tonfotos", - "description": "Intuitive photo and video archive manager and viewer.", - "website": "https://tonfotos.com/", - "keywords": [ - "tonfotos", - "photo", - "video", - "archive", - "viewer", - "manager", - "organizer" - ], + "name": "tonfotos", + "description": "Intuitive photo and video archive manager and viewer.", + "website": "https://tonfotos.com/", + "keywords": ["tonfotos", "photo", "video", "archive", "viewer", "manager", "organizer"], "category": "Photo & Video", "icon": "tonfotos-icon.png", "icon32": "tonfotos-icon-32.png", @@ -11610,10 +9528,7 @@ "website": "https://bitbucket.org/speedydemon/electron_top_browser/", "category": "Utilities", "repository": "https://bitbucket.org/speedydemon/electron_top_browser/", - "keywords": [ - "browser", - "top" - ], + "keywords": ["browser", "top"], "license": "MIT", "icon": "top-browser-icon.png", "icon32": "top-browser-icon-32.png", @@ -11696,11 +9611,7 @@ "description": "Simple and useful tool for quick translation", "website": "https://alessioforte.github.io/transee/", "repository": "https://github.com/alessioforte/transee", - "keywords": [ - "translator", - "google translate", - "language" - ], + "keywords": ["translator", "google translate", "language"], "license": "MIT", "category": "Utilities", "icon": "transee-icon.png", @@ -11716,11 +9627,7 @@ "description": "Translation files editor for INTL ICU messages (see formatjs.io)", "website": "https://bitbucket.org/bflower/react-intl-editor/wiki/Home", "repository": "https://bitbucket.org/bflower/react-intl-editor", - "keywords": [ - "Translation", - "React", - "Intl" - ], + "keywords": ["Translation", "React", "Intl"], "license": "MIT", "category": "Utilities", "icon": "translation-editor-icon.png", @@ -11735,11 +9642,7 @@ "name": "Trello", "description": "The ultimate project management tool. Start up a board in seconds, automate tedious tasks, and collaborate anywhere, even on mobile.", "website": "https://trello.com", - "keywords": [ - "project management", - "tasks", - "kanban" - ], + "keywords": ["project management", "tasks", "kanban"], "category": "Productivity", "icon": "trello-icon.png", "icon32": "trello-icon-32.png", @@ -11754,13 +9657,7 @@ "description": "This app converts an excel spreadsheet (xls/xlsx/csv) to a table/collection in mysql/mongodb.", "website": "https://github.com/ngudbhav/TriCo-electron-app", "category": "Developer Tools", - "keywords": [ - "excel", - "mongodb", - "mysql", - "covert", - "developer" - ], + "keywords": ["excel", "mongodb", "mysql", "covert", "developer"], "license": "MIT", "icon": "trico-icon.png", "icon32": "trico-icon-32.png", @@ -11799,15 +9696,7 @@ "website": "https://tropy.org", "category": "Photo & Video", "repository": "https://github.com/tropy/tropy/", - "keywords": [ - "photo", - "images", - "research", - "metadata", - "node-js", - "sqlite3", - "javascript" - ], + "keywords": ["photo", "images", "research", "metadata", "node-js", "sqlite3", "javascript"], "license": "AGPL", "goodColorOnWhite": "#2971dd", "goodColorOnBlack": "#6382cb", @@ -11823,9 +9712,7 @@ "name": "Trym", "description": "Beautiful small app for macOS to help you view, optimize and convert SVG icons", "website": "https://kontentapps.com/trym", - "keywords": [ - "svg" - ], + "keywords": ["svg"], "category": "Photo & Video", "icon": "trym-icon.png", "icon32": "trym-icon-32.png", @@ -11859,10 +9746,7 @@ "Xing" ], "category": "Productivity", - "locales": [ - "en-EN", - "de-DE" - ], + "locales": ["en-EN", "de-DE"], "icon": "ttth-icon.png", "icon32": "ttth-icon-32.png", "icon64": "ttth-icon-64.png", @@ -11897,9 +9781,7 @@ "name": "Turbo Download Manager", "description": "An open-source multi-threading download manager", "website": "https://add0n.com/turbo-download-manager.html", - "keywords": [ - "manager" - ], + "keywords": ["manager"], "category": "Utilities", "icon": "turbo-download-manager-icon.png", "icon32": "turbo-download-manager-icon-32.png", @@ -11915,12 +9797,7 @@ "website": "https://klaudiosinani.com/tusk/", "repository": "https://github.com/klaudiosinani/tusk", "snapcraftName": "tusk", - "keywords": [ - "note", - "productivity", - "note-taking", - "evernote" - ], + "keywords": ["note", "productivity", "note-taking", "evernote"], "license": "MIT", "category": "Productivity", "icon": "tusk-icon.png", @@ -11936,12 +9813,7 @@ "description": "Cross-platform Tizen Log Viewer.", "category": "Developer Tools", "repository": "https://github.com/msaltnet/T.Viewer", - "keywords": [ - "tizen", - "log", - "viewer", - "development" - ], + "keywords": ["tizen", "log", "viewer", "development"], "icon": "tviewer-icon.png", "icon32": "tviewer-icon-32.png", "icon64": "tviewer-icon-64.png", @@ -11954,9 +9826,7 @@ "name": "TweakStyle", "description": "The next code editor", "website": "https://tweakstyle.com", - "keywords": [ - "code" - ], + "keywords": ["code"], "category": "Developer Tools", "icon": "tweakstyle-icon.png", "icon32": "tweakstyle-icon-32.png", @@ -11970,11 +9840,7 @@ "name": "Tweeten", "description": "A better TweetDeck experience", "website": "https://tweetenapp.com/", - "keywords": [ - "twitter", - "tweetdeck", - "tweetdeck for windows" - ], + "keywords": ["twitter", "tweetdeck", "tweetdeck for windows"], "category": "Social", "icon": "tweeten-icon.png", "icon32": "tweeten-icon-32.png", @@ -11990,14 +9856,7 @@ "website": "https://twinkletray.com/", "category": "Utilities", "repository": "https://github.com/xanderfrangos/twinkle-tray", - "keywords": [ - "brightness", - "monitor", - "display", - "ddc-ic", - "windows", - "brightness-control" - ], + "keywords": ["brightness", "monitor", "display", "ddc-ic", "windows", "brightness-control"], "icon": "twinkle-tray-icon.png", "icon32": "twinkle-tray-icon-32.png", "icon64": "twinkle-tray-icon-64.png", @@ -12010,9 +9869,7 @@ "name": "Twitch", "description": "Interactive livestreaming service for content spanning gaming, entertainment, sports, music, and more.", "website": "https://app.twitch.tv", - "keywords": [ - "games" - ], + "keywords": ["games"], "category": "Games", "icon": "twitch-icon.png", "icon32": "twitch-icon-32.png", @@ -12028,9 +9885,7 @@ "website": "https://afractal.github.io/twittertron-app", "category": "Entertainment", "repository": "https://github.com/afractal/twittertron-app", - "keywords": [ - "twitter" - ], + "keywords": ["twitter"], "license": "Proprietary", "goodColorOnWhite": "#343e40", "goodColorOnBlack": "#fafbfc", @@ -12047,12 +9902,7 @@ "name": "Typetalk", "description": "A simply fun chat app for teams.", "website": "https://www.typetalk.in", - "keywords": [ - "chat", - "business", - "orgainzation", - "team" - ], + "keywords": ["chat", "business", "orgainzation", "team"], "category": "Business", "icon": "typetalk-icon.png", "icon32": "typetalk-icon-32.png", @@ -12066,11 +9916,7 @@ "name": "Tzared", "description": "Real-time strategy game for web browsers and PC.", "website": "https://tza.red", - "keywords": [ - "games", - "tzared", - "online" - ], + "keywords": ["games", "tzared", "online"], "category": "Games", "youtube_video_url": "https://www.youtube.com/watch?time_continue=612&v=4oFdzM81_Ls", "icon": "tzared-icon.png", @@ -12086,13 +9932,7 @@ "description": "App to help developers create access tokens for Uber applications with OAuth 2.0", "website": "http://ubauth.enytc.com", "repository": "https://github.com/chrisenytc/ubauth", - "keywords": [ - "uber", - "api", - "oauth", - "developer", - "tools" - ], + "keywords": ["uber", "api", "oauth", "developer", "tools"], "license": "MIT", "category": "Developer Tools", "icon": "ubauth-icon.png", @@ -12108,11 +9948,7 @@ "description": "This is a keystroke launcher for Windows and macOS.", "website": "https://ueli.app", "repository": "https://github.com/oliverschwendener/ueli", - "keywords": [ - "keystroke", - "launcher", - "search" - ], + "keywords": ["keystroke", "launcher", "search"], "license": "MIT", "category": "Utilities", "icon": "ueli-icon.png", @@ -12128,16 +9964,8 @@ "description": "Create UML class diagrams with a nice whiteboard look.", "website": "https://www.umlboard.com", "category": "Developer Tools", - "keywords": [ - "UML", - "whiteboard", - "class designer", - "handdrawn" - ], - "locales": [ - "en-US", - "de-DE" - ], + "keywords": ["UML", "whiteboard", "class designer", "handdrawn"], + "locales": ["en-US", "de-DE"], "icon": "umlboard-icon.png", "icon32": "umlboard-icon-32.png", "icon64": "umlboard-icon-64.png", @@ -12175,14 +10003,8 @@ "repository": "https://github.com/SafeStudio/unofficial-zalo", "category": "Productivity", "license": "GPL-3.0", - "keywords": [ - "chat", - "messaging", - "productivity" - ], - "locales": [ - "vi-VN" - ], + "keywords": ["chat", "messaging", "productivity"], + "locales": ["vi-VN"], "icon": "unofficial-zalo-icon.png", "icon32": "unofficial-zalo-icon-32.png", "icon64": "unofficial-zalo-icon-64.png", @@ -12197,20 +10019,12 @@ "website": "https://www.upcount.app", "category": "Business", "repository": "https://github.com/madisvain/upcount", - "keywords": [ - "invoice", - "invoicing", - "offline first", - "open source", - "configurable" - ], + "keywords": ["invoice", "invoicing", "offline first", "open source", "configurable"], "license": "GPLv3", "goodColorOnWhite": "#222222", "goodColorOnBlack": "#41DB7F", "faintColorOnWhite": "rgba(34, 34, 34, 0.3)", - "locales": [ - "en" - ], + "locales": ["en"], "icon": "upcount-icon.png", "icon32": "upcount-icon-32.png", "icon64": "upcount-icon-64.png", @@ -12263,25 +10077,10 @@ "name": "Vagrant Manager", "description": "Menu bar app for managing your vagrant machines.", "repository": "https://github.com/absalomedia/vagrant-manager", - "keywords": [ - "vagrant", - "manager", - "virtualbox", - "vmware", - "developer tools" - ], + "keywords": ["vagrant", "manager", "virtualbox", "vmware", "developer tools"], "license": "MIT", "category": "Developer Tools", - "locales": [ - "cs-CZ", - "hi-IN", - "ja-JP", - "en-GB", - "de-DE", - "pt-PT", - "uk-UA", - "zh-CN" - ], + "locales": ["cs-CZ", "hi-IN", "ja-JP", "en-GB", "de-DE", "pt-PT", "uk-UA", "zh-CN"], "icon": "vagrant-manager-icon.png", "icon32": "vagrant-manager-icon-32.png", "icon64": "vagrant-manager-icon-64.png", @@ -12294,10 +10093,7 @@ "name": "Vectr", "description": "Free Design App For Web + Desktop", "website": "https://vectr.com/", - "keywords": [ - "design", - "editor" - ], + "keywords": ["design", "editor"], "category": "Productivity", "icon": "vectr-icon.png", "icon32": "vectr-icon-32.png", @@ -12337,11 +10133,7 @@ "website": "https://vikunja.cloud/", "category": "Productivity", "repository": "https://code.vikunja.io/desktop", - "keywords": [ - "todo", - "task manager", - "tasks" - ], + "keywords": ["todo", "task manager", "tasks"], "license": "GPLv3", "icon": "vikunja-icon.png", "icon32": "vikunja-icon-32.png", @@ -12367,10 +10159,7 @@ "certificate", "life" ], - "locales": [ - "en-US", - "de-DE" - ], + "locales": ["en-US", "de-DE"], "icon": "visual-family-tree-icon.png", "icon32": "visual-family-tree-icon-32.png", "icon64": "visual-family-tree-icon-64.png", @@ -12385,9 +10174,7 @@ "website": "https://code.visualstudio.com", "homebrewCaskName": "visual-studio-code", "license": "MIT / Proprietary", - "keywords": [ - "code" - ], + "keywords": ["code"], "category": "Developer Tools", "icon": "visual-studio-code-icon.png", "icon32": "visual-studio-code-icon-32.png", @@ -12401,14 +10188,7 @@ "name": "VoIPstudio", "description": "Desktop Softphone client for VoIPstudio Business Phone System.", "website": "https://voipstudio.com", - "keywords": [ - "voip", - "chat", - "messaging", - "screen sharing", - "free online calls", - "free calls" - ], + "keywords": ["voip", "chat", "messaging", "screen sharing", "free online calls", "free calls"], "category": "Productivity", "icon": "voipstudio-icon.png", "icon32": "voipstudio-icon-32.png", @@ -12444,11 +10224,7 @@ "name": "Vue Calc", "description": "A Simple VueJS Calculator built with ElectronJS", "repository": "https://github.com/el3um4s/vue-calc", - "keywords": [ - "calculator", - "vuetify", - "vue" - ], + "keywords": ["calculator", "vuetify", "vue"], "category": "Utilities", "icon": "vue-calc-icon.png", "icon32": "vue-calc-icon-32.png", @@ -12461,11 +10237,7 @@ "slug": "vupc", "name": "VuPC", "description": "WebRTC screensharing.", - "keywords": [ - "screensharing", - "collaboration", - "WebRTC" - ], + "keywords": ["screensharing", "collaboration", "WebRTC"], "category": "Social", "repository": "https://github.com/machester4/vupc", "icon": "vupc-icon.png", @@ -12504,12 +10276,7 @@ "website": "https://www.waiterio.com", "category": "Business", "youtube_video_url": "https://www.youtube.com/watch?v=xkkHJUSXNI0", - "keywords": [ - "restaurant", - "pos", - "hospitality", - "business" - ], + "keywords": ["restaurant", "pos", "hospitality", "business"], "license": "Commercial", "locales": [ "cs-CZ", @@ -12599,12 +10366,7 @@ "name": "Wanna Class", "description": "Campus desktop software for YuanZe University students to select wanted course.", "repository": "https://github.com/MissterHao/WannaClass", - "keywords": [ - "course selection", - "Taiwan", - "YZU", - "students" - ], + "keywords": ["course selection", "Taiwan", "YZU", "students"], "category": "Education", "license": "GPL-3.0", "icon": "wanna-class-icon.png", @@ -12619,13 +10381,7 @@ "name": "Waqt", "description": "View current Islamic prayer times", "repository": "https://github.com/arafatamim/waqt", - "keywords": [ - "prayer-times", - "islam", - "islamic", - "waqt", - "prayer" - ], + "keywords": ["prayer-times", "islam", "islamic", "waqt", "prayer"], "category": "Utilities", "icon": "waqt-icon.png", "icon32": "waqt-icon-32.png", @@ -12640,12 +10396,7 @@ "description": "Explore, build, and most importantly survive in these unforgiving lands. Wayward is a challenging turn-based, top-down, wilderness survival roguelike.", "website": "http://www.waywardgame.com/", "category": "Games", - "keywords": [ - "game", - "roguelike", - "survival", - "sandbox" - ], + "keywords": ["game", "roguelike", "survival", "sandbox"], "youtube_video_url": "https://www.youtube.com/watch?v=kc69XEXiPzE", "icon": "wayward-icon.png", "icon32": "wayward-icon-32.png", @@ -12661,12 +10412,7 @@ "website": "https://www.webdesk.me/", "category": "Developer Tools", "repository": "https://github.com/Webdeskme/wdOS/releases", - "keywords": [ - "wdOS", - "WebDesktop", - "devloper", - "Webframe" - ], + "keywords": ["wdOS", "WebDesktop", "devloper", "Webframe"], "icon": "wdos-icon.png", "icon32": "wdos-icon-32.png", "icon64": "wdos-icon-64.png", @@ -12733,13 +10479,7 @@ "description": "Wrapper for Webkiosk portal of Jaypee college, Noida.", "website": "https://github.com/ngudbhav/Webkiosk-Wrapper", "category": "Utilities", - "keywords": [ - "webkiosk", - "jiit", - "college", - "wrapper", - "utility" - ], + "keywords": ["webkiosk", "jiit", "college", "wrapper", "utility"], "license": "MIT", "icon": "webkiosk-wrapper-icon.png", "icon32": "webkiosk-wrapper-icon-32.png", @@ -12755,14 +10495,7 @@ "website": "https://yikuansun.github.io/dartfling/product.html?pid=3", "repository": "https://github.com/yikuansun/webkitty", "license": "MIT", - "keywords": [ - "IDE", - "HTML", - "JS", - "CSS", - "Text Editor", - "Web Development" - ], + "keywords": ["IDE", "HTML", "JS", "CSS", "Text Editor", "Web Development"], "category": "Developer Tools", "icon": "webkitty-icon.png", "icon32": "webkitty-icon-32.png", @@ -12841,13 +10574,7 @@ "garmin", "withings" ], - "locales": [ - "en", - "es", - "de", - "fr", - "it" - ], + "locales": ["en", "es", "de", "fr", "it"], "goodColorOnWhite": "#1672b8", "goodColorOnBlack": "#428bca", "icon": "weighthub-icon.png", @@ -12863,16 +10590,9 @@ "description": "Open-source terrain generator.", "category": "Graphics & Design", "repository": "https://github.com/HoubkneghteS/Weltenschaft", - "keywords": [ - "Terrain", - "Map", - "Procedural generation" - ], + "keywords": ["Terrain", "Map", "Procedural generation"], "license": "MIT", - "locales": [ - "en", - "de" - ], + "locales": ["en", "de"], "icon": "weltenschaft-icon.png", "icon32": "weltenschaft-icon-32.png", "icon64": "weltenschaft-icon-64.png", @@ -12886,13 +10606,7 @@ "description": "An extensible web browser with beautiful UI and some innovative features.", "category": "Productivity", "repository": "https://github.com/wexond/wexond", - "keywords": [ - "browser", - "material", - "extensions", - "plugins", - "react" - ], + "keywords": ["browser", "material", "extensions", "plugins", "react"], "license": "MIT", "icon": "wexond-icon.png", "icon32": "wexond-icon-32.png", @@ -12905,9 +10619,7 @@ "slug": "whale", "name": "Whale", "description": "Unofficial Trello app", - "keywords": [ - "productivity" - ], + "keywords": ["productivity"], "category": "Productivity", "repository": "https://github.com/1000ch/whale", "icon": "whale-icon.png", @@ -12943,13 +10655,7 @@ "name": "Wildlink", "description": "The easiest way to earn some extra cash from links you already share. Wildlink is a tray utility that monitors your clipboard for eligible links to products and stores, then converts those links to shorter, profitable versions. When someone clicks through your links and makes a purchase, you earn a percentage of the purchase.", "website": "https://www.wildlink.me/", - "keywords": [ - "affiliate", - "clipboard", - "beer money", - "utility", - "tray" - ], + "keywords": ["affiliate", "clipboard", "beer money", "utility", "tray"], "license": "Commercial", "category": "Utilities", "icon": "wildlink-icon.png", @@ -12963,13 +10669,7 @@ "slug": "winds", "category": "Productivity", "description": "An open-source podcast & RSS desktop app", - "keywords": [ - "feed", - "rss", - "podcast", - "audio", - "syndication" - ], + "keywords": ["feed", "rss", "podcast", "audio", "syndication"], "name": "winds.yml", "repository": "https://github.com/getstream/winds", "website": "https://getstream.io", @@ -12986,13 +10686,7 @@ "description": "The most secure collaboration platform.", "website": "https://wire.com", "repository": "https://github.com/wireapp", - "keywords": [ - "communication", - "privacy", - "security", - "messenger", - "messaging" - ], + "keywords": ["communication", "privacy", "security", "messenger", "messaging"], "category": "Social", "icon": "wire-icon.png", "icon32": "wire-icon-32.png", @@ -13008,13 +10702,7 @@ "website": "https://github.com/Sanjit1/WizardMirror#wizard-mirror", "category": "Utilities", "repository": "https://www.github.com/Sanjit1/WizardMirror", - "keywords": [ - "wizard", - "mirror", - "magic", - "raspberry", - "pi" - ], + "keywords": ["wizard", "mirror", "magic", "raspberry", "pi"], "license": "MIT", "icon": "wizard-mirror-icon.png", "icon32": "wizard-mirror-icon-32.png", @@ -13043,10 +10731,7 @@ ], "license": "MPL2.0", "category": "Productivity", - "locales": [ - "en", - "zh-CN" - ], + "locales": ["en", "zh-CN"], "icon": "wnr-icon.png", "icon32": "wnr-icon-32.png", "icon64": "wnr-icon-64.png", @@ -13059,13 +10744,7 @@ "name": "WordofTheHour", "description": "Every hour, a new vocabulary word is featured along with translations into 10+ languages.", "website": "https://wordofthehour.org/desktopapp.html", - "keywords": [ - "education", - "language", - "learning", - "vocabulary", - "words" - ], + "keywords": ["education", "language", "learning", "vocabulary", "words"], "category": "Education", "icon": "wordofthehour-icon.png", "icon32": "wordofthehour-icon-32.png", @@ -13079,9 +10758,7 @@ "name": "WordPress", "description": "Desktop app that gives WordPress a permanent home in your dock.", "website": "https://desktop.wordpress.com", - "keywords": [ - "Productivity" - ], + "keywords": ["Productivity"], "category": "Productivity", "icon": "wordpress-icon.png", "icon32": "wordpress-icon-32.png", @@ -13096,11 +10773,7 @@ "description": "Employee monitoring and time tracking.", "website": "https://www.workpuls.com/", "category": "Business", - "keywords": [ - "employee monitoring", - "time tracking", - "screenshots" - ], + "keywords": ["employee monitoring", "time tracking", "screenshots"], "license": "Commercial", "icon": "workpuls-icon.png", "icon32": "workpuls-icon-32.png", @@ -13138,11 +10811,7 @@ "description": "World of Warcraft server uptime monitor", "repository": "https://github.com/arzynik/wowstat", "license": "MIT", - "keywords": [ - "wow", - "games", - "warcraft" - ], + "keywords": ["wow", "games", "warcraft"], "category": "Games", "icon": "wow-stat-icon.png", "icon32": "wow-stat-icon-32.png", @@ -13182,17 +10851,8 @@ "website": "https://xuanim.com/", "license": "ZENTAO OPEN SOFTWARE LICENSE 1.0 (http://zpl.pub/page/zoslv1.html)", "category": "Productivity", - "keywords": [ - "im", - "messaging", - "collaboration", - "office" - ], - "locales": [ - "zh-CN", - "zh-TW", - "en-US" - ], + "keywords": ["im", "messaging", "collaboration", "office"], + "locales": ["zh-CN", "zh-TW", "en-US"], "icon": "xuanxuan-icon.png", "icon32": "xuanxuan-icon-32.png", "icon64": "xuanxuan-icon-64.png", @@ -13206,18 +10866,9 @@ "description": "Download youtube videos to audio files.", "category": "Music", "repository": "https://github.com/moshfeu/y2mp3", - "keywords": [ - "youtube", - "playlist", - "download", - "mp3", - "free", - "audio" - ], + "keywords": ["youtube", "playlist", "download", "mp3", "free", "audio"], "license": "MIT", - "locales": [ - "en-US" - ], + "locales": ["en-US"], "icon": "y2mp3-icon.png", "icon32": "y2mp3-icon-32.png", "icon64": "y2mp3-icon-64.png", @@ -13231,11 +10882,7 @@ "description": "YAGR is yet another GitBook reader for desktop.", "repository": "https://github.com/gnu4cn/gitbook-reader-app", "category": "Education", - "keywords": [ - "gitbook reader", - "typeorm backed", - "nodegit backed" - ], + "keywords": ["gitbook reader", "typeorm backed", "nodegit backed"], "language": "English/Chinese", "icon": "yet-another-gitbook-reader-icon.png", "icon32": "yet-another-gitbook-reader-icon-32.png", @@ -13269,13 +10916,7 @@ "name": "Yout", "description": "The new way to watch your playlists from YouTube on desktop.", "website": "https://youtplayer.github.io/", - "keywords": [ - "yout", - "player", - "youtube", - "desktop", - "playlist" - ], + "keywords": ["yout", "player", "youtube", "desktop", "playlist"], "category": "Photo & Video", "icon": "yout-icon.png", "icon32": "yout-icon-32.png", @@ -13291,15 +10932,7 @@ "website": "https://ytmdesktop.app", "category": "Music", "repository": "https://github.com/adlerluiz/ytmdesktop", - "keywords": [ - "youtube", - "music", - "desktop", - "app", - "node", - "javascript", - "materializecss" - ], + "keywords": ["youtube", "music", "desktop", "app", "node", "javascript", "materializecss"], "icon": "youtube-music-desktop-app-icon.png", "icon32": "youtube-music-desktop-app-icon-32.png", "icon64": "youtube-music-desktop-app-icon-64.png", @@ -13343,9 +10976,7 @@ "description": "Ethiopian. Music.", "website": "https://zefenify.com/about.html", "repository": "https://github.com/Zefenify/Wolf-Cola", - "keywords": [ - "music" - ], + "keywords": ["music"], "license": "MIT", "category": "Music", "icon": "zefenify-icon.png", @@ -13384,13 +11015,7 @@ "name": "Zeplin", "description": "Collaboration app for designers and developers", "website": "https://zeplin.io", - "keywords": [ - "design", - "development", - "collaboration", - "sketch", - "photoshop" - ], + "keywords": ["design", "development", "collaboration", "sketch", "photoshop"], "category": "Developer Tools", "icon": "zeplin-icon.png", "icon32": "zeplin-icon-32.png", @@ -13405,13 +11030,7 @@ "description": "All-in-one product delivery and insight discovery platform.", "website": "https://www.documize.com/zerabase", "snapcraftName": "zerabase", - "keywords": [ - "productivity", - "product", - "project", - "feedback", - "analytics" - ], + "keywords": ["productivity", "product", "project", "feedback", "analytics"], "category": "Productivity", "icon": "zerabase-icon.png", "icon32": "zerabase-icon-32.png", @@ -13426,22 +11045,10 @@ "description": "Write Markdown with Zettelkasten and citation support and manage your book and paper projects", "website": "https://www.zettlr.com/", "repository": "https://github.com/zettlr/zettlr", - "keywords": [ - "markdown", - "editor", - "writing", - "academic", - "export", - "share" - ], + "keywords": ["markdown", "editor", "writing", "academic", "export", "share"], "category": "Productivity", "license": "GNU GPL v3", - "locales": [ - "de-DE", - "en-US", - "en-GB", - "fr-FR" - ], + "locales": ["de-DE", "en-US", "en-GB", "fr-FR"], "icon": "zettlr-icon.png", "icon32": "zettlr-icon-32.png", "icon64": "zettlr-icon-64.png", @@ -13455,9 +11062,7 @@ "description": "Beautiful & Free Markdown editor built to secure your text files.", "website": "https://znote.io", "repository": "https://github.com/alagrede/znote-app", - "keywords": [ - "notes" - ], + "keywords": ["notes"], "category": "Productivity", "icon": "znote-icon.png", "icon32": "znote-icon-32.png", @@ -13472,14 +11077,7 @@ "description": "Sticky notes + Markdown + Tabs. All in one .txt file.", "category": "Productivity", "repository": "https://github.com/zonetti/zonote", - "keywords": [ - "note-taking", - "sticky-notes", - "markdown", - "tabs", - "offline-first", - "notes" - ], + "keywords": ["note-taking", "sticky-notes", "markdown", "tabs", "offline-first", "notes"], "license": "MIT", "icon": "zonote-icon.png", "icon32": "zonote-icon-32.png", @@ -13493,9 +11091,7 @@ "name": "Zoommy", "description": "Helps you find awesome free stock photos for your creative product or inspiration", "website": "https://zoommyapp.com/", - "keywords": [ - "photos" - ], + "keywords": ["photos"], "category": "Photo & Video", "icon": "zoommy-icon.png", "icon32": "zoommy-icon-32.png", @@ -13511,13 +11107,7 @@ "website": "https://zulip.com/", "category": "Social", "repository": "https://github.com/zulip/zulip-desktop", - "keywords": [ - "zulip", - "chat", - "productivity", - "networking", - "social" - ], + "keywords": ["zulip", "chat", "productivity", "networking", "social"], "license": "https://github.com/zulip/zulip-desktop/blob/master/LICENSE", "icon": "zulip-icon.png", "icon32": "zulip-icon-32.png", @@ -13526,4 +11116,4 @@ "icon256": "zulip-icon-256.png", "date": "2019-03-22" } -] \ No newline at end of file +] diff --git a/lib/app-categories.js b/lib/app-categories.js index 04f38f484b1..a9c00d9993e 100644 --- a/lib/app-categories.js +++ b/lib/app-categories.js @@ -25,4 +25,4 @@ module.exports = [ 'Sports', 'Travel', 'Utilities', -] +]; diff --git a/lib/apps-with-github-repos.js b/lib/apps-with-github-repos.js index e47a8b8d59c..ff391f5f845 100644 --- a/lib/apps-with-github-repos.js +++ b/lib/apps-with-github-repos.js @@ -1,10 +1,10 @@ -const apps = require('./raw-app-list')() -const parseGitUrl = require('github-url-to-object') +const apps = require('./raw-app-list')(); +const parseGitUrl = require('github-url-to-object'); module.exports = apps.filter((app) => { // inherit repository from website if possible - if (!app.repository && parseGitUrl(app.website)) app.repository = app.website - if (!app.repository) return false - if (!parseGitUrl(app.repository)) return false - return true -}) + if (!app.repository && parseGitUrl(app.website)) app.repository = app.website; + if (!app.repository) return false; + if (!parseGitUrl(app.repository)) return false; + return true; +}); diff --git a/lib/broken-links.js b/lib/broken-links.js index 01fdec2bdd5..994299d4cc9 100644 --- a/lib/broken-links.js +++ b/lib/broken-links.js @@ -1,22 +1,22 @@ -const fsPromises = require('fs').promises -const { isUrl } = require('./is-url') -const path = require('path') -const readdirp = require('readdirp') -const yaml = require('yaml') +const fsPromises = require('fs').promises; +const { isUrl } = require('./is-url'); +const path = require('path'); +const readdirp = require('readdirp'); +const yaml = require('yaml'); -const topDir = path.dirname(__dirname) +const topDir = path.dirname(__dirname); // walk an object subtree looking for URL strings const getObjectUrls = (root) => { - const urls = [] - const queue = [root] + const urls = []; + const queue = [root]; while (queue.length !== 0) { - const vals = Object.values(queue.shift()) - urls.push(...vals.filter(isUrl)) - queue.push(...vals.filter((v) => typeof v === 'object')) + const vals = Object.values(queue.shift()); + urls.push(...vals.filter(isUrl)); + queue.push(...vals.filter((v) => typeof v === 'object')); } - return urls -} + return urls; +}; // scrape a url to see if the link is broken. // return a Promise that resolves as { url, err } @@ -28,8 +28,8 @@ const scrape = (url) => err: res.ok ? null : `${res.status} ${res.statusText}`, status: res.status, }), - (err) => ({ url, err, status: -2 }) - ) + (err) => ({ url, err, status: -2 }), + ); // scrape all the urls found in a yml file. // report broken links to console.log(). @@ -39,29 +39,29 @@ const processYmlEntry = (entry) => .readFile(entry.fullPath, { encoding: 'utf8' }) .then((file) => { try { - return yaml.parse(file) + return yaml.parse(file); } catch (error) { - console.error(`Failed to parse ${entry.path}. Skipping.`) - return { disabled: true } + console.error(`Failed to parse ${entry.path}. Skipping.`); + return { disabled: true }; } }) .then((o) => (o.disabled ? [] : getObjectUrls(o))) .then(async (urls) => { - const results = [] + const results = []; for (const url of urls) { // Scrape one by one to handle rate limiting - const r = await scrape(url) - results.push(r) + const r = await scrape(url); + results.push(r); } - return results + return results; }) .then((results) => results.filter((res) => !!res.err)) .then((fails) => { - fails.forEach((f) => console.log(`${entry.path} - ${f.url} (${f.err})`)) - return fails - }) + fails.forEach((f) => console.log(`${entry.path} - ${f.url} (${f.err})`)); + return fails; + }); const findBrokenLinks = (start = 0, end = Infinity) => readdirp @@ -70,23 +70,23 @@ const findBrokenLinks = (start = 0, end = Infinity) => directoryFilter: (entry) => entry.path.startsWith('apps'), }) .then(async (entries) => { - const result = [] - let limitedEntries = entries.reverse() + const result = []; + let limitedEntries = entries.reverse(); if (start !== 0 || end !== Infinity) { - limitedEntries = entries.slice(start, end) + limitedEntries = entries.slice(start, end); } for (const entry of limitedEntries) { - console.log(`Processing ${entry.path}`) + console.log(`Processing ${entry.path}`); result.push({ entry, result: await processYmlEntry(entry), - }) + }); } - return result + return result; }) - .then((arr) => arr.filter((inner) => !!inner.result.length)) + .then((arr) => arr.filter((inner) => !!inner.result.length)); -module.exports = findBrokenLinks +module.exports = findBrokenLinks; diff --git a/lib/grandfathered-descriptions.js b/lib/grandfathered-descriptions.js index 91f601fed3e..376d9389881 100644 --- a/lib/grandfathered-descriptions.js +++ b/lib/grandfathered-descriptions.js @@ -760,4 +760,4 @@ module.exports = [ 'zoommy', 'zulip', 'zuzu', -] +]; diff --git a/lib/grandfathered-links.js b/lib/grandfathered-links.js index 9aad5af7e49..e6414abd5de 100644 --- a/lib/grandfathered-links.js +++ b/lib/grandfathered-links.js @@ -63,4 +63,4 @@ module.exports = [ 'yhat-rodeo', 'zazu-app', 'zector', -] +]; diff --git a/lib/grandfathered-small-icons.js b/lib/grandfathered-small-icons.js index 6f02164efb5..7e6a0901daa 100644 --- a/lib/grandfathered-small-icons.js +++ b/lib/grandfathered-small-icons.js @@ -69,4 +69,4 @@ module.exports = [ 'wire', 'wordpress-com', 'writebar', -] +]; diff --git a/lib/is-url.js b/lib/is-url.js index 2483f28e23f..e3724219c75 100644 --- a/lib/is-url.js +++ b/lib/is-url.js @@ -1,12 +1,12 @@ -const { URL } = require('node:url') +const { URL } = require('node:url'); const isUrl = (value) => { try { - new URL(value) - return true + new URL(value); + return true; } catch { - return false + return false; } -} +}; -module.exports = { isUrl } +module.exports = { isUrl }; diff --git a/lib/old-electron-apps.js b/lib/old-electron-apps.js index 325b365247f..b485f3f2357 100644 --- a/lib/old-electron-apps.js +++ b/lib/old-electron-apps.js @@ -1,22 +1,22 @@ -const fsPromises = require('fs').promises -const { isUrl } = require('./is-url') -const path = require('path') -const readdirp = require('readdirp') -const yaml = require('yaml') +const fsPromises = require('fs').promises; +const { isUrl } = require('./is-url'); +const path = require('path'); +const readdirp = require('readdirp'); +const yaml = require('yaml'); -const topDir = path.dirname(__dirname) +const topDir = path.dirname(__dirname); // walk an object subtree looking for URL strings const getObjectUrls = (root) => { - const urls = [] - const queue = [root] + const urls = []; + const queue = [root]; while (queue.length !== 0) { - const vals = Object.values(queue.shift()) - urls.push(...vals.filter(isUrl)) - queue.push(...vals.filter((v) => typeof v === 'object')) + const vals = Object.values(queue.shift()); + urls.push(...vals.filter(isUrl)); + queue.push(...vals.filter((v) => typeof v === 'object')); } - return urls -} + return urls; +}; // scrape a url to see if the link is broken. // return a Promise that resolves as { url, err } @@ -24,28 +24,24 @@ const scrape = (url) => { const package = 'https://raw.githubusercontent.com/' + url.replace(/^.*com/g, '').replace(/.git$/g, '') + - '/master/package.json' + '/master/package.json'; return fetch(package, { method: 'GET' }) .then((res) => (res.status === 200 ? res.json() : {})) .then((json) => { - let version + let version; if (json.hasOwnProperty('devDependencies')) { if (json.devDependencies.hasOwnProperty('electron')) - version = json.devDependencies.electron - .replace(/^\^/g, '') - .replace(/^~/g, '') + version = json.devDependencies.electron.replace(/^\^/g, '').replace(/^~/g, ''); } if (json.hasOwnProperty('dependencies')) { if (json.dependencies.hasOwnProperty('electron')) - version = json.dependencies.electron - .replace(/^\^/g, '') - .replace(/^~/g, '') + version = json.dependencies.electron.replace(/^\^/g, '').replace(/^~/g, ''); } - return version - }) -} + return version; + }); +}; // scrape all the urls found in a yml file. // report broken links to console.log(). @@ -55,10 +51,10 @@ const processYmlEntry = (entry) => .readFile(entry.fullPath, { encoding: 'utf8' }) .then((file) => { try { - return yaml.parse(file) + return yaml.parse(file); } catch (error) { - console.error(`Failed to parse ${entry.path}. Skipping.`) - return { disabled: true } + console.error(`Failed to parse ${entry.path}. Skipping.`); + return { disabled: true }; } }) .then((o) => (o.disabled ? undefined : o.repository)) @@ -66,9 +62,9 @@ const processYmlEntry = (entry) => .then((version) => { version ? console.log(`${entry.path} - Electron v${version}`) - : console.log(`${entry.path} - Closed Source`) - return version - }) + : console.log(`${entry.path} - Closed Source`); + return version; + }); const findOldElectronApps = (start = 0, end = Infinity) => readdirp @@ -77,22 +73,22 @@ const findOldElectronApps = (start = 0, end = Infinity) => directoryFilter: (entry) => entry.path.startsWith('apps'), }) .then(async (entries) => { - const result = [] - let limitedEntries = entries + const result = []; + let limitedEntries = entries; if (start !== 0 || end !== Infinity) { - limitedEntries = entries.slice(start, end) + limitedEntries = entries.slice(start, end); } for (const entry of limitedEntries) { - console.log(`Processing ${entry.path}`) + console.log(`Processing ${entry.path}`); result.push({ entry, result: await processYmlEntry(entry), - }) + }); } - return result - }) + return result; + }); -module.exports = findOldElectronApps +module.exports = findOldElectronApps; diff --git a/lib/raw-app-list.js b/lib/raw-app-list.js index 7bd164aa43f..ddbb0eee6d5 100644 --- a/lib/raw-app-list.js +++ b/lib/raw-app-list.js @@ -1,29 +1,27 @@ -const fs = require('fs') -const path = require('path') -const yaml = require('yaml') +const fs = require('fs'); +const path = require('path'); +const yaml = require('yaml'); module.exports = function getSlugs() { return fs .readdirSync(path.join(__dirname, '../apps')) .filter((filename) => { - return fs - .statSync(path.join(__dirname, `../apps/${filename}`)) - .isDirectory() + return fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory(); }) .sort() .reduce((slugs, slug) => { - const yamlFile = path.join(__dirname, `../apps/${slug}/${slug}.yml`) - const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')) + const yamlFile = path.join(__dirname, `../apps/${slug}/${slug}.yml`); + const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')); if (meta.disabled) { - return slugs + return slugs; } else { const app = { slug: slug, iconPath: path.join(__dirname, `../apps/${slug}/${slug}-icon.png`), ...meta, - } - return [...slugs, app] + }; + return [...slugs, app]; } - }, []) -} + }, []); +}; diff --git a/meta/categories.json b/meta/categories.json index 68b16b0ba30..5acf0849f40 100644 --- a/meta/categories.json +++ b/meta/categories.json @@ -89,4 +89,4 @@ "count": 1, "slug": "health-fitness" } -] \ No newline at end of file +] diff --git a/meta/dates.json b/meta/dates.json index 119a137bf29..26e2c8a28ee 100644 --- a/meta/dates.json +++ b/meta/dates.json @@ -1188,4 +1188,4 @@ "agora-flat": "2022-08-23", "oomol-studio": "2025-02-19", "horse-browser": "2025-07-08" -} \ No newline at end of file +} diff --git a/package.json b/package.json index 2475be96a8b..e11975f44aa 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,17 @@ "build:dates": "node script/dates", "build:categories": "node script/categories", "build:pack": "node script/pack", - "prettier": "prettier --check \"./**/*.{ts,js,yml}\" --experimental-cli", - "test": "mocha --reporter min test/human-data.js && prettier --check \"./**/*.{ts,js,yml}\" --write", - "test:debug": "mocha --reporter spec test/human-data.js && prettier --check \"./**/*.{ts,js,yml}\" --write", + "lint": "oxfmt --check . && oxlint", + "lint:fix": "oxfmt --write . && oxlint --fix", + "test": "mocha --reporter min test/human-data.js && oxfmt --check .", + "test:debug": "mocha --reporter spec test/human-data.js && oxfmt --check .", "pretest-all": "npm run build", - "test-all": "mocha --reporter min && prettier --check \"./**/*.{ts,js,yml}\" --write", + "test-all": "mocha --reporter min && oxfmt --check .", "wizard": "node wizard.js", "remove:links": "node script/remove-broken-links", "remove:old": "node script/remove-old-electron-apps", - "remove:disabled": "node script/remove-disabled-apps" + "remove:disabled": "node script/remove-disabled-apps", + "prepare": "husky" }, "repository": "https://github.com/electron/apps", "keywords": [ @@ -39,7 +41,8 @@ "inquirer": "^8.2.4", "lint-staged": "^12.4.1", "mocha": "^11.7.4", - "prettier": "^3.6.2", + "oxfmt": "^0.44.0", + "oxlint": "^1.59.0", "readdirp": "^3.6.0", "semver": "^7.7.3", "sharp": "^0.34.4", @@ -51,7 +54,13 @@ "node": ">=22" }, "lint-staged": { - "*.{js,ts,yml}": "prettier --write --experimental-cli" + "*.js": [ + "oxfmt --write", + "oxlint --fix" + ], + "*.json": [ + "oxfmt --write" + ] }, "packageManager": "yarn@4.10.3+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f" } diff --git a/readme.md b/readme.md index e7c8df0854c..75d5d9d1cef 100644 --- a/readme.md +++ b/readme.md @@ -1,11 +1,12 @@ # electron-apps [![CI](https://github.com/electron/apps/actions/workflows/test.yml/badge.svg)](https://github.com/electron/apps/actions/workflows/test.yml) -A collection of apps built on Electron. [electronjs.org/apps](http://electronjs.org/apps). +A collection of apps built on Electron. +[electronjs.org/apps](http://electronjs.org/apps). ## Adding your app -If you have an Electron application you'd like to see added, -please read the [contributing](contributing.md) doc. +If you have an Electron application you'd like to see added, please read the +[contributing](contributing.md) doc. ## How it Works diff --git a/script/categories.js b/script/categories.js index d5195fca7b3..e44fef81f01 100755 --- a/script/categories.js +++ b/script/categories.js @@ -1,40 +1,40 @@ -const fs = require('fs') -const path = require('path') -const slugify = require('slugify') -const apps = require('../lib/raw-app-list')() +const fs = require('fs'); +const path = require('path'); +const slugify = require('slugify'); +const apps = require('../lib/raw-app-list')(); -console.log('Generating a list of categories with counts...') +console.log('Generating a list of categories with counts...'); const countArrayValues = function (arr, nameLabel, countLabel) { - var counts = {} - nameLabel = nameLabel || 'value' - countLabel = countLabel || 'count' + var counts = {}; + nameLabel = nameLabel || 'value'; + countLabel = countLabel || 'count'; arr.forEach(function (value) { - if (typeof value !== 'string') return - counts[value] ? counts[value]++ : (counts[value] = 1) - }) + if (typeof value !== 'string') return; + counts[value] ? counts[value]++ : (counts[value] = 1); + }); return Object.keys(counts) .map(function (key) { - var obj = {} - obj[nameLabel] = key - obj[countLabel] = counts[key] - return obj + var obj = {}; + obj[nameLabel] = key; + obj[countLabel] = counts[key]; + return obj; }) .sort(function (a, b) { - return b[countLabel] - a[countLabel] - }) -} + return b[countLabel] - a[countLabel]; + }); +}; const categories = countArrayValues( apps.map((app) => app.category), - 'name' + 'name', ) .map((category) => Object.assign(category, { slug: slugify(category.name) })) - .sort((a, b) => b.count - a.count) + .sort((a, b) => b.count - a.count); fs.writeFileSync( path.join(__dirname, '../meta/categories.json'), - JSON.stringify(categories, null, 2) -) + JSON.stringify(categories, null, 2), +); diff --git a/script/clean.js b/script/clean.js index 77c4c358585..5c6b1fc1587 100755 --- a/script/clean.js +++ b/script/clean.js @@ -4,22 +4,18 @@ // files are present in the repo. This script cleans up any leftover local // artifacts that were created by `npm run build`, such as `apps/foo-icon-128.png` -const fs = require('fs') -const path = require('path') +const fs = require('fs'); +const path = require('path'); fs.readdirSync(path.join(__dirname, '../apps')) .filter((filename) => { - return fs - .statSync(path.join(__dirname, `../apps/${filename}`)) - .isDirectory() + return fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory(); }) .filter((filename) => { - return !fs.existsSync( - path.join(__dirname, `../apps/${filename}/${filename}.yml`) - ) + return !fs.existsSync(path.join(__dirname, `../apps/${filename}/${filename}.yml`)); }) .forEach((filename) => { - const appDir = path.join(__dirname, `../apps/${filename}`) - console.log(`Removing leftover artifacts from ${appDir}`) - fs.rmSync(appDir, { recursive: true, force: true }) - }) + const appDir = path.join(__dirname, `../apps/${filename}`); + console.log(`Removing leftover artifacts from ${appDir}`); + fs.rmSync(appDir, { recursive: true, force: true }); + }); diff --git a/script/dates.js b/script/dates.js index f8cc9df2a75..42d79634af6 100755 --- a/script/dates.js +++ b/script/dates.js @@ -1,18 +1,18 @@ -const fs = require('fs') -const path = require('path') -const datesPath = path.join(__dirname, '../meta/dates.json') -const dates = require(datesPath) -const existingSlugs = Object.keys(dates) -const apps = require('../lib/raw-app-list')() +const fs = require('fs'); +const path = require('path'); +const datesPath = path.join(__dirname, '../meta/dates.json'); +const dates = require(datesPath); +const existingSlugs = Object.keys(dates); +const apps = require('../lib/raw-app-list')(); -console.log('Checking app submission dates...') +console.log('Checking app submission dates...'); apps .filter((app) => existingSlugs.indexOf(app.slug) === -1) .forEach((app) => { - const date = new Date().toISOString().slice(0, 10) - console.log(`${app.slug}: ${date}`) - dates[app.slug] = date - }) + const date = new Date().toISOString().slice(0, 10); + console.log(`${app.slug}: ${date}`); + dates[app.slug] = date; + }); -fs.writeFileSync(datesPath, JSON.stringify(dates, null, 2)) +fs.writeFileSync(datesPath, JSON.stringify(dates, null, 2)); diff --git a/script/find-broken-links.js b/script/find-broken-links.js index adda3cd1e69..9600a59e687 100755 --- a/script/find-broken-links.js +++ b/script/find-broken-links.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -const findBrokenLinks = require('../lib/broken-links') +const findBrokenLinks = require('../lib/broken-links'); /* Links can break at any time and it's outside of the repo's control, so it doesn't make sense to run this script as part of CI. Instead, @@ -10,24 +10,20 @@ const findBrokenLinks = require('../lib/broken-links') e.g. if all the links in a file are dead, disable the file? */ process.on('unhandledRejection', (reason, p) => { - console.log('Unhandled Rejection at: Promise', p, 'reason:', reason) -}) + console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); +}); -const numberArgs = process.argv.filter((v) => /^\d+$/.test(v)) -const possibleStart = - numberArgs.length > 0 ? parseInt(numberArgs[0], 10) : undefined -const possibleEnd = - numberArgs.length > 0 ? parseInt(numberArgs[1], 10) : undefined +const numberArgs = process.argv.filter((v) => /^\d+$/.test(v)); +const possibleStart = numberArgs.length > 0 ? parseInt(numberArgs[0], 10) : undefined; +const possibleEnd = numberArgs.length > 0 ? parseInt(numberArgs[1], 10) : undefined; console.log( - `Checking apps ${possibleStart || 0} through ${ - possibleEnd || 'infinity' - } for broken links` -) + `Checking apps ${possibleStart || 0} through ${possibleEnd || 'infinity'} for broken links`, +); findBrokenLinks(possibleStart, possibleEnd) .then((failArrays) => { - console.log(`${failArrays.length} failure groups`) - return failArrays.flat() + console.log(`${failArrays.length} failure groups`); + return failArrays.flat(); }) - .then((fails) => process.exit(fails.length)) + .then((fails) => process.exit(fails.length)); diff --git a/script/pack.js b/script/pack.js index e5cd4268836..13a4f8354ea 100755 --- a/script/pack.js +++ b/script/pack.js @@ -1,22 +1,20 @@ -const fs = require('fs') -const path = require('path') -const yaml = require('yaml') -const dates = require('../meta/dates.json') -const parseGitHubUrl = require('github-url-to-object') -const apps = [] +const fs = require('fs'); +const path = require('path'); +const yaml = require('yaml'); +const dates = require('../meta/dates.json'); +const parseGitHubUrl = require('github-url-to-object'); +const apps = []; fs.readdirSync(path.join(__dirname, '../apps')) .filter((filename) => { - return fs - .statSync(path.join(__dirname, `../apps/${filename}`)) - .isDirectory() + return fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory(); }) .forEach((slug) => { - const yamlFile = path.join(__dirname, `../apps/${slug}/${slug}.yml`) - const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')) + const yamlFile = path.join(__dirname, `../apps/${slug}/${slug}.yml`); + const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')); if (meta.disabled) { - return + return; } const app = Object.assign({ slug: slug }, meta, { @@ -26,23 +24,16 @@ fs.readdirSync(path.join(__dirname, '../apps')) icon128: `${slug}-icon-128.png`, icon256: `${slug}-icon-256.png`, date: dates[slug], - }) + }); // Delete website if it's the same URL as repository - const parsedWebsite = parseGitHubUrl(app.website) - const parsedRepo = parseGitHubUrl(app.repository) - if ( - parsedWebsite && - parsedRepo && - parsedWebsite.https_url === parsedRepo.https_url - ) { - delete app.website + const parsedWebsite = parseGitHubUrl(app.website); + const parsedRepo = parseGitHubUrl(app.repository); + if (parsedWebsite && parsedRepo && parsedWebsite.https_url === parsedRepo.https_url) { + delete app.website; } - apps.push(app) - }) + apps.push(app); + }); -fs.writeFileSync( - path.join(__dirname, '../index.json'), - JSON.stringify(apps, null, 2) -) +fs.writeFileSync(path.join(__dirname, '../index.json'), JSON.stringify(apps, null, 2)); diff --git a/script/remove-broken-links.js b/script/remove-broken-links.js index ee487945b7e..5f151063f95 100644 --- a/script/remove-broken-links.js +++ b/script/remove-broken-links.js @@ -1,58 +1,52 @@ #!/usr/bin/env node -const fs = require('fs').promises +const fs = require('fs').promises; -const findBrokenLinks = require('../lib/broken-links') +const findBrokenLinks = require('../lib/broken-links'); /* Links can break at any time and it's outside of the repo's control, so it doesn't make sense to run this script as part of CI. Instead, this should be run periodically as part of a separate process. */ process.on('unhandledRejection', (reason, p) => { - console.log('Unhandled Rejection at: Promise', p, 'reason:', reason) -}) + console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); +}); -const numberArgs = process.argv.filter((v) => /^\d+$/.test(v)) -const possibleStart = - numberArgs.length > 0 ? parseInt(numberArgs[0], 10) : undefined -const possibleEnd = - numberArgs.length > 0 ? parseInt(numberArgs[1], 10) : undefined +const numberArgs = process.argv.filter((v) => /^\d+$/.test(v)); +const possibleStart = numberArgs.length > 0 ? parseInt(numberArgs[0], 10) : undefined; +const possibleEnd = numberArgs.length > 0 ? parseInt(numberArgs[1], 10) : undefined; console.log( - `Checking apps ${possibleStart || 0} through ${ - possibleEnd || 'infinity' - } for broken links` -) + `Checking apps ${possibleStart || 0} through ${possibleEnd || 'infinity'} for broken links`, +); function isRateLimited(failures = []) { - return failures.every(({ status }) => status === 429) + return failures.every(({ status }) => status === 429); } async function main() { - const failArrays = (await findBrokenLinks(possibleStart, possibleEnd)).filter( - (failure) => { - return !isRateLimited(failure.result) - } - ) + const failArrays = (await findBrokenLinks(possibleStart, possibleEnd)).filter((failure) => { + return !isRateLimited(failure.result); + }); - console.log(`Will disable ${failArrays.length} entries`) + console.log(`Will disable ${failArrays.length} entries`); for (const failure of failArrays) { - console.timeLog(failure.result) - const deadLinks = failure.result.map(({ url }) => url).join(', ') - let data = await fs.readFile(failure.entry.fullPath, { encoding: 'utf-8' }) + console.timeLog(failure.result); + const deadLinks = failure.result.map(({ url }) => url).join(', '); + let data = await fs.readFile(failure.entry.fullPath, { encoding: 'utf-8' }); if (!data.endsWith('\n')) { - data += `\n` + data += `\n`; } - data += `disabled: true # Dead link(s): ${deadLinks}\n` + data += `disabled: true # Dead link(s): ${deadLinks}\n`; - await fs.writeFile(failure.entry.fullPath, data, { encoding: 'utf-8' }) + await fs.writeFile(failure.entry.fullPath, data, { encoding: 'utf-8' }); - console.log(data) - console.log(`\n---\n`) + console.log(data); + console.log(`\n---\n`); } } -main() +main(); diff --git a/script/remove-disabled-apps.js b/script/remove-disabled-apps.js index 21422078d40..648454a710e 100644 --- a/script/remove-disabled-apps.js +++ b/script/remove-disabled-apps.js @@ -1,22 +1,20 @@ #!/usr/bin/env node -const fs = require('fs') -const path = require('path') -const yaml = require('yaml') +const fs = require('fs'); +const path = require('path'); +const yaml = require('yaml'); fs.readdirSync(path.join(__dirname, '../apps')) .filter((filename) => { - return fs - .statSync(path.join(__dirname, `../apps/${filename}`)) - .isDirectory() + return fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory(); }) .filter((filename) => { - const yamlFile = path.join(__dirname, `../apps/${filename}/${filename}.yml`) - const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')) - return meta.disabled ? true : false + const yamlFile = path.join(__dirname, `../apps/${filename}/${filename}.yml`); + const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')); + return meta.disabled ? true : false; }) .forEach((filename) => { - const appDir = path.join(__dirname, `../apps/${filename}`) - console.log(`Removing disabled ${filename} app`) - fs.rmSync(appDir, { recursive: true, force: true }) - }) + const appDir = path.join(__dirname, `../apps/${filename}`); + console.log(`Removing disabled ${filename} app`); + fs.rmSync(appDir, { recursive: true, force: true }); + }); diff --git a/script/remove-old-electron-apps.js b/script/remove-old-electron-apps.js index 1927f519e06..b0a82732407 100644 --- a/script/remove-old-electron-apps.js +++ b/script/remove-old-electron-apps.js @@ -1,60 +1,54 @@ #!/usr/bin/env node -const fs = require('fs').promises -const semver = require('semver') +const fs = require('fs').promises; +const semver = require('semver'); -const findOldElectronApps = require('../lib/old-electron-apps') +const findOldElectronApps = require('../lib/old-electron-apps'); -const OLD_ELECTRON_VERSION = '6.0.0' +const OLD_ELECTRON_VERSION = '6.0.0'; /* Links can break at any time and it's outside of the repo's control, so it doesn't make sense to run this script as part of CI. Instead, this should be run periodically as part of a separate process. */ process.on('unhandledRejection', (reason, p) => { - console.log('Unhandled Rejection at: Promise', p, 'reason:', reason) -}) + console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); +}); -const numberArgs = process.argv.filter((v) => /^\d+$/.test(v)) -const possibleStart = - numberArgs.length > 0 ? parseInt(numberArgs[0], 10) : undefined -const possibleEnd = - numberArgs.length > 0 ? parseInt(numberArgs[1], 10) : undefined +const numberArgs = process.argv.filter((v) => /^\d+$/.test(v)); +const possibleStart = numberArgs.length > 0 ? parseInt(numberArgs[0], 10) : undefined; +const possibleEnd = numberArgs.length > 0 ? parseInt(numberArgs[1], 10) : undefined; console.log( - `Checking apps ${possibleStart || 0} through ${ - possibleEnd || 'infinity' - } for old electron apps` -) + `Checking apps ${possibleStart || 0} through ${possibleEnd || 'infinity'} for old electron apps`, +); async function main() { - const oldArrays = ( - await findOldElectronApps(possibleStart, possibleEnd) - ).filter((old) => { - if (old.result === undefined) return false + const oldArrays = (await findOldElectronApps(possibleStart, possibleEnd)).filter((old) => { + if (old.result === undefined) return false; try { - return semver.lt(old.result, OLD_ELECTRON_VERSION) + return semver.lt(old.result, OLD_ELECTRON_VERSION); } catch (err) { - return false + return false; } - }) + }); - console.log(`Will disable ${oldArrays.length} entries`) + console.log(`Will disable ${oldArrays.length} entries`); for (const old of oldArrays) { - let data = await fs.readFile(old.entry.fullPath, { encoding: 'utf-8' }) + let data = await fs.readFile(old.entry.fullPath, { encoding: 'utf-8' }); if (!data.endsWith('\n')) { - data += `\n` + data += `\n`; } - data += `disabled: true # Old Electron version: v${old.result}\n` + data += `disabled: true # Old Electron version: v${old.result}\n`; - await fs.writeFile(old.entry.fullPath, data, { encoding: 'utf-8' }) + await fs.writeFile(old.entry.fullPath, data, { encoding: 'utf-8' }); - console.log(data) - console.log(`\n---\n`) + console.log(data); + console.log(`\n---\n`); } } -main() +main(); diff --git a/script/resize.js b/script/resize.js index 6c82f049d87..19374cf8335 100755 --- a/script/resize.js +++ b/script/resize.js @@ -1,20 +1,17 @@ -const sharp = require('sharp') -const path = require('path') -const fs = require('fs') -const readdirp = require('readdirp') -const imagemin = require('imagemin') -const imageminPngquant = require('imagemin-pngquant') -const yaml = require('yaml') +const sharp = require('sharp'); +const path = require('path'); +const fs = require('fs'); +const readdirp = require('readdirp'); +const imagemin = require('imagemin'); +const imageminPngquant = require('imagemin-pngquant'); +const yaml = require('yaml'); async function resize(file, size) { - const newFile = file.replace('.png', `-${size}.png`) + const newFile = file.replace('.png', `-${size}.png`); // skip files that are up to date - if ( - fs.existsSync(newFile) && - fs.statSync(newFile).mtime > fs.statSync(file).mtime - ) { - return Promise.resolve(null) + if (fs.existsSync(newFile) && fs.statSync(newFile).mtime > fs.statSync(file).mtime) { + return Promise.resolve(null); } return sharp(fs.readFileSync(file)) @@ -23,51 +20,46 @@ async function resize(file, size) { .toBuffer() .then((buf) => imagemin.buffer(buf)) .then((buf) => imagemin.buffer(buf, { use: [imageminPngquant()] })) - .then((buf) => fs.writeFileSync(newFile, buf)) + .then((buf) => fs.writeFileSync(newFile, buf)); } async function main() { - const icons = [] + const icons = []; for await (const entry of readdirp(path.join(__dirname, '../apps'))) { if (entry.basename.match(/icon\.png/)) { - icons.push(entry.fullPath) + icons.push(entry.fullPath); } } - console.log(`Resizing ${icons.length} icons...`) + console.log(`Resizing ${icons.length} icons...`); const resizes = icons.reduce((acc, icon) => { - const iconName = path.basename(icon) + const iconName = path.basename(icon); // skip disabled app - const yamlFile = path.join(icon.replace('-icon.png', '.yml')) - const { disabled } = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')) + const yamlFile = path.join(icon.replace('-icon.png', '.yml')); + const { disabled } = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')); if (disabled) { - return acc + return acc; } return { ...acc, - [iconName]: [ - resize(icon, 32), - resize(icon, 64), - resize(icon, 128), - resize(icon, 256), - ], - } - }, {}) + [iconName]: [resize(icon, 32), resize(icon, 64), resize(icon, 128), resize(icon, 256)], + }; + }, {}); for (const icon in resizes) { - const promises = await Promise.allSettled(Object.values(resizes[icon])) - const failed = promises.filter((p) => p.status === 'rejected') + const promises = await Promise.allSettled(Object.values(resizes[icon])); + const failed = promises.filter((p) => p.status === 'rejected'); if (failed.length > 0) { - console.error(`🔴 Failed to resize icons for icon "${icon}"!`) + console.error(`🔴 Failed to resize icons for icon "${icon}"!`); for (const { reason } of failed) { - console.log(reason) + console.log(reason); } - process.exit(1) + process.exit(1); } } } -main() +main(); diff --git a/script/ymlupdate.js b/script/ymlupdate.js index 4556b71f0db..bff5fe5702d 100755 --- a/script/ymlupdate.js +++ b/script/ymlupdate.js @@ -1,14 +1,10 @@ -const categories = require('../lib/app-categories') -const fs = require('fs') -const path = require('path') -const yaml = require('yaml') -const slugs = fs - .readdirSync(path.join(__dirname, '../apps')) - .filter((filename) => { - return fs - .statSync(path.join(__dirname, `../apps/${filename}`)) - .isDirectory() - }) +const categories = require('../lib/app-categories'); +const fs = require('fs'); +const path = require('path'); +const yaml = require('yaml'); +const slugs = fs.readdirSync(path.join(__dirname, '../apps')).filter((filename) => { + return fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory(); +}); const keywordMappings = { book: 'Books', @@ -106,90 +102,86 @@ const keywordMappings = { gif: 'Photo & Video', nodejs: 'Developer Tools', github: 'Developer Tools', -} +}; -const keywordCounts = {} -const usedCategories = {} +const keywordCounts = {}; +const usedCategories = {}; function determineCategory(app, yamlPath) { - let guessingKeywords = false - let updateYaml = false - let matched = false - let matchedKeyword + let guessingKeywords = false; + let updateYaml = false; + let matched = false; + let matchedKeyword; if (!app.keywords) { - app.keywords = app.description.split(' ') - guessingKeywords = true + app.keywords = app.description.split(' '); + guessingKeywords = true; } app.keywords.some((keyword, index) => { matched = categories.find((category) => { if (keyword.toLowerCase() === category.toLowerCase()) { - matchedKeyword = keyword - return true + matchedKeyword = keyword; + return true; } - }) - return matched - }) + }); + return matched; + }); if (!matched) { // look in mappings app.keywords.some((keyword, index) => { - let lowerKeyword = keyword.toLowerCase() + let lowerKeyword = keyword.toLowerCase(); if (keywordMappings[lowerKeyword]) { - matched = keywordMappings[lowerKeyword] - matchedKeyword = keyword - return true + matched = keywordMappings[lowerKeyword]; + matchedKeyword = keyword; + return true; } else { - return false + return false; } - }) + }); } if (matched) { - app.category = matched - updateYaml = true + app.category = matched; + updateYaml = true; if (!usedCategories[matched]) { - usedCategories[matched] = 1 + usedCategories[matched] = 1; } else { - usedCategories[matched]++ + usedCategories[matched]++; } } if (!updateYaml) { app.keywords.forEach((keyword) => { - let lowerKeyword = keyword.toLowerCase() + let lowerKeyword = keyword.toLowerCase(); if (keywordCounts[lowerKeyword]) { - keywordCounts[lowerKeyword]++ + keywordCounts[lowerKeyword]++; } else { - keywordCounts[lowerKeyword] = 1 + keywordCounts[lowerKeyword] = 1; } - }) + }); } if (updateYaml) { if (guessingKeywords) { - app.keywords = [matchedKeyword] + app.keywords = [matchedKeyword]; console.log( - `SUCCESS ${app.name} has been given ${app.category} by guessing keyword: ${matchedKeyword}` - ) + `SUCCESS ${app.name} has been given ${app.category} by guessing keyword: ${matchedKeyword}`, + ); } else { console.log( - `SUCCESS ${app.name} has been given ${app.category} by using keyword: ${matchedKeyword}` - ) + `SUCCESS ${app.name} has been given ${app.category} by using keyword: ${matchedKeyword}`, + ); } - saveYaml(app, yamlPath) + saveYaml(app, yamlPath); } else { if (guessingKeywords) { - console.log( - `${app.name} does not have keywords, its description is: ${app.description}.` - ) + console.log(`${app.name} does not have keywords, its description is: ${app.description}.`); } else { console.log( `Could not find category for ${ app.name - }, keywords are: ${app.keywords.join(',')}, description is: ${ - app.description - }` - ) + }, keywords are: ${app.keywords.join(',')}, description is: ${app.description}`, + ); } } } @@ -197,49 +189,49 @@ function determineCategory(app, yamlPath) { function removeElectron(app, yamlPath) { if (app.keywords) { let electronIndex = app.keywords.findIndex((keyword) => { - return keyword.toLowerCase() === 'electron' - }) + return keyword.toLowerCase() === 'electron'; + }); if (electronIndex > -1) { - app.keywords.splice(electronIndex, 1) - saveYaml(app, yamlPath) + app.keywords.splice(electronIndex, 1); + saveYaml(app, yamlPath); } } } function saveYaml(app, yamlPath) { - const yamlContent = yaml.stringify(app, 2) - fs.writeFileSync(yamlPath, yamlContent) + const yamlContent = yaml.stringify(app, 2); + fs.writeFileSync(yamlPath, yamlContent); } slugs.forEach((slug) => { - const basedir = path.join(__dirname, `../apps/${slug}`) - const yamlFile = `${slug}.yml` - const yamlPath = path.join(basedir, yamlFile) - let app - let data + const basedir = path.join(__dirname, `../apps/${slug}`); + const yamlFile = `${slug}.yml`; + const yamlPath = path.join(basedir, yamlFile); + let app; + let data; try { - data = fs.readFileSync(yamlPath, { encoding: 'utf-8' }) - app = yaml.parse(data) + data = fs.readFileSync(yamlPath, { encoding: 'utf-8' }); + app = yaml.parse(data); } catch (err) { - console.log(`Error loading ${yamlPath}`, err) + console.log(`Error loading ${yamlPath}`, err); } - removeElectron(app, yamlPath) + removeElectron(app, yamlPath); if (!app.category) { - determineCategory(app, yamlPath) + determineCategory(app, yamlPath); } -}) +}); -let tags = [] +let tags = []; Object.keys(keywordCounts).forEach((keyword) => { tags.push({ tagName: `${keyword}`, count: keywordCounts[keyword], - }) -}) + }); +}); tags.sort((a, b) => { - return b.count - a.count -}) + return b.count - a.count; +}); -console.log(`Used categories: ${JSON.stringify(usedCategories, null, 2)}`) -console.log(`Keywords unmapped to categories: ${JSON.stringify(tags, null, 2)}`) +console.log(`Used categories: ${JSON.stringify(usedCategories, null, 2)}`); +console.log(`Keywords unmapped to categories: ${JSON.stringify(tags, null, 2)}`); diff --git a/test/human-data.js b/test/human-data.js index e29e01d14b6..7cf69533476 100644 --- a/test/human-data.js +++ b/test/human-data.js @@ -1,216 +1,201 @@ -const categories = require('../lib/app-categories') -const mocha = require('mocha') -const describe = mocha.describe -const it = mocha.it -const fs = require('fs') -const path = require('path') -const expect = require('chai').expect -const yaml = require('yaml') -const { isUrl } = require('../lib/is-url') -const { URL } = require('url') -const slugify = require('slugify') -const grandfatheredDescriptions = require('../lib/grandfathered-descriptions') -const grandfatheredLinks = require('../lib/grandfathered-links.js') -const grandfatheredSlugs = require('../lib/grandfathered-small-icons') -const slugs = fs - .readdirSync(path.join(__dirname, '../apps')) - .filter((filename) => { - return fs - .statSync(path.join(__dirname, `../apps/${filename}`)) - .isDirectory() - }) - -const IGNORE_IMAGES_SQUARE = ['asana', 'splice'] +const categories = require('../lib/app-categories'); +const mocha = require('mocha'); +const describe = mocha.describe; +const it = mocha.it; +const fs = require('fs'); +const path = require('path'); +const expect = require('chai').expect; +const yaml = require('yaml'); +const { isUrl } = require('../lib/is-url'); +const { URL } = require('url'); +const slugify = require('slugify'); +const grandfatheredDescriptions = require('../lib/grandfathered-descriptions'); +const grandfatheredLinks = require('../lib/grandfathered-links.js'); +const grandfatheredSlugs = require('../lib/grandfathered-small-icons'); +const slugs = fs.readdirSync(path.join(__dirname, '../apps')).filter((filename) => { + return fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory(); +}); + +const IGNORE_IMAGES_SQUARE = ['asana', 'splice']; describe('human-submitted app data', () => { it('includes lots of apps', () => { - expect(slugs.length).to.be.above(200) - }) + expect(slugs.length).to.be.above(200); + }); slugs.forEach((slug) => { describe(slug, () => { - const basedir = path.join(__dirname, `../apps/${slug}`) - const yamlFile = `${slug}.yml` - const yamlPath = path.join(basedir, yamlFile) - const iconPath = path.join(basedir, `${slug}-icon.png`) + const basedir = path.join(__dirname, `../apps/${slug}`); + const yamlFile = `${slug}.yml`; + const yamlPath = path.join(basedir, yamlFile); + const iconPath = path.join(basedir, `${slug}-icon.png`); it('is in a directory whose name is lowercase with dashes as a delimiter', () => { - expect(slugify(slug)).to.equal(slug) - }) + expect(slugify(slug)).to.equal(slug); + }); it(`includes a data file named ${slug}.yml`, () => { - expect(fs.existsSync(yamlPath)).to.equal(true) - }) + expect(fs.existsSync(yamlPath)).to.equal(true); + }); describe(`${yamlFile}`, () => { - const app = yaml.parse(fs.readFileSync(yamlPath, 'utf-8')) + const app = yaml.parse(fs.readFileSync(yamlPath, 'utf-8')); it('has a name', () => { - expect(app.name.length).to.be.above(0) - }) + expect(app.name.length).to.be.above(0); + }); describe('description', () => { it('exists', () => { - expect(app.description.length).to.be.above(0) - }) + expect(app.description.length).to.be.above(0); + }); it('should not start with app name', () => { - const appName = app.name.toLowerCase() - const description = app.description.toLowerCase() - expect(description).to.satisfy((desc) => !desc.startsWith(appName)) - }) + const appName = app.name.toLowerCase(); + const description = app.description.toLowerCase(); + expect(description).to.satisfy((desc) => !desc.startsWith(appName)); + }); - const descIsGrandfathered = grandfatheredDescriptions.includes(slug) + const descIsGrandfathered = grandfatheredDescriptions.includes(slug); if (!descIsGrandfathered) { it('should start with a capital letter', () => { - const firstLetter = app.description[0] - expect(firstLetter).to.equal(firstLetter.toUpperCase()) - }) + const firstLetter = app.description[0]; + expect(firstLetter).to.equal(firstLetter.toUpperCase()); + }); it('should end with a period / full stop', () => { expect(app.description[app.description.length - 1]).to.equal( '.', - `Description should end in a period / full stop: '${app.description}'` - ) - }) + `Description should end in a period / full stop: '${app.description}'`, + ); + }); it('should not mention Electron since Electron is already implied', () => { - const description = app.description.toLowerCase() + const description = app.description.toLowerCase(); expect(description.indexOf('electron')).to.equal( -1, - `Description should not mention Electron, as Electron is already implied: ${description}` - ) - }) + `Description should not mention Electron, as Electron is already implied: ${description}`, + ); + }); it('should not start description with "A" or "An"', () => { - const descriptionFirstWord = app.description - .toLowerCase() - .split(' ', 1)[0] - const badStarts = ['a', 'an'] + const descriptionFirstWord = app.description.toLowerCase().split(' ', 1)[0]; + const badStarts = ['a', 'an']; expect(badStarts).to.not.include( descriptionFirstWord, - `Description should not start with 'A' or 'An': '${app.description}'` - ) - }) + `Description should not start with 'A' or 'An': '${app.description}'`, + ); + }); } - }) + }); - const linksAreGrandfathered = grandfatheredLinks.includes(slug) + const linksAreGrandfathered = grandfatheredLinks.includes(slug); if (!linksAreGrandfathered) { // walk an object subtree looking for URLs const getObjectUrls = (root) => { - const found = [] - const queue = [root] + const found = []; + const queue = [root]; while (queue.length !== 0) { - const vals = Object.values(queue.shift()) - found.push(...vals.filter(isUrl).map((v) => new URL(v))) - queue.push(...vals.filter((v) => typeof v === 'object')) + const vals = Object.values(queue.shift()); + found.push(...vals.filter(isUrl).map((v) => new URL(v))); + queue.push(...vals.filter((v) => typeof v === 'object')); } - return found - } + return found; + }; it('should use ssl links', () => { - const goodProtocols = ['https:', 'sftp:'] - const urls = getObjectUrls(app) + const goodProtocols = ['https:', 'sftp:']; + const urls = getObjectUrls(app); - urls.forEach((url) => - expect(url.protocol, url).to.be.oneOf(goodProtocols) - ) - }) + urls.forEach((url) => expect(url.protocol, url).to.be.oneOf(goodProtocols)); + }); } it('has a website with a valid URL (or no website)', () => { - expect(!app.website || isUrl(app.website)).to.equal(true) - }) + expect(!app.website || isUrl(app.website)).to.equal(true); + }); it('has a valid repository URL (or no repository)', () => { - expect(!app.repository || isUrl(app.repository)).to.equal(true) - }) + expect(!app.repository || isUrl(app.repository)).to.equal(true); + }); describe('keywords', () => { it('should, if present, be an array of keywords', () => { - expect(app.keywords || []).to.be.an('array') - }) + expect(app.keywords || []).to.be.an('array'); + }); it("should not include 'electron'", () => { - expect( - (app.keywords || []).map((key) => key.toLocaleLowerCase()) - ).to.not.include('electron') - }) + expect((app.keywords || []).map((key) => key.toLocaleLowerCase())).to.not.include( + 'electron', + ); + }); it('should not include duplicates', () => { - const keywords = app.keywords || [] + const keywords = app.keywords || []; expect(keywords.sort().toString()).to.equal( - [...new Set(keywords).values()].sort().toString() - ) - }) - }) + [...new Set(keywords).values()].sort().toString(), + ); + }); + }); it('has a valid category', () => { - expect(app.category.length).to.be.above(0) - expect(app.category).to.be.oneOf(categories) - }) + expect(app.category.length).to.be.above(0); + expect(app.category).to.be.oneOf(categories); + }); describe('screenshots', () => { - const screenshots = app.screenshots || [] + const screenshots = app.screenshots || []; it('requires imageUrl to be a fully-qualified HTTPS URL', () => { screenshots.forEach((screenshot) => { - expect( - isUrl(screenshot.imageUrl) && /^https/.test(screenshot.imageUrl) - ).to.equal( + expect(isUrl(screenshot.imageUrl) && screenshot.imageUrl.startsWith('https')).to.equal( true, - `${app.slug} screenshot imageUrl must be a fully-qualified HTTPS URL` - ) - }) - }) + `${app.slug} screenshot imageUrl must be a fully-qualified HTTPS URL`, + ); + }); + }); it('requires linkUrl to be a fully-qualified URL, if present', () => { screenshots.forEach((screenshot) => { expect(!screenshot.linkUrl || isUrl(screenshot.linkUrl)).to.equal( true, - `${app.slug} screenshot linkURL must be a fully qualified URL` - ) - }) - }) - }) + `${app.slug} screenshot linkURL must be a fully qualified URL`, + ); + }); + }); + }); it('has a valid YouTube URL (or none)', () => { - expect( - !app.youtube_video_url || isUrl(app.youtube_video_url) - ).to.equal(true) - }) - }) + expect(!app.youtube_video_url || isUrl(app.youtube_video_url)).to.equal(true); + }); + }); // Do this without any external dependencies describe.skip('icon', () => { it(`exists as ${slug}-icon.png`, () => { - expect(fs.existsSync(iconPath)).to.equal( - true, - `${slug}-icon.png not found` - ) - }) + expect(fs.existsSync(iconPath)).to.equal(true, `${slug}-icon.png not found`); + }); it('is a square', function () { - if (IGNORE_IMAGES_SQUARE.includes(slug)) return this.skip() - if (!fs.existsSync(iconPath)) return this.skip() + if (IGNORE_IMAGES_SQUARE.includes(slug)) return this.skip(); + if (!fs.existsSync(iconPath)) return this.skip(); - const dimensions = imageSize(iconPath) - expect(dimensions.width).to.be.a('number') - expect(dimensions.width).to.equal(dimensions.height) - }) + const dimensions = imageSize(iconPath); + expect(dimensions.width).to.be.a('number'); + expect(dimensions.width).to.equal(dimensions.height); + }); - const minPixels = grandfatheredSlugs.indexOf(slug) > -1 ? 128 : 256 - const maxPixels = 1024 + const minPixels = grandfatheredSlugs.indexOf(slug) > -1 ? 128 : 256; + const maxPixels = 1024; it(`is between ${minPixels}px x ${minPixels}px and ${maxPixels}px x ${maxPixels}px`, function () { - if (IGNORE_IMAGES_SQUARE.includes(slug)) return this.skip() - if (!fs.existsSync(iconPath)) return this.skip() - const dimensions = imageSize(iconPath) - expect(dimensions.width).to.be.within(minPixels, maxPixels) - expect(dimensions.height).to.be.within(minPixels, maxPixels) - }) - }) - }) - }) -}) + if (IGNORE_IMAGES_SQUARE.includes(slug)) return this.skip(); + if (!fs.existsSync(iconPath)) return this.skip(); + const dimensions = imageSize(iconPath); + expect(dimensions.width).to.be.within(minPixels, maxPixels); + expect(dimensions.height).to.be.within(minPixels, maxPixels); + }); + }); + }); + }); +}); diff --git a/test/machine-data.js b/test/machine-data.js index b861cfabc51..4776e72eb3e 100644 --- a/test/machine-data.js +++ b/test/machine-data.js @@ -1,50 +1,44 @@ -const mocha = require('mocha') -const describe = mocha.describe -const it = mocha.it -const fs = require('fs') -const path = require('path') -const yaml = require('yaml') -const apps = require('..') -const categories = require('../categories') -const expect = require('chai').expect +const mocha = require('mocha'); +const describe = mocha.describe; +const it = mocha.it; +const fs = require('fs'); +const path = require('path'); +const yaml = require('yaml'); +const apps = require('..'); +const categories = require('../categories'); +const expect = require('chai').expect; describe('machine-generated app data (exported by the module)', () => { it('is an array', () => { - expect(apps).to.be.an('array') - }) + expect(apps).to.be.an('array'); + }); it('has the same number of apps as the apps directory', () => { const slugs = fs .readdirSync(path.join(__dirname, '../apps')) - .filter((filename) => - fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory() - ) + .filter((filename) => fs.statSync(path.join(__dirname, `../apps/${filename}`)).isDirectory()) .filter((filename) => { - const yamlFile = path.join( - __dirname, - `../apps/${filename}/${filename}.yml` - ) - const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')) + const yamlFile = path.join(__dirname, `../apps/${filename}/${filename}.yml`); + const meta = yaml.parse(fs.readFileSync(yamlFile, 'utf-8')); if (meta.disabled) { - return false + return false; } - return true - }) + return true; + }); - const generatedSlugs = apps.map((app) => app.slug) - const missingApps = slugs.filter((slug) => !generatedSlugs.includes(slug)) - if (missingApps) - console.log('missings theses apps from generated json:', missingApps) + const generatedSlugs = apps.map((app) => app.slug); + const missingApps = slugs.filter((slug) => !generatedSlugs.includes(slug)); + if (missingApps) console.log('missings theses apps from generated json:', missingApps); - expect(apps.length).to.be.above(100) - expect(apps.length).to.equal(slugs.length) - }) + expect(apps.length).to.be.above(100); + expect(apps.length).to.equal(slugs.length); + }); it('sets a `slug` property on every app', () => { - expect(apps.every((app) => app.slug.length > 0)).to.equal(true) - }) + expect(apps.every((app) => app.slug.length > 0)).to.equal(true); + }); it('sets a multi-size icon properties on every app', () => { expect( @@ -55,62 +49,53 @@ describe('machine-generated app data (exported by the module)', () => { app.icon64.endsWith('-icon-64.png') && app.icon128.endsWith('-icon-128.png') && app.icon256.endsWith('-icon-256.png') - ) - }) - ).to.equal(true) - }) + ); + }), + ).to.equal(true); + }); it('sets a (git-based) YYYY-MM-DD `date` property on every app', () => { - const datePattern = /\d{4}-\d{2}-\d{2}/ + const datePattern = /\d{4}-\d{2}-\d{2}/; apps.forEach((app) => { - expect(datePattern.test(app.date)).to.equal( - true, - `${app.slug} does not have date property` - ) - }) - }) + expect(datePattern.test(app.date)).to.equal(true, `${app.slug} does not have date property`); + }); + }); describe('releases', () => { - const appsWithRepos = require('../lib/apps-with-github-repos') - const appsWithLatestRelease = apps.filter((app) => app.latestRelease) + const appsWithRepos = require('../lib/apps-with-github-repos'); + const appsWithLatestRelease = apps.filter((app) => app.latestRelease); it('tries to fetch a release for every app with a GitHub repo', () => { expect(apps.filter((app) => app.latestReleaseFetchedAt).length).to.equal( - appsWithRepos.length - ) - }) + appsWithRepos.length, + ); + }); it('collects latest GitHub release data for apps that have it', () => { - expect(appsWithLatestRelease.length).to.be.above(50) - }) + expect(appsWithLatestRelease.length).to.be.above(50); + }); it('sets `latestRelease` on apps with GitHub repos that use Releases', () => { - expect(appsWithLatestRelease.every((app) => app.latestRelease)).to.eq( - true - ) - }) + expect(appsWithLatestRelease.every((app) => app.latestRelease)).to.eq(true); + }); it('sets `latestReleaseFetchedAt`', () => { - expect( - appsWithLatestRelease.every((app) => app.latestReleaseFetchedAt) - ).to.eq(true) - }) - }) -}) + expect(appsWithLatestRelease.every((app) => app.latestReleaseFetchedAt)).to.eq(true); + }); + }); +}); describe('machine-generated category data (exported by the module)', () => { it('is an array', () => { - expect(categories).to.be.an('array') - }) + expect(categories).to.be.an('array'); + }); it('sets a `slug` string on every category', () => { - expect(categories.every((category) => category.slug.length > 0)).to.equal( - true - ) - }) + expect(categories.every((category) => category.slug.length > 0)).to.equal(true); + }); it('sets a `count` number on every category', () => { - expect(categories.every((category) => category.count > 0)).to.equal(true) - }) -}) + expect(categories.every((category) => category.count > 0)).to.equal(true); + }); +}); diff --git a/wizard.js b/wizard.js index 94adcaf84a7..4dac9d129a6 100644 --- a/wizard.js +++ b/wizard.js @@ -1,11 +1,11 @@ -const categories = require('./lib/app-categories') -const { isUrl } = require('./lib/is-url') -const inquirer = require('inquirer') -const path = require('path') -const fs = require('fs') -const slugify = require('slugify') -const yaml = require('yaml') -const existingSlugs = fs.readdirSync(path.join(__dirname, 'apps')) +const categories = require('./lib/app-categories'); +const { isUrl } = require('./lib/is-url'); +const inquirer = require('inquirer'); +const path = require('path'); +const fs = require('fs'); +const slugify = require('slugify'); +const yaml = require('yaml'); +const existingSlugs = fs.readdirSync(path.join(__dirname, 'apps')); const questions = [ { @@ -13,11 +13,10 @@ const questions = [ name: 'name', message: 'What is the name of the app?', validate: function (value) { - if (!value) return 'Please enter a name' - const slug = slugify(value) - if (existingSlugs.includes(slug)) - return `There is already an app directory named '${slug}'.` - return true + if (!value) return 'Please enter a name'; + const slug = slugify(value); + if (existingSlugs.includes(slug)) return `There is already an app directory named '${slug}'.`; + return true; }, }, { @@ -25,9 +24,9 @@ const questions = [ name: 'description', message: 'Short description', validate: function (value) { - if (!value) return 'Please enter a description' - if (value.length > 100) return `Too long! Try shortening: ${value}` - return true + if (!value) return 'Please enter a description'; + if (value.length > 100) return `Too long! Try shortening: ${value}`; + return true; }, }, { @@ -35,8 +34,8 @@ const questions = [ name: 'website', message: 'Website (can be repository URL if app has no website)', validate: function (value) { - if (!isUrl(value)) return 'Please enter a fully-qualified URL' - return true + if (!isUrl(value)) return 'Please enter a fully-qualified URL'; + return true; }, }, { @@ -45,7 +44,7 @@ const questions = [ message: 'App category', choices: categories, validate: function (value) { - if (!value) return 'Please select a category' + if (!value) return 'Please select a category'; }, }, { @@ -58,7 +57,7 @@ const questions = [ name: 'keywords', message: 'Keywords (optional, comma-delimited)', filter: function (value) { - return value.split(',').map((keyword) => keyword.trim()) + return value.split(',').map((keyword) => keyword.trim()); }, }, { @@ -66,36 +65,31 @@ const questions = [ name: 'license', message: 'License (optional)', }, -] +]; inquirer .prompt(questions) .then(function (answers) { const app = Object.entries(answers).reduce((acc, [key, value]) => { - if ( - value === '' || - (Array.isArray(value) && value.length === 1 && value[0] === '') - ) { - return acc + if (value === '' || (Array.isArray(value) && value.length === 1 && value[0] === '')) { + return acc; } - acc[key] = value - return acc - }, {}) - console.log({ app }) - const slug = slugify(app.name) - const basepath = path.join(path.join(__dirname, 'apps'), slug) - const yamlPath = path.join(basepath, `${slug}.yml`) - const yamlContent = yaml.stringify(app, 2) - fs.mkdirSync(basepath) - fs.writeFileSync(yamlPath, yamlContent) - console.log() - console.log(`Yay! Created ${path.relative(process.cwd(), yamlPath)}`) - console.log(`Now you just need to add an icon named ${slug}-icon.png\n`) - console.log( - `Once you're done, run \`npm test\` to verify. Then open your pull request!` - ) - console.log() + acc[key] = value; + return acc; + }, {}); + console.log({ app }); + const slug = slugify(app.name); + const basepath = path.join(path.join(__dirname, 'apps'), slug); + const yamlPath = path.join(basepath, `${slug}.yml`); + const yamlContent = yaml.stringify(app, 2); + fs.mkdirSync(basepath); + fs.writeFileSync(yamlPath, yamlContent); + console.log(); + console.log(`Yay! Created ${path.relative(process.cwd(), yamlPath)}`); + console.log(`Now you just need to add an icon named ${slug}-icon.png\n`); + console.log(`Once you're done, run \`npm test\` to verify. Then open your pull request!`); + console.log(); }) .catch((error) => { - console.error(error) - }) + console.error(error); + }); diff --git a/yarn.lock b/yarn.lock index 1571e41159b..c579a5cfbf3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,7 +17,8 @@ __metadata: inquirer: "npm:^8.2.4" lint-staged: "npm:^12.4.1" mocha: "npm:^11.7.4" - prettier: "npm:^3.6.2" + oxfmt: "npm:^0.44.0" + oxlint: "npm:^1.59.0" readdirp: "npm:^3.6.0" semver: "npm:^7.7.3" sharp: "npm:^0.34.4" @@ -300,6 +301,272 @@ __metadata: languageName: node linkType: hard +"@oxfmt/binding-android-arm-eabi@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-android-arm-eabi@npm:0.44.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@oxfmt/binding-android-arm64@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-android-arm64@npm:0.44.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@oxfmt/binding-darwin-arm64@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-darwin-arm64@npm:0.44.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@oxfmt/binding-darwin-x64@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-darwin-x64@npm:0.44.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@oxfmt/binding-freebsd-x64@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-freebsd-x64@npm:0.44.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@oxfmt/binding-linux-arm-gnueabihf@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-arm-gnueabihf@npm:0.44.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@oxfmt/binding-linux-arm-musleabihf@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-arm-musleabihf@npm:0.44.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@oxfmt/binding-linux-arm64-gnu@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-arm64-gnu@npm:0.44.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@oxfmt/binding-linux-arm64-musl@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-arm64-musl@npm:0.44.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@oxfmt/binding-linux-ppc64-gnu@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-ppc64-gnu@npm:0.44.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@oxfmt/binding-linux-riscv64-gnu@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-riscv64-gnu@npm:0.44.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@oxfmt/binding-linux-riscv64-musl@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-riscv64-musl@npm:0.44.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@oxfmt/binding-linux-s390x-gnu@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-s390x-gnu@npm:0.44.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@oxfmt/binding-linux-x64-gnu@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-x64-gnu@npm:0.44.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@oxfmt/binding-linux-x64-musl@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-linux-x64-musl@npm:0.44.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@oxfmt/binding-openharmony-arm64@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-openharmony-arm64@npm:0.44.0" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@oxfmt/binding-win32-arm64-msvc@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-win32-arm64-msvc@npm:0.44.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@oxfmt/binding-win32-ia32-msvc@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-win32-ia32-msvc@npm:0.44.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@oxfmt/binding-win32-x64-msvc@npm:0.44.0": + version: 0.44.0 + resolution: "@oxfmt/binding-win32-x64-msvc@npm:0.44.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@oxlint/binding-android-arm-eabi@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-android-arm-eabi@npm:1.59.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@oxlint/binding-android-arm64@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-android-arm64@npm:1.59.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint/binding-darwin-arm64@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-darwin-arm64@npm:1.59.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint/binding-darwin-x64@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-darwin-x64@npm:1.59.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@oxlint/binding-freebsd-x64@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-freebsd-x64@npm:1.59.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@oxlint/binding-linux-arm-gnueabihf@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-arm-gnueabihf@npm:1.59.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@oxlint/binding-linux-arm-musleabihf@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-arm-musleabihf@npm:1.59.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@oxlint/binding-linux-arm64-gnu@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-arm64-gnu@npm:1.59.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@oxlint/binding-linux-arm64-musl@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-arm64-musl@npm:1.59.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@oxlint/binding-linux-ppc64-gnu@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-ppc64-gnu@npm:1.59.0" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@oxlint/binding-linux-riscv64-gnu@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-riscv64-gnu@npm:1.59.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@oxlint/binding-linux-riscv64-musl@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-riscv64-musl@npm:1.59.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@oxlint/binding-linux-s390x-gnu@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-s390x-gnu@npm:1.59.0" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@oxlint/binding-linux-x64-gnu@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-x64-gnu@npm:1.59.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@oxlint/binding-linux-x64-musl@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-linux-x64-musl@npm:1.59.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@oxlint/binding-openharmony-arm64@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-openharmony-arm64@npm:1.59.0" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint/binding-win32-arm64-msvc@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-win32-arm64-msvc@npm:1.59.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@oxlint/binding-win32-ia32-msvc@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-win32-ia32-msvc@npm:1.59.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@oxlint/binding-win32-x64-msvc@npm:1.59.0": + version: 1.59.0 + resolution: "@oxlint/binding-win32-x64-msvc@npm:1.59.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -2535,6 +2802,148 @@ __metadata: languageName: node linkType: hard +"oxfmt@npm:^0.44.0": + version: 0.44.0 + resolution: "oxfmt@npm:0.44.0" + dependencies: + "@oxfmt/binding-android-arm-eabi": "npm:0.44.0" + "@oxfmt/binding-android-arm64": "npm:0.44.0" + "@oxfmt/binding-darwin-arm64": "npm:0.44.0" + "@oxfmt/binding-darwin-x64": "npm:0.44.0" + "@oxfmt/binding-freebsd-x64": "npm:0.44.0" + "@oxfmt/binding-linux-arm-gnueabihf": "npm:0.44.0" + "@oxfmt/binding-linux-arm-musleabihf": "npm:0.44.0" + "@oxfmt/binding-linux-arm64-gnu": "npm:0.44.0" + "@oxfmt/binding-linux-arm64-musl": "npm:0.44.0" + "@oxfmt/binding-linux-ppc64-gnu": "npm:0.44.0" + "@oxfmt/binding-linux-riscv64-gnu": "npm:0.44.0" + "@oxfmt/binding-linux-riscv64-musl": "npm:0.44.0" + "@oxfmt/binding-linux-s390x-gnu": "npm:0.44.0" + "@oxfmt/binding-linux-x64-gnu": "npm:0.44.0" + "@oxfmt/binding-linux-x64-musl": "npm:0.44.0" + "@oxfmt/binding-openharmony-arm64": "npm:0.44.0" + "@oxfmt/binding-win32-arm64-msvc": "npm:0.44.0" + "@oxfmt/binding-win32-ia32-msvc": "npm:0.44.0" + "@oxfmt/binding-win32-x64-msvc": "npm:0.44.0" + tinypool: "npm:2.1.0" + dependenciesMeta: + "@oxfmt/binding-android-arm-eabi": + optional: true + "@oxfmt/binding-android-arm64": + optional: true + "@oxfmt/binding-darwin-arm64": + optional: true + "@oxfmt/binding-darwin-x64": + optional: true + "@oxfmt/binding-freebsd-x64": + optional: true + "@oxfmt/binding-linux-arm-gnueabihf": + optional: true + "@oxfmt/binding-linux-arm-musleabihf": + optional: true + "@oxfmt/binding-linux-arm64-gnu": + optional: true + "@oxfmt/binding-linux-arm64-musl": + optional: true + "@oxfmt/binding-linux-ppc64-gnu": + optional: true + "@oxfmt/binding-linux-riscv64-gnu": + optional: true + "@oxfmt/binding-linux-riscv64-musl": + optional: true + "@oxfmt/binding-linux-s390x-gnu": + optional: true + "@oxfmt/binding-linux-x64-gnu": + optional: true + "@oxfmt/binding-linux-x64-musl": + optional: true + "@oxfmt/binding-openharmony-arm64": + optional: true + "@oxfmt/binding-win32-arm64-msvc": + optional: true + "@oxfmt/binding-win32-ia32-msvc": + optional: true + "@oxfmt/binding-win32-x64-msvc": + optional: true + bin: + oxfmt: bin/oxfmt + checksum: 10c0/c4e0239ff9c7480a820cffd43a805a70df1b4569bdae5c253a0547f93a48ab70bb22454487c50529a5e6b2080717d15db981a52a99da7d6b55fa365c9b03fdb9 + languageName: node + linkType: hard + +"oxlint@npm:^1.59.0": + version: 1.59.0 + resolution: "oxlint@npm:1.59.0" + dependencies: + "@oxlint/binding-android-arm-eabi": "npm:1.59.0" + "@oxlint/binding-android-arm64": "npm:1.59.0" + "@oxlint/binding-darwin-arm64": "npm:1.59.0" + "@oxlint/binding-darwin-x64": "npm:1.59.0" + "@oxlint/binding-freebsd-x64": "npm:1.59.0" + "@oxlint/binding-linux-arm-gnueabihf": "npm:1.59.0" + "@oxlint/binding-linux-arm-musleabihf": "npm:1.59.0" + "@oxlint/binding-linux-arm64-gnu": "npm:1.59.0" + "@oxlint/binding-linux-arm64-musl": "npm:1.59.0" + "@oxlint/binding-linux-ppc64-gnu": "npm:1.59.0" + "@oxlint/binding-linux-riscv64-gnu": "npm:1.59.0" + "@oxlint/binding-linux-riscv64-musl": "npm:1.59.0" + "@oxlint/binding-linux-s390x-gnu": "npm:1.59.0" + "@oxlint/binding-linux-x64-gnu": "npm:1.59.0" + "@oxlint/binding-linux-x64-musl": "npm:1.59.0" + "@oxlint/binding-openharmony-arm64": "npm:1.59.0" + "@oxlint/binding-win32-arm64-msvc": "npm:1.59.0" + "@oxlint/binding-win32-ia32-msvc": "npm:1.59.0" + "@oxlint/binding-win32-x64-msvc": "npm:1.59.0" + peerDependencies: + oxlint-tsgolint: ">=0.18.0" + dependenciesMeta: + "@oxlint/binding-android-arm-eabi": + optional: true + "@oxlint/binding-android-arm64": + optional: true + "@oxlint/binding-darwin-arm64": + optional: true + "@oxlint/binding-darwin-x64": + optional: true + "@oxlint/binding-freebsd-x64": + optional: true + "@oxlint/binding-linux-arm-gnueabihf": + optional: true + "@oxlint/binding-linux-arm-musleabihf": + optional: true + "@oxlint/binding-linux-arm64-gnu": + optional: true + "@oxlint/binding-linux-arm64-musl": + optional: true + "@oxlint/binding-linux-ppc64-gnu": + optional: true + "@oxlint/binding-linux-riscv64-gnu": + optional: true + "@oxlint/binding-linux-riscv64-musl": + optional: true + "@oxlint/binding-linux-s390x-gnu": + optional: true + "@oxlint/binding-linux-x64-gnu": + optional: true + "@oxlint/binding-linux-x64-musl": + optional: true + "@oxlint/binding-openharmony-arm64": + optional: true + "@oxlint/binding-win32-arm64-msvc": + optional: true + "@oxlint/binding-win32-ia32-msvc": + optional: true + "@oxlint/binding-win32-x64-msvc": + optional: true + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + bin: + oxlint: bin/oxlint + checksum: 10c0/68614addf6b6a95df8a0c8ba764ee09d2d6d1693b55b62a4f31eda3be63915d24666a11b31dfe1fabbe88e1d7ab814243a1e7ecb40db87d0f567135d17f44e2c + languageName: node + linkType: hard + "p-cancelable@npm:^0.3.0": version: 0.3.0 resolution: "p-cancelable@npm:0.3.0" @@ -2802,15 +3211,6 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.6.2": - version: 3.6.2 - resolution: "prettier@npm:3.6.2" - bin: - prettier: bin/prettier.cjs - checksum: 10c0/488cb2f2b99ec13da1e50074912870217c11edaddedeadc649b1244c749d15ba94e846423d062e2c4c9ae683e2d65f754de28889ba06e697ac4f988d44f45812 - languageName: node - linkType: hard - "process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" @@ -3474,6 +3874,13 @@ __metadata: languageName: node linkType: hard +"tinypool@npm:2.1.0": + version: 2.1.0 + resolution: "tinypool@npm:2.1.0" + checksum: 10c0/9fb1c760558c6264e0f4cfde96a63b12450b43f1730fbe6274aa24ddbdf488745c08924d0dea7a1303b47d555416a6415f2113898c69b6ecf731e75ac95238a5 + languageName: node + linkType: hard + "to-buffer@npm:^1.1.1": version: 1.2.2 resolution: "to-buffer@npm:1.2.2" From d3f2dcc334896d84df20e3826f6ceddd80d0c60c Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Tue, 14 Apr 2026 16:56:34 -0700 Subject: [PATCH 2/2] zz --- test/human-data.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/human-data.js b/test/human-data.js index 7cf69533476..3c0837ee8e2 100644 --- a/test/human-data.js +++ b/test/human-data.js @@ -148,7 +148,9 @@ describe('human-submitted app data', () => { it('requires imageUrl to be a fully-qualified HTTPS URL', () => { screenshots.forEach((screenshot) => { - expect(isUrl(screenshot.imageUrl) && screenshot.imageUrl.startsWith('https')).to.equal( + expect( + isUrl(screenshot.imageUrl) && screenshot.imageUrl.startsWith('https'), + ).to.equal( true, `${app.slug} screenshot imageUrl must be a fully-qualified HTTPS URL`, );