├── .github └── workflows │ └── rust.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── Themefox-manager ├── .vscode │ └── settings.json ├── Cargo.lock ├── Cargo.toml └── src │ ├── build.rs │ └── main.rs ├── addon ├── addon │ ├── error.html │ ├── icons │ │ └── example_icon.png │ ├── index.html │ ├── manifest.json │ ├── popup.js │ ├── stylesheet.css │ ├── themefox_manager.js │ └── web-ext-artifacts │ │ ├── themefox_manager-1.0.zip │ │ ├── themefox_manager-1.1.5.zip │ │ └── themefox_manager-1.1.zip └── rust-app │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── main.rs └── files ├── protocol-handler.reg ├── themefox-manager.desktop ├── themefox-manager.json └── themefox.png /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Build 20 | working-directory: Themefox-manager 21 | run: cargo build --verbose 22 | - name: Run tests 23 | working-directory: Themefox-manager 24 | run: cargo test --verbose 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | <<<<<<< HEAD 2 | Themefox-manager/target/ 3 | addon/rust-app/target/ 4 | ======= 5 | /target 6 | /builds 7 | /ChromeFiles.zip 8 | >>>>>>> e884ba44d6f5bd592cd04dbb85db3b0d8f40dcf7 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "spellright.language": [], 3 | "spellright.documentTypes": [ 4 | "markdown", 5 | "latex", 6 | "plaintext" 7 | ] 8 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 The author of this software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Themefox-Manager 2 | ![Rust](https://github.com/alx365/Themefox-Manager/workflows/Rust/badge.svg?branch=master) 3 | [![works badge](https://cdn.jsdelivr.net/gh/nikku/works-on-my-machine@v0.2.0/badge.svg)](https://github.com/nikku/works-on-my-machine)[![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.png?v=103)](https://github.com/ellerbrock/open-source-badges/) 4 | 5 | [![forthebadge](https://forthebadge.com/images/badges/fuck-it-ship-it.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/you-didnt-ask-for-this.svg)](https://forthebadge.com) 6 | 7 | [![HitCount](http://hits.dwyl.com/themefox/Themefox-Manager.svg)](http://hits.dwyl.com/themefox/Themefox-Manager) [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity)![Works](https://img.shields.io/badge/May%20not%20work-on%20your%20machine-red) 8 | 9 | 10 | 11 | 12 | 13 | This is my first project in rust, so please excuse the terrible code quality and code logic. 14 | 15 | A minimal and super fast theme manager for Firefox written in 100% rust. 16 | 17 | 18 | ## Usage 19 | ```bash 20 | Installs themes to your firefox, from a valid themefox url, or git url 21 | 22 | USAGE: 23 | themefox-manager [FLAGS] [URL] 24 | 25 | FLAGS: 26 | -g, --git Installs from git repo, must be specified in a full URL. For example: 27 | https://githost.domain/foo/bar.git. Will remove all other files in the dir 28 | -h, --help Prints help information 29 | -p, --path Sets the path to install to, will automaticly trigger if no path is being found 30 | --reset Resets firefox theme by deleting all chrome files 31 | -V, --version Prints version information 32 | 33 | ARGS: 34 | Sets the URL to install from 35 | ``` 36 | 37 | ## Coming features: 38 | 39 | - Very close support with the themefox website (yet to be released) 40 | 41 | - A addon, to manage the themes, running on native messaging. 42 | 43 | ## Already implemented features: 44 | 45 | - Git support with the `--git` flag 46 | 47 | - Downloading and installing (would work if the website would be up) 48 | 49 | - Mac, GNU/Linux support and Windows support (Mac builds rather less, since i can't compile them on my main machine) 50 | 51 | - A flag for resetting the firefox themes and make firefox look normal 52 | 53 | - Automatically enables toolkit.legacyUserProfileCustomizations.stylesheets, in the settings. 54 | This program runs on curl/git, so make sure you have that installed, if you want to use that. 55 | You can install git from here: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git. 56 | Curl is installed on windows by default. 57 | 58 | ## Installing 59 | 60 | There are several ways to install themefox-manager, via the crates.io index, the binaries that you find here and if you are a linux user, maybe even in your package manager. 61 | 62 | Note that installing from crates.io/package manager is the best way, since you get updates through that. There is currently no update support planned for binaries downloded from the web. 63 | 64 | ### crates.io 65 | 66 | ​ Install `cargo`, and then run `cargo install themefox-manager`, to install it from crates.io. 67 | 68 | ### Package manager 69 | 70 | ​ AUR version will be released, once the version is in 1.0 71 | 72 | ### Binaries online 73 | 74 | ​ Download a binary, for your OS, and place it somewhere, add it to your path, and then you should be able to use it. 75 | 76 | ### Addon 77 | 78 | ​ There is a addon, to make it more user friendly, currently the addon doesn't support stdin stuff, so the user can't be running `-p` `-d` and also can't chose the flavour to install. 79 | 80 | ​ Note that the addon currently supports linux and macos only, since i haven't had enough time for windows. 81 | 82 | ​ To install the stuff on client side, run `themefox-manager --addon`, which will make two files, once a native messaging manifest, in the native messaging dir (on linux its in the firefox dir, on mac its in the ~/Library/Application Support/Mozilla/ dir), and once it puts a new executable in the ~/.local/bin dir (i might merge these two executables any time soon). 83 | 84 | 85 | 86 | ## New features: 87 | 88 | Please leave a pull request / open a issue , if you want to have new features added. 89 | 90 | 91 | 92 | ## Compiling from Source (Not recommended, only to this if you have another architecture) 93 | This branch is development, so it will be buggy. 94 | 95 | 1. Install rust (best with rustup, see https://www.rust-lang.org/learn/get-started), and cargo (comes installed with rustup) 96 | 2. Clone this project, and then go to the Themefox-manager dir of the project 97 | 3. Build it with `cargo build --release` 98 | 4. switch back to the root of this project: `cd ..` 99 | 5. Go into addon/rust-app and also compile that 100 | 6. You will have to change all of the file locations in the files/ directory, and put them in the right places. 101 | 7. Enjoy! 102 | 103 | 104 | 105 | ## Issues (Since there aren't any issues with this, there actually shouldn't be any need for this :)) 106 | 107 | If you experience any issues (i hope not), please leave a issue, on the issues tab, on the top of the page. 108 | 109 | For windows issues, you should definitly take a look at [this](https://wiki.archlinux.org/index.php/Installation_guide). 110 | 111 | 112 | 113 | ## Contributing: 114 | 115 | I am open to contributions. Please feel free to creaete a pull request and somewhat describe what you changed. 116 | -------------------------------------------------------------------------------- /Themefox-manager/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "spellright.language": [], 3 | "spellright.documentTypes": [ 4 | "markdown", 5 | "latex", 6 | "plaintext" 7 | ] 8 | } -------------------------------------------------------------------------------- /Themefox-manager/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "adler" 5 | version = "0.2.3" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" 8 | 9 | [[package]] 10 | name = "ansi_term" 11 | version = "0.11.0" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 14 | dependencies = [ 15 | "winapi", 16 | ] 17 | 18 | [[package]] 19 | name = "arrayref" 20 | version = "0.3.6" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" 23 | 24 | [[package]] 25 | name = "arrayvec" 26 | version = "0.5.1" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 29 | 30 | [[package]] 31 | name = "atty" 32 | version = "0.2.14" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 35 | dependencies = [ 36 | "hermit-abi", 37 | "libc", 38 | "winapi", 39 | ] 40 | 41 | [[package]] 42 | name = "autocfg" 43 | version = "1.0.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 46 | 47 | [[package]] 48 | name = "base64" 49 | version = "0.11.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" 52 | 53 | [[package]] 54 | name = "bitflags" 55 | version = "1.2.1" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 58 | 59 | [[package]] 60 | name = "blake2b_simd" 61 | version = "0.5.10" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" 64 | dependencies = [ 65 | "arrayref", 66 | "arrayvec", 67 | "constant_time_eq", 68 | ] 69 | 70 | [[package]] 71 | name = "bzip2" 72 | version = "0.3.3" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" 75 | dependencies = [ 76 | "bzip2-sys", 77 | "libc", 78 | ] 79 | 80 | [[package]] 81 | name = "bzip2-sys" 82 | version = "0.1.9+1.0.8" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "ad3b39a260062fca31f7b0b12f207e8f2590a67d32ec7d59c20484b07ea7285e" 85 | dependencies = [ 86 | "cc", 87 | "libc", 88 | "pkg-config", 89 | ] 90 | 91 | [[package]] 92 | name = "cc" 93 | version = "1.0.58" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" 96 | 97 | [[package]] 98 | name = "cfg-if" 99 | version = "0.1.10" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 102 | 103 | [[package]] 104 | name = "clap" 105 | version = "2.33.1" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" 108 | dependencies = [ 109 | "ansi_term", 110 | "atty", 111 | "bitflags", 112 | "strsim", 113 | "textwrap", 114 | "unicode-width", 115 | "vec_map", 116 | ] 117 | 118 | [[package]] 119 | name = "colored" 120 | version = "1.9.3" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" 123 | dependencies = [ 124 | "atty", 125 | "lazy_static", 126 | "winapi", 127 | ] 128 | 129 | [[package]] 130 | name = "console" 131 | version = "0.11.3" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "8c0994e656bba7b922d8dd1245db90672ffb701e684e45be58f20719d69abc5a" 134 | dependencies = [ 135 | "encode_unicode", 136 | "lazy_static", 137 | "libc", 138 | "regex", 139 | "terminal_size", 140 | "termios", 141 | "unicode-width", 142 | "winapi", 143 | "winapi-util", 144 | ] 145 | 146 | [[package]] 147 | name = "constant_time_eq" 148 | version = "0.1.5" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" 151 | 152 | [[package]] 153 | name = "crc32fast" 154 | version = "1.2.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 157 | dependencies = [ 158 | "cfg-if", 159 | ] 160 | 161 | [[package]] 162 | name = "crossbeam-utils" 163 | version = "0.7.2" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" 166 | dependencies = [ 167 | "autocfg", 168 | "cfg-if", 169 | "lazy_static", 170 | ] 171 | 172 | [[package]] 173 | name = "dialoguer" 174 | version = "0.6.2" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "f4aa86af7b19b40ef9cbef761ed411a49f0afa06b7b6dcd3dfe2f96a3c546138" 177 | dependencies = [ 178 | "console", 179 | "lazy_static", 180 | "tempfile", 181 | ] 182 | 183 | [[package]] 184 | name = "dirs" 185 | version = "2.0.2" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" 188 | dependencies = [ 189 | "cfg-if", 190 | "dirs-sys", 191 | ] 192 | 193 | [[package]] 194 | name = "dirs-sys" 195 | version = "0.3.5" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" 198 | dependencies = [ 199 | "libc", 200 | "redox_users", 201 | "winapi", 202 | ] 203 | 204 | [[package]] 205 | name = "encode_unicode" 206 | version = "0.3.6" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 209 | 210 | [[package]] 211 | name = "flate2" 212 | version = "1.0.16" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" 215 | dependencies = [ 216 | "cfg-if", 217 | "crc32fast", 218 | "libc", 219 | "miniz_oxide", 220 | ] 221 | 222 | [[package]] 223 | name = "getrandom" 224 | version = "0.1.14" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" 227 | dependencies = [ 228 | "cfg-if", 229 | "libc", 230 | "wasi", 231 | ] 232 | 233 | [[package]] 234 | name = "hermit-abi" 235 | version = "0.1.15" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" 238 | dependencies = [ 239 | "libc", 240 | ] 241 | 242 | [[package]] 243 | name = "itoa" 244 | version = "0.4.6" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 247 | 248 | [[package]] 249 | name = "lazy_static" 250 | version = "1.4.0" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 253 | 254 | [[package]] 255 | name = "libc" 256 | version = "0.2.73" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" 259 | 260 | [[package]] 261 | name = "miniz_oxide" 262 | version = "0.4.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" 265 | dependencies = [ 266 | "adler", 267 | ] 268 | 269 | [[package]] 270 | name = "pkg-config" 271 | version = "0.3.18" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" 274 | 275 | [[package]] 276 | name = "podio" 277 | version = "0.1.7" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "b18befed8bc2b61abc79a457295e7e838417326da1586050b919414073977f19" 280 | 281 | [[package]] 282 | name = "ppv-lite86" 283 | version = "0.2.8" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" 286 | 287 | [[package]] 288 | name = "rand" 289 | version = "0.7.3" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 292 | dependencies = [ 293 | "getrandom", 294 | "libc", 295 | "rand_chacha", 296 | "rand_core", 297 | "rand_hc", 298 | ] 299 | 300 | [[package]] 301 | name = "rand_chacha" 302 | version = "0.2.2" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 305 | dependencies = [ 306 | "ppv-lite86", 307 | "rand_core", 308 | ] 309 | 310 | [[package]] 311 | name = "rand_core" 312 | version = "0.5.1" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 315 | dependencies = [ 316 | "getrandom", 317 | ] 318 | 319 | [[package]] 320 | name = "rand_hc" 321 | version = "0.2.0" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 324 | dependencies = [ 325 | "rand_core", 326 | ] 327 | 328 | [[package]] 329 | name = "redox_syscall" 330 | version = "0.1.57" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" 333 | 334 | [[package]] 335 | name = "redox_users" 336 | version = "0.3.4" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" 339 | dependencies = [ 340 | "getrandom", 341 | "redox_syscall", 342 | "rust-argon2", 343 | ] 344 | 345 | [[package]] 346 | name = "regex" 347 | version = "1.3.9" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" 350 | dependencies = [ 351 | "regex-syntax", 352 | ] 353 | 354 | [[package]] 355 | name = "regex-syntax" 356 | version = "0.6.18" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" 359 | 360 | [[package]] 361 | name = "remove_dir_all" 362 | version = "0.5.3" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 365 | dependencies = [ 366 | "winapi", 367 | ] 368 | 369 | [[package]] 370 | name = "rust-argon2" 371 | version = "0.7.0" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" 374 | dependencies = [ 375 | "base64", 376 | "blake2b_simd", 377 | "constant_time_eq", 378 | "crossbeam-utils", 379 | ] 380 | 381 | [[package]] 382 | name = "ryu" 383 | version = "1.0.5" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 386 | 387 | [[package]] 388 | name = "serde" 389 | version = "1.0.114" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" 392 | 393 | [[package]] 394 | name = "serde_json" 395 | version = "1.0.56" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" 398 | dependencies = [ 399 | "itoa", 400 | "ryu", 401 | "serde", 402 | ] 403 | 404 | [[package]] 405 | name = "strsim" 406 | version = "0.8.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 409 | 410 | [[package]] 411 | name = "tempfile" 412 | version = "3.1.0" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 415 | dependencies = [ 416 | "cfg-if", 417 | "libc", 418 | "rand", 419 | "redox_syscall", 420 | "remove_dir_all", 421 | "winapi", 422 | ] 423 | 424 | [[package]] 425 | name = "terminal_size" 426 | version = "0.1.13" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13" 429 | dependencies = [ 430 | "libc", 431 | "winapi", 432 | ] 433 | 434 | [[package]] 435 | name = "termios" 436 | version = "0.3.2" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "6f0fcee7b24a25675de40d5bb4de6e41b0df07bc9856295e7e2b3a3600c400c2" 439 | dependencies = [ 440 | "libc", 441 | ] 442 | 443 | [[package]] 444 | name = "textwrap" 445 | version = "0.11.0" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 448 | dependencies = [ 449 | "unicode-width", 450 | ] 451 | 452 | [[package]] 453 | name = "themefox-manager" 454 | version = "0.9.11" 455 | dependencies = [ 456 | "clap", 457 | "colored", 458 | "dialoguer", 459 | "dirs", 460 | "serde_json", 461 | "zip", 462 | ] 463 | 464 | [[package]] 465 | name = "time" 466 | version = "0.1.43" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" 469 | dependencies = [ 470 | "libc", 471 | "winapi", 472 | ] 473 | 474 | [[package]] 475 | name = "unicode-width" 476 | version = "0.1.8" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 479 | 480 | [[package]] 481 | name = "vec_map" 482 | version = "0.8.2" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 485 | 486 | [[package]] 487 | name = "wasi" 488 | version = "0.9.0+wasi-snapshot-preview1" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 491 | 492 | [[package]] 493 | name = "winapi" 494 | version = "0.3.9" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 497 | dependencies = [ 498 | "winapi-i686-pc-windows-gnu", 499 | "winapi-x86_64-pc-windows-gnu", 500 | ] 501 | 502 | [[package]] 503 | name = "winapi-i686-pc-windows-gnu" 504 | version = "0.4.0" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 507 | 508 | [[package]] 509 | name = "winapi-util" 510 | version = "0.1.5" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 513 | dependencies = [ 514 | "winapi", 515 | ] 516 | 517 | [[package]] 518 | name = "winapi-x86_64-pc-windows-gnu" 519 | version = "0.4.0" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 522 | 523 | [[package]] 524 | name = "zip" 525 | version = "0.5.6" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "58287c28d78507f5f91f2a4cf1e8310e2c76fd4c6932f93ac60fd1ceb402db7d" 528 | dependencies = [ 529 | "bzip2", 530 | "crc32fast", 531 | "flate2", 532 | "podio", 533 | "time", 534 | ] 535 | -------------------------------------------------------------------------------- /Themefox-manager/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "themefox-manager" 3 | version = "0.9.11" 4 | authors = ["The authors Name "] 5 | edition = "2018" 6 | license = "MIT" 7 | description = "A manager for firefox CSS aka userchrome files" 8 | readme = "../README.md" 9 | homepage = "https://github.com/themefox/themefox-manager" 10 | repository = "https://github.com/alx365/themefox-manager" 11 | license-file = "../LICENSE" 12 | keywords = ["cli", "firefox", "esthetics"] 13 | categories = ["command-line-interface", ] 14 | 15 | [profile.release] 16 | panic = 'abort' 17 | 18 | [dependencies] 19 | dirs = "2.0.2" 20 | clap = "2.33.0" 21 | zip = "0.5.5" 22 | serde_json = "1.0" 23 | dialoguer = "0.6.2" 24 | colored = "1.9.3" 25 | -------------------------------------------------------------------------------- /Themefox-manager/src/build.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/legendofmiracles/Themefox-Manager/a53d7ca8034628a0602c9064605131c149a52734/Themefox-manager/src/build.rs -------------------------------------------------------------------------------- /Themefox-manager/src/main.rs: -------------------------------------------------------------------------------- 1 | // People called this code as bad as Yandere devs, so don't look at it. 2 | use clap::{App, Arg}; 3 | use colored::*; 4 | use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select}; 5 | use dirs; 6 | use serde_json::Value; 7 | use std::{ 8 | env, fs, fs::File, fs::OpenOptions, io, io::Read, io::Write, path::Path, path::PathBuf, 9 | process::Command, str, 10 | }; 11 | use zip::ZipArchive; 12 | 13 | static mut SILENT: bool = false; 14 | fn main() { 15 | let os = std::env::consts::OS; 16 | // The ascii art message 17 | let mut app = App::new("themefox-manager") 18 | .name("themefox-manager") 19 | .version("v0.9.11") 20 | .author("The authors name ") 21 | .about("Installs themes to your firefox, from a valid themefox url, or git url") 22 | .arg( 23 | Arg::with_name("URL") 24 | .help("Sets the URL to install from") 25 | .required(false) 26 | .index(1)) 27 | .arg( 28 | Arg::with_name("reset") 29 | .long("reset") 30 | .help("Resets firefox theme by deleting all chrome files") 31 | ) 32 | .arg( 33 | Arg::with_name("path") 34 | .long("dir") 35 | .short("d") 36 | .help("Sets the path to install to, will automaticly trigger if no path is being found") 37 | .long_help("Sets the path to install to, will automaticly trigger if no path is being found. Can very well be used to install themes for waterfox, firefox developer edition and other browsers that are a fork from firefox") 38 | ) 39 | .arg( 40 | Arg::with_name("git") 41 | .long("git") 42 | .short("g") 43 | .help("Installs from git repo, must be specified in a full URL. For example: https://githost.domain/foo/bar.git.") 44 | //.long("Installs from git repo, must be specified in a full URL. . Will remove all other files in the dir") 45 | ) 46 | .arg( 47 | Arg::with_name("profile") 48 | .long("profile") 49 | .short("p") 50 | .help("This argument lets you chose which profile you want to install to") 51 | ) 52 | .arg( 53 | Arg::with_name("addon") 54 | .long("addon") 55 | .short("a") 56 | .help("This argument installs the files on client side, for the browser addon to work.") 57 | ) 58 | //.arg( 59 | // Arg::with_name("verbose") 60 | // .long("verbose") 61 | // .short("v") 62 | // .help("prints more information to the screen") 63 | //) 64 | .arg( 65 | Arg::with_name("silent") 66 | .long("silent") 67 | .short("s") 68 | .help("prints less info to the screen") 69 | ); 70 | let matches = app.get_matches(); 71 | if !matches.is_present("silent") { 72 | let message = r#" 73 | ______ __ __ ___ __ __ ___ ___ __ ___ __ __ _ __ __ _ __ __ ___ ___ 74 | |_ _| | || | | __| | V | | __| | __| /__\ \ \_/ / __ | V | / \ | \| | / \ / _| | __| | _ \ 75 | | | | >< | | _| | \_/ | | _| | _| | \/ | > , < |__| | \_/ | | /\ | | | ' | | /\ | | |/\ | _| | v / 76 | |_| |_||_| |___| |_| |_| |___| |_| \__/ /_/ \_\ |_| |_| |_||_| |_|\__| |_||_| \__/ |___| |_|_\ 77 | "#; 78 | // prints it 79 | print!("{}\n", message.bright_red()); 80 | } else { 81 | unsafe { 82 | SILENT = true; 83 | } 84 | } 85 | /* 86 | if os == "linux" { 87 | let mut shell_path = PathBuf::new(); 88 | let extension = ".fish"; 89 | shell_path.push(dirs::config_dir().unwrap()); 90 | shell_path.push("fish/completions"); 91 | fs::create_dir_all(&shell_path).expect(&format!( 92 | "{}", 93 | "Failed to create the fish autocomplete dir".red() 94 | )); 95 | shell_path.push(format!("themefox-manager{}", extension)); 96 | 97 | let mut completion = File::create(shell_path) 98 | .expect(&format!("{}", "Failed to make shell completion".red())); 99 | 100 | app.gen_completions_to("themefox-manager", clap::Shell::Fish, &mut completion); 101 | } else if os == "windows" { 102 | app.gen_completions_to( 103 | "themefox-manager", 104 | clap::Shell::PowerShell, 105 | &mut io::stdout(), 106 | ); 107 | }*/ 108 | 109 | if matches.is_present("reset") { 110 | if Confirm::new() 111 | .with_prompt("Do you want to continue, and delete all chrome files?") 112 | .interact() 113 | .unwrap() 114 | { 115 | println!("ok, your chrome files will be deleted"); 116 | } else { 117 | println!("Ok, looks like you changed your mind"); 118 | panic!("{}", "Quitting...".red()); 119 | } 120 | // i know we already fetched it way earlier, but the user doesn't know that :) 121 | succes("Fetched your operating system"); 122 | if os == "linux" { 123 | get_firefox_linux(true, matches, "null".to_string()) 124 | } else if os == "macos" { 125 | firefox_dir(&matches); 126 | find_profile(false, matches.is_present("profile")); 127 | fs::remove_dir_all("chrome").expect(&format!("{}", "Error: failed to rmdir".red())); 128 | } else if os == "windows" { 129 | firefox_dir(&matches); 130 | env::set_current_dir("firefox").expect(&format!( 131 | "{}", 132 | "failed to cd into the firefox dir in the firefox dir".red() 133 | )); 134 | find_profile(false, matches.is_present("profile")); 135 | fs::remove_dir_all("chrome").expect(&format!("{}", "Error: failed to rmdir".red())); 136 | } 137 | } else if matches.is_present("URL") { 138 | let mut download_url = String::new(); 139 | 140 | if !matches.is_present("git") { 141 | //let mut output = ""; 142 | let arguments: Vec = env::args().collect(); 143 | let mut the_argument: Vec<&str> = Vec::new(); 144 | //println!("{}", arguments[arguments.len() - 1]); 145 | if arguments[arguments.len() - 1].starts_with("themefox-manager:// ") { 146 | the_argument = arguments[arguments.len() - 1].split(' ').collect(); 147 | } else { 148 | the_argument.push("nothing"); 149 | the_argument.push(&arguments[arguments.len() - 1]); 150 | } 151 | 152 | if the_argument[1].starts_with("http") 153 | && the_argument[1].contains("://") 154 | && the_argument[1].contains("themefox.net") 155 | && the_argument[1].contains("/") 156 | //&& the_argument[1].ends_with(".git") || the_argument[1].ends_with(".zip") 157 | { 158 | succes("Good url"); 159 | let id: Vec<&str> = the_argument[1].split('/').collect(); 160 | 161 | let output_exit = Command::new("curl") 162 | .arg(format!("127.0.0.1:1234/get/{}", id[id.len() - 2])) 163 | .output() 164 | .expect(&format!("{}", "Error: cURL failed to spawn".red())); 165 | 166 | let output = output_exit.stdout; 167 | let output = str::from_utf8(&output).unwrap(); 168 | let downloads; 169 | let output_json: Value = serde_json::from_str(output) 170 | .expect("the json seems to be corrupt. Please report this issue on github."); 171 | if let Some(output_json) = output_json.as_array() { 172 | downloads = output_json.len(); 173 | } else { 174 | panic!( 175 | "{}", 176 | "json again seemed to be wrong formatted... Please report this issue." 177 | .red() 178 | ); 179 | } 180 | succes("Good response from the server"); 181 | if downloads - 2 == 1 { 182 | download_url = format!( 183 | "http://beta.themefox.net/themes/{}/{}-{}.{}", 184 | output_json[3]["theme_id"], 185 | output_json[3]["id"], 186 | output_json[3]["filename"], 187 | output_json[3]["filetype"] 188 | ); 189 | } else if downloads - 2 > 1 { 190 | let mut selections = Vec::new(); 191 | for i in 0..downloads - 2 { 192 | selections.push(&output_json[i + 2]["title"]); 193 | } 194 | let selection = Select::with_theme(&ColorfulTheme::default()) 195 | .with_prompt(format!( 196 | "{}", 197 | "Pick your flavor of the theme (navigate with arrow keys)".yellow() 198 | )) 199 | .default(0) 200 | .items(&selections[..]) 201 | .interact() 202 | .unwrap(); 203 | download_url = format!( 204 | "http://beta.themefox.net/themes/{}/{}-{}.{}", 205 | output_json[selection + 2]["theme_id"], 206 | output_json[selection + 2]["id"], 207 | output_json[selection + 2]["filename"], 208 | output_json[selection + 2]["filetype"] 209 | ); 210 | //} 211 | } 212 | } else { 213 | println!("The argument you supplied didn't seem to be a correct url, or you didn't supply any url. \nRun with -h in order to see the usage"); 214 | panic!("{}", "\nThere is nothing to do. \nQuitting...".red()); 215 | } 216 | } else if matches.is_present("git") { 217 | let arguments: Vec = env::args().collect(); 218 | let mut _the_argument: Vec<&str> = Vec::new(); 219 | _the_argument = arguments[arguments.len() - 1].split(' ').collect(); 220 | download_url = _the_argument[0].to_string(); 221 | } 222 | 223 | // fetches what operating system you use 224 | //let os = std::env::consts::OS; 225 | succes("Fetched your operating system"); 226 | // If the operating system is linux then it does everything that is in those brackets 227 | if os == "linux" { 228 | get_firefox_linux(false, matches, download_url); 229 | } else if os == "macos" { 230 | firefox_dir(&matches); 231 | find_profile(true, matches.is_present("profile")); 232 | download(&download_url, matches.is_present("git")); 233 | } else if os == "windows" { 234 | firefox_dir(&matches); 235 | env::set_current_dir("firefox").expect(&format!( 236 | "{}", 237 | "failed to cd into the firefox dir in the firefox dir".red() 238 | )); 239 | find_profile(true, matches.is_present("profile")); 240 | download(&download_url, matches.is_present("git")); 241 | } else { 242 | eprintln!("Error: You seem to use a Operating System that is not supported. If you want support for it, consider leaving a issue on the github page."); 243 | panic!("{}", "Quitting...".red()); 244 | } 245 | } else if matches.is_present("addon") { 246 | let os = std::env::consts::OS; 247 | install(os, matches); 248 | } else { 249 | print!( 250 | "Bad usage.\nHave a look at the usage with the '{}' flag. ", 251 | "--help".green() 252 | ); 253 | } 254 | } 255 | 256 | fn find_profile(go_chrome: bool, find_profile: bool) { 257 | if !find_profile { 258 | find_default_profile(); 259 | } else { 260 | ask_for_profile(); 261 | } 262 | 263 | // Now we are in the default profile, the programm now enables stylesheets, so that the theme will also be shown. 264 | enable_css(); 265 | if Path::new("chrome").exists() == false { 266 | if go_chrome == true { 267 | fs::create_dir("chrome").expect("Error: failed to mkdir"); 268 | unsafe { 269 | if !SILENT { 270 | println!("Created the chrome directory, because it didn't exist before"); 271 | } 272 | } 273 | } else { 274 | println!("Your chrome directory doesn't exist, so we can't remove it -.-"); 275 | panic!("{}", "Quitting...".red()) 276 | } 277 | } 278 | if go_chrome == true { 279 | let mut chrome_path = PathBuf::new(); 280 | chrome_path.push("chrome"); 281 | env::set_current_dir(chrome_path).expect(&format!( 282 | "{}", 283 | "Error: failed to cd into the Chrome dir".red() 284 | )); 285 | } 286 | succes("Almost everything is finished. Now installing/uninstalling the theme"); 287 | } 288 | 289 | fn download(file: &str, git: bool) { 290 | if !git { 291 | Command::new("curl") 292 | .arg("-L") 293 | .arg(file) 294 | .arg("-o") 295 | .arg("ChromeFiles.zip") 296 | .status() 297 | .expect(&format!( 298 | "{}", 299 | "Error: cURL failed to start. Do you have it installed?".red() 300 | )); 301 | succes("Downloaded the theme now unzipping"); 302 | let file = fs::File::open("ChromeFiles.zip").unwrap(); 303 | let mut archive = ZipArchive::new(file).unwrap(); 304 | 305 | for i in 0..archive.len() { 306 | let mut file = archive.by_index(i).unwrap(); 307 | let outpath = file.sanitized_name(); 308 | 309 | if (&*file.name()).ends_with('/') { 310 | println!( 311 | "File {} extracted to \"{}\"", 312 | i, 313 | outpath.as_path().display() 314 | ); 315 | fs::create_dir_all(&outpath).unwrap(); 316 | } else { 317 | println!( 318 | "File {} extracted to \"{}\" ({} bytes)", 319 | i, 320 | outpath.as_path().display(), 321 | file.size() 322 | ); 323 | if let Some(p) = outpath.parent() { 324 | if !p.exists() { 325 | fs::create_dir_all(&p).unwrap(); 326 | } 327 | } 328 | let mut outfile = fs::File::create(&outpath).unwrap(); 329 | io::copy(&mut file, &mut outfile).unwrap(); 330 | } 331 | } 332 | fs::remove_file("ChromeFiles.zip").expect(&format!( 333 | "{}", 334 | "Error: failed to rm the Chrome zip file".red() 335 | )); 336 | succes("Finished installing the theme: enjoy!"); 337 | } else { 338 | // ptr = path to repo 339 | // download git only suceeds if there are no errors, so we can be positive that the ptr has the files we need. 340 | let ptr = download_git(file); 341 | // Then we remove everything in the current dir 342 | let paths = fs::read_dir(".").unwrap(); 343 | 344 | for path in paths { 345 | let foobar = path.unwrap().path(); 346 | if !foobar.is_dir() { 347 | fs::remove_file(format!("{}", foobar.display())).expect(&format!( 348 | "{}", 349 | "Failed to remove all files in the chrome dir".red() 350 | )); 351 | } else { 352 | fs::remove_dir_all(format!("{}", foobar.display())).expect(&format!( 353 | "{}", 354 | "Failed to remove all files in the chrome dir".red() 355 | )); 356 | } 357 | } 358 | println!("{}", &format!("{}/userChrome.css", ptr)); 359 | // The program looks if two key files exist, in the download, if not it proceeds 360 | if !Path::new(&format!("{}/userChrome.css", ptr)).exists() 361 | || !Path::new(&format!("{}/userContent.css", ptr)).exists() 362 | { 363 | let exceptions = [ 364 | "userContent.css", 365 | "userChrome.css", 366 | "userContent.js", 367 | "userChrome.js", 368 | ]; 369 | let tabu = [".git"]; 370 | let mut options: Vec = Vec::new(); 371 | let paths = fs::read_dir(".").unwrap(); 372 | // for thing in this directory 373 | // zero loop 374 | for dir in paths { 375 | // sets name to the thing in the directry 376 | let name = &dir.unwrap().path(); 377 | // First loop 378 | // Checks if name is a directory and if its not an exception like .git 379 | if name.is_dir() && !tabu.contains(&name.file_name().unwrap().to_str().unwrap()) { 380 | // !after this point the recurive loops are running 381 | // Checks the content of the dir in the current dir 382 | for path in fs::read_dir(&name).unwrap() { 383 | // ! 384 | let tmp = path.unwrap(); 385 | // Checks that its not a dir and if it already exists in the exceptions variable, so that only the right files can pass 386 | if !tmp.path().is_dir() 387 | && exceptions.contains(&tmp.file_name().to_str().unwrap()) 388 | { 389 | // Then it checks if it already exists in the vec 390 | if !options.contains(&name.to_str().unwrap().to_string()) { 391 | // Adds the dir to the vec 392 | options.push(tmp.path().to_str().unwrap().to_string()); 393 | } 394 | // println!("HEY"); 395 | } else { 396 | // ! 397 | // sets name to the last dir we were in 398 | let name = tmp.path(); 399 | // Checks if it is a dir, because we don't want to visit files 400 | if tmp.path().is_dir() { 401 | //reads every file in the dir 402 | println!("{:?}", name); 403 | for path2 in fs::read_dir(&name).unwrap() { 404 | let tmp2 = path2.unwrap(); 405 | 406 | if !tmp2.path().is_dir() 407 | && exceptions.contains(&tmp2.file_name().to_str().unwrap()) 408 | { 409 | if !options.contains(&name.to_str().unwrap().to_string()) { 410 | options.push(name.to_str().unwrap().to_string()); 411 | } 412 | } else { 413 | // ! 414 | let name = tmp2.path(); 415 | println!("{:?}", name); 416 | if tmp2.path().is_dir() { 417 | for path3 in fs::read_dir(&name).unwrap() { 418 | let tmp3 = path3.unwrap(); 419 | if !tmp3.path().is_dir() 420 | && exceptions.contains( 421 | &tmp3.file_name().to_str().unwrap(), 422 | ) 423 | { 424 | if !options.contains( 425 | &name.to_str().unwrap().to_string(), 426 | ) { 427 | options.push( 428 | name.to_str().unwrap().to_string(), 429 | ); 430 | } 431 | } else { 432 | // ! 433 | let name = tmp3.path(); 434 | 435 | println!("{:?}", name); 436 | if tmp3.path().is_dir() { 437 | for path4 in fs::read_dir(&name).unwrap() { 438 | let tmp4 = path4.unwrap(); 439 | if !tmp4.path().is_dir() 440 | && exceptions.contains( 441 | &tmp4 442 | .file_name() 443 | .to_str() 444 | .unwrap(), 445 | ) 446 | { 447 | if !options.contains( 448 | &name 449 | .to_str() 450 | .unwrap() 451 | .to_string(), 452 | ) { 453 | options.push( 454 | name.to_str() 455 | .unwrap() 456 | .to_string(), 457 | ); 458 | } 459 | } else { 460 | // ! 461 | let name = tmp4.path(); 462 | println!("{:?}", name); 463 | if tmp4.path().is_dir() { 464 | for path5 in 465 | fs::read_dir(&name).unwrap() 466 | { 467 | let tmp5 = path5.unwrap(); 468 | if !tmp5.path().is_dir() 469 | && exceptions.contains( 470 | &tmp5 471 | .file_name() 472 | .to_str() 473 | .unwrap(), 474 | ) 475 | { 476 | if !options.contains( 477 | &name 478 | .to_str() 479 | .unwrap() 480 | .to_string(), 481 | ) { 482 | options.push( 483 | name.to_str() 484 | .unwrap() 485 | .to_string( 486 | ), 487 | ); 488 | } 489 | } else { 490 | // ! 491 | let name = tmp5.path(); 492 | println!("{:?}", name); 493 | if tmp5.path().is_dir() 494 | { 495 | for path6 in 496 | fs::read_dir( 497 | &name, 498 | ) 499 | .unwrap() 500 | { 501 | let tmp6 = 502 | path6 503 | .unwrap( 504 | ); 505 | if !tmp6.path().is_dir() 506 | && exceptions.contains( 507 | &tmp6 508 | .file_name() 509 | .to_str() 510 | .unwrap(), 511 | ) 512 | { 513 | if !options.contains( 514 | &name 515 | .to_str() 516 | .unwrap() 517 | .to_string(), 518 | ) { 519 | options.push( 520 | name.to_str() 521 | .unwrap() 522 | .to_string( 523 | ), 524 | ); 525 | } 526 | } 527 | } 528 | } 529 | } 530 | } 531 | } 532 | } 533 | } 534 | } 535 | } 536 | } 537 | } 538 | } 539 | } 540 | } 541 | } 542 | } 543 | } 544 | } 545 | copy(&ptr, env::current_dir().unwrap()).expect(&format!( 546 | "{}", 547 | "failed to copy from the tmp dir to the chrome dir".red() 548 | )); 549 | fs::remove_dir_all(ptr).expect(&format!( 550 | "{}", 551 | "Failed to remove the tempoary directory".red() 552 | )); 553 | println!("{:?}", options); 554 | if options.len() > 0 { 555 | options.sort(); 556 | 557 | let selection = Select::with_theme(&ColorfulTheme::default()) 558 | .with_prompt(format!( 559 | "{}", 560 | "Couldn't find any files, that change the way firefox behaves, we searched 7 directories deep, to find something, here is what we found.\nPick your profile, to install into (navigate with arrow keys)".yellow() 561 | )) 562 | .default(0) 563 | .items(&options[..]) 564 | .interact() 565 | .unwrap(); 566 | for file in fs::read_dir(Path::new(&options[selection])).unwrap() { 567 | let tmp = &file.unwrap().path(); 568 | 569 | syslinks(&tmp); 570 | } 571 | } else { 572 | println!("{}", "Warning: The file doesn't have any files, that change the way firefox looks/behave. Unfortunately we couldn't find anything in the subdirectories".yellow()) 573 | } 574 | } 575 | } 576 | } 577 | 578 | pub fn copy, V: AsRef>(from: U, to: V) -> Result<(), std::io::Error> { 579 | let mut stack = Vec::new(); 580 | stack.push(PathBuf::from(from.as_ref())); 581 | 582 | let output_root = PathBuf::from(to.as_ref()); 583 | let input_root = PathBuf::from(from.as_ref()).components().count(); 584 | 585 | while let Some(working_path) = stack.pop() { 586 | // println!("process: {:?}", &working_path); 587 | 588 | // Generate a relative path 589 | let src: PathBuf = working_path.components().skip(input_root).collect(); 590 | 591 | // Create a destination if missing 592 | let dest = if src.components().count() == 0 { 593 | output_root.clone() 594 | } else { 595 | output_root.join(&src) 596 | }; 597 | if fs::metadata(&dest).is_err() { 598 | //println!(" mkdir: {:?}", dest); 599 | fs::create_dir_all(&dest)?; 600 | } 601 | 602 | for entry in fs::read_dir(working_path)? { 603 | let entry = entry?; 604 | let path = entry.path(); 605 | if path.is_dir() { 606 | stack.push(path); 607 | } else { 608 | match path.file_name() { 609 | Some(filename) => { 610 | let dest_path = dest.join(filename); 611 | //println!(" copy: {:?} -> {:?}", &path, &dest_path); 612 | fs::copy(&path, &dest_path)?; 613 | } 614 | None => { 615 | println!("failed: {:?}", path); 616 | } 617 | } 618 | } 619 | } 620 | } 621 | 622 | Ok(()) 623 | } 624 | 625 | fn download_git(file: &str) -> String { 626 | let temp = get_tmp_dir(); 627 | fs::create_dir_all(&temp).expect(&format!("{}", "Failed to create the tmp dir".red())); 628 | let git = Command::new("git") 629 | .arg("clone") 630 | .arg(file) 631 | .arg(format!("{}/chrome/", temp.to_str().unwrap())) 632 | .status() 633 | .expect(&format!( 634 | "{}", 635 | "Error: git failed to complete. Do you have it installed?".red() 636 | )); 637 | match git.code() { 638 | Some(code) => { 639 | if code > 0 { 640 | panic!("{}", "failed to clone git repo".red()) 641 | } 642 | } 643 | None => panic!("Process terminated by signal".red()), 644 | } 645 | return temp.to_str().unwrap().to_string(); 646 | } 647 | fn get_tmp_dir() -> PathBuf { 648 | if env::consts::OS == "windows" { 649 | let mut temp = dirs::home_dir().unwrap(); 650 | temp.push("AppData/Local/Temp/firefox-css"); 651 | println!("{:?}", temp); 652 | return temp; 653 | } else { 654 | return PathBuf::from("/tmp/firefox-css"); 655 | } 656 | } 657 | // #[cfg(target_os = "windows")] 658 | // fn download_git(file: &str) { 659 | // use git2::Repository; 660 | // let _repo = match Repository::clone(file, ".") { 661 | // Ok(repo) => repo, 662 | // Err(e) => panic!("failed to clone: {}".red(), e), 663 | // }; 664 | // } 665 | 666 | // #[cfg(target_os = "macos")] 667 | // fn download_git(file: &str) { 668 | // use git2::Repository; 669 | // let _repo = match Repository::clone(file, ".") { 670 | // Ok(repo) => repo, 671 | // Err(e) => panic!("failed to clone: {}".red(), e), 672 | // }; 673 | // } 674 | 675 | #[cfg(unix)] 676 | fn syslinks(tmp: &std::path::PathBuf) { 677 | std::os::unix::fs::symlink(tmp, tmp.file_name().unwrap()).expect("Failed to create systemlink"); 678 | } 679 | #[cfg(windows)] 680 | fn syslinks(tmp: &std::path::PathBuf) { 681 | if tmp.is_dir() { 682 | std::os::windows::fs::symlink_dir(tmp, tmp.file_name().unwrap()) 683 | .expect(&format!("{}", "Failed to create syslinks".red())); 684 | 685 | std::os::windows::fs::symlink_file(tmp, tmp.file_name().unwrap()) 686 | .expect(&format!("{}", "Failed to create syslinks".red())); 687 | } 688 | } 689 | fn manual_profile_path() -> String { 690 | eprintln!("Error: We can not seem to find your firefox folder. \nIf you ran this application with elevated permissions, please try again without. \nYou can find your profile folder by typing about:profiles in the adress bar and then select the button open directory on the first one. Then navigate back one directory and thats the path you should enter\n" ); 691 | if Confirm::new() 692 | .with_prompt(format!( 693 | "{}", 694 | "Would you now like to manually specify the chrome directory?".yellow() 695 | )) 696 | .interact() 697 | .unwrap() 698 | { 699 | let path: String = Input::with_theme(&ColorfulTheme::default()) 700 | .with_prompt(format!("{}", "What is the path?".yellow())) 701 | .interact() 702 | .unwrap(); 703 | return path; 704 | } else { 705 | println!("Ok, Bye."); 706 | panic!("{}", "Quitting...".red()); 707 | } 708 | } 709 | 710 | fn install(os: &str, matches: clap::ArgMatches) { 711 | println!("Performing first time setup and installing, configuring stuff, so that this application will work."); 712 | if os == "linux" { 713 | firefox_dir(&matches); 714 | } else if os == "macos" { 715 | env::set_current_dir(dirs::home_dir().unwrap()) 716 | .expect(&format!("{}", "failed to cd into home dir")); 717 | env::set_current_dir("Library/Application Support/Mozilla") 718 | .expect(&format!("{}", "failed to cd into mozilla dir dir")); 719 | } 720 | let mut name = "native-messaging-hosts"; 721 | if os == "macos" { 722 | name = "NativeMessagingHosts"; 723 | } 724 | if fs::create_dir(name).is_err() { 725 | if !Path::new(name).exists() { 726 | panic!("Failed to mkdir the native messaging dir in firefox dir, do we have enough permissions?".red()) 727 | } else { 728 | println!("You already had the native-messaging-hosts directory.") 729 | } 730 | } 731 | 732 | env::set_current_dir(name).expect(&format!("{}", "Failed changing dir".red())); 733 | 734 | let file = Command::new("curl") 735 | .arg("https://raw.githubusercontent.com/alx365/Themefox-Manager/master/files/themefox-manager.json") 736 | //.arg("-o") 737 | //.arg("themefox_manager.json") 738 | .output() 739 | .expect(&format!("{}", "Error: curl failed to complete".red())); 740 | let mut user = "F U Windows"; 741 | if os == "linux" { 742 | user = "/home"; 743 | } else if os == "macos" { 744 | user = "/Users"; 745 | } 746 | let output = str::from_utf8(&file.stdout).unwrap().replace( 747 | "$USER", 748 | &format!("{}/{}", user, &std::env::var("USER").unwrap()), 749 | ); 750 | fs::File::create("themefox_manager.json") 751 | .expect(&format!( 752 | "{}", 753 | "Error: failed creating the themefox_manager.json file".red() 754 | )) 755 | .write_all(output.as_bytes()) 756 | .expect(&format!( 757 | "{}", 758 | "Error: failed to write to json config firefox file" 759 | )); 760 | install_helper(os); 761 | 762 | if Confirm::with_theme(&ColorfulTheme::default()) 763 | .with_prompt("Do you want to install the browser addon now?") 764 | .interact() 765 | .unwrap() 766 | { 767 | println!("You will have to press the add to firefox button"); 768 | if os == "macos" { 769 | Command::new("open") 770 | .arg("https://addons.mozilla.org/en-US/firefox/addon/themefox-manager/") 771 | .status() 772 | .expect(&format!("{}", "\'open\' failed to spawn".red())); 773 | } else if os == "linux" { 774 | Command::new("firefox") 775 | .arg("--new-tab") 776 | .arg("https://addons.mozilla.org/en-US/firefox/addon/themefox-manager/") 777 | .status() 778 | .expect(&format!("{}", "\'firefox\' failed to spawn".red())); 779 | } 780 | } 781 | succes("Finished installing Enjoy!"); 782 | } 783 | //#[cfg(linux)] 784 | fn install_helper(os: &str) { 785 | env::set_current_dir(dirs::home_dir().unwrap()).expect(&format!( 786 | "{}", 787 | "failed to cd into the homdir in the helper function".red() 788 | )); 789 | //let dir 790 | if fs::create_dir_all(".local/bin").is_err() { 791 | if !Path::new(".local/bin").exists() { 792 | panic!( 793 | "Couldn't create the .local/bin directory, do we have enough permissions?".red() 794 | ); 795 | } else { 796 | println!("You already had the .local/bin directory") 797 | } 798 | } 799 | let mut url = "error"; 800 | if os == "linux" { 801 | url = "https://github.com/alx365/Themefox-Manager/releases/download/v0.9.9.9/stdin-themefox-manager" 802 | } else if os == "macos" { 803 | url = "https://github.com/alx365/Themefox-Manager/releases/download/v0.9.9.9/stdin-themefox-manager-mac"; 804 | } 805 | Command::new("curl") 806 | .arg("-L") 807 | .arg(format!("{}", url)) 808 | .arg("-o") 809 | .arg(".local/bin/stdin-themefox-manager") 810 | //.output() 811 | .status() 812 | .expect(&format!("{}", "Error: curl failed to spawn".red())); 813 | 814 | if os == "linux" || os == "macos" { 815 | Command::new("chmod") 816 | .arg("+x") 817 | .arg(".local/bin/stdin-themefox-manager") 818 | .status() 819 | .expect(&format!("{}", "Error: chmod failed to complete")); 820 | } 821 | } 822 | 823 | fn succes(msg: &str) { 824 | unsafe { 825 | if !SILENT { 826 | println!("{}", format!("✔ {}", &msg).green()); 827 | } 828 | } 829 | } 830 | 831 | fn enable_css() { 832 | // This asssumes that you already are in the profile directory 833 | let file = PathBuf::from("user.js"); 834 | //let option = "" 835 | if !file.is_file() { 836 | let mut file = 837 | File::create(file).expect(&format!("{}", "failed to make user.js file".red())); 838 | file.write_all( 839 | b"user_pref(\"toolkit.legacyUserProfileCustomizations.stylesheets\", true); ", 840 | ) 841 | .expect(&format!("{}", "Failed to write to user.js file".red())); 842 | succes("Enabled stylesheets in your browsers settings"); 843 | } else { 844 | let mut file = File::open(file).expect(&"Failed to open user.js".red()); 845 | let mut contents = String::new(); 846 | file.read_to_string(&mut contents) 847 | .expect(&"Failed to read the contents of the user.js file".red()); 848 | if contents.contains("\"toolkit.legacyUserProfileCustomizations.stylesheets\", true") { 849 | succes("You already had the stylesheet option enabled") 850 | } else { 851 | let mut file = OpenOptions::new() 852 | .append(true) 853 | .write(true) 854 | .open("user.js") 855 | .unwrap(); 856 | if let Err(e) = writeln!( 857 | file, 858 | "\nuser_pref(\"toolkit.legacyUserProfileCustomizations.stylesheets\", true); " 859 | ) { 860 | eprintln!("Couldn't write to file: {}", e); 861 | eprintln!( 862 | "You will have to enable them manually, if you do not yet have them enabled." 863 | ); 864 | } else { 865 | succes("Enabled stylesheets in your browsers settings"); 866 | } 867 | } 868 | } 869 | } 870 | 871 | fn get_firefox_linux(reset: bool, matches: clap::ArgMatches, download_url: String) { 872 | firefox_dir(&matches); 873 | env::set_current_dir("firefox") 874 | .expect(&format!("{}", "failed to cd into the firefox dir".red())); 875 | 876 | find_profile(!reset, matches.is_present("profile")); 877 | 878 | if !reset { 879 | download(&download_url, matches.is_present("git")); 880 | } else { 881 | fs::remove_dir_all("chrome").expect(&format!("{}", "Error: failed to rmdir".red())); 882 | } 883 | } 884 | 885 | fn find_default_profile() { 886 | let default_profile; 887 | let mut contents = String::new(); 888 | if Path::new("installs.ini").is_file() == true { 889 | let mut file = File::open("installs.ini") 890 | .expect(&format!("{}", "Error: unable to open installs.ini".red())); 891 | file.read_to_string(&mut contents) 892 | .expect("Error: Unable to read file"); 893 | } else if Path::new("profiles.ini").is_file() == true { 894 | let mut file = File::open("profiles.ini") 895 | .expect(&format!("{}", "Error: unable to open profiles.ini".red())); 896 | file.read_to_string(&mut contents) 897 | .expect("Error: Unable to read file"); 898 | } else { 899 | println!("Error: We cannot find your last used or your default profile. because the file is missing, with which we can find out.\nPlease report this issue on github (https://github.com/alx365/Themefox-Manager)"); 900 | panic!("{}", "Quitting...".red()); 901 | } 902 | succes("Found your default profile"); 903 | let v: Vec<&str> = contents 904 | .split(|c| c == '=' || c == ']' || c == '\n') 905 | .collect(); 906 | 907 | default_profile = v[3].to_string(); 908 | 909 | if !default_profile.contains(".") { 910 | println!("{}", "You seem to be using a very old firefox version. Consider updating. \nWe do not support such old versions. \nIf you want, you can try again with the --profile flag".red()); 911 | panic!("Quitting...".red()); 912 | } 913 | let default_profile_path: Vec<&str> = default_profile.split('/').collect(); 914 | let mut new_path = PathBuf::new(); 915 | for el in &default_profile_path { 916 | new_path.push(el.trim_end()); 917 | } 918 | env::set_current_dir(new_path).expect(&format!( 919 | "{}", 920 | "failed to cd. \nPlease report this issue on GitHub".red() 921 | )); 922 | } 923 | 924 | fn ask_for_profile() { 925 | let mut options: Vec = Vec::new(); 926 | let exceptions = ["Pending Pings", "Crash Reports", "Caches", ".mozilla"]; 927 | 928 | if env::consts::OS == "macos" || env::consts::OS == "windows" { 929 | env::set_current_dir("Profiles").expect(&format!( 930 | "{}", 931 | "Failed to cd into the Profiles dir (windows macos)".red() 932 | )); 933 | } 934 | let paths = fs::read_dir(".").unwrap(); 935 | for path in paths { 936 | let tmp = path.unwrap(); 937 | if tmp.path().is_dir() && !exceptions.contains(&tmp.file_name().to_str().unwrap()) { 938 | options.push(tmp.file_name().to_str().unwrap().to_string()); 939 | } 940 | } 941 | options.sort(); 942 | let selection = Select::with_theme(&ColorfulTheme::default()) 943 | .with_prompt(format!( 944 | "{}", 945 | "Pick your profile, to install into (navigate with arrow keys)".yellow() 946 | )) 947 | .default(0) 948 | .items(&options[..]) 949 | .interact() 950 | .unwrap(); 951 | env::set_current_dir(PathBuf::from(&options[selection])).unwrap(); 952 | } 953 | 954 | fn firefox_dir(matches: &clap::ArgMatches) { 955 | let os = env::consts::OS; 956 | 957 | // It gets your home directory 958 | let home_dir: PathBuf = dirs::home_dir().unwrap(); 959 | // It changes the directory in which it is being executed to the previously set variable (in this case it is the homedir) 960 | env::set_current_dir(home_dir).expect("Error: failed to cd"); 961 | // Makes a new variable 962 | let mut complete_path = PathBuf::new(); 963 | if os == "linux" { 964 | // The next part is that the program tries to understand with which package manager you have firefox installed 965 | // The native package manager installs the config files of firefox to /home/USER/.mozilla/firefox 966 | let native = Path::new(".mozilla/").exists(); 967 | // The snap one to /home/USER/snap.firefox/common/.mozilla/firefox 968 | let snap = Path::new("snap/firefox/common/.mozilla/").exists(); 969 | // checks If native is true, which is being set to true/false further up 970 | if native == true && !matches.is_present("path") { 971 | complete_path.push(".mozilla/"); 972 | 973 | // Checks if the variable that determines if firefox was installed via snap is true 974 | } else if snap == true && !matches.is_present("path") { 975 | complete_path.push("snap/firefox/common/.mozilla/"); 976 | } else { 977 | complete_path.push(manual_profile_path()); 978 | } 979 | } else if os == "macos" { 980 | let native = Path::new("Library/Application Support/Firefox/Profiles").exists(); 981 | if native == true && !matches.is_present("path") { 982 | complete_path.push("Library/Application Support/Firefox"); 983 | } else { 984 | complete_path.push(manual_profile_path()); 985 | } 986 | } else if os == "windows" { 987 | let native = Path::new("AppData\\Roaming\\Mozilla\\Firefox\\Profiles").exists(); 988 | // checks If native is true, which is being set to true/false further up 989 | if native == true && !matches.is_present("path") { 990 | complete_path.push("AppData\\Roaming\\Mozilla\\Firefox"); 991 | } else { 992 | complete_path.push(manual_profile_path()); 993 | } 994 | } 995 | 996 | succes("Got your firefox directory"); 997 | env::set_current_dir(complete_path).expect(&format!("{}", "Error: unable to cd".red())); 998 | } 999 | -------------------------------------------------------------------------------- /addon/addon/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Error: couldn't find the native app, do you have it installed? You can get it from here.

9 | 10 | -------------------------------------------------------------------------------- /addon/addon/icons/example_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/legendofmiracles/Themefox-Manager/a53d7ca8034628a0602c9064605131c149a52734/addon/addon/icons/example_icon.png -------------------------------------------------------------------------------- /addon/addon/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /addon/addon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "themefox_manager", 4 | "version": "1.1.5", 5 | "description": "The firefox theme manager (themefox-manager), now as a browser extension, so that you can use it easier and faster then ever.", 6 | "icons": { 7 | "643": "icons/example_icon.png" 8 | }, 9 | "browser_specific_settings": { 10 | "gecko": { 11 | "id": "lolsu@themefox.net", 12 | "strict_min_version": "50.0" 13 | } 14 | }, 15 | "background": { 16 | "scripts": [ 17 | "themefox_manager.js" 18 | ] 19 | }, 20 | "permissions": [ 21 | "nativeMessaging", 22 | "tabs" 23 | ], 24 | "browser_action": { 25 | "default_icon": "icons/example_icon.png", 26 | "default_title": "Themefox-manager-addon", 27 | "default_popup": "index.html" 28 | } 29 | } -------------------------------------------------------------------------------- /addon/addon/popup.js: -------------------------------------------------------------------------------- 1 | var myport; 2 | var message; 3 | window.addEventListener("DOMContentLoaded", async (event) => { 4 | // browser.browserAction.setPopup({ popup: "index.html" }) 5 | var tab = await browser.tabs.query({ 6 | currentWindow: true, 7 | active: true, 8 | }); 9 | //var tab = tab.then(browserTabs); 10 | 11 | var input = document.getElementById("URL"); 12 | input.value = tab[0].url; 13 | document.getElementById("install-button").onclick = install; 14 | 15 | // connects to bg script 16 | myport = browser.runtime.connect({ name: "lolsu@themefox.net" }); 17 | //sends a message 18 | myport.postMessage({ output: "ping" }); 19 | // on a message 20 | myport.onMessage.addListener(function (m) { 21 | //console.log("In content script, received message from background script: "); 22 | //console.log(m.message); 23 | if (m.message.startsWith("themefox: ")) { 24 | message = m.message; 25 | //console.log(message) 26 | output(); 27 | } else if (m.message == "pong") { } else { 28 | // browser.browserAction.setPopup({ popup: "error.html" }) 29 | console.log("Error: didn't get a anwser from the native application"); 30 | 31 | } 32 | //if () 33 | }); 34 | 35 | 36 | }); 37 | var injection = document.createElement("textarea") 38 | function install() { 39 | var mode = document.getElementById("select") 40 | var strMode = mode.options[mode.selectedIndex].text 41 | //console.log("mode: " + strMode); 42 | var url = document.getElementById("URL").value; 43 | //console.log("url: " + url) 44 | if (strMode == "Themefox") { 45 | strMode = "DO" 46 | } else if (strMode == "git") { } 47 | else { 48 | console.log("Weird, no correct mode.") 49 | } 50 | myport.postMessage({ output: strMode, url: url }); 51 | 52 | document.getElementById("install-button").after(injection); 53 | injection.before(document.createElement("br")); 54 | injection.before(document.createElement("br")); 55 | injection.toggleAttribute("readonly"); 56 | injection.id = "textarea" 57 | injection.rows = 20; 58 | injection.cols = 115; 59 | injection.placeholder = "The output from the native application will appear here." 60 | } 61 | 62 | function output() { 63 | console.log(message); 64 | injection.value = message; 65 | 66 | } -------------------------------------------------------------------------------- /addon/addon/stylesheet.css: -------------------------------------------------------------------------------- 1 | .button { 2 | text-align: center; 3 | background-color: #0060df; 4 | min-height: 32px; 5 | border: 1px solid transparent; 6 | border-radius: 2px; 7 | font-weight: 400; 8 | padding: 0 8px; 9 | text-decoration: none; 10 | /*margin: 4px 8px;*/ 11 | font-size: 1em; 12 | color: #fff; 13 | min-width: 6.3em; 14 | } 15 | 16 | body { 17 | background-color: rgba(249, 249, 250, 0.1); 18 | } 19 | 20 | .button:hover { 21 | background-color: #003eaa; 22 | } 23 | 24 | .body { 25 | background-color: #2A2A2E; 26 | color: white; 27 | 28 | } 29 | a { 30 | color:rgb(69, 161, 255); 31 | } 32 | 33 | #url { 34 | color: white; 35 | background-color: #2A2A2E; 36 | } 37 | 38 | #input { 39 | background-color: rgb(32, 32, 35); 40 | color: rgb(249, 249, 250); 41 | fill: rgb(249, 249, 250); 42 | } -------------------------------------------------------------------------------- /addon/addon/themefox_manager.js: -------------------------------------------------------------------------------- 1 | /* 2 | On a click on the browser action, send the app a message. 3 | */ 4 | var portFromCS; 5 | 6 | function connected(p) { 7 | portFromCS = p; 8 | //portFromCS.postMessage({ greeting: "hi there content script!" }); 9 | portFromCS.onMessage.addListener(function (m) { 10 | //console.log("In background script, received message from content script"); 11 | if (m.output == "ping") { 12 | testConnection(); 13 | } else if (m.output.startsWith("DO") || m.output.startsWith("git")) { 14 | console.log(JSON.stringify(m)); 15 | request(m.url, m.output); 16 | } else { 17 | console.log("Weird, no correct signal."); 18 | } 19 | }); 20 | } 21 | 22 | browser.runtime.onConnect.addListener(connected); 23 | 24 | 25 | function onResponse(response) { 26 | if (response["status"] !== null) { 27 | response["status"] = response["status"].toString().replace("0", "Sucess") 28 | } else { 29 | response["status"] = "Failure." 30 | } 31 | portFromCS.postMessage({ message: "themefox: " + response["output"] + response["error"] + response["status"]}); 32 | console.log("Received stdout: " + response["output"]); 33 | console.log("Received stderr: " + response["error"]); 34 | console.log("Quitted with error code: " + response["status"]); 35 | } 36 | 37 | function onError(error) { 38 | console.log(`Error: ${error}`); 39 | portFromCS.postMessage({ message: "F you frontend" }) 40 | } 41 | 42 | function request(tabURL, mode) { 43 | console.log("Sending request"); 44 | var sending = browser.runtime.sendNativeMessage( 45 | "themefox_manager", 46 | mode + " " + tabURL 47 | ); 48 | sending.then(onResponse, onError); 49 | } 50 | 51 | function onTestResponse(response) { 52 | console.log(response) 53 | portFromCS.postMessage({ message: response["msg"] }) 54 | console.log("Connected"); 55 | } 56 | 57 | function testConnection() { 58 | 59 | var sending = browser.runtime.sendNativeMessage("themefox_manager", {"message": "ping"}); 60 | sending.then(onTestResponse, onError); 61 | } 62 | -------------------------------------------------------------------------------- /addon/addon/web-ext-artifacts/themefox_manager-1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/legendofmiracles/Themefox-Manager/a53d7ca8034628a0602c9064605131c149a52734/addon/addon/web-ext-artifacts/themefox_manager-1.0.zip -------------------------------------------------------------------------------- /addon/addon/web-ext-artifacts/themefox_manager-1.1.5.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/legendofmiracles/Themefox-Manager/a53d7ca8034628a0602c9064605131c149a52734/addon/addon/web-ext-artifacts/themefox_manager-1.1.5.zip -------------------------------------------------------------------------------- /addon/addon/web-ext-artifacts/themefox_manager-1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/legendofmiracles/Themefox-Manager/a53d7ca8034628a0602c9064605131c149a52734/addon/addon/web-ext-artifacts/themefox_manager-1.1.zip -------------------------------------------------------------------------------- /addon/rust-app/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "byteorder" 5 | version = "1.3.4" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 8 | 9 | [[package]] 10 | name = "itoa" 11 | version = "0.4.5" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 14 | 15 | [[package]] 16 | name = "ryu" 17 | version = "1.0.5" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 20 | 21 | [[package]] 22 | name = "serde" 23 | version = "1.0.111" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "c9124df5b40cbd380080b2cc6ab894c040a3070d995f5c9dc77e18c34a8ae37d" 26 | 27 | [[package]] 28 | name = "serde_json" 29 | version = "1.0.53" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" 32 | dependencies = [ 33 | "itoa", 34 | "ryu", 35 | "serde", 36 | ] 37 | 38 | [[package]] 39 | name = "stdin-themefox-manager" 40 | version = "0.1.0" 41 | dependencies = [ 42 | "byteorder", 43 | "serde_json", 44 | ] 45 | -------------------------------------------------------------------------------- /addon/rust-app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stdin-themefox-manager" 3 | version = "0.1.0" 4 | authors = ["Definitly not the author "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | "byteorder" = "*" 11 | "serde_json" = "*" -------------------------------------------------------------------------------- /addon/rust-app/src/lib.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; 2 | use serde_json; 3 | use std::io::{self, Read, Write}; 4 | 5 | pub fn read_input(mut input: R) -> io::Result { 6 | let length = input.read_u32::().unwrap(); 7 | let mut buffer = vec![0; length as usize]; 8 | input.read_exact(&mut buffer)?; 9 | let json_val: serde_json::Value = serde_json::from_slice(&buffer).unwrap(); 10 | Ok(json_val) 11 | } 12 | 13 | pub fn write_output(mut output: W, value: std::string::String) -> io::Result<()> { 14 | //let msg = serde_json::to_string(value)?; 15 | let msg = value; 16 | let len = msg.len(); 17 | // Chrome won't accept a message larger than 1MB 18 | if len > 1024 * 1024 { 19 | panic!("Message was too large, length: {}", len) 20 | } 21 | output.write_u32::(len as u32)?; 22 | output.write_all(msg.as_bytes())?; 23 | output.flush()?; 24 | Ok(()) 25 | } 26 | -------------------------------------------------------------------------------- /addon/rust-app/src/main.rs: -------------------------------------------------------------------------------- 1 | mod lib; 2 | use std::io; 3 | use std::process::Command; 4 | fn main() { 5 | #[derive(Debug, Clone)] 6 | struct Output<'a> { 7 | field: &'a std::result::Result, 8 | }; 9 | let json_val = match lib::read_input(io::stdin()) { 10 | Err(why) => panic!("{{\"error\": \"{}\"}}", why.to_string()), 11 | Ok(json_val) => json_val, 12 | }; 13 | if json_val["message"] == "ping" { 14 | // your code here 15 | let response = "{\"message\": \"pong\" }"; 16 | std::fs::write("/home/legendofmiracles/foo.text", response); 17 | match lib::write_output(io::stdout(), response.to_string()) { 18 | Err(why) => panic!("{{\"error\": \"{}\"}}", why.to_string()), 19 | Ok(_) => (), 20 | }; 21 | } else if json_val.as_str().unwrap().starts_with("DO") { 22 | let string = json_val.as_str().unwrap(); 23 | let string: Vec<&str> = string.split_ascii_whitespace().collect(); 24 | 25 | let output = Output { 26 | field: &Command::new("themefox-manager") 27 | .arg(format!("{}", string[1])) 28 | .output(), 29 | }; 30 | 31 | if output.field.is_err() { 32 | let response = format!("{{\"error\": {:?}}}", output.field.as_ref().err()); 33 | match lib::write_output(io::stdout(), response) { 34 | Err(why) => panic!("{{\"error\": \"{}\"}}", why.to_string()), 35 | Ok(_) => (), 36 | }; 37 | } 38 | let test = output.field.as_ref().unwrap(); 39 | let stdout = std::str::from_utf8(test.stdout.as_slice()).unwrap(); 40 | let stderr = std::str::from_utf8(test.stderr.as_slice()).unwrap(); 41 | let response = format!( 42 | "{{ \"output\": {}, \"error\": {}, \"status\": {:?}}}", 43 | stdout, 44 | stderr, 45 | output.field.as_ref().unwrap().status.code() 46 | ); 47 | match lib::write_output(io::stdout(), response) { 48 | Err(why) => panic!("{{\"error\": \"{}\"}}", why.to_string()), 49 | Ok(_) => (), 50 | }; 51 | } else if json_val.as_str().unwrap().starts_with("git") { 52 | let string = json_val.as_str().unwrap(); 53 | let string: Vec<&str> = string.split_ascii_whitespace().collect(); 54 | let output = Output { 55 | field: &Command::new("themefox-manager") 56 | .arg("-g") 57 | .arg(format!("{}", string[1])) 58 | .output(), 59 | }; 60 | if output.field.as_ref().is_err() { 61 | let response = format!("{{\"error\": {:?}}}", output.field.as_ref().err()); 62 | match lib::write_output(io::stdout(), response) { 63 | Err(why) => panic!("{{\"error\": \"{}\"}}", why.to_string()), 64 | Ok(_) => (), 65 | } 66 | } 67 | let test = &output.field.as_ref().unwrap().stdout; 68 | let test2 = &output.field.as_ref().unwrap().stderr; 69 | let stdout = std::str::from_utf8(test.as_slice()).unwrap(); 70 | let stderr = std::str::from_utf8(test2.as_slice()).unwrap(); 71 | let response = format!( 72 | "{{ \"output\": {}, \"error\": {}, \"status\": {:?}}}", 73 | stdout, 74 | stderr, 75 | output.field.as_ref().unwrap().status.code() 76 | ); 77 | match lib::write_output(io::stdout(), response) { 78 | Err(why) => panic!("{{\"error\": \"{}\"}}", why.to_string()), 79 | Ok(_) => (), 80 | }; 81 | } else { 82 | match lib::write_output( 83 | io::stdout(), 84 | "{{\"output\": \"umm, no known signal\"}})".to_string(), 85 | ) { 86 | Err(why) => panic!("{{\"error\": \"{}\"}}", why.to_string()), 87 | Ok(_) => (), 88 | }; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /files/protocol-handler.reg: -------------------------------------------------------------------------------- 1 | HKEY_CLASSES_ROOT 2 | themefox-manager 3 | (Default) = "URL:themefox-manager Protocol" 4 | URL Protocol = "themefox-manager" 5 | shell 6 | open 7 | command (Default) = "C:\Program Files\themefox\themefox-manager.exe" "%1" 8 | -------------------------------------------------------------------------------- /files/themefox-manager.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | 3 | Name=themefox-manager 4 | 5 | Comment=A userchrome css manager for firefox with good support for the themefox website 6 | 7 | Exec=/usr/bin/themefox-manager "%U" 8 | 9 | Terminal=true 10 | 11 | Type=Application 12 | 13 | MimeType=x-scheme-handler/themefox-manager; 14 | -------------------------------------------------------------------------------- /files/themefox-manager.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "themefox_manager", 3 | "description": "Example host for native messaging", 4 | "path": "$USER/.local/bin/stdin-themefox-manager", 5 | "type": "stdio", 6 | "allowed_extensions": [ "lolsu@themefox.net" ] 7 | } -------------------------------------------------------------------------------- /files/themefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/legendofmiracles/Themefox-Manager/a53d7ca8034628a0602c9064605131c149a52734/files/themefox.png --------------------------------------------------------------------------------