Commit 88725d89 authored by SpinShare's avatar SpinShare

added userdetail and manual install and fixed download queue

parent 69b916f5
......@@ -1842,6 +1842,11 @@
"integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==",
"dev": true
},
"adm-zip": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz",
"integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g=="
},
"aggregate-error": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
......@@ -7030,12 +7035,6 @@
}
}
},
"http-parser-js": {
"version": "0.4.10",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
"integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=",
"dev": true
},
"http-proxy": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
......@@ -7289,12 +7288,6 @@
"loose-envify": "^1.0.0"
}
},
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
......@@ -7893,15 +7886,6 @@
"readable-stream": "^2.0.5"
}
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true,
"requires": {
"invert-kv": "^2.0.0"
}
},
"less": {
"version": "3.11.1",
"resolved": "https://registry.npmjs.org/less/-/less-3.11.1.tgz",
......@@ -8177,15 +8161,6 @@
"semver": "^5.6.0"
}
},
"map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"dev": true,
"requires": {
"p-defer": "^1.0.0"
}
},
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
......@@ -8230,25 +8205,6 @@
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true
},
"mem": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"dev": true,
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"p-is-promise": "^2.0.0"
},
"dependencies": {
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
}
}
},
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
......@@ -9054,17 +9010,6 @@
"integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
"dev": true
},
"os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true,
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
......@@ -9077,24 +9022,12 @@
"integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
"dev": true
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
"dev": true
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true
},
"p-is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
"dev": true
},
"p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
......@@ -11352,13 +11285,14 @@
}
},
"sockjs": {
"version": "0.3.19",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
"integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
"version": "0.3.20",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz",
"integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==",
"dev": true,
"requires": {
"faye-websocket": "^0.10.0",
"uuid": "^3.0.1"
"uuid": "^3.4.0",
"websocket-driver": "0.6.5"
}
},
"sockjs-client": {
......@@ -13315,9 +13249,9 @@
}
},
"webpack-dev-server": {
"version": "3.10.3",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz",
"integrity": "sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ==",
"version": "3.11.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz",
"integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==",
"dev": true,
"requires": {
"ansi-html": "0.0.7",
......@@ -13328,31 +13262,31 @@
"debug": "^4.1.1",
"del": "^4.1.1",
"express": "^4.17.1",
"html-entities": "^1.2.1",
"html-entities": "^1.3.1",
"http-proxy-middleware": "0.19.1",
"import-local": "^2.0.0",
"internal-ip": "^4.3.0",
"ip": "^1.1.5",
"is-absolute-url": "^3.0.3",
"killable": "^1.0.1",
"loglevel": "^1.6.6",
"loglevel": "^1.6.8",
"opn": "^5.5.0",
"p-retry": "^3.0.1",
"portfinder": "^1.0.25",
"portfinder": "^1.0.26",
"schema-utils": "^1.0.0",
"selfsigned": "^1.10.7",
"semver": "^6.3.0",
"serve-index": "^1.9.1",
"sockjs": "0.3.19",
"sockjs": "0.3.20",
"sockjs-client": "1.4.0",
"spdy": "^4.0.1",
"spdy": "^4.0.2",
"strip-ansi": "^3.0.1",
"supports-color": "^6.1.0",
"url": "^0.11.0",
"webpack-dev-middleware": "^3.7.2",
"webpack-log": "^2.0.0",
"ws": "^6.2.1",
"yargs": "12.0.5"
"yargs": "^13.3.2"
},
"dependencies": {
"ansi-regex": {
......@@ -13362,33 +13296,39 @@
"dev": true
},
"cliui": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true,
"requires": {
"string-width": "^2.1.1",
"strip-ansi": "^4.0.0",
"wrap-ansi": "^2.0.0"
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
"ansi-regex": "^4.1.0"
}
}
}
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
......@@ -13398,27 +13338,12 @@
"locate-path": "^3.0.0"
}
},
"get-caller-file": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
"dev": true
},
"is-absolute-url": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz",
"integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
......@@ -13453,11 +13378,27 @@
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"require-main-filename": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
"dev": true
"portfinder": {
"version": "1.0.26",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz",
"integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==",
"dev": true,
"requires": {
"async": "^2.6.2",
"debug": "^3.1.1",
"mkdirp": "^0.5.1"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
}
}
},
"schema-utils": {
"version": "1.0.0",
......@@ -13476,6 +13417,34 @@
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
}
}
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
......@@ -13495,52 +13464,55 @@
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true,
"requires": {
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1"
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
},
"dependencies": {
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
"ansi-regex": "^4.1.0"
}
}
}
},
"yargs": {
"version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
"integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
"version": "13.3.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
"dev": true,
"requires": {
"cliui": "^4.0.0",
"decamelize": "^1.2.0",
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^1.0.1",
"os-locale": "^3.0.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^3.2.1 || ^4.0.0",
"yargs-parser": "^11.1.1"
"y18n": "^4.0.0",
"yargs-parser": "^13.1.2"
}
},
"yargs-parser": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
......@@ -13587,13 +13559,11 @@
}
},
"websocket-driver": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
"integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
"integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=",
"dev": true,
"requires": {
"http-parser-js": ">=0.4.0 <0.4.11",
"safe-buffer": ">=5.1.0",
"websocket-extensions": ">=0.1.1"
}
},
......
......@@ -12,6 +12,7 @@
},
"main": "background.js",
"dependencies": {
"adm-zip": "^0.4.14",
"axios": "^0.19.2",
"core-js": "^3.6.4",
"electron-download-manager": "^2.1.2",
......
......@@ -12,7 +12,7 @@
</transition>
<transition name="slideDownloadOverlay">
<DownloadOverlay v-if="showDownloadOverlay" v-bind:downloadQueue="downloadQueue"></DownloadOverlay>
<DownloadOverlay v-if="showDownloadOverlay" v-bind:downloadQueue="downloadQueue" v-bind:finishedQueue="finishedQueue" v-bind:failedQueue="failedQueue"></DownloadOverlay>
</transition>
</div>
</template>
......@@ -24,7 +24,6 @@
import fs from 'fs';
import glob from 'glob';
import path from 'path';
import ncp from 'ncp';
import UserSettings from '@/modules/module.usersettings.js';
import SSAPI from '@/modules/module.api.js';
......@@ -46,6 +45,8 @@
data: function() {
return {
downloadQueue: [],
finishedQueue: [],
failedQueue: [],
downloadQueueProcessing: false,
showUpdateOverlay: false,
showDownloadOverlay: false,
......@@ -53,6 +54,10 @@
}
},
mounted: function() {
document.addEventListener('auxclick', function(e) {
e.preventDefault();
});
this.$root.$on('download', (url) => {
this.addToQueue(url);
});
......@@ -88,28 +93,62 @@
let srxdControl = new SRXD();
let userSettings = new UserSettings();
srxdControl.extractBackup(downloadItem.downloadPath, path.basename(downloadItem.downloadPath)).then((extractResult) => {
if(extractResult) {
this.installBackup(extractResult, userSettings.get('gameDirectory')).then((result) => {
let queueItem = this.$data.downloadQueue.findIndex(function(i) {
return i.id === downloadItem.id;
});
console.info("████ #" + queueItem + " - '" + this.$data.downloadQueue[queueItem].title + "' ████");
if(downloadItem.status == 1) {
// Failed, add to failed Array
this.$data.failedQueue.push(queueItem);
this.$data.downloadQueue.splice(queueItem, 1);
} else {
// Finished, unpacking
srxdControl.extractBackup(downloadItem.downloadPath, path.basename(downloadItem.downloadPath)).then((extractResult) => {
if(extractResult !== false) {
srxdControl.installBackup(extractResult, userSettings.get('gameDirectory')).then((result) => {
console.log("[COPY] Backup installed!");
this.$data.downloadQueueProcessing = false;
console.log("[QUEUE] Remaining Items: " + this.$data.downloadQueue.length);
this.$data.finishedQueue.push(queueItem);
this.$data.downloadQueue.splice(queueItem, 1);
if(this.$data.downloadQueue.length > 0) {
this.processQueue();
}
}).catch(error => {
console.error(error);
});
} else {
console.error("[COPY] Backup could not be installed!");
this.$data.downloadQueueProcessing = false;
console.log("Queue Remaining: " + this.$data.downloadQueue.length);
this.$data.downloadQueue.splice(this.$data.downloadQueue.findIndex(function(i) {
return i.id === downloadItem.id;
}), 1);
console.log("[QUEUE] Remaining Items: " + this.$data.downloadQueue.length);
this.$data.failedQueue.push(queueItem);
this.$data.downloadQueue.splice(queueItem, 1);
if(this.$data.downloadQueue.length > 0) {
this.processQueue();
}
}).catch(error => {
console.error(error);
});
} else {
console.error("Backup could not be loaded!");
}
}).catch(error => {
console.error(error);
});
}
}).catch(error => {
console.error(error);
this.$data.downloadQueueProcessing = false;
console.log("[QUEUE] Remaining Items: " + this.$data.downloadQueue.length);
this.$data.failedQueue.push(queueItem);
this.$data.downloadQueue.splice(queueItem, 1);
if(this.$data.downloadQueue.length > 0) {
this.processQueue();
}
});
}
});
},
methods: {
......@@ -133,19 +172,6 @@
closeOverlays: function() {
this.$data.showUpdateOverlay = false;
this.$data.showDownloadOverlay = false;
},
installBackup: async function(backupLocation, gameDirLocation) {
await ncp(backupLocation, gameDirLocation, function(error) {
if(error) {
console.error(error);
console.error("Couldn't copy backup!");
return true;
}
console.log("Copied Backup!");
});
return true;
}
}
}
......
......@@ -2,6 +2,10 @@ const { app, protocol, BrowserWindow, ipcMain } = require('electron');
const DownloadManager = require("electron-download-manager");
const { createProtocol } = require('vue-cli-plugin-electron-builder/lib');
const isDevelopment = process.env.NODE_ENV !== 'production';
const fs = require('fs');
const http = require('http');
const path = require('path');
const uniqid = require('uniqid');
let win;
let deeplinkingUrl;
......@@ -73,19 +77,43 @@ if (isDevelopment) {
}
ipcMain.on("download", (event, ipcData) => {
console.log("Download: " + ipcData.queueItem.title);
console.log("Starting download of > " + ipcData.queueItem.title);
DownloadManager.download({url: ipcData.queueItem.downloadPath}, (error, dlInfo) => {
download(ipcData.queueItem.downloadPath, uniqid(), (error, dlInfo) => {
if (error) {
console.log(error);
let downloadItem = {
id: ipcData.queueItem.id,
status: 1,
downloadPath: null
}
win.webContents.send("download-complete", downloadItem);
return;
}
let downloadItem = {
id: ipcData.queueItem.id,
downloadPath: dlInfo.filePath
status: 2,
downloadPath: dlInfo
}
win.webContents.send("download-complete", downloadItem);
});
});
\ No newline at end of file
});
function download(url, fileName, cb) {
let dest = path.join(app.getPath('temp'), fileName + ".zip");
let file = fs.createWriteStream(dest);
let request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb(null, dest)); // async call of the callback
});
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message, dest);
});
};
\ No newline at end of file
......@@ -11,9 +11,6 @@
</template>
<script>
import { remote } from 'electron';
const { clipboard } = remote;
export default {
name: 'SongInstallItem',
data: function() {
......@@ -23,7 +20,8 @@
mounted: function() {
},
methods: {
install: function(e) {
install: function() {
this.$parent.$parent.$emit('install');
}
}
}
......
<template>
<div class="song-item" v-on:contextmenu="showContextMenu($event)">
<div class="song-item" v-on:auxclick="shortDownload($event)" v-on:contextmenu="showContextMenu($event)">
<router-link :to="{ name: 'SongDetail', params: { id: id } }">
<div class="song-cover" :style="'background-image: url(' + cover + '), url(' + require('@/assets/img/defaultAlbumArt.jpg') + ');'">
<div class="song-charter-info">
<div class="song-charter"><i class="mdi mdi-account-circle"></i><span>{{ charter }}</span></div>
</div>
<div class="song-cover" :style="'background-image: url(' + cover + '), url(' + require('@/assets/img/defaultAlbumArt.jpg') + ');'">
<div class="song-charter-info">
<div class="song-charter"><i class="mdi mdi-account-circle"></i><span>{{ charter }}</span></div>
</div>
<div class="song-metadata">
<div class="song-title">{{ title }}</div>
<div class="song-artist">{{ artist }}</div>
<div class="song-difficulties">
<img src="@/assets/img/difficultyEasy.svg" :class="hasEasyDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyNormal.svg" :class="hasNormalDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyHard.svg" :class="hasHardDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyExtreme.svg" :class="hasExtremeDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyXD.svg" :class="hasXDDifficulty ? 'active' : ''" />
</div>
</div>
<div class="song-metadata">
<div class="song-title">{{ title }}</div>
<div class="song-artist">{{ artist }}</div>
<div class="song-difficulties">
<img src="@/assets/img/difficultyEasy.svg" :class="hasEasyDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyNormal.svg" :class="hasNormalDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyHard.svg" :class="hasHardDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyExtreme.svg" :class="hasExtremeDifficulty ? 'active' : ''" />
<img src="@/assets/img/difficultyXD.svg" :class="hasXDDifficulty ? 'active' : ''" />
</div>
</div>
</router-link>
</div>
</template>
......@@ -61,7 +61,16 @@
{ icon: "download", title: "Download", method: () => { this.download(); } }
]});
},
download: function() {
shortDownload: function(e) {
e.preventDefault();
if(e.which == 2) {
this.download(e);
}
},
download: function(e) {
e.preventDefault();
this.$root.$emit('download', {id: this.$props.id, cover: this.$props.cover, title: this.$props.title, artist: this.$props.artist, downloadPath: this.$props.zip});
}
}
......
......@@ -9,6 +9,8 @@
<div class="song-list">
<slot name="song-list"></slot>
</div>
<div class="noresults">
</div>
</div>
</template>
......
<template>
<div class="stream" v-if="isLive">
<div class="header">
<div class="viewers"><i class="mdi mdi-eye-outline"></i> {{ viewers }}</div>
<div class="title">{{ title }}</div>
</div>
<div class="video-container">
<iframe src="https://player.twitch.tv/?channel=spinshare&enableExtensions=true&muted=true&player=popout&volume=1"></iframe>
</div>
</div>
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
export default {
name: 'Stream',
props: [
'title',
'viewers',
'isLive'
]
}
</script>
<style scoped lang="less">
.stream {
margin-top: 50px;
& .header {
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 15px;
margin-bottom: 15px;
& .viewers {
background: #ff294d;
color: #fff;
padding: 5px;
font-size: 12px;
font-weight: bold;
border-radius: 20px;
}
& .title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
align-self: center;
}
}
& .video-container {
position: relative;
width: 100%;
padding-top: 50%;
& iframe {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
border: 0px;
}
}
}
</style>
<template>
<div class="user-item">
<router-link :to="{ name: 'UserDetail', params: { id: id } }" class="user-item">
<div class="user-avatar" :style="'background-image: url(' + avatar + '), url(' + require('@/assets/img/defaultAvatar.jpg') + ');'"></div>
<div class="user-metadata">
<div class="user-username">{{ username }}</div>
</div>
</div>
</router-link>
</template>
<script>
......@@ -51,6 +51,8 @@
display: grid;
padding: 10px;
grid-gap: 15px;
color: #fff;
text-decoration: none;
grid-template-columns: 32px 1fr;
& .user-avatar {
......
......@@ -26,6 +26,22 @@ class SSAPI {
});
}
async getStreamStatus() {
let apiPath = this.apiBase + "streamStatus";
let supportedVersion = this.supportedVersion;
return axios.get(apiPath)
.then(function(response) {
if(response.data.version !== supportedVersion) {
throw new Error("Client is outdated!");
}
return response.data.data;
}).catch(function(error) {
throw new Error(error);
});
}
async getLatestVersion() {
let apiPath = this.apiBase + "latestVersion/" + process.platform;
let supportedVersion = this.supportedVersion;
......
......@@ -3,6 +3,8 @@ const fs = require('fs');
const path = require('path');
const rimraf = require('rimraf');
const unzipper = require('unzipper');
const ncp = require('ncp');
const admzip = require('adm-zip');
const uniqid = require('uniqid');
const { app } = require('electron').remote;
const UserSettings = require('./module.usersettings');
......@@ -20,51 +22,42 @@ class SRXD {
// Extract a local backup folder
async extractBackup(filePath, fileName) {
if(this.backupLocation != "") {
console.log("Unload previous Backup.");
console.log("{EXTRACT] Unloading previous Backup.");
this.unloadBackup();
}
console.log("Extracting Backup.");
console.log("[EXTRACT] Starting Extraction.");
this.backupLocation = path.join(app.getPath('temp'), "extract-" + uniqid());
console.info(this.backupLocation);
console.info("[EXTRACT] Backup Location: " + this.backupLocation);
// Unzip to temp/CustomSpeens/Song
await fs.createReadStream(filePath).pipe(unzipper.Extract({ path: this.backupLocation })).promise();
// Find SRTB & OGG files
let srtbFilesInBackupLocation = this.getFilesFromPath(this.backupLocation, ".srtb");
if(srtbFilesInBackupLocation.length < 1) {
console.error("No SRTB file found in backup.");
try {
console.log("[EXTRACT] Unzipping.");
console.log("[EXTRACT] " + filePath);
console.log("[EXTRACT] " + this.backupLocation);
let zip = admzip(filePath);
await zip.extractAllTo(this.backupLocation, true);
} catch(e) {
console.log("[EXTRACT] Couldn't unzip backup");
console.error(e);
return false;
}
// Load SRTB file
this.srtbLocation = path.join(this.backupLocation, srtbFilesInBackupLocation[0]);
let srtbFile = JSON.parse( fs.readFileSync(this.srtbLocation) );
let songTrackInfo = "";
srtbFile.largeStringValuesContainer.values.forEach(function(value) {
if(value.key == "SO_TrackInfo_TrackInfo") {
songTrackInfo = value.val;
return this.backupLocation;
}
async installBackup(backupLocation, gameDirLocation) {
await ncp(backupLocation, gameDirLocation, function(error) {
if(error) {
console.error(error);
console.error("[COPY] Couldn't copy backup!");
return false;
}
console.info("[COPY] Done!");
return true;
});
this.songTrackInfo = songTrackInfo;
// Load OGG file
let OggFilePath = fs.existsSync(path.join(this.backupLocation, "AudioClips"), ".ogg")
if (fs.existsSync(OggFilePath)) {
let oggFilesInBackupLocation = this.getFilesFromPath(OggFilePath);
this.songLocation = path.join(this.backupLocation, oggFilesInBackupLocation[0]);
// TODO: Backup Validation
return this.backupLocation;
}
else{
return this.backupLocation;
}
}
async unloadBackup() {
......@@ -123,7 +116,11 @@ class SRXD {
if(fileExtension.length > 0) {
let finalPath = path.join(this.userSettings.get('gameDirectory'), "AlbumArt", fileExtension[0]);
let base64Data = "data:image/jpg;base64," + fs.readFileSync(finalPath, { encoding: 'base64' });
try {
let base64Data = "data:image/jpg;base64," + fs.readFileSync(finalPath, { encoding: 'base64' });
} catch(e) {
return "";
}
return base64Data;
} else {
......
......@@ -10,6 +10,7 @@ import ViewStartupPopularSongs from '../views/StartupPopularSongs.vue';
import ViewSearch from '../views/Search.vue';
import ViewLibrary from '../views/Library.vue';
import ViewSongDetail from '../views/SongDetail.vue';
import ViewUserDetail from '../views/UserDetail.vue';
import ViewSettings from '../views/Settings.vue';
Vue.use(VueRouter);
......@@ -53,6 +54,10 @@ const routes = [{
path: '/song/:id',
name: 'SongDetail',
component: ViewSongDetail
},, {
path: '/user/:id',
name: 'UserDetail',
component: ViewUserDetail
}, {
path: '/settings',
name: 'Settings',
......
......@@ -20,6 +20,9 @@
</template>
<script>
import { remote } from 'electron';
const { dialog } = remote;
import fs from 'fs';
import glob from 'glob';
import path from 'path';
......@@ -66,6 +69,9 @@
this.$data.showDeleteOverlay = false;
this.$data.deleteFiles = "";
});
this.$on('install', () => {
this.install();
});
},
methods: {
refreshLibrary: function() {
......@@ -149,6 +155,35 @@
});
return connectedFiles;
},
install: function(e) {
dialog.showOpenDialog({ title: "Open Backup", properties: ['openFile', 'multiSelections'], filters: [{"name": "Backup Archive", "extensions": ["zip"]}] }).then(result => {
if(!result.canceled) {
result.filePaths.forEach((rawFilePath) => {
let filePath = glob.sync(rawFilePath);
if(filePath.length > 0) {
let srxdControl = new SRXD();
let userSettings = new UserSettings();
srxdControl.extractBackup(filePath[0], path.basename(filePath[0])).then((extractResult) => {
if(extractResult !== false) {
srxdControl.installBackup(extractResult, userSettings.get('gameDirectory')).then((result) => {
console.log("[COPY] Backup installed!");
setTimeout(() => {
this.refreshLibrary();
}, 250);
}).catch(error => {
console.error(error);
});
} else {
console.error("[COPY] Backup could not be installed!");
}
}).catch(error => {
console.error(error);
});
}
});
}
});
}
}
}
......
<template>
<div class="staff-promos">
<StaffPromoPlaceholder
v-if="isPromoLoading"
v-for="n in 2"
v-bind:key="n" />
<StaffPromo
v-if="!isPromoLoading"
v-for="staffPromo in staffPromos"
v-bind:key="staffPromo.id"
v-bind="staffPromo" />
<div class="frontpage">
<div class="staff-promos">
<StaffPromoPlaceholder
v-if="isPromoLoading"
v-for="n in 2"
v-bind:key="n" />
<StaffPromo
v-if="!isPromoLoading"
v-for="staffPromo in staffPromos"
v-bind:key="staffPromo.id"
v-bind="staffPromo" />
</div>
<Stream v-bind="streamStatus" />
</div>
</template>
......@@ -16,13 +20,15 @@
import SSAPI from '@/modules/module.api.js';
import StaffPromo from '@/components/Startup/StaffPromo.vue';
import StaffPromoPlaceholder from '@/components/Startup/StaffPromoPlaceholder.vue';
import Stream from '@/components/Startup/Stream.vue';
export default {
name: 'StartupFrontpage',
data: function() {
return {
isPromoLoading: true,
staffPromos: []
staffPromos: [],
streamStatus: []
}
},
mounted: function() {
......@@ -32,10 +38,15 @@
this.$data.isPromoLoading = false;
this.$data.staffPromos = data;
});
ssapi.getStreamStatus().then((data) => {
this.$data.streamStatus = data;
});
},
components: {
StaffPromo,
StaffPromoPlaceholder
StaffPromoPlaceholder,
Stream
},
methods: {
}
......
<template>
<section class="section-user-detail">
<div class="user-detail-background" :style="'background-image: url(' + avatar + '), url(' + require('@/assets/img/defaultAvatar.jpg') + ');'" v-if="apiFinished">
<div class="user-detail-dim">
<div class="user-detail">
<div class="user-avatar" :style="'background-image: url(' + avatar + '), url(' + require('@/assets/img/defaultAvatar.jpg') + ');'"></div>
<div class="user-meta-data">
<div class="user-name">{{ username }}</div>
<div class="user-badge user-badge-verified">
<i class="mdi mdi-check-decagram"></i>
</div>
<div class="user-badge user-badge-patreon">
<i class="mdi mdi-patreon"></i>
</div>
</div>
</div>
</div>
</div>
<div class="user-detail-actions" v-if="apiFinished">
<button class="button-report button" v-on:click="OpenReport">{{ $t('userdetail.actions.reportButton') }}</button>
</div>
<SongRow
class="song-row-user"
:title="$t('userdetail.uploaded.header')"
v-if="apiFinished && songs.length > 0">
<template v-slot:song-list>
<SongItem
v-for="song in songs"
v-bind:key="song.id"
v-bind="song" />
</template>
</SongRow>
<Loading v-if="!apiFinished" />
</section>
</template>
<script>
import { remote } from 'electron';
const { clipboard, shell } = remote;
import SSAPI from '@/modules/module.api.js';
import SongRow from '@/components/Song/SongRow.vue';
import SongItem from '@/components/Song/SongItem.vue';
import Loading from '@/components/Loading.vue';
export default {
name: 'UserDetail',
components: {
SongRow,
SongItem,
Loading
},
data: function() {
return {
apiFinished: false,
id: 0,
username: "",
isVerified: false,
isPatreon: false,
avatar: "",
songs: []
}
},
mounted: function() {
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
ssapi.getUserDetail(this.$route.params.id).then((data) => {
this.$data.id = data.data.id;
this.$data.username = data.data.username;
this.$data.isVerified = data.data.isVerified;
this.$data.isPatreon = data.data.isPatreon;
this.$data.avatar = data.data.avatar;
this.$data.songs = data.data.songs;
this.$data.apiFinished = true;
});
},
methods: {
OpenReport: function() {
shell.openExternal("https://spinsha.re/report/user/" + this.$data.id);
}
}
}
</script>
<style scoped lang="less">
.section-user-detail {
& .user-detail-background {
background-size: cover;
background-position: center;
& .user-detail-dim {
backdrop-filter: blur(10px);
background: linear-gradient(180deg, rgba(0,0,0,0.4), #212629);
& .user-detail {
padding: 50px;
display: grid;
grid-template-columns: 200px 1fr;
grid-gap: 25px;
& .user-avatar {
width: 200px;
height: 200px;
align-self: center;
background: #eee;
border-radius: 50%;
background-size: cover;
background-position: center;
}
& .user-meta-data {
display: flex;
height: 48px;
align-items: center;
& .user-name {
font-weight: bold;
font-size: 48px;
}
& .user-badge {
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
margin-left: 20px;
}
}
}
}
}
& .user-detail-actions {
padding: 50px;
padding-top: 0px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 25px;
& .button {
padding: 15px 0px;
font-size: 16px;
transition: 0.2s ease-in-out all, 0.1s ease-in-out transform;
&.button-primary {
background: #fff;
color: #222;
&:hover {
background: #fff;
color: #222;
}
}
&:hover {
background: rgba(255,255,255,0.2);
color: #fff;
opacity: 0.6;
transform: translateY(-4px);
}
&:active {
transform: translateY(-2px);
}
}
}
& .song-row-user {
display: grid;
padding: 50px;
}
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment