diff --git a/README.md b/README.md index 5790761..f95bf72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ -[![Build Status](https://travis-ci.org/StarGazer1258/BeatDrop.svg?branch=master)](https://travis-ci.org/StarGazer1258/BeatDrop) # BeatDrop -The ultimate content-manager for Beat Saber. +![GitHub package.json version](https://img.shields.io/github/package-json/v/StarGazer1258/BeatDrop.svg) ![GitHub All Releases](https://img.shields.io/github/downloads/StarGazer1258/BeatDrop/total.svg) ![GitHub Releases](https://img.shields.io/github/downloads/StarGazer1258/BeatDrop/latest/total.svg) [![Build Status](https://travis-ci.org/StarGazer1258/BeatDrop.svg?branch=master)](https://travis-ci.org/StarGazer1258/BeatDrop) + +![BeatSaver Songs](https://img.shields.io/badge/dynamic/json.svg?color=success&label=BeatSaver&query=total&suffix=%20Songs&url=http%3A%2F%2Fbeatsaver.com%2Fapi%2Fsongs%2Fnew) ![BeatMods Mods](https://img.shields.io/badge/dynamic/json.svg?color=success&label=BeatMods&query=length&suffix=%20Mods&url=https%3A%2F%2Fbeatmods.com%2Fapi%2Fv1%2Fmod%3Fstatus%3Dapproved) + +The ultimate content-manager for Beat Saber. The best way to download and manage mods, songs, and more for the VR game Beat Saber. ## How to get BeatDrop 1. Go to [Releases](https://github.com/StarGazer1258/BeatDrop/releases) diff --git a/package-lock.json b/package-lock.json index 3c41c17..cb2a51e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "beatdrop", - "version": "2.1.8", + "version": "2.3.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3093,24 +3093,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, "requires": { @@ -3120,15 +3124,15 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true + "resolved": false, + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": false, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3136,37 +3140,40 @@ }, "chownr": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true + "resolved": false, + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true + "resolved": false, + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true + "resolved": false, + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "bundled": true, + "resolved": false, + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, "requires": { @@ -3175,25 +3182,29 @@ }, "deep-extend": { "version": "0.6.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, "requires": { @@ -3202,13 +3213,15 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, "requires": { @@ -3224,7 +3237,8 @@ }, "glob": { "version": "7.1.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "optional": true, "requires": { @@ -3238,13 +3252,15 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "bundled": true, + "resolved": false, + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, "requires": { @@ -3253,7 +3269,8 @@ }, "ignore-walk": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, "requires": { @@ -3262,7 +3279,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": false, + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, "requires": { @@ -3272,48 +3290,52 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true + "resolved": false, + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, + "resolved": false, + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "minipass": { "version": "2.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, "requires": { "safe-buffer": "^5.1.2", @@ -3322,7 +3344,8 @@ }, "minizlib": { "version": "1.2.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "dev": true, "optional": true, "requires": { @@ -3331,7 +3354,8 @@ }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { "minimist": "0.0.8" @@ -3339,13 +3363,15 @@ }, "ms": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", "dev": true, "optional": true, "requires": { @@ -3356,7 +3382,8 @@ }, "node-pre-gyp": { "version": "0.10.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", "dev": true, "optional": true, "requires": { @@ -3374,7 +3401,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, "requires": { @@ -3384,13 +3412,15 @@ }, "npm-bundled": { "version": "1.0.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==", "dev": true, "optional": true, "requires": { @@ -3400,7 +3430,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, "requires": { @@ -3412,40 +3443,44 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true + "resolved": false, + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, "requires": { @@ -3455,19 +3490,22 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.8", - "bundled": true, + "resolved": false, + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, "requires": { @@ -3479,7 +3517,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -3487,7 +3526,8 @@ }, "readable-stream": { "version": "2.3.6", - "bundled": true, + "resolved": false, + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, "requires": { @@ -3502,7 +3542,8 @@ }, "rimraf": { "version": "2.6.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "optional": true, "requires": { @@ -3511,44 +3552,50 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.6.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3557,7 +3604,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, "requires": { @@ -3566,7 +3614,8 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -3574,13 +3623,15 @@ }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.8", - "bundled": true, + "resolved": false, + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "dev": true, "optional": true, "requires": { @@ -3595,13 +3646,15 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, "requires": { @@ -3610,12 +3663,14 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "yallist": { "version": "3.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true } } @@ -6978,24 +7033,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "aproba": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, "requires": { @@ -7005,12 +7064,14 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.11", - "bundled": true, + "resolved": false, + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -7019,34 +7080,40 @@ }, "chownr": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, "core-util-is": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "bundled": true, + "resolved": false, + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, "requires": { @@ -7055,25 +7122,29 @@ }, "deep-extend": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, "requires": { @@ -7082,13 +7153,15 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": false, + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, "requires": { @@ -7104,7 +7177,8 @@ }, "glob": { "version": "7.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, "requires": { @@ -7118,13 +7192,15 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "bundled": true, + "resolved": false, + "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, "requires": { @@ -7133,7 +7209,8 @@ }, "ignore-walk": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, "requires": { @@ -7142,7 +7219,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": false, + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, "requires": { @@ -7152,18 +7230,21 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "ini": { "version": "1.3.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { "number-is-nan": "^1.0.0" @@ -7171,13 +7252,15 @@ }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -7185,12 +7268,14 @@ }, "minimist": { "version": "0.0.8", - "bundled": true, + "resolved": false, + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "minipass": { "version": "2.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, "requires": { "safe-buffer": "^5.1.1", @@ -7199,7 +7284,8 @@ }, "minizlib": { "version": "1.1.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, "requires": { @@ -7208,7 +7294,8 @@ }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { "minimist": "0.0.8" @@ -7216,13 +7303,15 @@ }, "ms": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, "requires": { @@ -7233,7 +7322,8 @@ }, "node-pre-gyp": { "version": "0.10.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, "requires": { @@ -7251,7 +7341,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, "requires": { @@ -7261,13 +7352,15 @@ }, "npm-bundled": { "version": "1.0.3", - "bundled": true, + "resolved": false, + "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "bundled": true, + "resolved": false, + "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, "requires": { @@ -7277,7 +7370,8 @@ }, "npmlog": { "version": "4.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, "requires": { @@ -7289,18 +7383,21 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" @@ -7308,19 +7405,22 @@ }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "bundled": true, + "resolved": false, + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, "requires": { @@ -7330,19 +7430,22 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "bundled": true, + "resolved": false, + "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, "requires": { @@ -7354,7 +7457,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -7362,7 +7466,8 @@ }, "readable-stream": { "version": "2.3.6", - "bundled": true, + "resolved": false, + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, "requires": { @@ -7377,7 +7482,8 @@ }, "rimraf": { "version": "2.6.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, "requires": { @@ -7386,42 +7492,49 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "bundled": true, + "resolved": false, + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "bundled": true, + "resolved": false, + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -7431,7 +7544,8 @@ }, "string_decoder": { "version": "1.1.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, "requires": { @@ -7440,7 +7554,8 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -7448,13 +7563,15 @@ }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": false, + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "bundled": true, + "resolved": false, + "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, "requires": { @@ -7469,13 +7586,15 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "bundled": true, + "resolved": false, + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, "requires": { @@ -7484,12 +7603,14 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "yallist": { "version": "3.0.2", - "bundled": true, + "resolved": false, + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true } } diff --git a/package.json b/package.json index ce9c69e..1fb2be2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "beatdrop", "description": "A desktop app for downloading Beat Saber songs.", "author": "Nathaniel Johns (StarGazer1258)", - "version": "2.2.0-alpha", + "version": "2.3.3", "private": false, "license": "CC-BY-NC-SA-4.0", "repository": { diff --git a/public/electron.js b/public/electron.js index d04bc2a..e5f8b48 100644 --- a/public/electron.js +++ b/public/electron.js @@ -212,9 +212,9 @@ function handleArgs(argv, sendImmediately) { function createWindow() { mainWindow = new BrowserWindow({ - width: 1015, + width: 1080, height: 615, - minWidth: 1015, + minWidth: 1090, minHeight: 615, resizable: true, frame: false, diff --git a/src/actions/detailsActions.js b/src/actions/detailsActions.js index a68283b..0d84477 100644 --- a/src/actions/detailsActions.js +++ b/src/actions/detailsActions.js @@ -30,7 +30,8 @@ export const loadDetails = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: '404: Song details not found!' + text: '404: Song details not found!', + timeout: 2500 } }) } diff --git a/src/actions/modActions.js b/src/actions/modActions.js index 9718300..063d8b9 100644 --- a/src/actions/modActions.js +++ b/src/actions/modActions.js @@ -2,7 +2,6 @@ import { SET_MOD_LIST, SET_VIEW, SET_RESOURCE, SET_LOADING, LOAD_MOD_DETAILS, IN import { MODS_VIEW, MOD_DETAILS } from '../views' import { BEATMODS, LIBRARY } from '../constants/resources' -import { MODS as EMERGENCY_MODS } from '../constants/emergencyMods' import modIcon from '../assets/dark/mod.png' @@ -16,7 +15,7 @@ const execFile = remote.require('child_process').execFile const { ipcRenderer } = window.require('electron') -export const fetchApprovedMods = () => dispatch => { +export const fetchApprovedMods = () => (dispatch, getState) => { dispatch({ type: SET_VIEW, payload: MODS_VIEW @@ -29,7 +28,7 @@ export const fetchApprovedMods = () => dispatch => { type: SET_LOADING, payload: true }) - fetch('https://beatmods.com/api/v1/mod?status=approved') + fetch(`https://beatmods.com/api/v1/mod?status=approved&gameVersion=${getState().settings.gameVersion}`) .then(res => res.json()) .then(beatModsResponse => { dispatch({ @@ -43,30 +42,7 @@ export const fetchApprovedMods = () => dispatch => { }) } -export const fetchEmergencyMods = () => dispatch => { - dispatch({ - type: SET_VIEW, - payload: MODS_VIEW - }) - dispatch({ - type: SET_RESOURCE, - payload: BEATMODS.NEW_MODS - }) - dispatch({ - type: SET_LOADING, - payload: true - }) - dispatch({ - type: SET_MOD_LIST, - payload: EMERGENCY_MODS - }) - dispatch({ - type: SET_LOADING, - payload: false - }) -} - -export const fetchRecommendedMods = () => dispatch => { +export const fetchRecommendedMods = () => (dispatch, getState) => { dispatch({ type: SET_VIEW, payload: MODS_VIEW @@ -82,7 +58,7 @@ export const fetchRecommendedMods = () => dispatch => { let recommendedMods = ['CameraPlus', 'YUR Fit Calorie Tracker', 'SyncSaber', 'Custom Sabers', 'Custom Platforms', 'Custom Avatars', 'BeatSaberTweaks', 'PracticePlugin', 'Counters+'] let mods = [] for(let i = 0; i < recommendedMods.length; i++) { - fetch(`https://beatmods.com/api/v1/mod?name=${encodeURIComponent(recommendedMods[i])}`) + fetch(`https://beatmods.com/api/v1/mod?name=${encodeURIComponent(recommendedMods[i])}&gameVersion=${getState().settings.gameVersion}`) .then(res => res.json()) .then(beatModsResponse => { if(beatModsResponse.length === 0) { recommendedMods.splice(i, 1); return } @@ -120,7 +96,7 @@ export const fetchModCategories = () => dispatch => { }) } -export const fetchModCategory = category => dispatch => { +export const fetchModCategory = category => (dispatch, getState) => { dispatch({ type: SET_VIEW, payload: MODS_VIEW @@ -133,7 +109,7 @@ export const fetchModCategory = category => dispatch => { type: SET_LOADING, payload: true }) - fetch(`https://beatmods.com/api/v1/mod?category=${ category }&status=approved`) + fetch(`https://beatmods.com/api/v1/mod?category=${ category }&status=approved&gameVersion=${getState().settings.gameVersion}`) .then(res => res.json()) .then(beatModsResponse => { dispatch({ @@ -166,7 +142,7 @@ export const fetchLocalMods = () => (dispatch, getState) => { let installedMods = getState().mods.installedMods let m = [] for(let i = 0; i < installedMods.length; i++) { - if(beatModsResponse.filter(mod => mod.name === installedMods[i].name)[0]) m.push(beatModsResponse.filter(mod => mod.name === installedMods[i].name)[0]) + if(beatModsResponse.filter(mod => mod._id === installedMods[i].id)[0]) m.push(beatModsResponse.filter(mod => mod._id === installedMods[i].id)[0]) console.log(installedMods[i].name) } dispatch({ @@ -182,7 +158,8 @@ export const fetchLocalMods = () => (dispatch, getState) => { type: DISPLAY_WARNING, payload: { color: 'gold', - text: 'No mods found!' + text: 'No mods found!', + timeout: 2500 } }) } @@ -224,7 +201,8 @@ export const fetchActivatedMods = () => (dispatch, getState) => { type: DISPLAY_WARNING, payload: { color: 'gold', - text: 'No mods found!' + text: 'No mods found!', + timeout: 2500 } }) } @@ -283,7 +261,7 @@ export const installMod = (modName, version, dependencyOf = '') => (dispatch, ge return } console.log(`Fetching ${modName}@${version} from BeatMods...`) - fetch(`https://beatmods.com/api/v1/mod?status=approved&status=inactive&name=${encodeURIComponent(modName)}&version=${version}`) + fetch(`https://beatmods.com/api/v1/mod?status=approved${!!version ? `&status=inactive&version=${version}` : ''}&name=${encodeURIComponent(modName)}&gameVersion=${getState().settings.gameVersion}`) .then(res => res.json()) .then(beatModsResponse => { console.log(`Got the BeatMods response for ${modName}@${version}`) @@ -323,7 +301,7 @@ export const installMod = (modName, version, dependencyOf = '') => (dispatch, ge dispatch({ type: DISPLAY_WARNING, payload: { text: `An error occured while downloading ${modName}. There may have been a connection error. - Please try again and file a bug report if the problem persists.` } + Please try again and file a bug report if the problem persists.`, timeout: 4000 } }) return } @@ -370,7 +348,7 @@ export const installMod = (modName, version, dependencyOf = '') => (dispatch, ge dispatch({ type: DISPLAY_WARNING, payload: { text: `An error occured while downloading ${modName}. There may have been a connection error. - Please try again and file a bug report if the problem persists.` } + Please try again and file a bug report if the problem persists.`, timeout: 2500 } }) return } @@ -402,7 +380,8 @@ export const installMod = (modName, version, dependencyOf = '') => (dispatch, ge dispatch({ type: DISPLAY_WARNING, payload: { - text: `The mod ${mod.name} does not have a version for ${installationType} installations.` + text: `The mod ${mod.name} does not have a version for ${installationType} v${getState().settings.gameVersion} installations.`, + timeout: 2500 } }) } @@ -540,7 +519,8 @@ export const checkInstalledMods = () => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `Could not find Plugins directory. Please make sure you have your installation directory and type set correctly.` + text: `Could not find Plugins directory. Please make sure you have your installation directory and type set correctly.`, + timeout: 4000 } }) dispatch({ diff --git a/src/actions/playlistsActions.js b/src/actions/playlistsActions.js index d2b1c62..a9db6cb 100644 --- a/src/actions/playlistsActions.js +++ b/src/actions/playlistsActions.js @@ -40,7 +40,8 @@ export const fetchLocalPlaylists = (doSetView) => (dispatch, getState) => { type: DISPLAY_WARNING, payload: { color: 'gold', - text: 'No playlists found!' + text: 'No playlists found!', + timeout: 2500 } }) } @@ -108,7 +109,8 @@ export const deletePlaylist = playlistFile => dispatch => { dispatch({ type: DISPLAY_WARNING, payload: { - text: 'Cannot delete playlist file! Try restarting BeatDrop and try again.' + text: 'Cannot delete playlist file! Try restarting BeatDrop and try again.', + timeout: 2500 } }) return @@ -152,7 +154,8 @@ export const loadPlaylistDetails = playlistFile => (dispatch, getState) => { type: DISPLAY_WARNING, payload: { color: 'gold', - text: 'Cannot access playlist file! Try redownloading the playlist or restarting BeatDrop and try again.' + text: 'Cannot access playlist file! Try redownloading the playlist or restarting BeatDrop and try again.', + timeout: 3000 } }) return @@ -264,19 +267,12 @@ export const savePlaylistDetails = details => (dispatch, getState) => { let file = details.playlistFile delete details.playlistFile let newSongs = [] - function findWithAttr(array, attr, value) { - for(var i = 0; i < array.length; i += 1) { - if(array[i][attr] === value) { - return i; - } - } - return -1; - } for(let i = 0; i < details.newOrder.length; i++) { - if(findWithAttr(details.songs, 'hash', details.newOrder[i]) >= 0) { - newSongs.push({ hash: details.songs[findWithAttr(details.songs, 'hash', details.newOrder[i])].hash, songName: details.songs[findWithAttr(details.songs, 'hash', details.newOrder[i])].songName }) + let identifier = details.newOrder[i].split('.')[0] + if(details.songs.findIndex((v) => v.hash === identifier) >= 0) { + newSongs.push({ hash: details.songs[details.songs.findIndex((v) => v.hash === identifier)].hash, songName: details.songs[details.songs.findIndex((v) => v.hash === identifier)].songName }) } else { - newSongs.push({ key: details.songs[findWithAttr(details.songs, 'key', details.newOrder[i])].key, songName: details.songs[findWithAttr(details.songs, 'key', details.newOrder[i])].songName }) + newSongs.push({ key: details.songs[details.songs.findIndex((v) => v.key === identifier)].key, songName: details.songs[details.songs.findIndex((v) => v.key === identifier)].songName }) } } details.songs = newSongs @@ -353,7 +349,7 @@ export const addSongToPlaylist = (song, playlistFile) => (dispatch, getState) => } catch(err) { dispatch({ type: DISPLAY_WARNING, - action: { text: 'Error reading difficulty level information, the song\'s files may be corrupt. Try redownloading the song and try again.' } + action: { text: 'Error reading difficulty level information, the song\'s files may be corrupt. Try redownloading the song and try again.', timeout: 4000 } }) return } diff --git a/src/actions/queueActions.js b/src/actions/queueActions.js index cf27c1b..aa739fd 100644 --- a/src/actions/queueActions.js +++ b/src/actions/queueActions.js @@ -1,4 +1,4 @@ -import { SET_QUEUE_OPEN, ADD_TO_QUEUE, CLEAR_QUEUE, UPDATE_PROGRESS, SET_VIEW, SET_DOWNLOADED_SONGS, SET_DOWNLOADING_COUNT, SET_WAIT_LIST, DISPLAY_WARNING, SET_SCANNING_FOR_SONGS } from './types' +import { SET_QUEUE_OPEN, ADD_TO_QUEUE, CLEAR_QUEUE, UPDATE_PROGRESS, SET_VIEW, SET_DOWNLOADED_SONGS, SET_DOWNLOADING_COUNT, SET_WAIT_LIST, DISPLAY_WARNING, SET_SCANNING_FOR_SONGS, SET_DISCOVERED_FILES, SET_PROCESSED_FILES } from './types' import { SONG_LIST } from '../views' import { isModInstalled, installEssentialMods } from './modActions'; @@ -7,7 +7,6 @@ const fs = remote.require('fs') const path = remote.require('path') const md5 = remote.require('md5') const AdmZip = remote.require('adm-zip') -const Walker = remote.require('walker') const request = remote.require('request') const rimraf = remote.require('rimraf') @@ -79,7 +78,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.` + text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.`, + timeout: 4000 } }) return @@ -98,7 +98,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error unpacking the song "${results.songs[0].songName}." The song's files may be corrupt or use formatting other than UTF-8 (Why UTF-8? The IETF says so! https://tools.ietf.org/html/rfc8259#section-8.1). Please try again and contact the song's uploader, ${results.songs[0].uploader}, if problem persists.` + text: `There was an error unpacking the song "${results.songs[0].songName}." The song's files may be corrupt or use formatting other than UTF-8 (Why UTF-8? The IETF says so! https://tools.ietf.org/html/rfc8259#section-8.1). Please try again and contact the song's uploader, ${results.songs[0].uploader}, if problem persists.`, + timeout: 4000 } }) return @@ -149,7 +150,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error downloading the song with hash ${hash}. The song requested is no longer be available for download.` + text: `There was an error downloading the song with hash ${hash}. The song requested is no longer be available for download.`, + timeout: 4000 } }) } @@ -171,7 +173,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.` + text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.`, + timeout: 4000 } }) }) @@ -180,7 +183,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error downloading the song with key ${identity}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.` + text: `There was an error downloading the song with key ${identity}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.`, + timeout: 4000 } }) return @@ -235,7 +239,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.` + text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.`, + timeout: 4000 } }) return @@ -305,7 +310,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error downloading the song with hash ${hash}. The song requested is no longer be available for download.` + text: `There was an error downloading the song with hash ${hash}. The song requested is no longer be available for download.`, + timeout: 4000 } }) } @@ -327,7 +333,8 @@ export const downloadSong = (identity) => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.` + text: `There was an error downloading the song with hash ${hash}. There may have been an error with BeatSaver's servers or the song may no longer be available. Please try again and contact the BeatSaver developers if problem persists.`, + timeout: 6000 } }) }) @@ -376,106 +383,99 @@ export const deleteSong = (identity) => (dispatch, getState) => { } export const checkDownloadedSongs = () => (dispatch, getState) => { - setTimeout(() => { + let discoveredFiles = 0, processedFiles = 0 dispatch({ - type: SET_SCANNING_FOR_SONGS, - payload: true + type: SET_DISCOVERED_FILES, + payload: discoveredFiles }) - let state = { ...getState() } - let songs = [] - let count = 0 - let ended = false - let decrementCounter = () => { - count-- - if(ended && count === 0) { - dispatch({ - type: SET_DOWNLOADED_SONGS, - payload: songs - }) - dispatch({ - type: SET_SCANNING_FOR_SONGS, - payload: false - }) - return - } - } - fs.access(path.join(state.settings.installationDirectory, 'CustomSongs'), (err) => { - if(err) { - fs.mkdir(path.join(state.settings.installationDirectory, 'CustomSongs'), (err) => { - if(err) { - dispatch({ - type: DISPLAY_WARNING, - payload: { - text: 'Could not create CustomSongs directory. Make sure you have your Beat Saber indsatllation directory set properly.' - } - }) - } - }) - installEssentialMods()(dispatch, getState) - dispatch({ - type: SET_DOWNLOADED_SONGS, - payload: [] - }) + dispatch({ + type: SET_PROCESSED_FILES, + payload: processedFiles + }) + const walk = function(pathName, cb) { + let songs = [] + fs.readdir(pathName, (err, files) => { + if(err) return cb(err) + let pending = files.length dispatch({ - type: SET_SCANNING_FOR_SONGS, - payload: false + type: SET_DISCOVERED_FILES, + payload: discoveredFiles += pending }) - return - } - Walker(path.join(getState().settings.installationDirectory, 'CustomSongs')) - .on('file', (file) => { - if(file === 'info.json') { - count++ - fs.readFile(file, 'UTF-8', (err, data) => { - if(err) { decrementCounter(); return } - let dirs = file.split('\\') - dirs.pop() - let dir = dirs.join('\\') - let song - try { - song = JSON.parse(data) - } catch(err) { - decrementCounter() - return - } - if(song.hasOwnProperty('hash')) { - songs.push({ hash: song.hash, file }) - decrementCounter() - } else { - let to_hash = '' - for(let i = 0; i < song.difficultyLevels.length; i++) { - try { - to_hash += fs.readFileSync(path.join(dir, song.difficultyLevels[i].jsonPath), 'UTF8') - } catch(err) { - decrementCounter() - return + if(!pending) return cb(null, songs) + for(let i = 0; i < files.length; i++) { + const file = path.join(pathName, files[i]) + fs.stat(file, (err, stat) => { // eslint-disable-line no-loop-func + if(err) return cb(err) + if(stat && stat.isDirectory()) { + walk(file, (_, s) => { + songs = songs.concat(s) + dispatch({ + type: SET_PROCESSED_FILES, + payload: ++processedFiles + }) + if(!--pending) cb(null, songs) + }) + } else { + if(files[i].toLowerCase() === 'info.json') { + fs.readFile(file, { encoding: 'UTF-8' }, (err, data) => { + if(err) return cb(err) + let song = JSON.parse(data) + if(song.hasOwnProperty('hash')) { + songs.push({ hash: song.hash, file }) + dispatch({ + type: SET_PROCESSED_FILES, + payload: ++processedFiles + }) + if(!--pending) cb(null, songs) + } else { + let to_hash = '' + for(let i = 0; i < song.difficultyLevels.length; i++) { + try { + let dir = file.split(path.sep) + dir.pop() + to_hash += fs.readFileSync(path.join(dir, song.difficultyLevels[i].jsonPath), 'UTF8') + } catch(err) {} + } + let hash = md5(to_hash) + song.hash = hash + fs.writeFile(file, JSON.stringify(song), 'UTF8', (err) => { if(err) return }) + songs.push({ hash, file }) + dispatch({ + type: SET_PROCESSED_FILES, + payload: ++processedFiles + }) + if(!--pending) cb(null, songs) } - } - let hash = md5(to_hash) - song.hash = hash - fs.writeFile(file, JSON.stringify(song), 'UTF8', (err) => { if(err) return }) - songs.push({ hash, file }) - decrementCounter() + }) + } else { + dispatch({ + type: SET_PROCESSED_FILES, + payload: ++processedFiles + }) + if(!--pending) cb(null, songs) } - }) - } - }) - .on('end', () => { - if(count === 0) { - dispatch({ - type: SET_DOWNLOADED_SONGS, - payload: songs - }) - dispatch({ - type: SET_SCANNING_FOR_SONGS, - payload: false - }) - return - } - ended = true - }) + } + }) + } + }) + } + + dispatch({ + type: SET_SCANNING_FOR_SONGS, + payload: true + }) + + walk(path.join(getState().settings.installationDirectory, 'CustomSongs'), (err, songs) => { + dispatch({ + type: SET_DOWNLOADED_SONGS, + payload: songs + }) + + dispatch({ + type: SET_SCANNING_FOR_SONGS, + payload: false + }) }) - }, 1000) } export const clearQueue = () => dispatch => { @@ -493,4 +493,4 @@ export const resetDownloads = () => dispatch => { type: SET_WAIT_LIST, payload: [] }) -} \ No newline at end of file +} diff --git a/src/actions/settingsActions.js b/src/actions/settingsActions.js index 239d46f..001574b 100644 --- a/src/actions/settingsActions.js +++ b/src/actions/settingsActions.js @@ -1,4 +1,4 @@ -import { SET_SETTINGS_OPEN, SET_INSTALLATION_DIRECTORY, SET_AUTO_LOAD_MORE, SET_OFFLINE_MODE, SET_THEME, SET_FOLDER_STRUCTURE, SET_UPDATE_CHANNEL, SET_LATEST_RELEASE_NOTES, SET_INSTALLATION_TYPE } from './types' +import { SET_SETTINGS_OPEN, SET_INSTALLATION_DIRECTORY, SET_AUTO_LOAD_MORE, SET_OFFLINE_MODE, SET_THEME, SET_THEME_IMAGE, SET_FOLDER_STRUCTURE, SET_UPDATE_CHANNEL, SET_LATEST_RELEASE_NOTES, SET_INSTALLATION_TYPE, SET_GAME_VERSION } from './types' import { checkDownloadedSongs } from './queueActions' @@ -26,6 +26,13 @@ export const setInstallationType = type => dispatch => { }) } +export const setGameVersion = version => dispatch => { + dispatch({ + type: SET_GAME_VERSION, + payload: version + }) +} + export const setAutoLoadMore = willAutoLoadMore => dispatch => { dispatch({ type: SET_AUTO_LOAD_MORE, @@ -47,6 +54,13 @@ export const setTheme = theme => dispatch => { }) } +export const setThemeImage = imagePath => dispatch => { + dispatch({ + type: SET_THEME_IMAGE, + payload: imagePath + }) +} + export const setFolderStructure = structure => dispatch => { dispatch({ type: SET_FOLDER_STRUCTURE, diff --git a/src/actions/songListActions.js b/src/actions/songListActions.js index af282bb..36f1066 100644 --- a/src/actions/songListActions.js +++ b/src/actions/songListActions.js @@ -296,7 +296,8 @@ export const loadMore = () => (dispatch, getState) => { dispatch({ type: DISPLAY_WARNING, payload: { - text: 'There was error loading more songs. Check your connection to the internet and try again.' + text: 'There was error loading more songs. Check your connection to the internet and try again.', + timeout: 5000 } }) }) diff --git a/src/actions/types.js b/src/actions/types.js index 879d42d..e8e4155 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -14,6 +14,8 @@ export const SET_SCROLLTOP = 'SET_SCROLLTOP' export const SET_DOWNLOADING_COUNT = 'SET_DOWNLOADING_COUNT' export const SET_WAIT_LIST = 'EST_WAIT_LIST' export const SET_SCANNING_FOR_SONGS = 'SET_SCANNING_FOR SONGS' +export const SET_DISCOVERED_FILES = 'SET_DISCOVERED_FILES' +export const SET_PROCESSED_FILES = 'SET_PROCESSED_FILES' export const SET_LOADING = 'SET_LOADING' export const SET_LOADING_MORE = 'SET_LOADING_MORE' @@ -70,9 +72,11 @@ export const SET_SECTION = 'SET_SECTION' export const SET_SETTINGS_OPEN = 'SET_SETTINGS_OPEN' export const SET_INSTALLATION_DIRECTORY = 'SET_INSTALLATION_DIRECTORY' export const SET_INSTALLATION_TYPE = 'SET_INSTALLATION_TYPE' +export const SET_GAME_VERSION = 'SET_GAME_VERSION' export const SET_AUTO_LOAD_MORE = 'SET_AUTO_LOAD_MORE' export const SET_OFFLINE_MODE = 'SET_OFFLINE_MODE' export const SET_THEME = 'SET_THEME' +export const SET_THEME_IMAGE = 'SET_THEME_IMAGE' export const SET_FOLDER_STRUCTURE = 'SET_FOLDER_STRUCTURE' export const SET_UPDATE_CHANNEL = 'SET_UPDATE_CHANNEL' export const SET_LATEST_RELEASE_NOTES = 'SET_LATEST_RELEASE_NOTES' diff --git a/src/components/ModDetails.js b/src/components/ModDetails.js index 5a65641..82e7ac9 100644 --- a/src/components/ModDetails.js +++ b/src/components/ModDetails.js @@ -59,6 +59,7 @@ class ModDetails extends Component {

{ this.props.details.name }

by { this.props.details.author.username }

{ this.props.details.category.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()}) } + Beat Saber v{ this.props.details.gameVersion } { this.props.installedMods.some(mod => mod.id === this.props.details._id) ?
This mod is in your library.
: null } { this.props.details.name === 'BSIPA' ?
BSIPA is required to load mods and cannot be uninstalled or deactivated.
: null } { this.props.installedMods.some(mod => mod.id === this.props.details._id) && (this.props.installedMods.filter(m => m.name === this.props.details.name)[0].dependencyOf.some(dependent => this.props.installedMods.some(installedMod => installedMod.name === dependent))) ?
{ this.props.details.name } is required by { this.props.installedMods.filter(m => m.name === this.props.details.name)[0].dependencyOf.filter(dependent => this.props.installedMods.some(installedMod => installedMod.name === dependent)).join(', ') } and cannot be uninstalled or deactivated.
: null } diff --git a/src/components/ModsListView.js b/src/components/ModsListView.js index e9782ad..9aa5bd1 100644 --- a/src/components/ModsListView.js +++ b/src/components/ModsListView.js @@ -12,6 +12,8 @@ import Loader from '../assets/loading-dots2.png' import { connect } from 'react-redux' import SortBar from './SortBar'; +const { shell } = window.require('electron') + class ModsListView extends Component { constructor(props) { super(props) @@ -59,6 +61,7 @@ class ModsListView extends Component {   { this.setState({ sortBy: 'name', sortDirection: this.state.sortBy === 'name' ? !this.state.sortDirection : 0 }) } }>Mod Name{ this.state.sortBy === 'name' ? this.state.sortDirection ? '▼' : '▲' : null } { this.setState({ sortBy: 'version', sortDirection: this.state.sortBy === 'version' ? !this.state.sortDirection : 0 }) } }>Version{ this.state.sortBy === 'version' ? this.state.sortDirection ? '▼' : '▲' : null } + { this.setState({ sortBy: 'gameVersion', sortDirection: this.state.sortBy === 'gameVersion' ? !this.state.sortDirection : 0 }) } }>Game V.{ this.state.sortBy === 'gameVersion' ? this.state.sortDirection ? '▼' : '▲' : null } { this.setState({ sortBy: 'author', sortDirection: this.state.sortBy === 'author' ? !this.state.sortDirection : 0 }) } }>Author{ this.state.sortBy === 'author' ? this.state.sortDirection ? '▼' : '▲' : null } { this.setState({ sortBy: 'category', sortDirection: this.state.sortBy === 'category' ? !this.state.sortDirection : 0 }) } }>Category{ this.state.sortBy === 'category' ? this.state.sortDirection ? '▼' : '▲' : null } { this.setState({ sortBy: 'uploadDate', sortDirection: this.state.sortBy === 'uploadDate' ? !this.state.sortDirection : 0 }) } }>Upload Date{ this.state.sortBy === 'uploadDate' ? this.state.sortDirection ? '▼' : '▲' : null } @@ -78,6 +81,10 @@ class ModsListView extends Component { if(a.version < b.version) return this.state.sortDirection * 2 - 1 if(a.version > b.version) return -(this.state.sortDirection * 2 - 1) return 0 + case 'gameVersion': + if(a.gameVersion < b.gameVersion) return this.state.sortDirection * 2 - 1 + if(a.gameVersion > b.gameVersion) return -(this.state.sortDirection * 2 - 1) + return 0 case 'author': if(a.author.username < b.author.username) return this.state.sortDirection * 2 - 1 if(a.author.username > b.author.username) return -(this.state.sortDirection * 2 - 1) @@ -127,7 +134,8 @@ class ModsListView extends Component { { mod.name } { mod.version } - { mod.author.username } + { mod.gameVersion } + { mod.name === 'YUR Fit Calorie Tracker' ? { e.preventDefault(); e.stopPropagation(); shell.openExternal('https://yur.chat') } }>https://yur.chat : (mod.author.username || 'Unknown') } { mod.category } { `${new Date(mod.uploadDate).toLocaleDateString() }, ${ new Date(mod.uploadDate).toLocaleTimeString() }` } diff --git a/src/components/ModsView.js b/src/components/ModsView.js index a4036b4..9ab7ed1 100644 --- a/src/components/ModsView.js +++ b/src/components/ModsView.js @@ -132,7 +132,7 @@ class ModsView extends Component { { this.props.mods.installedMods.some(m => m.name === mod.name) ? (!this.props.mods.installedMods.filter(m => m.name === mod.name)[0].active ? : null) : null }
- { mod.name } v{ mod.version } + { mod.name } v{ mod.version } (for v{ mod.gameVersion })
{ mod.name === 'YUR Fit Calorie Tracker' ? <>Join our discord: { e.preventDefault(); e.stopPropagation(); shell.openExternal('https://yur.chat') } }>https://yur.chat : `by ${ mod.author.username || 'Unknown' }` }
{ category.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()}).replace('Ui', 'UI') }
diff --git a/src/components/ReleaseNotesModal.js b/src/components/ReleaseNotesModal.js index 77c0927..8689e1d 100644 --- a/src/components/ReleaseNotesModal.js +++ b/src/components/ReleaseNotesModal.js @@ -25,13 +25,18 @@ class ReleaseNotesModal extends Component {

What's new?


What's fixed?



diff --git a/src/components/SettingsView.js b/src/components/SettingsView.js index 48e50cf..5f831d7 100644 --- a/src/components/SettingsView.js +++ b/src/components/SettingsView.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import { connect } from 'react-redux' import PropTypes from 'prop-types' -import { setInstallationDirectory, setInstallationType, setAutoLoadMore, setOfflineMode, setTheme, setFolderStructure, setUpdateChannel, setLatestReleaseNotes } from '../actions/settingsActions' +import { setInstallationDirectory, setInstallationType, setGameVersion, setAutoLoadMore, setOfflineMode, setTheme, setThemeImage, setFolderStructure, setUpdateChannel, setLatestReleaseNotes } from '../actions/settingsActions' import { checkDownloadedSongs } from '../actions/queueActions' import { checkInstalledMods } from '../actions/modActions' import '../css/SettingsView.scss' @@ -16,7 +16,8 @@ class SettingsView extends Component { super(props) this.state = { - updateStatus: '' + updateStatus: '', + gameVersions: [] } } @@ -26,6 +27,10 @@ class SettingsView extends Component { this.setState({ updateStatus: event }) } }) + + fetch('https://beatmods.com/api/v1/version') + .then(res => res.json()) + .then(gameVersions => this.setState({ gameVersions })) } updateValue() { @@ -52,11 +57,26 @@ class SettingsView extends Component { {this.props.setInstallationDirectory(e.target.files[0].path || this.props.settings.installationDirectory)} } />


-

- + + + + + +
+ + + + +
Installation Type Game Version
+ + + +
{ this.props.settings.installationType === 'steam' && this.props.settings.installationDirectory.includes('Oculus') ? <>

Warning: BeatDrop has detected that you may be using the Oculus version of BeatSaber. If this is the case, please set "Installation Type" to "Oculus". Otherwise, you can ignore this message.

: null } { this.props.settings.installationType === 'oculus' && this.props.settings.installationDirectory.includes('Steam') ? <>

Warning: BeatDrop has detected that you may be using the Steam version of BeatSaber. If this is the case, please set "Installation Type" to "Steam". Otherwise, you can ignore this message.

: null }
@@ -77,7 +97,11 @@ class SettingsView extends Component { - +

+

+ + {this.props.setThemeImage(e.target.files[0].path || this.props.settings.themeImagePath)} } />
+


Updates

Current Version: { require('../../package.json').version }

@@ -118,8 +142,22 @@ class SettingsView extends Component { Wave Tier +
  • + Hurricane Tiere + +
  • +
  • + Tsunami Tier + +


  • @@ -144,6 +182,6 @@ const mapStateToProps = state => ({ scanningForMods: state.mods.scanning }) -export default connect(mapStateToProps, { setInstallationDirectory, setInstallationType, setAutoLoadMore, setOfflineMode, setTheme, setFolderStructure, setUpdateChannel, setLatestReleaseNotes, checkDownloadedSongs, checkInstalledMods })(SettingsView) +export default connect(mapStateToProps, { setInstallationDirectory, setInstallationType, setGameVersion, setAutoLoadMore, setOfflineMode, setTheme, setThemeImage, setFolderStructure, setUpdateChannel, setLatestReleaseNotes, checkDownloadedSongs, checkInstalledMods })(SettingsView) // this.props.setAutoLoadMore(!this.props.settings.autoLoadMore)} /> \ No newline at end of file diff --git a/src/components/Slate.js b/src/components/Slate.js index a2be274..fb49ed0 100644 --- a/src/components/Slate.js +++ b/src/components/Slate.js @@ -7,7 +7,7 @@ import PropTypes from 'prop-types' class Slate extends Component { render() { return ( -
    +
    ) } } @@ -17,7 +17,8 @@ Slate.propTypes = { } let mapStateToProps = state => ({ - theme: state.settings.theme + theme: state.settings.theme, + themeImage: state.settings.themeImagePath }) export default connect(mapStateToProps, null)(Slate) \ No newline at end of file diff --git a/src/components/SongList.js b/src/components/SongList.js index b196fe1..4a3f59f 100644 --- a/src/components/SongList.js +++ b/src/components/SongList.js @@ -90,7 +90,7 @@ class SongList extends Component { ] return ( - + {e.stopPropagation(); (!!song.file || this.props.songs.downloadedSongs.some(dsong => dsong.hash === (song.hash || song.hashMd5))) ? this.props.deleteSong(song.file || song.hash || song.hashMd5) : this.props.downloadSong(song.hash || song.hashMd5)} }> {`${(!!song.file || this.props.songs.downloadedSongs.some(dsong => dsong.hash === (song.hash || song.hashMd5))) ? 'Delete' : 'Download'} ${song.songName}`} diff --git a/src/components/SongListItem.js b/src/components/SongListItem.js index abf3152..aec1195 100644 --- a/src/components/SongListItem.js +++ b/src/components/SongListItem.js @@ -16,7 +16,7 @@ import { COMPACT_LIST } from '../views' function Uploader(props) { if(!props.isDownloaded && !!props.uploader) return ( -
    Uploaded by: {props.uploader}
    +
    Uploaded by: {props.uploader}{(!!props.uploadDate ? props.uploadDate : '')}
    ) return null } @@ -104,7 +104,7 @@ class SongListItem extends Component {
    {this.props.title}{!!this.props.songKey ? this.props.songKey : ''}
    {(!!this.props.file || this.props.downloadedSongs.some(dsong => dsong.hash === this.props.hash)) && this.props.view.songView === COMPACT_LIST ? : null}
    {this.props.artist}
    - +
    diff --git a/src/components/SongScanningDialog.js b/src/components/SongScanningDialog.js index d6c45ac..5e9f458 100644 --- a/src/components/SongScanningDialog.js +++ b/src/components/SongScanningDialog.js @@ -5,16 +5,28 @@ import { connect } from 'react-redux' import Modal from './Modal'; import ProgressBar from './ProgressBar'; -import { SET_SCANNING_FOR_SONGS } from '../actions/types' - class SongScanningDialog extends Component { + constructor(props) { + super(props) + + this.state = { + open: false + } + } + + componentWillReceiveProps(props) { + if(props.scanning === true) this.setState({ open: true }) + } + render() { return ( - this.props.scanning ? - { this.props.dispatch({ type: SET_SCANNING_FOR_SONGS, payload: false }) } }> -

    Scanning for songs...

    - + this.state.open ? + { this.setState({ open: false }) } }> +

    { !this.props.scanning ? `Finished scanning for songs.` : 'Scanning for songs...' }

    + +
    { `${ this.props.processedFiles } / ${ this.props.discoveredFiles } Files scanned.${ !this.props.scanning ? ` | ${this.props.songs.length } songs discovered.` : '..' }` }
    + { !this.props.scanning ?
    Click outside to exit.
    : null }
    : null ) @@ -23,9 +35,10 @@ class SongScanningDialog extends Component { let mapStateToProps = state => ({ theme: state.settings.theme, + songs: state.songs.downloadedSongs, scanning: state.songs.scanningForSongs, - songsLoaded: state.songs.songsLoaded, - songsDicovered: state.songs.songsDiscovered + discoveredFiles: state.songs.discoveredFiles, + processedFiles: state.songs.processedFiles }) export default connect(mapStateToProps, null)(SongScanningDialog) \ No newline at end of file diff --git a/src/components/ViewSwitcher.js b/src/components/ViewSwitcher.js index 061cdd5..b97d242 100644 --- a/src/components/ViewSwitcher.js +++ b/src/components/ViewSwitcher.js @@ -77,8 +77,18 @@ class ViewSwitcher extends Component {
    - { [VIEWS.SONG_LIST].some(view => this.props.view === view) && } - + { (this.props.settings.installationDirectory === '' || + this.props.settings.installationType === undefined || + this.props.settings.installationType === 'choose' || + this.props.settings.gameVersion === undefined || + this.props.settings.gameVersion === 'choose') && + this.props.view !== VIEWS.WELCOME ? + : + <> + { [VIEWS.SONG_LIST].some(view => this.props.view === view) && } + + + }
    diff --git a/src/components/WelcomePage.js b/src/components/WelcomePage.js index 5f0fe09..4a261ef 100644 --- a/src/components/WelcomePage.js +++ b/src/components/WelcomePage.js @@ -6,7 +6,7 @@ import PatreonButton from '../assets/become-a-patron-button.png' import Button from './Button'; import Modal from './Modal' -import { setInstallationDirectory, setInstallationType } from '../actions/settingsActions' +import { setInstallationDirectory, setInstallationType, setGameVersion } from '../actions/settingsActions' import { checkDownloadedSongs } from '../actions/queueActions' import { checkInstalledMods } from '../actions/modActions' import { fetchNew } from '../actions/songListActions' @@ -20,12 +20,23 @@ class WelcomePage extends Component { super(props) this.state = { - modalOpen: false + modalOpen: false, + gameVersions: [] } } componentDidMount() { - if(this.props.settings.installationDirectory === '' || this.props.settings.installationType === 'choose') { this.setState({ modalOpen: true }) } + if(this.props.settings.installationDirectory === '' || + this.props.settings.installationType === 'choose' || + this.props.settings.installationType === undefined || + this.props.settings.gameVersion === 'choose' || + this.props.settings.gameVersion === undefined) { + this.setState({ modalOpen: true }) + } + + fetch('https://beatmods.com/api/v1/version') + .then(res => res.json()) + .then(gameVersions => this.setState({ gameVersions })) } render() { @@ -44,15 +55,32 @@ class WelcomePage extends Component { {this.props.setInstallationDirectory(e.target.files[0].path || this.props.settings.installationDirectory)} } />




    - + + + + + +
    + + + + +
    Installation Type Game Version
    + + + +


    { this.props.settings.installationType === 'steam' && this.props.settings.installationDirectory.includes('Oculus') ? <>Warning: BeatDrop has detected that you may be using the Oculus version of BeatSaber. If this is the case, please set "Installation Type" to "Oculus". Otherwise, you can ignore this message.

    : null } { this.props.settings.installationType === 'oculus' && this.props.settings.installationDirectory.includes('Steam') ? <>Warning: BeatDrop has detected that you may be using the Steam version of BeatSaber. If this is the case, please set "Installation Type" to "Steam". Otherwise, you can ignore this message.

    : null } - +
    : null } ) @@ -64,4 +92,4 @@ const mapStateToProps = state => ({ settings: state.settings }) -export default connect(mapStateToProps, { fetchNew, checkDownloadedSongs, checkInstalledMods, setInstallationDirectory, setInstallationType })(WelcomePage) \ No newline at end of file +export default connect(mapStateToProps, { fetchNew, checkDownloadedSongs, checkInstalledMods, setInstallationDirectory, setInstallationType, setGameVersion })(WelcomePage) \ No newline at end of file diff --git a/src/constants/emergencyMods.js b/src/constants/emergencyMods.js deleted file mode 100644 index b435af4..0000000 --- a/src/constants/emergencyMods.js +++ /dev/null @@ -1,210 +0,0 @@ -export const MODS = [ - { - title: 'SongLoader', - name: 'song-loader', - version: '6.9.5', - author: 'xyonico/Kyle1413', - category: 'Core', - downloadUrl: 'https://bsaber.com/mods/song-loader-6.9.5.zip' - }, - { - title: 'CustomMenuText', - name: 'custommenutext', - version: '3.0.1', - author: 'Arti', - category: 'Text Changes', - downloadUrl: 'https://bsaber.com/mods/custommenutext-3.0.1.zip' - }, - { - title: 'HTTP Status', - name: 'http-status', - version: '1.4.1', - author: 'opl', - category: 'Other', - downloadUrl: 'https://bsaber.com/mods/http-status-1.4.1.zip' - }, - { - title: 'Perfection Display', - name: 'perfectiondisplay', - version: '1.5.1', - author: 'monkeymanboy', - category: 'Cosmetic Changes', - downloadUrl: 'https://bsaber.com/mods/perfectiondisplay-1.5.1.zip' - }, - { - title: 'Counters+', - name: 'countersplus', - version: '1.5.2', - author: 'Caeden117', - category: 'Practice / Training', - downloadUrl: 'https://bsaber.com/mods/countersplus-1.5.2.zip' - }, - { - title: 'Simplest Rainbow Mod', - name: 'simplest-rainbow-mod', - version: '1.5.1', - author: 'Oshi', - category: 'Cosmetic Changes', - downloadUrl: 'https://bsaber.com/mods/simplest-rainbow-mod-1.5.1.zip' - }, - { - title: 'SongBrowserPlugin (mildly borkd)', - name: 'songbrowserplugin', - version: '3.0.4', - author: 'halsafar', - category: 'Core', - downloadUrl: 'https://bsaber.com/mods/songbrowserplugin-3.0.4.zip' - }, - { - title: 'Camera+', - name: 'camera-plus', - version: '3.2.6', - author: 'xyonico/brian', - category: 'Core', - downloadUrl: 'https://bsaber.com/mods/camera-plus-3.2.6.zip' - }, - { - title: 'BeatSaverDownloader', - name: 'beatsaverdownloader', - version: '3.3.1', - author: 'andruzzzhka', - category: 'Core', - downloadUrl: 'https://bsaber.com/mods/beatsaverdownloader-3.3.1.zip' - }, - { - title: 'LeaderboardInSong', - name: 'leaderboardinsong', - version: '1.1.2', - author: 'Kyle1413', - category: 'Cosmetic Changes', - downloadUrl: 'https://bsaber.com/mods/leaderboardinsong-1.1.2.zip' - }, - { - title: 'Beat Saber Tweaks', - name: 'beat-saber-tweaks', - version: '4.4.1', - author: 'Megalon', - category: 'Gameplay Changes', - downloadUrl: 'https://bsaber.com/mods/beat-saber-tweaks-4.4.1.zip' - }, - { - title: 'Practice Plugin', - name: 'practice-plugin', - version: '4.2.4', - author: 'xyonico', - category: 'Practice / Training', - downloadUrl: 'https://bsaber.com/mods/practice-plugin-4.2.4.zip' - }, - { - title: 'Notes Left', - name: 'notesleftcounter', - version: '1.1.0', - author: 'Kyle1413', - category: 'Practice / Training', - downloadUrl: 'https://bsaber.com/mods/notesleftcounter-1.1.0.zip' - }, - { - title: 'IntroSkip', - name: 'introskip', - version: '2.2.2', - author: 'Kyle1413', - category: 'Gameplay Changes', - downloadUrl: 'https://bsaber.com/mods/introskip-2.2.2.zip' - }, - { - title: 'Mapping Extensions', - name: 'mapping-extensions', - version: '1.1.1', - author: 'Kyle1413', - category: 'Gameplay Changes', - downloadUrl: 'https://bsaber.com/mods/mapping-extensions-1.1.1.zip' - }, - { - title: 'Gameplay Restrictions Plus', - name: 'gameplay-restrictions-plus', - version: '1.2.0', - author: 'Kyle1413', - category: 'Gameplay Changes', - downloadUrl: 'https://bsaber.com/mods/gameplay-restrictions-plus-1.2.0.zip' - }, - { - title: 'Gameplay Modifiers Plus', - name: 'gameplay-modifiers-plus', - version: '1.9.2', - author: 'Kyle1413', - category: 'Gameplay Changes', - downloadUrl: 'https://bsaber.com/mods/gameplay-modifiers-plus-1.9.2.zip' - }, - { - title: 'Darth Maul Mod', - name: 'darthmaul', - version: '0.7.0', - author: 'PureDark', - category: 'Gameplay Changes', - downloadUrl: 'https://bsaber.com/mods/darthmaul-0.7.0.zip' - }, - { - title: 'Custom Sabers', - name: 'custom-saber', - version: '2.8.3', - author: 'Reaxt', - category: 'Cosmetic Changes', - downloadUrl: 'https://bsaber.com/mods/custom-saber-2.8.3.zip' - }, - { - title: 'Custom Colors', - name: 'custom-colors', - version: '1.11.3', - author: 'Kyle1413', - category: 'Cosmetic Changes', - downloadUrl: 'https://bsaber.com/mods/custom-colors-1.11.3.zip' - }, - { - title: 'BeatSaber IPA', - name: 'beatsaber-ipa-reloaded', - version: 'x.x.x', - author: '', - category: 'Core', - downloadUrl: 'https://github.com/nike4613/BeatSaber-IPA-Reloaded/releases' - }, - { - title: 'Newtonsoft JSON (dependency)', - name: 'newtonsoft-json', - version: '12.0.1', - author: '', - category: 'Libraries', - downloadUrl: 'https://bsaber.com/mods/newtonsoft-json-12.0.1.zip' - }, - { - title: 'Harmony (dependency)', - name: 'harmony', - version: '1.2.0', - author: '', - category: 'Libraries', - downloadUrl: 'https://bsaber.com/mods/harmony-1.2.0.zip' - }, - { - title: 'CustomUI (dependency)', - name: 'customui', - version: '1.4.0', - author: 'Various Modders', - category: 'Libraries', - downloadUrl: 'https://bsaber.com/mods/customui-1.4.0.zip' - }, - { - title: 'ini-parser (dependency)', - name: 'ini-parser', - version: '2.5.2', - author: '', - category: 'Libraries', - downloadUrl: 'https://bsaber.com/mods/ini-parser-2.5.2.zip ini-parser' - }, - { - title: 'BS-Utils (dependency)', - name: 'bs-utils', - version: '1.2.2', - author: 'Kyle1413', - category: 'Libraries', - downloadUrl: 'https://bsaber.com/mods/bs-utils-1.2.2.zip BS-Utils' - } -] \ No newline at end of file diff --git a/src/css/SettingsView.scss b/src/css/SettingsView.scss index fd7c9db..39b8a58 100644 --- a/src/css/SettingsView.scss +++ b/src/css/SettingsView.scss @@ -23,7 +23,12 @@ } } - #dl-location { + th { + font-weight: 400; + margin-bottom: 5px; + } + + #dl-location, #theme-image-path { display: none; margin-bottom: 20px; } diff --git a/src/css/Slate.scss b/src/css/Slate.scss index 462cf4d..8b95462 100644 --- a/src/css/Slate.scss +++ b/src/css/Slate.scss @@ -10,12 +10,9 @@ width: 100%; height: 100vh; overflow-y: scroll; - background: $theme-light-background-color; - background-size: 110%; -} - -#slate.theme-dark { - background: $theme-dark-background-color; + background-blend-mode: overlay; + background-size: cover; + background-position: center; } .theme-hc { diff --git a/src/css/SongListItem.scss b/src/css/SongListItem.scss index ff08a10..2cf86a7 100644 --- a/src/css/SongListItem.scss +++ b/src/css/SongListItem.scss @@ -49,6 +49,11 @@ white-space: nowrap; text-overflow: ellipsis; } + .upload-date { + font-size: 10pt; + margin-left: 5px; + opacity: 0.5; + } } .beatmap-details { diff --git a/src/css/SongScanningDialog.scss b/src/css/SongScanningDialog.scss index 07cab52..532fe5e 100644 --- a/src/css/SongScanningDialog.scss +++ b/src/css/SongScanningDialog.scss @@ -1,7 +1,7 @@ -#scanning-text { +.scanning-text { text-align: center; - &::before { + &:first-child::before { content: ""; display: block; position: relative; @@ -10,12 +10,17 @@ width: 100px; height: 100px; padding: 30px 0; + margin-top: -20px; background: url(../assets/update.png); background-repeat: no-repeat; transition: .5s; } } +h5.scanning-text { + margin: 10px 0; +} + #scanning-text.theme-dark, #scanning-text.theme-hc { &::before { background: url(../assets/dark/update.png); diff --git a/src/css/TitleBar.scss b/src/css/TitleBar.scss index 5e875db..850835d 100644 --- a/src/css/TitleBar.scss +++ b/src/css/TitleBar.scss @@ -22,7 +22,6 @@ #close-button, #resize-button, #minimize-button { width: 45px; height: 100%; - background: white; float: right; display: flex; flex-flow: row wrap; @@ -89,21 +88,9 @@ } &.theme-dark { - background: #252525; + background: rgba(0, 0, 0, 0.6); color: white; border-bottom: 1px solid #454545; - - #close-button { - background: #252525; - } - - #resize-button { - background: #252525; - } - - #minimize-button { - background: #252525; - } } &.theme-hc { @@ -125,14 +112,14 @@ #close-button { &:hover { - background: #e0021f; + background: #ff1938; transition: 0s; } } #resize-button, #minimize-button { &:hover { - background: silver; + background: rgba(128, 128, 128, 0.3); transition: 0s; } } diff --git a/src/reducers/modReducer.js b/src/reducers/modReducer.js index 23b5d28..4c2e7e6 100644 --- a/src/reducers/modReducer.js +++ b/src/reducers/modReducer.js @@ -1,4 +1,4 @@ -import { SET_MOD_LIST, APPEND_MOD_LIST, LOAD_MOD_DETAILS, INSTALL_MOD, UNINSTALL_MOD, CLEAR_MODS, SET_INSTALLED_MODS, SET_SCANNING_FOR_MODS, SET_MOD_ACTIVE, ADD_PENDING_MOD, ADD_DEPENDENT, SET_PATCHING } from '../actions/types' +import { SET_MOD_LIST, APPEND_MOD_LIST, LOAD_MOD_DETAILS, INSTALL_MOD, UNINSTALL_MOD, CLEAR_MODS, SET_INSTALLED_MODS, SET_SCANNING_FOR_MODS, SET_MOD_ACTIVE, ADD_PENDING_MOD, ADD_DEPENDENT, SET_PATCHING, REMOVE_DEPENDENT } from '../actions/types' const initialState = { mods: [], @@ -43,6 +43,10 @@ export default function(state = initialState, action) { let newDependentState = { ...state } newDependentState.installedMods[action.payload.index].dependencyOf.push(action.payload.dependent) return newDependentState + case REMOVE_DEPENDENT: + let removedDependantState = { ...state } + removedDependantState.installedMods[action.payload.index].dependencyOf.splice(removedDependantState.installedMods[action.payload.index].dependencyOf.findIndex(m => m.name === action.payload.dependant), 1) + return removedDependantState case UNINSTALL_MOD: let uninstalledState = { ...state } uninstalledState.installedMods.splice(action.payload, 1) diff --git a/src/reducers/settingsReducer.js b/src/reducers/settingsReducer.js index d243849..76c25eb 100644 --- a/src/reducers/settingsReducer.js +++ b/src/reducers/settingsReducer.js @@ -1,12 +1,14 @@ -import { SET_INSTALLATION_DIRECTORY, SET_AUTO_LOAD_MORE, SET_OFFLINE_MODE, SET_SETTINGS_OPEN, SET_THEME, SET_FOLDER_STRUCTURE, SET_UPDATE_CHANNEL, SET_LATEST_RELEASE_NOTES, SET_INSTALLATION_TYPE } from '../actions/types' +import { SET_INSTALLATION_DIRECTORY, SET_AUTO_LOAD_MORE, SET_OFFLINE_MODE, SET_SETTINGS_OPEN, SET_THEME, SET_THEME_IMAGE, SET_FOLDER_STRUCTURE, SET_UPDATE_CHANNEL, SET_LATEST_RELEASE_NOTES, SET_INSTALLATION_TYPE, SET_GAME_VERSION } from '../actions/types' const initialState = { isOpen: false, installationDirectory: "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Beat Saber", installationType: "choose", + gameVersion: "choose", autoLoadMore: true, offlineMode: false, theme: 'light', + themeImagePath: '', folderStructure: 'idKey', updateChannel: 'latest', latestReleaseNotes: '0.0.0' @@ -29,6 +31,11 @@ export default function(state = initialState, action) { ...state, installationType: action.payload } + case SET_GAME_VERSION: + return { + ...state, + gameVersion: action.payload + } case SET_AUTO_LOAD_MORE: return { ...state, @@ -44,6 +51,11 @@ export default function(state = initialState, action) { ...state, theme: action.payload } + case SET_THEME_IMAGE: + return { + ...state, + themeImagePath: action.payload + } case SET_FOLDER_STRUCTURE: return { ...state, diff --git a/src/reducers/songListReducer.js b/src/reducers/songListReducer.js index 3c22ec8..f1f3296 100644 --- a/src/reducers/songListReducer.js +++ b/src/reducers/songListReducer.js @@ -1,6 +1,18 @@ -import { FETCH_NEW, FETCH_TOP_DOWNLOADS, FETCH_TOP_FINISHED, LOAD_MORE, REFRESH, ADD_BSABER_RATING, FETCH_LOCAL_SONGS, SET_DOWNLOADED_SONGS, SET_SCROLLTOP, SET_DOWNLOADING_COUNT, SET_WAIT_LIST, SET_SCANNING_FOR_SONGS } from '../actions/types' +import { FETCH_NEW, FETCH_TOP_DOWNLOADS, FETCH_TOP_FINISHED, LOAD_MORE, REFRESH, ADD_BSABER_RATING, FETCH_LOCAL_SONGS, SET_DOWNLOADED_SONGS, SET_SCROLLTOP, SET_DOWNLOADING_COUNT, SET_WAIT_LIST, SET_SCANNING_FOR_SONGS, SET_DISCOVERED_FILES, SET_PROCESSED_FILES } from '../actions/types' -export default function(state = { songs: [], scrollTop: 0, downloadingCount: 0, waitingToDownload: [], downloadedSongs: [], scanningForSongs: false, totalSongs: 0 }, action) { +const initialState = { + songs: [], + scrollTop: 0, + downloadingCount: 0, + waitingToDownload: [], + downloadedSongs: [], + scanningForSongs: false, + discoveredFiles: 0, + processedFiles: 0, + totalSongs: 0 +} + +export default function(state = initialState, action) { switch(action.type) { case FETCH_NEW: case FETCH_TOP_DOWNLOADS: @@ -59,6 +71,16 @@ export default function(state = { songs: [], scrollTop: 0, downloadingCount: 0, ...state, scanningForSongs: action.payload } + case SET_DISCOVERED_FILES: + return { + ...state, + discoveredFiles: action.payload + } + case SET_PROCESSED_FILES: + return { + ...state, + processedFiles: action.payload + } default: return state }