Commit ae49df63 authored by Amy Yan's avatar Amy Yan

Merge remote-tracking branch 'origin/vue-rewrite' into vue-rewrite-download-progree

parents 76cf1416 b4094f92
const fs = require('fs');
const glob = require('glob');
const path = require('path');
const chalk = require('chalk');
const chalkTable = require('chalk-table');
const localeBaseRaw = fs.readFileSync(path.join(__dirname, '/src/i18n/en.json'), 'utf8');
const localeBase = JSON.parse(localeBaseRaw);
console.clear();
console.log('---- LOCALE CHECK ----');
console.log('');
let results = [];
const allLocales = glob.sync(path.join(__dirname, '/src/i18n', '*.json'));
allLocales.forEach((locale) => {
if(!locale.includes("en.json")) {
let rawLocale = locale.split("/")[locale.split("/").length - 1];
let localeNewRaw = fs.readFileSync(locale, 'utf8');
let localeNew = JSON.parse(localeNewRaw);
let newKeys = 0;
let removedKeys = 0;
// Find missing keys
for (let [key, value] of Object.entries(localeBase)) {
if (!localeNew.hasOwnProperty(key)) {
newKeys++;
}
}
// Find removed keys
for (let [key, value] of Object.entries(localeNew)) {
if (!localeBase.hasOwnProperty(key)) {
removedKeys++;
}
}
results.push({
locale: rawLocale,
missing: newKeys + " keys",
removed: removedKeys + " keys",
ready: ((newKeys == 0 && removedKeys == 0) ? chalk.green("READY") : chalk.red("NOT READY"))
});
}
});
let tableOptions = {
leftPad: 2,
columns: [
{ field: "locale", name: chalk.cyan("Locale")},
{ field: "missing", name: chalk.cyan("Missing")},
{ field: "removed", name: chalk.cyan("Removed")},
{ field: "ready", name: chalk.white("Ready to ship?")},
]
}
console.log(chalkTable(tableOptions, results));
console.log('');
console.log('---------------------');
\ No newline at end of file
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const languageToCompare = process.argv[2];
// Load reference (en) and target locale
const localeBaseRaw = fs.readFileSync(path.join(__dirname, '/src/i18n/en.json'), 'utf8');
const localeNewRaw = fs.readFileSync(path.join(__dirname, '/src/i18n', languageToCompare + '.json'), 'utf8');
const localeBase = JSON.parse(localeBaseRaw);
const localeNew = JSON.parse(localeNewRaw);
console.clear();
console.log('---- LOCALE DIFF ----');
console.log('');
let newKeys = 0;
let removedKeys = 0;
// Find missing keys
for (let [key, value] of Object.entries(localeBase)) {
if (!localeNew.hasOwnProperty(key)) {
console.log('[' + languageToCompare + '][' + chalk.red('MISSING') + '] "' + key + '": "' + value + '"');
newKeys++;
}
}
// Find removed keys
for (let [key, value] of Object.entries(localeNew)) {
if (!localeBase.hasOwnProperty(key)) {
console.log('[en][' + chalk.blue('REMOVED') + '] "' + key + '": "' + value + '"');
removedKeys++;
}
}
console.log('');
console.log('------ RESULTS ------');
console.log('');
if (newKeys > 0 || removedKeys > 0) {
console.log(
chalk.white('There are ') +
chalk.red(newKeys + ' keys') +
chalk.white(' missing in ') +
chalk.green(languageToCompare) +
chalk.white(' and ') +
chalk.blue(removedKeys + ' keys') +
chalk.white(' which are not present in en anymore.')
)
} else {
console.log(
chalk.green('Language ') +
chalk.white(languageToCompare) +
chalk.green(' is up to date with ') + chalk.white('en')
);
}
console.log('');
console.log('---------------------');
\ No newline at end of file
......@@ -312,6 +312,28 @@
"@babel/helper-validator-identifier": "^7.9.0",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"@babel/parser": {
......@@ -1560,11 +1582,31 @@
"strip-ansi": "^6.0.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
......@@ -2270,6 +2312,28 @@
"num2fraction": "^1.2.2",
"postcss": "^7.0.27",
"postcss-value-parser": "^4.0.3"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"aws-sign2": {
......@@ -2592,6 +2656,17 @@
"widest-line": "^2.0.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
......@@ -2618,6 +2693,15 @@
"ansi-regex": "^4.1.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"type-fest": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz",
......@@ -2837,6 +2921,17 @@
"temp-file": "^3.3.4"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
......@@ -2847,6 +2942,15 @@
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
......@@ -3155,6 +3259,53 @@
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
},
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"dev": true,
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
}
}
},
"chalk-table": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/chalk-table/-/chalk-table-1.0.2.tgz",
"integrity": "sha512-lmtmQtr/GCtbiJiiuXPE5lj0arIXJir5hSjIhye/4Uyr7oTQlP+ufPnHzUS3Bre0xS/VWbz9NfeuPnvse9BXoQ==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"strip-ansi": "^5.2.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
......@@ -3166,6 +3317,26 @@
"supports-color": "^5.3.0"
}
},
"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"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
......@@ -3447,6 +3618,28 @@
"@types/q": "^1.5.1",
"chalk": "^2.4.1",
"q": "^1.1.2"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"code-point-at": {
......@@ -4831,6 +5024,17 @@
"yargs": "^13.3.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
......@@ -4922,6 +5126,15 @@
"ansi-regex": "^4.1.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
......@@ -5027,6 +5240,17 @@
"mime": "^2.4.4"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
......@@ -5037,6 +5261,15 @@
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
......@@ -7021,6 +7254,7 @@
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
......@@ -7181,6 +7415,17 @@
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
......@@ -7189,6 +7434,15 @@
"requires": {
"ansi-regex": "^3.0.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
......@@ -7796,6 +8050,28 @@
"requires": {
"chalk": "^2.3.0",
"shell-quote": "^1.6.1"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"launch-editor-middleware": {
......@@ -8034,6 +8310,28 @@
"dev": true,
"requires": {
"chalk": "^2.0.1"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"loglevel": {
......@@ -8457,7 +8755,8 @@
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"multicast-dns": {
"version": "6.2.3",
......@@ -8523,26 +8822,6 @@
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M="
},
"needle": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz",
"integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==",
"requires": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
......@@ -8941,6 +9220,17 @@
"wcwidth": "^1.0.1"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
......@@ -8949,6 +9239,15 @@
"requires": {
"ansi-regex": "^4.1.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
......@@ -9353,6 +9652,28 @@
"supports-color": "^6.1.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
......@@ -10780,7 +11101,8 @@
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"sanitize-filename": {
"version": "1.6.3",
......@@ -10794,7 +11116,8 @@
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
"schema-utils": {
"version": "2.6.5",
......@@ -11787,12 +12110,20 @@
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
"has-flag": "^4.0.0"
},
"dependencies": {
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
}
}
},
"svg-tags": {
......@@ -11820,6 +12151,28 @@
"stable": "^0.1.8",
"unquote": "~1.1.1",
"util.promisify": "~1.0.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"tapable": {
......@@ -12446,6 +12799,28 @@
"latest-version": "^5.0.0",
"semver-diff": "^2.0.0",
"xdg-basedir": "^3.0.0"
},
"dependencies": {
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"upper-case": {
......@@ -13154,6 +13529,26 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
"integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==",
"dev": true
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
......
......@@ -10,6 +10,8 @@
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"locale:check": "node localeCheck.js",
"locale:diff": "node localeDiff.js",
"electron:build": "vue-cli-service electron:build",
"electron:serve": "vue-cli-service electron:serve",
"postinstall": "electron-builder install-app-deps",
......@@ -23,7 +25,6 @@
"glob": "^7.1.6",
"moment": "^2.26.0",
"ncp": "^2.0.0",
"needle": "^2.5.0",
"rimraf": "^3.0.2",
"uniqid": "^5.2.0",
"vue": "^2.6.11",
......@@ -40,6 +41,8 @@
"electron": "^6.0.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"chalk": "^4.1.0",
"chalk-table": "^1.0.2",
"vue-cli-plugin-electron-builder": "~1.4.6",
"vue-template-compiler": "^2.6.11"
}
......
......@@ -8,7 +8,7 @@
<title>SpinSha.re</title>
<!-- Styles -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap" />
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&family=Oswald:wght@500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.materialdesignicons.com/5.0.45/css/materialdesignicons.min.css" />
</head>
<body>
......
......@@ -231,27 +231,24 @@
min-height: 100vh;
overflow-y: scroll;
}
section {
&.section-library {
padding: 50px;
}
}
button, .button {
font-family: 'Open Sans', sans-serif;
font-size: 12px;
text-decoration: none;
border: 0px;
color: #fff;
background: rgba(255,255,255,0.2);
text-transform: uppercase;
font-weight: 700;
font-size: 12px;
font-weight: bold;
letter-spacing: 0.1em;
background: linear-gradient(135deg, rgba(255,255,255,0.3), rgba(255,255,255,0.1));
padding: 10px 20px;
border-radius: 4px;
padding: 7px 14px;
border: 0px;
text-transform: uppercase;
transition: 0.2s ease-in-out all;
cursor: pointer;
&:hover {
background: #fff;
color: #222;
cursor: pointer;
opacity: 0.6;
}
&:focus {
outline: 0;
......
src/assets/img/defaultAvatar.jpg

51.5 KB | W: | H:

src/assets/img/defaultAvatar.jpg

169 KB | W: | H:

src/assets/img/defaultAvatar.jpg
src/assets/img/defaultAvatar.jpg
src/assets/img/defaultAvatar.jpg
src/assets/img/defaultAvatar.jpg
  • 2-up
  • Swipe
  • Onion skin
......@@ -2,6 +2,7 @@ const { app, protocol, BrowserWindow, ipcMain, dialog } = require('electron');
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 https = require('https');
const path = require('path');
const uniqid = require('uniqid');
......@@ -160,6 +161,27 @@ ipcMain.on("getDeeplink", (event) => {
function download(url, fileName, cb) {
let dest = path.join(app.getPath('temp'), fileName + ".zip");
let file = fs.createWriteStream(dest);
if(new URL(url).protocol == "https:") {
let request = https.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);
});
} else {
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);
});
}
let request = https.get(url, function(response) {
......
<template>
<div class="collapsableText">
<div :class="isCollapsed ? 'text collapsed' : 'text'" ref="text" v-html="nl2br(text)"></div>
<div class="toggleButton" v-on:click="Toggle()" v-if="canCollapse && isCollapsed">{{ $t('songdetail.showmore') }}</div>
<div class="toggleButton" v-on:click="Toggle()" v-if="canCollapse && !isCollapsed">{{ $t('songdetail.showless') }}</div>
</div>
</template>
<script>
export default {
name: 'CollapsableText',
props: [
'text'
],
data: function() {
return {
isCollapsed: false,
canCollapse: false
}
},
mounted: function() {
if(this.$refs.text.clientHeight > 84) {
this.$data.isCollapsed = true;
this.$data.canCollapse = true;
} else {
this.$data.isCollapsed = false;
this.$data.canCollapse = false;
}
},
methods: {
nl2br: function(text) {
return text.replace(/(?:\r\n|\r|\n)/g, '<br />');
},
Toggle: function() {
this.$data.isCollapsed = !this.$data.isCollapsed;
}
}
}
</script>
<style scoped lang="less">
& .collapsableText {
& .text {
line-height: 1.5em;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
transition: 1s ease max-height;
&.collapsed {
max-height: 6em;
}
}
& .toggleButton {
margin-top: 10px;
text-transform: uppercase;
font-weight: bold;
color: #f74e94;
cursor: pointer;
transition: 0.2s ease opacity;
&:hover {
opacity: 0.6;
}
}
}
</style>
......@@ -2,7 +2,7 @@
<div class="download-overlay">
<header>
<div class="title">
Download Queue
{{ $t('download.queue.header') }}
</div>
<div class="icon" v-on:click="close()">
<i class="mdi mdi-close"></i>
......
<template>
<div class="play-overlay">
<div class="play-content">
<div class="play-main">
<div class="play-title">{{ $t('songdetail.playmodal.title') }}</div>
<div class="play-difficulties">
<div :class="hasEasyDifficulty ? 'button active' : 'button'" v-on="hasEasyDifficulty ? { click: () => play(0) } : {}">
<img src="@/assets/img/difficultyEasy.svg" :class="hasEasyDifficulty ? 'active' : ''" />
</div>
<div :class="hasNormalDifficulty ? 'button active' : 'button'" v-on="hasNormalDifficulty ? { click: () => play(1) } : {}">
<img src="@/assets/img/difficultyNormal.svg" :class="hasNormalDifficulty ? 'active' : ''" />
</div>
<div :class="hasHardDifficulty ? 'button active' : 'button'" v-on="hasHardDifficulty ? { click: () => play(2) } : {}">
<img src="@/assets/img/difficultyHard.svg" :class="hasHardDifficulty ? 'active' : ''" />
</div>
<div :class="hasExpertDifficulty ? 'button active' : 'button'" v-on="hasExpertDifficulty ? { click: () => play(3) } : {}">
<img src="@/assets/img/difficultyExtreme.svg" :class="hasExpertDifficulty ? 'active' : ''" />
</div>
<div :class="hasXDDifficulty ? 'button active' : 'button'" v-on="hasXDDifficulty ? { click: () => play(4) } : {}">
<img src="@/assets/img/difficultyXD.svg" :class="hasXDDifficulty ? 'active' : ''" />
</div>
</div>
</div>
<div class="play-actions">
<div class="button" v-on:click="close()">{{ $t('songdetail.playmodal.actions.close') }}</div>
</div>
</div>
</div>
</template>
<script>
import { remote } from 'electron';
const { shell } = remote;
export default {
name: 'PlayOverlay',
props: [
'fileReference',
'hasEasyDifficulty',
'hasNormalDifficulty',
'hasHardDifficulty',
'hasExpertDifficulty',
'hasXDDifficulty'
],
methods: {
play: function(difficulty) {
shell.openExternal('steam://run/1058830//play "' + this.$props.fileReference + '.srtb" difficulty ' + difficulty);
this.close();
},
close: function() {
this.$parent.$emit('closePlayOverlay');
}
}
}
</script>
<style scoped lang="less">
.play-overlay {
position: fixed;
z-index: 100;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
background: rgba(0,0,0,0.75);
display: flex;
justify-content: center;
align-items: center;
& .play-content {
width: 700px;
background: #212629;
border-radius: 6px;
position: relative;
overflow: hidden;
& .play-main {
padding: 25px;
& .play-title {
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
}
& .play-difficulties {
margin-top: 15px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-gap: 15px;
grid-auto-flow: column;
& .button {
opacity: 0.4;
cursor: default;
display: flex;
justify-content: center;
align-items: center;
&.active {
opacity: 1;
cursor: pointer;
&:hover {
opacity: 0.6;
}
}
& img {
width: 48px;
padding: 20px 0px;
}
}
}
}
& .play-actions {
display: flex;
justify-content: flex-end;
padding: 25px;
background: rgba(0,0,0,0.4);
& button {
margin-left: 10px;
}
}
}
}
</style>
<template>
<div class="song-item" v-on:click="install()">
<div class="song-cover">
<div class="song-icon"><i class="mdi mdi-folder-music"></i></div>
</div>
<div class="song-metadata">
<div class="song-title">{{ $t('library.installed.install.title') }}</div>
<div class="song-artist">{{ $t('library.installed.install.text') }}</div>
</div>
</div>
</template>
<script>
export default {
name: 'SongInstallItem',
data: function() {
return {
}
},
mounted: function() {
},
methods: {
install: function() {
this.$parent.$parent.$emit('install');
}
}
}
</script>
<style scoped lang="less">
.song-item {
background: rgba(255,255,255,0.1);
transition: 0.2s ease-in-out transform, 0.2s ease-in-out box-shadow;
overflow: hidden;
border-radius: 6px;
& .song-cover {
background: rgba(255,255,255,0.1);
background-size: cover;
width: 100%;
padding-top: 100%;
position: relative;
background-position: center;
& .song-icon {
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
display: flex;
justify-content: center;
align-items: center;
font-size: 32px;
}
}
& .song-metadata {
padding: 15px;
& .song-title {
font-weight: bold;
overflow: hidden;
white-space: nowrap;
}
& .song-artist {
margin-top: 5px;
opacity: 0.6;
overflow: hidden;
white-space: nowrap;
}
& .song-difficulties {
margin-top: 10px;
height: 20px;
display: flex;
& img {
height: 18px;
margin-right: 10px;
opacity: 0.3;
&.active {
opacity: 1;
}
}
}
}
&:hover {
transform: scale(1.1);
cursor: pointer;
box-shadow: 0px 4px 20px 5px rgba(0, 0, 0, 0.4);
& .song-cover {
& .song-charter {
opacity: 1;
}
}
}
}
</style>
......@@ -58,9 +58,9 @@
x: e.pageX,
y: e.pageY,
items: [
{ icon: "eye", title: "Open", method: () => { this.$router.push({ name: 'SongDetail', params: { id: this.$props.id } }) } },
{ icon: "link", title: "Copy Link", method: () => { clipboard.writeText('https://spinsha.re/song/' + this.$props.id) } },
{ icon: "download", title: "Download", method: () => { this.download(); } }
{ icon: "eye", title: this.$t('contextmenu.open'), method: () => { this.$router.push({ name: 'SongDetail', params: { id: this.$props.id } }) } },
{ icon: "link", title: this.$t('contextmenu.copyLink'), method: () => { clipboard.writeText('https://spinsha.re/song/' + this.$props.id) } },
{ icon: "download", title: this.$t('contextmenu.download'), method: () => { this.download(); } }
]});
},
shortDownload: function(e) {
......
<template>
<div :class="'song-item-local ' + (isSpinShare ? '' : 'song-item-onlylocal')" v-on:contextmenu="showContextMenu($event)">
<div :class="'song-item-local ' + (isSpinShare ? '' : 'song-item-onlylocal')" v-on:contextmenu="showContextMenu($event)" v-on:click="openOnSpinShare()">
<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>{{ detail.charter ? detail.charter : "Unknown" }}</span></div>
......@@ -14,7 +14,8 @@
<script>
import { remote } from 'electron';
const { clipboard } = remote;
import path from 'path';
const { clipboard, shell } = remote;
export default {
name: 'SongLocalItem',
......@@ -34,12 +35,28 @@
},
methods: {
showContextMenu: function(e) {
let items = [];
if(this.isSpinShare) {
items.push({ icon: "open-in-app", title: this.$t('contextmenu.openOnSpinShare'), method: () => { this.openOnSpinShare(); } });
}
items.push({ icon: "folder-outline", title: this.$t('contextmenu.openInExplorer'), method: () => { this.openInExplorer(); } });
items.push({ icon: "delete", title: this.$t('contextmenu.delete'), method: () => { this.$parent.$parent.$emit('delete', this.$props.file); } });
this.$root.$emit('showContextMenu', {
x: e.pageX,
y: e.pageY,
items: [
{ icon: "delete", title: "Delete", method: () => { this.$parent.$parent.$emit('delete', this.$props.file); } }
]});
items: items
});
},
openOnSpinShare: function() {
if(this.isSpinShare.includes("spinshare_")) {
this.$router.push({ name: 'SongDetail', params: { id: this.isSpinShare } });
}
},
openInExplorer: function() {
shell.showItemInFolder(path.normalize(this.file));
}
}
}
......
......@@ -12,9 +12,7 @@
<div class="actions">
</div>
</div>
<div class="comment" v-if="comment">
{{ comment }}
</div>
<CollapsableText v-bind:text="comment" v-if="comment" />
</div>
</template>
......@@ -22,8 +20,13 @@
import { remote } from 'electron';
const { clipboard } = remote;
import CollapsableText from '@/components/CollapsableText.vue';
export default {
name: 'SongReview',
components: {
CollapsableText
},
props: [
'id',
'user',
......@@ -43,6 +46,9 @@
background: rgba(255,255,255,0.1);
border-radius: 4px;
padding: 20px;
overflow: hidden;
word-wrap: break-word;
word-break: break-all;
& .metadata {
display: grid;
......@@ -110,10 +116,8 @@
}
}
}
& .comment {
& .collapsableText {
margin-top: 15px;
line-height: 1.5em;
}
}
</style>
<template>
<div class="song-row song-row-new">
<div class="song-header">
<div class="song-header" v-if="title">
<div :class="'row-title ' + (noactions ? 'row-title-noactions' : '')">{{ title }}</div>
<div class="row-controls" v-if="!noactions">
<slot name="controls"></slot>
......
......@@ -2,7 +2,7 @@
<div :style="'background-image: url(' + image_path + ');'" :class="isLoading ? 'staff-promo promo-loading' : 'staff-promo' ">
<div class="promo-type" :style="'color:' + color">{{ type }}</div>
<div class="promo-title" :style="'color:' + textColor" v-html="title"></div>
<div class="promo-button" :style="'background-color:' + color" v-on:click="buttonClick()">CHECK IT OUT</div>
<div class="promo-button" :style="'background-color:' + color" v-on:click="buttonClick()">{{ $t('startup.staffpromo.action') }}</div>
</div>
</template>
......@@ -14,19 +14,27 @@
name: 'StaffPromo',
methods: {
buttonClick: function() {
switch(this.$props.buttonType) {
console.log(this.$props.button.type);
console.log(this.$props.button.data);
switch(this.$props.button.type) {
case 0:
// Song
this.$router.push({ name: 'SongDetail', params: { id: this.$props.button.data } });
break;
case 1:
// Playlist (unused)
break;
case 2:
// Search Query
this.$router.push({ name: 'Search', params: { searchQuery: this.$props.button.data } });
break;
case 3:
// External
shell.openExternal(this.$props.buttonData);
shell.openExternal(this.$props.button.data);
break;
case 4:
// User
this.$router.push({ name: 'UserDetail', params: { id: this.$props.button.data } });
break;
}
}
......@@ -36,8 +44,7 @@
'image_path',
'type',
'title',
'buttonType',
'buttonData',
'button',
'textColor',
'color'
]
......
......@@ -3,6 +3,8 @@
<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 class="user-badge" v-if="patreon"><i class="mdi mdi-patreon"></i></div>
<div class="user-badge" v-if="isVerified"><i class="mdi mdi-check-decagram"></i></div>
</div>
</router-link>
</template>
......@@ -20,24 +22,9 @@
'isPatreon',
'isVerified'
],
data: function() {
return {
isContextMenuActive: false
}
},
mounted: function() {
},
methods: {
showContextMenu: function(e) {
this.$root.$emit('showContextMenu', {
x: e.pageX,
y: e.pageY,
items: [
{ icon: "eye", title: "Open", method: function() { alert('TODO') }.bind(this) },
{ icon: "link", title: "Copy Link", method: function() { clipboard.writeText('https://spinsha.re/song/' + this.$props.id) }.bind(this) },
{ icon: "download", title: "Download", method: function() { this.$root.$emit('download', this.$props.isVerified); }.bind(this) }
]});
}
}
}
</script>
......
......@@ -2,6 +2,7 @@
"locale.translatedBy": "Übersetzung von thatanimeweirdo",
"locale.dateFormat": "DD.MM.YYYY",
"startup.staffpromo.action": "CHECK ES AUS",
"startup.tabs.frontpage": "Startseite",
"startup.tabs.new": "Neu",
"startup.tabs.hot": "Heiß",
......@@ -10,16 +11,22 @@
"startup.hotsongs.header": "Heiße Songs",
"startup.popularsongs.header": "Populäre Songs",
"search.header": "Suche",
"search.input.placeholder": "Suche nach Songs, Tags & Profilen...",
"search.results.users.header": "Nutzer",
"search.results.songs.header": "Songs",
"search.noresults.text": "Deine Suche ergab kein Ergebnis. Vergewissere dich, dass alle Wörter korrekt geschrieben wurden oder versuche es mit einem anderen Suchbegriff.",
"search.showall.button": "Alle anzeigen",
"library.installed.header": "Installierte Songs",
"library.installed.install.title": "Installieren",
"library.installed.install.text": "Lokale .zip installieren",
"library.contextmenu.delete": "Löschen",
"library.header": "Deine Sammlung",
"library.actions.install": "Installieren",
"library.actions.refresh": "Neu laden",
"library.actions.open": "Sammlung öffnen",
"library.cleanup.title": "Sammlungs-Bereinigung",
"library.cleanup.copy": "Deine Spin Rhythm Sammlung hat ungenutzte Dateien, welche keinem Song zugewiesen wurden. Diese Dateien können automatisch aufgeräumt werden!",
"library.cleanup.action": "Aufräumen",
"library.installmodal.title": "Backup öffnen",
"library.installmodal.filetype": "Backup Archiv",
"library.deletemodal.title": "Bestätigung",
"library.deletemodal.text": "Diese Dateien werden entfernt.",
"library.deletemodal.delete": "Löschen",
......@@ -36,16 +43,21 @@
"songdetail.reviews.recommended.addReview": "Review schreiben",
"songdetail.reviews.noresults.title": "Es gibt noch keine Reviews.",
"songdetail.reviews.noresults.explaination": "Komm doch später zurück, oder schreib selbst eine!",
"songdetail.showmore": "Mehr anzeigen",
"songdetail.showless": "Weniger anzeigen",
"songdetail.spinplays.add.label": "Füge dein Gameplay-Video hinzu!",
"songdetail.spinplays.add.text": "Hast du diesen Song gespielt? Sende dein Video ein und werde hier vorgestellt!",
"songdetail.spinplays.add.submitVideo": "Video einreichen",
"songdetail.spinplays.noresults.title": "Es gibt noch keine SpinPlays.",
"songdetail.spinplays.noresults.explaination": "Komm doch später zurück, oder sende ein neues ein!",
"songdetail.playmodal.title": "Wähle eine Schwierigkeit",
"songdetail.playmodal.actions.close": "Lieber doch nicht",
"userdetail.uploaded.header": "Hochgeladene Songs",
"userdetail.uploaded.noresults": "Dieser Nutzer hat noch keine Songs hochgeladen.",
"userdetail.actions.reportButton": "Melden",
"settings.header": "Einstellungen",
"settings.general.header": "SpinShare",
"settings.general.version.label": "Version",
"settings.general.update.label": "Update",
......@@ -62,6 +74,7 @@
"connectionerror.notfound.title": "404 - Nicht gefunden",
"connectionerror.notfound.text": "Entschuldigung, das konnten wir nicht finden. Es wurde entweder gelöscht oder war ohnehin nie verfügbar.",
"download.queue.header": "Download Warteschlange",
"download.status.downloading": "Herunterladen",
"download.status.extracting": "Auspacken",
"download.status.extractingFailed": "Konnte den Song nicht auspacken!",
......@@ -74,5 +87,18 @@
"update.latestText": "Du hast bereits die neueste Version.",
"update.download": "Herunterladen",
"update.later": "Später",
"update.close": "Schließen"
"update.close": "Schließen",
"contextmenu.play": "Spielen",
"contextmenu.play.easy": "Einfach Spielen",
"contextmenu.play.normal": "Normal Spielen",
"contextmenu.play.hard": "Schwer Spielen",
"contextmenu.play.expert": "Expert Spielen",
"contextmenu.play.xd": "XD Spielen",
"contextmenu.delete": "Löschen",
"contextmenu.copyLink": "Link kopieren",
"contextmenu.download": "Herunterladen",
"contextmenu.open": "Öffnen",
"contextmenu.openInExplorer": "Im Explorer öffnen",
"contextmenu.openOnSpinShare": "Auf SpinShare öffnen"
}
\ No newline at end of file
......@@ -6,20 +6,27 @@
"startup.tabs.new": "New",
"startup.tabs.hot": "Hot",
"startup.tabs.popular": "Popular",
"startup.staffpromo.action": "CHECK IT OUT",
"startup.newsongs.header": "New Songs",
"startup.hotsongs.header": "Hot Songs",
"startup.popularsongs.header": "Popular Songs",
"search.header": "Search",
"search.input.placeholder": "Search for songs, tags & profiles...",
"search.results.users.header": "Users",
"search.results.songs.header": "Songs",
"search.noresults.text": "Your search did not match any songs or users. Make sure, that all words are spelled correctly or try a different query.",
"search.showall.button": "Show All",
"library.installed.header": "Installed Songs",
"library.installed.install.title": "Install",
"library.installed.install.text": "Install a local .zip",
"library.contextmenu.delete": "Delete",
"library.header": "Your library",
"library.actions.install": "Install",
"library.actions.refresh": "Refresh",
"library.actions.open": "Open Library",
"library.cleanup.title": "Library Cleanup",
"library.cleanup.copy": "Your Spin Rhythm library has unused files not connected to any chart. These files can be removed to make up some space!",
"library.cleanup.action": "Cleanup",
"library.installmodal.title": "Open backup",
"library.installmodal.filetype": "Backup Archive",
"library.deletemodal.title": "Confirmation",
"library.deletemodal.text": "These files will be removed.",
"library.deletemodal.delete": "Delete",
......@@ -41,11 +48,16 @@
"songdetail.spinplays.add.submitVideo": "Submit Video",
"songdetail.spinplays.noresults.title": "There are no SpinPlays yet.",
"songdetail.spinplays.noresults.explaination": "Come back later or submit a new one!",
"songdetail.showmore": "Show more",
"songdetail.showless": "Show less",
"songdetail.playmodal.title": "Chose a difficulty",
"songdetail.playmodal.actions.close": "Nevermind",
"userdetail.uploaded.header": "Uploaded Songs",
"userdetail.uploaded.noresults": "This user did not upload any songs yet.",
"userdetail.actions.reportButton": "Report",
"settings.header": "Settings",
"settings.general.header": "SpinShare",
"settings.general.version.label": "Version",
"settings.general.update.label": "Update",
......@@ -62,6 +74,7 @@
"connectionerror.notfound.title": "404 - Not Found",
"connectionerror.notfound.text": "Sorry, we couldn't find that. It was either removed or never available in the first place.",
"download.queue.header": "Download Queue",
"download.status.downloading": "Downloading",
"download.status.extracting": "Extracting",
"download.status.extractingFailed": "Could not extract song!",
......@@ -74,5 +87,18 @@
"update.latestText": "You already have the latest version.",
"update.download": "Download",
"update.later": "Later",
"update.close": "Close"
"update.close": "Close",
"contextmenu.play": "Play",
"contextmenu.play.easy": "Play Easy",
"contextmenu.play.normal": "Play Normal",
"contextmenu.play.hard": "Play Hard",
"contextmenu.play.expert": "Play Expert",
"contextmenu.play.xd": "Play XD",
"contextmenu.delete": "Delete",
"contextmenu.copyLink": "Copy Link",
"contextmenu.download": "Download",
"contextmenu.open": "Open",
"contextmenu.openInExplorer": "Open in Explorer",
"contextmenu.openOnSpinShare": "Open on SpinShare"
}
\ No newline at end of file
......@@ -2,6 +2,7 @@
"locale.translatedBy": "Vertaling door Ellite",
"locale.dateFormat": "DD-MM-YYYY",
"startup.staffpromo.action": "BEKIJK HET",
"startup.tabs.frontpage": "Frontpage",
"startup.tabs.new": "New",
"startup.tabs.hot": "Hot",
......@@ -10,21 +11,27 @@
"startup.hotsongs.header": "Hot Songs",
"startup.popularsongs.header": "Populaire Nummers",
"search.header": "Zoek",
"search.input.placeholder": "Zoek naar nummers, labels & Profielen",
"search.results.users.header": "Gebruikers",
"search.results.nummers.header": "Nummers",
"search.results.songs.header": "Nummers",
"search.noresults.text": "Jouw zoekopdracht leverde geen nummers of gebruikers op. Check of alle woorden correct zijn gespeld, of probeer een andere zoekopdracht.",
"search.showall.button": "Show All",
"library.installed.header": "Geïnstalleerde nummers",
"library.installed.install.title": "Installeer",
"library.installed.install.text": "Installeer een lokale .zip",
"library.contextmenu.delete": "Verwijder",
"library.header": "Je collectie",
"library.actions.install": "Installeer",
"library.actions.refresh": "Ververs",
"library.actions.open": "Open collectie",
"library.deletemodal.title": "Bevestiging",
"library.deletemodal.text": "Deze bestanden zullen verwijderd worden.",
"library.deletemodal.delete": "Verwijder",
"library.deletemodal.close": "Sluit",
"library.deletemodal.explorer": "Open in Explorer",
"library.cleanup.title": "Collectie schoonmaak",
"library.cleanup.copy": "Je Spin Rhythm-bibliotheek heeft ongebruikte bestanden die niet zijn verbonden met een chart. Deze bestanden kunnen verwijderd worden om ruimte te creëren!",
"library.cleanup.action": "Maak schoon",
"library.installmodal.title": "Open backup",
"library.installmodal.filetype": "Backup Archive",
"songdetail.createdBy": "Gemaakt door {charter}",
"songdetail.uploadedBy": "Geüpload door ",
......@@ -41,11 +48,16 @@
"songdetail.spinplays.add.submitVideo": "Voeg video toe",
"songdetail.spinplays.noresults.title": "Er zijn nog geen SpinPlays.",
"songdetail.spinplays.noresults.explaination": "Kom later terug of voeg een nieuwe toe!",
"songdetail.showmore": "Laat meer zien",
"songdetail.showless": "Laat minder zien",
"songdetail.playmodal.title": "Kies een moeilijkheidsgraad",
"songdetail.playmodal.actions.close": "Toch niet",
"userdetail.uploaded.header": "Geüploade nummers",
"userdetail.uploaded.noresults": "Deze gebruiker heeft nog geen nummers geüpload.",
"userdetail.actions.reportButton": "Rapporteren",
"settings.header": "Instellingen",
"settings.general.header": "SpinShare",
"settings.general.version.label": "Versie",
"settings.general.update.label": "Update",
......@@ -62,6 +74,7 @@
"connectionerror.notfound.title": "404 – Niet Gevonden",
"connectionerror.notfound.text": "Sorry, dat konden we niet vinden. Het is of verwijderd, of het heft nooit bestaan",
"download.queue.header": "Download Wachtlijst",
"download.status.downloading": "Downloaden",
"download.status.extracting": "Uitpakken",
"download.status.extractingFailed": "Kon het nummer niet uitpakken!",
......@@ -74,5 +87,18 @@
"update.latestText": "Je hebt al de meest recente versie.",
"update.download": "Download",
"update.later": "Later",
"update.close": "Sluit"
"update.close": "Sluit",
"contextmenu.play": "Speel",
"contextmenu.play.easy": "Speel Easy",
"contextmenu.play.normal": "Speel Normal",
"contextmenu.play.hard": "Speel Hard",
"contextmenu.play.expert": "Speel Expert",
"contextmenu.play.xd": "Speel XD",
"contextmenu.delete": "Verwijder",
"contextmenu.copyLink": "Kopieer Link",
"contextmenu.download": "Download",
"contextmenu.open": "Open",
"contextmenu.openInExplorer": "Open in Verkenner",
"contextmenu.openOnSpinShare": "Open op SpinShare"
}
......@@ -2,6 +2,7 @@
"locale.translatedBy": "Tłumaczenie autorstwa _λmbινα|eηce",
"locale.dateFormat": "YYYY-MM-DD",
"startup.staffpromo.action": "ZOBACZ WIĘCEJ",
"startup.tabs.frontpage": "Frontpage",
"startup.tabs.new": "New",
"startup.tabs.hot": "Hot",
......@@ -10,28 +11,53 @@
"startup.hotsongs.header": "Hot Songs",
"startup.popularsongs.header": "Popularne Utwory",
"search.header": "Szukaj",
"search.input.placeholder": "Szukaj utworów, tagów i profili...",
"search.results.users.header": "Użytkownicy",
"search.results.songs.header": "Utwory",
"search.noresults.text": "Nie znaleziono żadnych pasujących utworów ani użytkowników. Upewnij się, że wszystkie wyrazy zostały napisane poprawnie lub spróbuj szukać czegoś innego.",
"search.showall.button": "Show All",
"library.installed.header": "Zainstalowane Utwory",
"library.installed.install.title": "Zainstaluj",
"library.installed.install.text": "Zainstaluj lokalny .zip",
"library.contextmenu.delete": "Usuń",
"library.header": "Twoja biblioteka",
"library.actions.install": "Zainstaluj",
"library.actions.refresh": "Odśwież",
"library.actions.open": "Otwórz Bibliotekę",
"library.deletemodal.title": "Potwierdzenie",
"library.deletemodal.text": "Te pliki zostaną usunięte.",
"library.deletemodal.delete": "Usuń",
"library.deletemodal.close": "Zamknij",
"library.deletemodal.explorer": "Open in Explorer",
"library.cleanup.title": "Czyszczenie Biblioteki",
"library.cleanup.copy": "Twoja biblioteka Spin Rhythm ma nieużywane pliki, które nie są połączone z żadną mapą. Możesz je usunąć by odzyskać trochę miejsca na dysku!",
"library.cleanup.action": "Wyczyść",
"library.installmodal.title": "Otwórz kopię zapasową",
"library.installmodal.filetype": "Archiwum Kopii Zapasowych",
"songdetail.createdBy": "Autorstwa {charter}",
"songdetail.uploadedBy": "Udostępnione przez ",
"songdetail.tabs.reviews": "RECENZJE",
"songdetail.tabs.spinplays": "SPINPLAYS",
"songdetail.reviews.recommended.label": "POLECIŁO",
"songdetail.reviews.recommended.notenough": "Ta mapa ma niewystarczającą ilość recenzji użytkowników.",
"songdetail.reviews.recommended.basedon": "Oparte na {amountOfReviews} recenzjach użytkowników",
"songdetail.reviews.recommended.addReview": "Dodaj Recenzję",
"songdetail.reviews.noresults.title": "Nie ma jeszcze żadnych recenzji.",
"songdetail.reviews.noresults.explaination": "Zajrzyj ponownie później lub napisz własną!",
"songdetail.spinplays.add.label": "Dodaj Własne Nagranie z Gry",
"songdetail.spinplays.add.text": "Czy grałeś tę mapę? Prześlij własne nagranie, które będzie widoczne tutaj!",
"songdetail.spinplays.add.submitVideo": "Prześlij Nagranie",
"songdetail.spinplays.noresults.title": "Nie ma jeszcze żadnych SpinPlays.",
"songdetail.spinplays.noresults.explaination": "Zajrzyj ponownie później lub prześlij własne!",
"songdetail.showmore": "Pokaż więcej",
"songdetail.showless": "Pokaż mniej",
"songdetail.playmodal.title": "Wybierz poziom trudności",
"songdetail.playmodal.actions.close": "Nieważne",
"userdetail.uploaded.header": "Przesłane Utwory",
"userdetail.uploaded.noresults": "Ten użytkownik nie przesłał jeszcze żadnych utworów.",
"userdetail.actions.reportButton": "Zgłoś",
"settings.header": "Ustawienia",
"settings.general.header": "SpinShare",
"settings.general.version.label": "Wersja",
"settings.general.update.label": "Aktualizuj",
......@@ -48,6 +74,7 @@
"connectionerror.notfound.title": "404 - Nie znaleziono",
"connectionerror.notfound.text": "Przepraszamy, nie udało nam się tego znaleźć, ponieważ zostało usunięte lub nigdy nie było dostępne.",
"download.queue.header": "Kolejka do pobrania",
"download.status.downloading": "Pobieranie",
"download.status.extracting": "Wypakowywanie",
"download.status.extractingFailed": "Nie udało się wypakować utworu!",
......@@ -60,5 +87,17 @@
"update.latestText": "Posiadasz już najnowszą wersję.",
"update.download": "Pobierz",
"update.later": "Później",
"update.close": "Zamknij"
"update.close": "Zamknij",
"contextmenu.play": "Graj",
"contextmenu.play.easy": "Zagraj Łatwy",
"contextmenu.play.normal": "Zagraj Normalny",
"contextmenu.play.hard": "Zagraj Trudny",
"contextmenu.play.expert": "Zagraj Ekspert",
"contextmenu.play.xd": "Zagraj XD",
"contextmenu.delete": "Usuń",
"contextmenu.copyLink": "Kopiuj Link",
"contextmenu.download": "Pobierz",
"contextmenu.open": "Otwórz",
"contextmenu.openInExplorer": "Otwórz w Przeglądarce Plików",
"contextmenu.openOnSpinShare": "Otwórz w SpinShare"
}
\ No newline at end of file
{
"locale.translatedBy": "SPEEN SPEEN SPEEN",
"locale.dateFormat": "SPEEN/SPEEN/SPEEN",
"startup.tabs.frontpage": "SPEEN",
"startup.tabs.new": "SPEEN",
"startup.tabs.hot": "SPEEN",
......@@ -9,23 +8,15 @@
"startup.newsongs.header": "SPEEN SPEEN",
"startup.hotsongs.header": "SPEEN SPEEN",
"startup.popularsongs.header": "SPEEN SPEEN",
"search.input.placeholder": "SPEEN...",
"search.results.users.header": "SPEEN",
"search.results.songs.header": "SPEEN",
"search.noresults.text": "SPEEN",
"search.showall.button": "SPEEN SPEEN",
"library.deletemodal.title": "SPEEN",
"library.deletemodal.text": "SPEEN",
"library.deletemodal.delete": "SPEEN",
"library.deletemodal.close": "SPEEN",
"library.installed.header": "SPEEN",
"library.installed.install.title": "SPEEN",
"library.installed.install.text": "SPEEN",
"library.contextmenu.delete": "SPEEN",
"songdetail.createdBy": "SPEEN {charter}",
"songdetail.uploadedBy": "SPEEN SPEEN ",
"songdetail.tabs.reviews": "SPEENS",
......@@ -41,11 +32,9 @@
"songdetail.spinplays.add.submitVideo": "SPEEN",
"songdetail.spinplays.noresults.title": "SPEEN SPEEN SPEEN.",
"songdetail.spinplays.noresults.explaination": "SPEEN SPEEN SPEEN SPEEN!",
"userdetail.uploaded.header": "SPEEN",
"userdetail.uploaded.noresults": "SPEEN",
"userdetail.actions.reportButton": "SPEEN",
"settings.general.header": "SPEENSHARE",
"settings.general.version.label": "SPEEN",
"settings.general.update.label": "SPEEN",
......@@ -56,12 +45,10 @@
"settings.directories.gameDirectory.label": "SPEEN",
"settings.directories.gameDirectory.changeButton": "SPEEN",
"settings.directories.gameDirectory.resetButton": "SPEEN",
"connectionerror.server.title": "SPEEN :(",
"connectionerror.server.text": "SPEEN",
"connectionerror.notfound.title": "SPEEN :(",
"connectionerror.notfound.text": "SPEEN",
"download.status.downloading": "SPEEN",
"download.status.extracting": "SPEEN",
"download.status.extractingFailed": "SPEEN",
......@@ -69,10 +56,39 @@
"download.status.installingFailed": "SPEEN",
"download.status.done": "SPEEN :)",
"download.closeButton": "SPEEN",
"update.availableText": "SPEEN",
"update.latestText": "SPEEN",
"update.download": "SPEEN!",
"update.later": "SPEEN...",
"update.close": "SPEEN"
"update.close": "SPEEN",
"startup.staffpromo.action": "SPEEN",
"search.header": "SPEEN",
"library.header": "SPEEN SPEEN",
"library.actions.install": "SPEEN",
"library.actions.refresh": "SPEEN",
"library.actions.open": "SPEEN SPEEN",
"library.cleanup.title": "SPEEN SPEEN",
"library.cleanup.copy": "SPEEN SPEEN SPEEN SPEEN SPEEN. SPEEN SPEEN SPEEN SPEEN!",
"library.cleanup.action": "SPEEN",
"library.installmodal.title": "SPEEN SPEEN",
"library.installmodal.filetype": "SPEEN SPEEN",
"library.deletemodal.explorer": "SPEEN SPEEN",
"songdetail.showmore": "SPEEN SPEEN",
"songdetail.showless": "SPEEN SPEEN",
"songdetail.playmodal.title": "SPEEN SPEEN SPEEN",
"songdetail.playmodal.actions.close": "SPEEN",
"settings.header": "SPEEN",
"download.queue.header": "SPEEN SPEEN",
"contextmenu.play": "SPEEN",
"contextmenu.play.easy": "SPEEN SPEEN",
"contextmenu.play.normal": "SPEEN SPEEN",
"contextmenu.play.hard": "SPEEN SPEEN",
"contextmenu.play.expert": "SPEEN SPEEN",
"contextmenu.play.xd": "SPEEN SPEEN",
"contextmenu.delete": "SPEEN",
"contextmenu.copyLink": "SPEEN SPEEN",
"contextmenu.download": "SPEEN",
"contextmenu.open": "SPEEN",
"contextmenu.openInExplorer": "SPEEN SPEEN SPEEN",
"contextmenu.openOnSpinShare": "SPEEN SPEEN SPEEN"
}
\ No newline at end of file
......@@ -34,12 +34,22 @@ class UserSettings {
fs.writeFileSync(this.path, JSON.stringify(this.data));
}
// TODO: Mac/Linux Support
// TODO: Custom Dir Support
detectGameDirectory() {
if(process.platform == "win32") {
switch(process.platform) {
default:
alert("Unsupported platform!");
break;
case "win32":
return path.join(app.getPath("userData"), "../..", "LocalLow", "Super Spin Digital", "Spin Rhythm XD", "Custom");
} else {
console.error("Unsupported system");
break;
case "darwin":
return path.join(app.getPath("appData"), "Super Spin Digital", "Spin Rhythm XD", "Custom");
break;
case "linux":
let linuxHomedir = require('os').homedir();
return path.join(linuxHomedir, ".local", "share", "Steam", "steamapps", "compatdata", "1058830", "pfx", "drive_c", "users", "steamuser", "AppData", "LocalLow", "Super Spin Digital", "Spin Rhythm XD", "Custom");
break;
}
}
}
......
<template>
<section class="section-library" @dragover.prevent @drop.stop.prevent="drop()">
<SongRow :title="$t('library.installed.header')">
<template v-slot:controls>
<div class="item"></div>
<div class="item" v-on:click="refreshLibrary()"><i class="mdi mdi-refresh"></i></div>
</template>
<template v-slot:song-list>
<SongInstallItem />
<header>
<div class="title">{{ $t('library.header') }}</div>
<div class="actions">
<div class="button" v-on:click="install()">{{ $t('library.actions.install') }}</div>
<div class="button" v-on:click="refreshLibrary()">{{ $t('library.actions.refresh') }}</div>
<div class="button" v-on:click="openLibrary()">{{ $t('library.actions.open') }}</div>
<span></span>
</div>
</header>
<div class="cleanup-banner" v-if="hasUnusedFiles">
<div class="icon">
<i class="mdi mdi-hand-water"></i>
</div>
<div class="text">
<div class="title">{{ $t('library.cleanup.title') }}</div>
<div class="copy">{{ $t('library.cleanup.copy') }}</div>
</div>
<div class="button" v-on:click="cleanLibrary()">{{ $t('library.cleanup.action') }}</div>
</div>
<SongRow noactions="true">
<template v-slot:song-list>
<SongLocalItem
v-for="song in librarySongs"
v-bind:key="song.detail.id"
......@@ -21,19 +36,19 @@
<script>
import { remote } from 'electron';
const { dialog } = remote;
const { dialog, shell } = remote;
import fs from 'fs';
import glob from 'glob';
import { glob, globSync } from 'glob';
import path from 'path';
import UserSettings from '@/modules/module.usersettings.js';
import SSAPI from '@/modules/module.api.js';
import SRXD from '@/modules/module.srxd.js';
import DeleteOverlay from '@/components/Overlays/DeleteOverlay.vue';
import SongRow from '@/components/Song/SongRow.vue';
import SongLocalItem from '@/components/Song/SongLocalItem.vue';
import SongInstallItem from '@/components/Song/SongInstallItem.vue';
export default {
name: 'Library',
......@@ -41,13 +56,13 @@
return {
librarySongs: [],
showDeleteOverlay: false,
deleteFiles: []
deleteFiles: [],
hasUnusedFiles: false
}
},
components: {
SongRow,
SongLocalItem,
SongInstallItem,
DeleteOverlay
},
mounted: function() {
......@@ -74,9 +89,12 @@
});
},
methods: {
refreshLibrary: function() {
// TODO: Make this truly async
refreshLibrary: async function() {
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
let userSettings = new UserSettings();
this.$data.hasUnusedFiles = false;
this.$data.librarySongs = [];
// Load local .srtb
......@@ -99,12 +117,34 @@
file: file,
detail: songDetail,
cover: songCover,
modifiedDate: fs.statSync(file).mtime,
isSpinShare: songSpinShareReference
};
this.$data.librarySongs.push(librarySong);
});
// Order library by modifiedDate
this.$data.librarySongs.sort(function(a, b) {
return new Date(b.modifiedDate) - new Date(a.modifiedDate);
});
});
this.getUnusedFiles().then((data) => {
if(data.differingAssets.length > 0) {
this.$data.hasUnusedFiles = true;
} else {
this.$data.hasUnusedFiles = false;
}
});
},
openLibrary: function() {
let userSettings = new UserSettings();
shell.openExternal(userSettings.get('gameDirectory'));
},
install: function() {
this.$parent.$parent.$emit('install');
},
getSongDetail: function(filePath) {
let srtbContent = JSON.parse( fs.readFileSync(filePath) );
......@@ -156,8 +196,39 @@
return connectedFiles;
},
getUnusedFiles: async function() {
let userSettings = new UserSettings();
let allLinkedAssets = [];
let differingAssets = [];
// Create array of assets from the srtb files
let allLinkedAssetsPromise = new Promise((resolve, reject) => {
glob(path.join(userSettings.get('gameDirectory'), "*.srtb"), (error, files) => {
files.forEach((file) => {
allLinkedAssets.push((this.getConnectedFiles(file)).slice(1)[0]);
allLinkedAssets.push((this.getConnectedFiles(file)).slice(1)[1]);
allLinkedAssets.push(file);
});
resolve(allLinkedAssets);
})
});
// Waits for resolve in order to avoid bug where all songs would be added to differingAssets
let allLinkedAssetsResults = await allLinkedAssetsPromise;
// Creates differingAssets by seeing if each entry in the assets folder is included in the allLinkedAssets.
let allFiles = glob.sync(path.join(userSettings.get('gameDirectory'), "*"));
allFiles.forEach((file) => {
if (!allLinkedAssetsResults.includes(file) && fs.statSync(file).isFile()) {
differingAssets.push(file);
}
});
let thisData = this.$data;
return {differingAssets, thisData};
},
install: function(e) {
dialog.showOpenDialog({ title: "Open Backup", properties: ['openFile', 'multiSelections'], filters: [{"name": "Backup Archive", "extensions": ["zip"]}] }).then(result => {
dialog.showOpenDialog({ title: this.$t('library.installmodal.title'), properties: ['openFile', 'multiSelections'], filters: [{"name": this.$t('library.installmodal.filetype'), "extensions": ["zip"]}] }).then(result => {
if(!result.canceled) {
result.filePaths.forEach((rawFilePath) => {
this.extract(rawFilePath)
......@@ -192,6 +263,12 @@
console.error(error);
});
}
},
cleanLibrary: function() {
this.getUnusedFiles().then( (data) => {
data.thisData.deleteFiles = data.differingAssets;
data.thisData.showDeleteOverlay = true;
});
}
}
}
......@@ -199,6 +276,65 @@
<style scoped lang="less">
section {
& header {
background: rgba(0,0,0,0.3);
padding: 50px;
padding-bottom: 25px;
& .title {
font-size: 32px;
letter-spacing: 0.05em;
text-transform: uppercase;
margin-bottom: 15px;
font-family: 'Oswald', sans-serif;
}
& .actions {
display: grid;
grid-template-columns: auto auto auto auto 1fr;
grid-gap: 15px;
}
}
& .cleanup-banner {
background: rgba(255,255,255,0.1);
padding: 20px;
border-radius: 4px;
display: grid;
grid-template-columns: 40px 1fr auto;
grid-gap: 15px;
margin: 0px 50px;
margin-top: 25px;
align-items: center;
& .icon {
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
& .mdi {
font-size: 32px;
}
}
& .text {
& .title {
margin: 0;
letter-spacing: 0.25em;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
}
& .text {
opacity: 0.6;
line-height: 1.5;
}
}
}
& .song-row {
padding: 50px;
padding-top: 25px;
}
}
</style>
\ No newline at end of file
<template>
<section class="section-search">
<div class="search-bar">
<div class="show-all">
<div class="button button-label" v-on:click="searchAll()">{{ $t('search.showall.button') }}</div>
</div>
<header>
<div class="title">{{ $t('search.header') }}</div>
<div class="actions">
<input type="search" :placeholder="$t('search.input.placeholder')" v-on:input="search()" v-model="searchQuery" ref="searchInput">
<div class="button" v-on:click="searchAll()">{{ $t('search.showall.button') }}</div>
</div>
</header>
<div class="search-results">
<UserRow :title="$t('search.results.users.header')" v-show="searchResultsUsers.length > 0">
<UserItem
......@@ -101,16 +102,27 @@
<style scoped lang="less">
.section-search {
grid-template-rows: auto 1fr;
grid-gap: 25px;
& header {
background: rgba(0,0,0,0.3);
padding: 50px;
display: grid;
padding-bottom: 25px;
& .search-bar {
background: rgba(255, 255, 255, 0.2);
border-radius: 4px;
& .title {
font-size: 32px;
letter-spacing: 0.05em;
text-transform: uppercase;
margin-bottom: 15px;
font-family: 'Oswald', sans-serif;
}
& .actions {
display: grid;
grid-template-columns: auto auto auto auto 1fr;
grid-gap: 15px;
}
& .actions {
display: grid;
grid-template-columns: auto 1fr;
grid-template-columns: 1fr auto;
align-items: center;
& .show-all {
height: 100%;
......@@ -127,26 +139,31 @@
background: transparent;
color: #fff;
border-radius: 4px;
padding: 14px 28px;
padding: 9px 20px;
background: rgba(255,255,255,0.2);
border: 0px;
transition: 0.2s ease-in-out all;
&:hover {
background: rgba(255,255,255,0.2);
background: rgba(255,255,255,0.1);
color: #fff;
}
&:focus {
outline: 0;
border-color: rgba(255,255,255,0.6);
}
&::placeholder {
color: rgba(255,255,255,0.6);
}
}
}
}
& .search-results {
display: grid;
grid-template-rows: auto auto auto 1fr;
grid-gap: 25px;
padding: 50px;
padding-top: 25px;
& .search-results-users {
display: grid;
......
<template>
<section class="section-settings">
<header>
<div class="title">{{ $t('settings.header') }}</div>
</header>
<div class="settings">
<div class="settings-box">
<div class="settings-title">{{ $t('settings.general.header') }}</div>
<div class="settings-item">
......@@ -48,6 +52,7 @@
</div>
</div>
</div>
</div>
</section>
</template>
......@@ -119,24 +124,36 @@
<style scoped lang="less">
.section-settings {
& header {
background: rgba(0,0,0,0.3);
padding: 50px;
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 25px;
& .settings-title {
font-size: 14px;
letter-spacing: 0.25em;
font-weight: bold;
& .title {
font-size: 32px;
letter-spacing: 0.05em;
text-transform: uppercase;
font-family: 'Oswald', sans-serif;
}
}
& .settings {
padding: 25px 50px;
& .settings-box {
width: 600px;
padding: 25px;
background: rgba(255,255,255,0.1);
max-width: 650px;
padding: 25px;
border-radius: 6px;
margin-bottom: 25px;
& .settings-title {
font-size: 14px;
letter-spacing: 0.25em;
font-weight: bold;
text-transform: uppercase;
}
& .settings-item {
display: grid;
grid-template-columns: 170px 1fr;
......@@ -201,4 +218,5 @@
}
}
}
}
</style>
\ No newline at end of file
......@@ -13,11 +13,16 @@
</div>
</div>
<div :class="'song-actions ' + (previewIsPlaying ? 'player-active' : '')">
<div v-on:click="AddToQueue()" class="action">
<div v-on:click="AddToQueue()" class="action" v-if="!isInstalled">
<div class="icon">
<i class="mdi mdi-download"></i>
</div>
</div>
<div v-on:click="ShowPlayOverlay()" class="action" v-if="isInstalled">
<div class="icon">
<i class="mdi mdi-gamepad-variant"></i>
</div>
</div>
<div class="action-player">
<div class="icon" v-on:click="TogglePreview()">
<i class="mdi mdi-play" v-if="!previewIsPlaying"></i>
......@@ -47,7 +52,7 @@
<img src="@/assets/img/difficultyEasy.svg" :class="hasEasyDifficulty ? 'active' : ''" alt="Easy Difficulty" />
<img src="@/assets/img/difficultyNormal.svg" :class="hasNormalDifficulty ? 'active' : ''" alt="Normal Difficulty" />
<img src="@/assets/img/difficultyHard.svg" :class="hasHardDifficulty ? 'active' : ''" alt="Hard Difficulty" />
<img src="@/assets/img/difficultyExtreme.svg" :class="hasExtremeDifficulty ? 'active' : ''" alt="Extreme Difficulty" />
<img src="@/assets/img/difficultyExtreme.svg" :class="hasExpertDifficulty ? 'active' : ''" alt="Expert Difficulty" />
<img src="@/assets/img/difficultyXD.svg" :class="hasXDDifficulty ? 'active' : ''" alt="xD Difficulty" />
</div>
</div>
......@@ -81,7 +86,7 @@
<UserItem v-bind="uploader" />
</div>
<div class="song-description" v-if="description || tags.length > 0">
<div class="text" v-if="description">{{ description }}</div>
<CollapsableText v-bind:text="description" v-if="description" />
<div class="tags">
<router-link class="tag" v-for="tag in tags" v-bind:key="tag" :to="{ name: 'Search', params: { searchQuery: tag } }">{{ tag }}</router-link>
</div>
......@@ -89,30 +94,46 @@
</div>
<div class="song-social" v-if="apiFinished">
<div class="tab-header">
<router-link :to="{ name: 'SongDetailReviews', params: { id: id } }" class="tab-header-item tab-header-item-reviews"><span>{{ $t('songdetail.tabs.reviews') }}</span></router-link>
<router-link :to="{ name: 'SongDetailSpinPlays', params: { id: id } }" class="tab-header-item tab-header-item-spinplays"><span>{{ $t('songdetail.tabs.spinplays') }}</span></router-link>
<router-link :to="{ name: 'SongDetailReviews', params: { id: id } }" class="tab-header-item tab-header-item-reviews" exact><span>{{ $t('songdetail.tabs.reviews') }}</span></router-link>
<router-link :to="{ name: 'SongDetailSpinPlays', params: { id: id } }" class="tab-header-item tab-header-item-spinplays" exact><span>{{ $t('songdetail.tabs.spinplays') }}</span></router-link>
</div>
<router-view></router-view>
</div>
<Loading v-if="!apiFinished" />
<PlayOverlay v-if="showPlayOverlay"
v-bind:fileReference="fileReference"
v-bind:hasEasyDifficulty="hasEasyDifficulty"
v-bind:hasNormalDifficulty="hasNormalDifficulty"
v-bind:hasHardDifficulty="hasHardDifficulty"
v-bind:hasExpertDifficulty="hasExpertDifficulty"
v-bind:hasXDDifficulty="hasXDDifficulty" />
</section>
</template>
<script>
import { remote } from 'electron';
import path from 'path';
import fs from 'fs';
const { clipboard, shell } = remote;
import SSAPI from '@/modules/module.api.js';
import UserSettings from '@/modules/module.usersettings.js';
import UserItem from '@/components/User/UserItem.vue';
import CollapsableText from '@/components/CollapsableText.vue';
import Loading from '@/components/Loading.vue';
import PlayOverlay from '@/components/Overlays/PlayOverlay.vue';
export default {
name: 'SongDetail',
components: {
UserItem,
Loading
CollapsableText,
Loading,
PlayOverlay
},
data: function() {
return {
......@@ -126,11 +147,13 @@
hasEasyDifficulty: false,
hasNormalDifficulty: false,
hasHardDifficulty: false,
hasExtremeDifficulty: false,
hasExpertDifficulty: false,
hasXDDifficulty: false,
tags: [],
uploader: null,
uploadDate: null,
fileReference: "",
isInstalled: false,
previewPath: "",
downloadPath: "",
downloads: 0,
......@@ -138,11 +161,13 @@
description: "",
previewIsPlaying: false,
currentPreviewAudio: null,
previewVolume: 50
previewVolume: 50,
showPlayOverlay: false
}
},
mounted: function() {
let ssapi = new SSAPI(process.env.NODE_ENV === 'development');
let userSettings = new UserSettings();
ssapi.getSongDetail(this.$route.params.id).then((data) => {
this.$data.id = data.data.id;
......@@ -154,7 +179,7 @@
this.$data.hasEasyDifficulty = data.data.hasEasyDifficulty;
this.$data.hasNormalDifficulty = data.data.hasNormalDifficulty;
this.$data.hasHardDifficulty = data.data.hasHardDifficulty;
this.$data.hasExtremeDifficulty = data.data.hasExtremeDifficulty;
this.$data.hasExpertDifficulty = data.data.hasExtremeDifficulty;
this.$data.hasXDDifficulty = data.data.hasXDDifficulty;
if(data.data.tags != "") {
this.$data.tags = data.data.tags;
......@@ -165,14 +190,25 @@
this.$data.views = data.data.views;
this.$data.description = data.data.description;
this.$data.uploadDate = data.data.uploadDate;
this.$data.fileReference = data.data.fileReference;
// Check if Song is already installed by searching for the srtb file
this.$data.isInstalled = fs.existsSync(path.join(userSettings.get('gameDirectory'), this.$data.fileReference + ".srtb"));
ssapi.getUserDetail(data.data.uploader).then((data) => {
this.$data.uploader = data.data;
this.$data.apiFinished = true;
});
});
this.$on('closePlayOverlay', () => {
this.$data.showPlayOverlay = false;
});
},
methods: {
ShowPlayOverlay: function() {
this.$data.showPlayOverlay = true;
},
AddToQueue: function() {
this.$root.$emit('download', {id: this.$data.id, cover: this.$data.cover, title: this.$data.title, artist: this.$data.artist, downloadPath: this.$data.downloadPath});
},
......@@ -449,7 +485,7 @@
color: rgba(255,255,255,0.75);
}
&.router-link-exact-active {
&.router-link-active {
opacity: 1;
color: rgba(255,255,255,1);
background: #383C3F;
......
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