mirror of
https://github.com/danbulant/osuVisualizer
synced 2026-07-05 11:10:56 +00:00
Settings and video backgrounds, bug fixes
This commit is contained in:
parent
86a45a90ae
commit
98c9cff4b5
14 changed files with 2545 additions and 530 deletions
179
package-lock.json
generated
179
package-lock.json
generated
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "osu",
|
"name": "osu",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -804,7 +804,6 @@
|
||||||
"version": "6.12.5",
|
"version": "6.12.5",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
|
||||||
"integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
|
"integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
|
@ -930,6 +929,11 @@
|
||||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
|
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"atomically": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/atomically/-/atomically-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-MAiqx5ir1nOoMeG2vLXJnj4oFROJYB1hMqa2aAo6GQVIkPdkIcrq9W9SR0OaRtvEowO7Y2bsXqKFuDMTO4iOAQ=="
|
||||||
|
},
|
||||||
"author-regex": {
|
"author-regex": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/author-regex/-/author-regex-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/author-regex/-/author-regex-1.0.0.tgz",
|
||||||
|
|
@ -1509,6 +1513,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"conf": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/conf/-/conf-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-r8/HEoWPFn4CztjhMJaWNAe5n+gPUCSaJ0oufbqDLFKsA1V8JjAG7G+p0pgoDFAws9Bpk2VtVLLXqOBA7WxLeg==",
|
||||||
|
"requires": {
|
||||||
|
"ajv": "^6.12.2",
|
||||||
|
"atomically": "^1.3.1",
|
||||||
|
"debounce-fn": "^4.0.0",
|
||||||
|
"dot-prop": "^5.2.0",
|
||||||
|
"env-paths": "^2.2.0",
|
||||||
|
"json-schema-typed": "^7.0.3",
|
||||||
|
"make-dir": "^3.1.0",
|
||||||
|
"onetime": "^5.1.0",
|
||||||
|
"pkg-up": "^3.1.0",
|
||||||
|
"semver": "^7.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"config-chain": {
|
"config-chain": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
|
||||||
|
|
@ -1605,6 +1626,21 @@
|
||||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
|
||||||
"integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ=="
|
"integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ=="
|
||||||
},
|
},
|
||||||
|
"debounce-fn": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==",
|
||||||
|
"requires": {
|
||||||
|
"mimic-fn": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-fn": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "2.6.9",
|
"version": "2.6.9",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
|
@ -1695,6 +1731,30 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"discord-rpc": {
|
||||||
|
"version": "3.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/discord-rpc/-/discord-rpc-3.1.4.tgz",
|
||||||
|
"integrity": "sha512-QaBu+gHica2SzgRAmTpuJ4J8DX9+fDwAqhvaie3hcbkU9WPqewEPh21pWdd/7vTI/JNuapU7PFm2ZKg3BTkbGg==",
|
||||||
|
"requires": {
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"ws": "^7.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": {
|
||||||
|
"version": "7.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
||||||
|
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dot-prop": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
|
||||||
|
"requires": {
|
||||||
|
"is-obj": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"duplexer3": {
|
"duplexer3": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||||
|
|
@ -2038,6 +2098,22 @@
|
||||||
"debug": "^2.2.0"
|
"debug": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"electron-store": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/electron-store/-/electron-store-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-ujb0a/6gxMxb9vOQ2BjOehK9VCyq5OKvttekd9v/tohA9oBHnAdV+Vxu4eoRh+/F9ShPFhcvDZkMdqO5i+TXUw==",
|
||||||
|
"requires": {
|
||||||
|
"conf": "^7.1.1",
|
||||||
|
"type-fest": "^0.16.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": {
|
||||||
|
"version": "0.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz",
|
||||||
|
"integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"electron-winstaller": {
|
"electron-winstaller": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-4.0.1.tgz",
|
||||||
|
|
@ -2159,8 +2235,7 @@
|
||||||
"env-paths": {
|
"env-paths": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
|
||||||
"integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
|
"integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"error-ex": {
|
"error-ex": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
|
|
@ -2335,14 +2410,12 @@
|
||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"fd-slicer": {
|
"fd-slicer": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
|
@ -3041,6 +3114,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||||
},
|
},
|
||||||
|
"is-obj": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
|
||||||
|
},
|
||||||
"is-plain-object": {
|
"is-plain-object": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||||
|
|
@ -3164,8 +3242,12 @@
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||||
"dev": true
|
},
|
||||||
|
"json-schema-typed": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A=="
|
||||||
},
|
},
|
||||||
"json-stringify-safe": {
|
"json-stringify-safe": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
|
|
@ -3341,6 +3423,21 @@
|
||||||
"sourcemap-codec": "^1.4.4"
|
"sourcemap-codec": "^1.4.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"make-dir": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||||
|
"requires": {
|
||||||
|
"semver": "^6.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"semver": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"map-age-cleaner": {
|
"map-age-cleaner": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
|
||||||
|
|
@ -3505,8 +3602,7 @@
|
||||||
"mimic-fn": {
|
"mimic-fn": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"mimic-response": {
|
"mimic-response": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
|
|
@ -3596,8 +3692,7 @@
|
||||||
"node-fetch": {
|
"node-fetch": {
|
||||||
"version": "2.6.1",
|
"version": "2.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node-gyp": {
|
"node-gyp": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
|
|
@ -3749,7 +3844,6 @@
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||||
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"mimic-fn": "^2.1.0"
|
"mimic-fn": "^2.1.0"
|
||||||
}
|
}
|
||||||
|
|
@ -4040,6 +4134,54 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pkg-up": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
|
||||||
|
"requires": {
|
||||||
|
"find-up": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"find-up": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||||
|
"requires": {
|
||||||
|
"locate-path": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"locate-path": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||||
|
"requires": {
|
||||||
|
"p-locate": "^3.0.0",
|
||||||
|
"path-exists": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-limit": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||||
|
"requires": {
|
||||||
|
"p-try": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-locate": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||||
|
"requires": {
|
||||||
|
"p-limit": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"p-try": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"plist": {
|
"plist": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz",
|
||||||
|
|
@ -4124,8 +4266,7 @@
|
||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
|
|
@ -4445,8 +4586,7 @@
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "7.3.2",
|
"version": "7.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
|
||||||
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
|
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"semver-compare": {
|
"semver-compare": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|
@ -5042,7 +5182,6 @@
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
|
||||||
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
|
"integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "osu",
|
"name": "osu",
|
||||||
"productName": "osu",
|
"productName": "osu",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"description": "Osu! visualizer",
|
"description": "Osu! visualizer",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -48,9 +48,11 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"concurrently": "^5.3.0",
|
"concurrently": "^5.3.0",
|
||||||
|
"discord-rpc": "^3.1.4",
|
||||||
"electron-is-dev": "^1.2.0",
|
"electron-is-dev": "^1.2.0",
|
||||||
"electron-reload": "^1.5.0",
|
"electron-reload": "^1.5.0",
|
||||||
"electron-squirrel-startup": "^1.0.0",
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
|
"electron-store": "^6.0.0",
|
||||||
"osu-db-parser": "^1.0.35",
|
"osu-db-parser": "^1.0.35",
|
||||||
"osu-parser": "^0.3.3",
|
"osu-parser": "^0.3.3",
|
||||||
"sirv-cli": "^1.0.0",
|
"sirv-cli": "^1.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
main.svelte-5atqf{position:relative;width:100vw;height:100vh}.background.svelte-5atqf{position:fixed;z-index:0;left:0;right:0;width:100vw;height:100vh}.menu.svelte-5atqf{position:absolute;z-index:1;left:0;right:0;width:100vw;height:100vh}
|
main.svelte-5atqf{position:relative;width:100vw;height:100vh}.background.svelte-5atqf{position:fixed;z-index:0;left:0;right:0;width:100vw;height:100vh}.menu.svelte-5atqf{position:absolute;z-index:1;left:0;right:0;width:100vw;height:100vh}
|
||||||
.info.svelte-1j9fr45.svelte-1j9fr45{opacity:1;position:relative;top:0;left:0;width:100vw;height:80px;transition:opacity 0.6s;z-index:1}.volume.svelte-1j9fr45.svelte-1j9fr45{opacity:1;position:fixed;z-index:2;right:0;bottom:0;border-radius:50%;color:black;font-size:30px}.hidden.svelte-1j9fr45.svelte-1j9fr45{opacity:0;transition:opacity 1s}.info.svelte-1j9fr45 .song.svelte-1j9fr45{color:white;position:absolute;padding:5px 5px 5px 25px;top:0;right:0;text-align:right;background:black;background:linear-gradient(90deg, transparent 0%, rgba(0,0,0,0.5) 15%, rgba(0,0,0,0.5) 100%)}.info.svelte-1j9fr45 .song h2.svelte-1j9fr45{margin:0}.info.svelte-1j9fr45 .controls.svelte-1j9fr45{height:50px;display:flex}.info.svelte-1j9fr45 .controls div.svelte-1j9fr45{height:100%}.info.svelte-1j9fr45 .controls img.svelte-1j9fr45{height:100%;filter:invert(100%)}
|
.info.svelte-1qt5obi.svelte-1qt5obi{opacity:1;position:relative;top:0;left:0;width:100vw;height:80px;transition:opacity 0.6s;z-index:2}.volume.svelte-1qt5obi.svelte-1qt5obi{opacity:1;position:fixed;z-index:5;right:0;bottom:0;border-radius:50%;font-size:30px;color:white;background-color:black;width:100px;height:100px}.volume.svelte-1qt5obi .slider.svelte-1qt5obi{position:relative;top:0;left:0;width:100%;height:100%}.percent.svelte-1qt5obi.svelte-1qt5obi{position:absolute;top:25px;left:0;width:100%;height:100%;text-align:center}.progress-ring.svelte-1qt5obi.svelte-1qt5obi{position:absolute;top:0;left:0;width:100%;height:100%}.progress-ring.svelte-1qt5obi circle.svelte-1qt5obi{transition:stroke-dashoffset 0.32s;transform:rotate(-90deg);transform-origin:50% 50%;position:absolute;top:1px;left:1px;width:100%;height:100%}.hidden.svelte-1qt5obi.svelte-1qt5obi{opacity:0;transition:opacity 1s}.info.svelte-1qt5obi .song.svelte-1qt5obi{color:white;position:absolute;padding:5px 5px 5px 25px;top:0;right:0;text-align:right;background:black;background:linear-gradient(90deg, transparent 0%, rgba(0,0,0,0.5) 15%, rgba(0,0,0,0.5) 100%)}.info.svelte-1qt5obi .song h2.svelte-1qt5obi{margin:0}.info.svelte-1qt5obi .controls.svelte-1qt5obi{height:50px;display:flex}.info.svelte-1qt5obi .controls div.svelte-1qt5obi{height:100%}.info.svelte-1qt5obi .controls img.svelte-1qt5obi{height:100%;filter:invert(100%)}.info.svelte-1qt5obi .controls .settings img.svelte-1qt5obi{height:65%;padding-top:25%}
|
||||||
.main.svelte-yh70k3.svelte-yh70k3{width:100%;height:100%;background-size:cover;background-repeat:no-repeat}@keyframes svelte-yh70k3-bpm{from{width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px)}to{width:525px;height:525px;top:calc(50vh - 262.5px);left:calc(50vw - 262.5px)}}@keyframes svelte-yh70k3-bpmShadow{0%{width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px)}70%{width:510px;height:510px;top:calc(50vh - 255px);left:calc(50vw - 255px)}100%{width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px)}}.main.svelte-yh70k3 img.svelte-yh70k3{position:fixed;width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px)}.main.svelte-yh70k3 .logo.svelte-yh70k3{animation-name:svelte-yh70k3-bpm;animation-iteration-count:infinite;animation-direction:alternate}.main.svelte-yh70k3 .shadow.svelte-yh70k3{opacity:0.2;animation-name:svelte-yh70k3-bpmShadow;animation-iteration-count:infinite;animation-delay:50ms}
|
.main.svelte-18bmol8.svelte-18bmol8{width:100%;height:100%;background-size:cover;background-repeat:no-repeat}@keyframes svelte-18bmol8-bpm{from{width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px)}to{width:525px;height:525px;top:calc(50vh - 262.5px);left:calc(50vw - 262.5px)}}@keyframes svelte-18bmol8-bpmShadow{0%{width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px)}70%{width:510px;height:510px;top:calc(50vh - 255px);left:calc(50vw - 255px)}100%{width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px)}}video.svelte-18bmol8.svelte-18bmol8{position:fixed;z-index:0;top:0;left:0;width:100vw;height:100vh}.main.svelte-18bmol8 img.svelte-18bmol8{position:fixed;width:500px;height:500px;top:calc(50vh - 250px);left:calc(50vw - 250px);z-index:1}.main.svelte-18bmol8 .logo.svelte-18bmol8{animation-name:svelte-18bmol8-bpm;animation-direction:alternate}.main.svelte-18bmol8 .shadow.svelte-18bmol8{opacity:0.2;animation-name:svelte-18bmol8-bpmShadow;animation-delay:50ms}.main.svelte-18bmol8 .repeat.svelte-18bmol8{animation-iteration-count:infinite}
|
||||||
|
.bg.svelte-1895ym0{position:fixed;display:none;width:100vw;height:100vh;top:0;left:0;z-index:3}.bg.visible.svelte-1895ym0{display:block}nav.svelte-1895ym0{position:fixed;height:100vh;width:400px;top:0;left:-400px;opacity:0;background:rgba(0,0,0,0.4);color:white;z-index:4;transition:opacity 0.3s, left 0.3s}nav.visible.svelte-1895ym0{left:0;opacity:1}
|
||||||
|
|
||||||
/*# sourceMappingURL=bundle.css.map */
|
/*# sourceMappingURL=bundle.css.map */
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
BIN
public/images/logo.png
Normal file
BIN
public/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
20
public/images/settings.svg
Normal file
20
public/images/settings.svg
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="25px" height="25.001px" viewBox="0 0 25 25.001" style="enable-background:new 0 0 25 25.001;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M24.38,10.175l-2.231-0.268c-0.228-0.851-0.562-1.655-0.992-2.401l1.387-1.763c0.212-0.271,0.188-0.69-0.057-0.934
|
||||||
|
l-2.299-2.3c-0.242-0.243-0.662-0.269-0.934-0.057l-1.766,1.389c-0.743-0.43-1.547-0.764-2.396-0.99L14.825,0.62
|
||||||
|
C14.784,0.279,14.469,0,14.125,0h-3.252c-0.344,0-0.659,0.279-0.699,0.62L9.906,2.851c-0.85,0.227-1.655,0.562-2.398,0.991
|
||||||
|
L5.743,2.455c-0.27-0.212-0.69-0.187-0.933,0.056L2.51,4.812C2.268,5.054,2.243,5.474,2.456,5.746L3.842,7.51
|
||||||
|
c-0.43,0.744-0.764,1.549-0.991,2.4l-2.23,0.267C0.28,10.217,0,10.532,0,10.877v3.252c0,0.344,0.279,0.657,0.621,0.699l2.231,0.268
|
||||||
|
c0.228,0.848,0.561,1.652,0.991,2.396l-1.386,1.766c-0.211,0.271-0.187,0.69,0.057,0.934l2.296,2.301
|
||||||
|
c0.243,0.242,0.663,0.269,0.933,0.057l1.766-1.39c0.744,0.43,1.548,0.765,2.398,0.991l0.268,2.23
|
||||||
|
c0.041,0.342,0.355,0.62,0.699,0.62h3.252c0.345,0,0.659-0.278,0.699-0.62l0.268-2.23c0.851-0.228,1.655-0.562,2.398-0.991
|
||||||
|
l1.766,1.387c0.271,0.212,0.69,0.187,0.933-0.056l2.299-2.301c0.244-0.242,0.269-0.662,0.056-0.935l-1.388-1.764
|
||||||
|
c0.431-0.744,0.764-1.548,0.992-2.397l2.23-0.268C24.721,14.785,25,14.473,25,14.127v-3.252
|
||||||
|
C25.001,10.529,24.723,10.216,24.38,10.175z M12.501,18.75c-3.452,0-6.25-2.798-6.25-6.25s2.798-6.25,6.25-6.25
|
||||||
|
s6.25,2.798,6.25,6.25S15.954,18.75,12.501,18.75z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
515
public/lib/osu-parser.js
Normal file
515
public/lib/osu-parser.js
Normal file
|
|
@ -0,0 +1,515 @@
|
||||||
|
var fs = require('fs');
|
||||||
|
var slidercalc = require('osu-parser/lib/slidercalc.js');
|
||||||
|
|
||||||
|
function beatmapParser() {
|
||||||
|
var beatmap = {
|
||||||
|
nbCircles: 0,
|
||||||
|
nbSliders: 0,
|
||||||
|
nbSpinners: 0,
|
||||||
|
timingPoints: [],
|
||||||
|
breakTimes: [],
|
||||||
|
hitObjects: []
|
||||||
|
};
|
||||||
|
|
||||||
|
var osuSection;
|
||||||
|
var bpmMin;
|
||||||
|
var bpmMax;
|
||||||
|
var members;
|
||||||
|
|
||||||
|
var timingLines = [];
|
||||||
|
var objectLines = [];
|
||||||
|
var eventsLines = [];
|
||||||
|
var sectionReg = /^\[([a-zA-Z0-9]+)\]$/;
|
||||||
|
var keyValReg = /^([a-zA-Z0-9]+)[ ]*:[ ]*(.+)$/;
|
||||||
|
var curveTypes = {
|
||||||
|
C: "catmull",
|
||||||
|
B: "bezier",
|
||||||
|
L: "linear",
|
||||||
|
P: "pass-through"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the timing point affecting a specific offset
|
||||||
|
* @param {Integer} offset
|
||||||
|
* @return {Object} timingPoint
|
||||||
|
*/
|
||||||
|
var getTimingPoint = function (offset) {
|
||||||
|
for (var i = beatmap.timingPoints.length - 1; i >= 0; i--) {
|
||||||
|
if (beatmap.timingPoints[i].offset <= offset) { return beatmap.timingPoints[i]; }
|
||||||
|
}
|
||||||
|
return beatmap.timingPoints[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse additions member
|
||||||
|
* @param {String} str additions member (sample:add:customSampleIndex:Volume:hitsound)
|
||||||
|
* @return {Object} additions a list of additions
|
||||||
|
*/
|
||||||
|
var parseAdditions = function (str) {
|
||||||
|
if (!str) return {};
|
||||||
|
|
||||||
|
var additions = {};
|
||||||
|
var adds = str.split(':');
|
||||||
|
|
||||||
|
if (adds[0] && adds[0] !== '0') {
|
||||||
|
var sample;
|
||||||
|
switch (adds[0]) {
|
||||||
|
case '1':
|
||||||
|
sample = 'normal';
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
sample = 'soft';
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
sample = 'drum';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
additions.sample = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adds[1] && adds[1] !== '0') {
|
||||||
|
var addSample;
|
||||||
|
switch (adds[1]) {
|
||||||
|
case '1':
|
||||||
|
addSample = 'normal';
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
addSample = 'soft';
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
addSample = 'drum';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
additions.additionalSample = addSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adds[2] && adds[2] !== '0') { additions.customSampleIndex = parseInt(adds[2]); }
|
||||||
|
if (adds[3] && adds[3] !== '0') { additions.hitsoundVolume = parseInt(adds[3]); }
|
||||||
|
if (adds[4]) { additions.hitsound = adds[4]; }
|
||||||
|
|
||||||
|
return additions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a timing line
|
||||||
|
* @param {String} line
|
||||||
|
*/
|
||||||
|
var parseTimingPoint = function (line) {
|
||||||
|
members = line.split(',');
|
||||||
|
|
||||||
|
var timingPoint = {
|
||||||
|
offset: parseInt(members[0]),
|
||||||
|
beatLength: parseFloat(members[1]),
|
||||||
|
velocity: 1,
|
||||||
|
timingSignature: parseInt(members[2]),
|
||||||
|
sampleSetId: parseInt(members[3]),
|
||||||
|
customSampleIndex: parseInt(members[4]),
|
||||||
|
sampleVolume: parseInt(members[5]),
|
||||||
|
timingChange: (members[6] == 1),
|
||||||
|
kiaiTimeActive: (members[7] == 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isNaN(timingPoint.beatLength) && timingPoint.beatLength !== 0) {
|
||||||
|
if (timingPoint.beatLength > 0) {
|
||||||
|
// If positive, beatLength is the length of a beat in milliseconds
|
||||||
|
var bpm = Math.round(60000 / timingPoint.beatLength);
|
||||||
|
beatmap.bpmMin = beatmap.bpmMin ? Math.min(beatmap.bpmMin, bpm) : bpm;
|
||||||
|
beatmap.bpmMax = beatmap.bpmMax ? Math.max(beatmap.bpmMax, bpm) : bpm;
|
||||||
|
timingPoint.bpm = bpm;
|
||||||
|
} else {
|
||||||
|
// If negative, beatLength is a velocity factor
|
||||||
|
timingPoint.velocity = Math.abs(100 / timingPoint.beatLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beatmap.timingPoints.push(timingPoint);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an object line
|
||||||
|
* @param {String} line
|
||||||
|
*/
|
||||||
|
var parseHitObject = function (line) {
|
||||||
|
members = line.split(',');
|
||||||
|
|
||||||
|
var soundType = members[4];
|
||||||
|
var objectType = members[3];
|
||||||
|
|
||||||
|
var hitObject = {
|
||||||
|
startTime: parseInt(members[2]),
|
||||||
|
newCombo: ((objectType & 4) == 4),
|
||||||
|
soundTypes: [],
|
||||||
|
position: [
|
||||||
|
parseInt(members[0]),
|
||||||
|
parseInt(members[1])
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sound type is a bitwise flag enum
|
||||||
|
* 0 : normal
|
||||||
|
* 2 : whistle
|
||||||
|
* 4 : finish
|
||||||
|
* 8 : clap
|
||||||
|
*/
|
||||||
|
if ((soundType & 2) == 2) { hitObject.soundTypes.push('whistle'); }
|
||||||
|
if ((soundType & 4) == 4) { hitObject.soundTypes.push('finish'); }
|
||||||
|
if ((soundType & 8) == 8) { hitObject.soundTypes.push('clap'); }
|
||||||
|
if (hitObject.soundTypes.length === 0) { hitObject.soundTypes.push('normal'); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* object type is a bitwise flag enum
|
||||||
|
* 1: circle
|
||||||
|
* 2: slider
|
||||||
|
* 8: spinner
|
||||||
|
*/
|
||||||
|
if ((objectType & 1) == 1) {
|
||||||
|
// Circle
|
||||||
|
beatmap.nbCircles++;
|
||||||
|
hitObject.objectName = 'circle';
|
||||||
|
hitObject.additions = parseAdditions(members[5]);
|
||||||
|
} else if ((objectType & 8) == 8) {
|
||||||
|
// Spinner
|
||||||
|
beatmap.nbSpinners++;
|
||||||
|
hitObject.objectName = 'spinner';
|
||||||
|
hitObject.endTime = parseInt(members[5]);
|
||||||
|
hitObject.additions = parseAdditions(members[6]);
|
||||||
|
} else if ((objectType & 2) == 2) {
|
||||||
|
// Slider
|
||||||
|
beatmap.nbSliders++;
|
||||||
|
hitObject.objectName = 'slider';
|
||||||
|
hitObject.repeatCount = parseInt(members[6]);
|
||||||
|
hitObject.pixelLength = parseInt(members[7]);
|
||||||
|
hitObject.additions = parseAdditions(members[10]);
|
||||||
|
hitObject.edges = [];
|
||||||
|
hitObject.points = [
|
||||||
|
[hitObject.position[0], hitObject.position[1]]
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate slider duration
|
||||||
|
*/
|
||||||
|
var timing = getTimingPoint(hitObject.startTime);
|
||||||
|
|
||||||
|
if (timing) {
|
||||||
|
var pxPerBeat = beatmap.SliderMultiplier * 100 * timing.velocity;
|
||||||
|
var beatsNumber = (hitObject.pixelLength * hitObject.repeatCount) / pxPerBeat;
|
||||||
|
hitObject.duration = Math.ceil(beatsNumber * timing.beatLength);
|
||||||
|
hitObject.endTime = hitObject.startTime + hitObject.duration;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Parse slider points
|
||||||
|
*/
|
||||||
|
var points = (members[5] || '').split('|');
|
||||||
|
if (points.length) {
|
||||||
|
hitObject.curveType = curveTypes[points[0]] || 'unknown';
|
||||||
|
|
||||||
|
for (var i = 1, l = points.length; i < l; i++) {
|
||||||
|
var coordinates = points[i].split(':');
|
||||||
|
hitObject.points.push([
|
||||||
|
parseInt(coordinates[0]),
|
||||||
|
parseInt(coordinates[1])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var edgeSounds = [];
|
||||||
|
var edgeAdditions = [];
|
||||||
|
if (members[8]) { edgeSounds = members[8].split('|'); }
|
||||||
|
if (members[9]) { edgeAdditions = members[9].split('|'); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get soundTypes and additions for each slider edge
|
||||||
|
*/
|
||||||
|
for (var j = 0, lgt = hitObject.repeatCount + 1; j < lgt; j++) {
|
||||||
|
var edge = {
|
||||||
|
soundTypes: [],
|
||||||
|
additions: parseAdditions(edgeAdditions[j])
|
||||||
|
};
|
||||||
|
|
||||||
|
if (edgeSounds[j]) {
|
||||||
|
var sound = edgeSounds[j];
|
||||||
|
if ((sound & 2) == 2) { edge.soundTypes.push('whistle'); }
|
||||||
|
if ((sound & 4) == 4) { edge.soundTypes.push('finish'); }
|
||||||
|
if ((sound & 8) == 8) { edge.soundTypes.push('clap'); }
|
||||||
|
if (edge.soundTypes.length === 0) { edge.soundTypes.push('normal'); }
|
||||||
|
} else {
|
||||||
|
edge.soundTypes.push('normal');
|
||||||
|
}
|
||||||
|
|
||||||
|
hitObject.edges.push(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get coordinates of the slider endpoint
|
||||||
|
var endPoint = slidercalc.getEndPoint(hitObject.curveType, hitObject.pixelLength, hitObject.points);
|
||||||
|
if (endPoint && endPoint[0] && endPoint[1]) {
|
||||||
|
hitObject.endPosition = [
|
||||||
|
Math.round(endPoint[0]),
|
||||||
|
Math.round(endPoint[1])
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// If endPosition could not be calculated, approximate it by setting it to the last point
|
||||||
|
hitObject.endPosition = hitObject.points[hitObject.points.length - 1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Unknown
|
||||||
|
hitObject.objectName = 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
beatmap.hitObjects.push(hitObject);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an event line
|
||||||
|
* @param {String} line
|
||||||
|
*/
|
||||||
|
var parseEvent = function (line) {
|
||||||
|
/**
|
||||||
|
* Background line : 0,0,"bg.jpg"
|
||||||
|
* TODO: confirm that the second member is always zero
|
||||||
|
*
|
||||||
|
* Breaktimes lines : 2,1000,2000
|
||||||
|
* second integer is start offset
|
||||||
|
* third integer is end offset
|
||||||
|
*/
|
||||||
|
members = line.split(',');
|
||||||
|
|
||||||
|
if (members[0] == '0' && members[1] == '0' && members[2]) {
|
||||||
|
var bgName = members[2].trim();
|
||||||
|
|
||||||
|
if (bgName.charAt(0) == '"' && bgName.charAt(bgName.length - 1) == '"') {
|
||||||
|
beatmap.bgFilename = bgName.substring(1, bgName.length - 1);
|
||||||
|
} else {
|
||||||
|
beatmap.bgFilename = bgName;
|
||||||
|
}
|
||||||
|
} else if (members[0] == 'Video' && members[2]) {
|
||||||
|
var bgName = members[2].trim();
|
||||||
|
|
||||||
|
if (bgName.charAt(0) == '"' && bgName.charAt(bgName.length - 1) == '"') {
|
||||||
|
beatmap.video = bgName.substring(1, bgName.length - 1);
|
||||||
|
} else {
|
||||||
|
beatmap.video = bgName;
|
||||||
|
}
|
||||||
|
} else if (members[0] == '2' && /^[0-9]+$/.test(members[1]) && /^[0-9]+$/.test(members[2])) {
|
||||||
|
beatmap.breakTimes.push({
|
||||||
|
startTime: parseInt(members[1]),
|
||||||
|
endTime: parseInt(members[2])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the total time and the draining time of the beatmap
|
||||||
|
*/
|
||||||
|
var computeDuration = function () {
|
||||||
|
var firstObject = beatmap.hitObjects[0];
|
||||||
|
var lastObject = beatmap.hitObjects[beatmap.hitObjects.length - 1];
|
||||||
|
|
||||||
|
var totalBreakTime = 0;
|
||||||
|
|
||||||
|
beatmap.breakTimes.forEach(function (breakTime) {
|
||||||
|
totalBreakTime += (breakTime.endTime - breakTime.startTime);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (firstObject && lastObject) {
|
||||||
|
beatmap.totalTime = Math.floor(lastObject.startTime / 1000);
|
||||||
|
beatmap.drainingTime = Math.floor((lastObject.startTime - firstObject.startTime - totalBreakTime) / 1000);
|
||||||
|
} else {
|
||||||
|
beatmap.totalTime = 0;
|
||||||
|
beatmap.drainingTime = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Browse objects and compute max combo
|
||||||
|
*/
|
||||||
|
var computeMaxCombo = function () {
|
||||||
|
if (beatmap.timingPoints.length === 0) { return; }
|
||||||
|
|
||||||
|
var maxCombo = 0;
|
||||||
|
var sliderMultiplier = parseFloat(beatmap.SliderMultiplier);
|
||||||
|
var sliderTickRate = parseInt(beatmap.SliderTickRate, 10);
|
||||||
|
|
||||||
|
var timingPoints = beatmap.timingPoints;
|
||||||
|
var currentTiming = timingPoints[0];
|
||||||
|
var nextOffset = timingPoints[1] ? timingPoints[1].offset : Infinity;
|
||||||
|
var i = 1;
|
||||||
|
|
||||||
|
beatmap.hitObjects.forEach(function (hitObject) {
|
||||||
|
if (hitObject.startTime >= nextOffset) {
|
||||||
|
currentTiming = timingPoints[i++];
|
||||||
|
nextOffset = timingPoints[i] ? timingPoints[i].offset : Infinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
var osupxPerBeat = sliderMultiplier * 100 * currentTiming.velocity;
|
||||||
|
var tickLength = osupxPerBeat / sliderTickRate;
|
||||||
|
|
||||||
|
switch (hitObject.objectName) {
|
||||||
|
case 'spinner':
|
||||||
|
case 'circle':
|
||||||
|
maxCombo++;
|
||||||
|
break;
|
||||||
|
case 'slider':
|
||||||
|
var tickPerSide = Math.ceil((Math.floor(hitObject.pixelLength / tickLength * 100) / 100) - 1);
|
||||||
|
maxCombo += (hitObject.edges.length - 1) * (tickPerSide + 1) + 1; // 1 combo for each tick and endpoint
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
beatmap.maxCombo = maxCombo;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a single line, parse when key/value, store when further parsing needed
|
||||||
|
* @param {String|Buffer} line
|
||||||
|
*/
|
||||||
|
var readLine = function (line) {
|
||||||
|
line = line.toString().trim();
|
||||||
|
if (!line) { return; }
|
||||||
|
|
||||||
|
var match = sectionReg.exec(line);
|
||||||
|
if (match) {
|
||||||
|
osuSection = match[1].toLowerCase();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(line.startsWith("//")) return;
|
||||||
|
|
||||||
|
switch (osuSection) {
|
||||||
|
case 'timingpoints':
|
||||||
|
timingLines.push(line);
|
||||||
|
break;
|
||||||
|
case 'hitobjects':
|
||||||
|
objectLines.push(line);
|
||||||
|
break;
|
||||||
|
case 'events':
|
||||||
|
eventsLines.push(line);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!osuSection) {
|
||||||
|
match = /^osu file format (v[0-9]+)$/.exec(line);
|
||||||
|
if (match) {
|
||||||
|
beatmap.fileFormat = match[1];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apart from events, timingpoints and hitobjects sections, lines are "key: value"
|
||||||
|
*/
|
||||||
|
match = keyValReg.exec(line);
|
||||||
|
if (match) { beatmap[match[1]] = match[2]; }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute everything that require the file to be completely parsed and return the beatmap
|
||||||
|
* @return {Object} beatmap
|
||||||
|
*/
|
||||||
|
var buildBeatmap = function () {
|
||||||
|
if (beatmap.Tags) {
|
||||||
|
beatmap.tagsArray = beatmap.Tags.split(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
eventsLines.forEach(parseEvent);
|
||||||
|
beatmap.breakTimes.sort(function (a, b) { return (a.startTime > b.startTime ? 1 : -1); });
|
||||||
|
|
||||||
|
timingLines.forEach(parseTimingPoint);
|
||||||
|
beatmap.timingPoints.sort(function (a, b) { return (a.offset > b.offset ? 1 : -1); });
|
||||||
|
|
||||||
|
var timingPoints = beatmap.timingPoints;
|
||||||
|
|
||||||
|
for (var i = 1, l = timingPoints.length; i < l; i++) {
|
||||||
|
if (!timingPoints[i].hasOwnProperty('bpm')) {
|
||||||
|
timingPoints[i].beatLength = timingPoints[i - 1].beatLength;
|
||||||
|
timingPoints[i].bpm = timingPoints[i - 1].bpm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
objectLines.forEach(parseHitObject);
|
||||||
|
beatmap.hitObjects.sort(function (a, b) { return (a.startTime > b.startTime ? 1 : -1); });
|
||||||
|
|
||||||
|
computeMaxCombo();
|
||||||
|
computeDuration();
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
readLine: readLine,
|
||||||
|
buildBeatmap: buildBeatmap
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a .osu file
|
||||||
|
* @param {String} file path to the file
|
||||||
|
* @param {Function} callback(err, beatmap)
|
||||||
|
*/
|
||||||
|
exports.parseFile = function (file, callback) {
|
||||||
|
if (!fs.existsSync(file)) {
|
||||||
|
callback(new Error('File does not exist'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parser = beatmapParser();
|
||||||
|
var stream = fs.createReadStream(file);
|
||||||
|
var buffer = '';
|
||||||
|
|
||||||
|
|
||||||
|
stream.on('data', function (chunk) {
|
||||||
|
buffer += chunk;
|
||||||
|
var lines = buffer.split(/\r?\n/);
|
||||||
|
buffer = lines.pop() || '';
|
||||||
|
lines.forEach(parser.readLine);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('error', function (err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('end', function () {
|
||||||
|
buffer.split(/\r?\n/).forEach(parser.readLine);
|
||||||
|
callback(null, parser.buildBeatmap());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a stream containing .osu content
|
||||||
|
* @param {Stream} stream
|
||||||
|
* @param {Function} callback(err, beatmap)
|
||||||
|
*/
|
||||||
|
exports.parseStream = function (stream, callback) {
|
||||||
|
var parser = beatmapParser();
|
||||||
|
var buffer = '';
|
||||||
|
|
||||||
|
stream.on('data', function (chunk) {
|
||||||
|
buffer += chunk.toString();
|
||||||
|
var lines = buffer.split(/\r?\n/);
|
||||||
|
buffer = lines.pop() || '';
|
||||||
|
lines.forEach(parser.readLine);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('error', function (err) {
|
||||||
|
callback(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('end', function () {
|
||||||
|
buffer.split(/\r?\n/).forEach(parser.readLine);
|
||||||
|
callback(null, parser.buildBeatmap());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the content of a .osu
|
||||||
|
* @param {String|Buffer} content
|
||||||
|
* @return {Object} beatmap
|
||||||
|
*/
|
||||||
|
exports.parseContent = function (content) {
|
||||||
|
var parser = beatmapParser();
|
||||||
|
content.toString().split(/[\n\r]+/).forEach(function (line) {
|
||||||
|
parser.readLine(line);
|
||||||
|
});
|
||||||
|
|
||||||
|
return parser.buildBeatmap();
|
||||||
|
};
|
||||||
|
|
@ -1,18 +1,59 @@
|
||||||
<script>
|
<script>
|
||||||
import Menu from "./Menu.svelte";
|
import Menu from "./Menu.svelte";
|
||||||
import Visualizer from "./Visualizer.svelte";
|
import Visualizer from "./Visualizer.svelte";
|
||||||
|
const Store = require('electron-store');
|
||||||
|
|
||||||
|
const store = new Store();
|
||||||
|
|
||||||
var songData = {};
|
var songData = {};
|
||||||
|
var config = store.get("config");
|
||||||
var osuData = {};
|
var osuData = {};
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const configTemplate = {
|
||||||
|
parallax: {
|
||||||
|
enabled: true,
|
||||||
|
treshold: 10
|
||||||
|
},
|
||||||
|
rpc: true,
|
||||||
|
backgrounds: 0,
|
||||||
|
mediaSession: true,
|
||||||
|
videoBackground: true,
|
||||||
|
autohide: {
|
||||||
|
info: 2000,
|
||||||
|
volume: 2000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function checkSettings(value, template) {
|
||||||
|
if(value === undefined) return template;
|
||||||
|
if(typeof value !== "object") return value;
|
||||||
|
|
||||||
|
var out = {};
|
||||||
|
|
||||||
|
for(var key in template) {
|
||||||
|
if(value[key] === undefined || typeof value[key] === "undefined") {
|
||||||
|
out[key] = template[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(typeof value[key] === "object") out[key] = checkSettings(value[key], template[key]);
|
||||||
|
if(typeof value[key] !== "object") out[key] = value[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
config = checkSettings(config, configTemplate);
|
||||||
|
})();
|
||||||
|
|
||||||
|
$: store.set("config", config);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div class="background">
|
<div class="background">
|
||||||
<Visualizer bind:songData bind:osuData/>
|
<Visualizer bind:songData bind:osuData {config} />
|
||||||
</div>
|
</div>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<Menu bind:song={songData} bind:osuData/>
|
<Menu bind:song={songData} bind:osuData bind:config />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
|
||||||
207
src/Menu.svelte
207
src/Menu.svelte
|
|
@ -1,17 +1,20 @@
|
||||||
<script>
|
<script>
|
||||||
|
import Options from "./components/options.svelte";
|
||||||
|
const fs = require("fs");
|
||||||
|
const osuParser = require("./lib/osu-parser.js");
|
||||||
|
|
||||||
export var osuData;
|
export var osuData;
|
||||||
export var song;
|
export var song;
|
||||||
|
export var config;
|
||||||
|
|
||||||
var last = Date.now();
|
var last = Date.now();
|
||||||
var lastVolumeUpdate = Date.now() - 5000;
|
var lastVolumeUpdate = Date.now() - 5000;
|
||||||
var dialogActive = false;
|
var settingsOpen = false;
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
now = Date.now();
|
now = Date.now();
|
||||||
}, 500);
|
}, 800);
|
||||||
|
|
||||||
var playing = true;
|
|
||||||
|
|
||||||
function resetPool() {
|
function resetPool() {
|
||||||
if(!osuData.songs) return false;
|
if(!osuData.songs) return false;
|
||||||
|
|
@ -21,6 +24,11 @@
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
[a[i], a[j]] = [a[j], a[i]];
|
[a[i], a[j]] = [a[j], a[i]];
|
||||||
}
|
}
|
||||||
|
osuData.songPool.forEach(v => {
|
||||||
|
delete v.audio;
|
||||||
|
delete v.video;
|
||||||
|
v.playing = true;
|
||||||
|
})
|
||||||
song = osuData.songPool.shift();
|
song = osuData.songPool.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,85 +48,143 @@
|
||||||
$: console.log(song);
|
$: console.log(song);
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if(song && song.folder && !song.audio) {
|
(() => {
|
||||||
song.audio = new Audio(process.env.USERPROFILE + "/AppData/Local/osu!/Songs/" + song.folder + "/" + song.audioFile);
|
if(song && song.folder && !song.audio) {
|
||||||
song.audio.play();
|
// var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
// song.context = audioCtx;
|
||||||
|
// song.analyser = audioCtx.createAnalyser();
|
||||||
|
song.audio = new Audio(process.env.USERPROFILE + "/AppData/Local/osu!/Songs/" + song.folder + "/" + song.audioFile);
|
||||||
|
// song.source = audioCtx.createMediaElementSource(song.audio);
|
||||||
|
// song.source.connect(song.analyser);
|
||||||
|
// song.analyser.connect(audioCtx.destination);
|
||||||
|
song.audio.play();
|
||||||
|
|
||||||
song.audio.onended = () => {
|
song.audio.onended = () => {
|
||||||
playNext();
|
playNext();
|
||||||
}
|
}
|
||||||
song.audio.onpause = () => {
|
song.audio.onpause = () => {
|
||||||
playing = false;
|
song.playing = false;
|
||||||
}
|
if(song.video) song.video.pause();
|
||||||
song.audio.onplay = () => {
|
}
|
||||||
playing = true;
|
song.audio.onplay = () => {
|
||||||
}
|
song.playing = true;
|
||||||
if ('mediaSession' in navigator) {
|
if(song.video) song.video.play();
|
||||||
navigator.mediaSession.metadata = new MediaMetadata({
|
}
|
||||||
title: song.song,
|
if ('mediaSession' in navigator && config.mediaSession) {
|
||||||
artist: song.artist,
|
navigator.mediaSession.metadata = new MediaMetadata({
|
||||||
album: "Osu! visualizer",
|
title: song.song,
|
||||||
artwork: [
|
artist: song.artist,
|
||||||
{ src: process.env.USERPROFILE + "/AppData/Local/osu!/Data/bt/" + song.id + ".jpg", type: 'image/jpeg' },
|
album: "Osu! visualizer",
|
||||||
]
|
artwork: [
|
||||||
});
|
// { src: process.env.USERPROFILE + "/AppData/Local/osu!/Data/bt/" + song.id + ".jpg", type: 'image/jpeg' },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
navigator.mediaSession.setActionHandler('play', function() { playing = true; song.audio.play(); });
|
navigator.mediaSession.setActionHandler('play', function() { song.playing = true; song.audio.play(); });
|
||||||
navigator.mediaSession.setActionHandler('pause', function() { playing = false; song.audio.pause(); });
|
navigator.mediaSession.setActionHandler('pause', function() { song.playing = false; song.audio.pause(); });
|
||||||
navigator.mediaSession.setActionHandler('nexttrack', function() { playNext()});
|
navigator.mediaSession.setActionHandler('nexttrack', function() { playNext()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if(song && song.audio && config.rpc) {
|
||||||
|
if(song.playing) {
|
||||||
|
window.songActivity = {
|
||||||
|
state: "Listening to osu! beatmaps",
|
||||||
|
details: `${song.artist} - ${song.song}`,
|
||||||
|
startTimestamp: Date.now(),
|
||||||
|
endTimestamp: Date.now() + song.audio.duration * 1000,
|
||||||
|
instance: false,
|
||||||
|
largeImageKey: "logo",
|
||||||
|
largeImageText: "Osu!visualizer"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.songActivity = {
|
||||||
|
state: "Paused",
|
||||||
|
details: `${song.artist} - ${song.song}`,
|
||||||
|
instance: false,
|
||||||
|
largeImageKey: "logo",
|
||||||
|
largeImageText: "Osu!visualizer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePlay() {
|
function togglePlay() {
|
||||||
playing = !playing;
|
song.playing = !song.playing;
|
||||||
if(playing) {
|
if(!song.audio) return;
|
||||||
|
if(song.playing) {
|
||||||
song.audio.play();
|
song.audio.play();
|
||||||
} else {
|
} else {
|
||||||
song.audio.pause();
|
song.audio.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var volume = 1;
|
||||||
|
|
||||||
function updateVolume(e) {
|
function updateVolume(e) {
|
||||||
if(!song || !song.audio || !e.altKey) return;
|
if(!song || !song.audio || !e.altKey) return;
|
||||||
lastVolumeUpdate = Date.now();
|
lastVolumeUpdate = Date.now();
|
||||||
var volume = song.audio.volume;
|
|
||||||
volume += e.deltaY * -0.0005;
|
volume += e.deltaY * -0.0005;
|
||||||
song.audio.volume = Math.min(1, Math.max(volume, 0));
|
volume = Math.min(1, Math.max(volume, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: if(song.audio) song.audio.volume = volume;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
song = song;
|
playNext();
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
|
const volumeWidth = 100;
|
||||||
|
const volumeStroke = 4;
|
||||||
|
const volumeRadius = 50;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:mousemove={() => last = Date.now()} on:wheel={e => updateVolume(e)} />
|
<svelte:window on:mousemove={() => last = Date.now()} on:wheel={e => updateVolume(e)} />
|
||||||
|
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="info" class:hidden={now - last > 2000}>
|
{#if now - last < config.autohide.info + 1000}
|
||||||
{#if song}
|
<div class="info" class:hidden={now - last > config.autohide.info}>
|
||||||
<div class="song">
|
{#if song}
|
||||||
<h2>{song.artist} - {song.song}</h2>
|
<div class="song">
|
||||||
<div class="controls">
|
<h2>{song.artist} - {song.song}</h2>
|
||||||
<div class="play" on:click={togglePlay}>
|
<div class="controls">
|
||||||
<img src="images/music_{playing ? "pause" : "play"}.svg" alt="{playing ? "Pause" : "Play"} music" title="{playing ? "Pause" : "Play"} music">
|
<div class="play" on:click={togglePlay}>
|
||||||
</div>
|
<img src="images/music_{song.playing ? "pause" : "play"}.svg" alt="{song.playing ? "Pause" : "Play"} music" title="{song.playing ? "Pause" : "Play"} music">
|
||||||
<div class="forward" on:click={playNext}>
|
</div>
|
||||||
<img src="images/music_forward.svg" alt="Skip the song" title="Skip the song">
|
<div class="forward" on:click={playNext}>
|
||||||
|
<img src="images/music_forward.svg" alt="Skip the song" title="Skip the song">
|
||||||
|
</div>
|
||||||
|
<div class="settings" on:click={() => settingsOpen = !settingsOpen}>
|
||||||
|
<img src="images/settings.svg" alt="Settings" title="Open settings">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</div>
|
||||||
</div>
|
{/if}
|
||||||
{#if now - lastVolumeUpdate < 4000 && song && song.audio}
|
{#if now - lastVolumeUpdate < config.autohide.volume + 1000 && song && song.audio}
|
||||||
<div class="volume" class:hidden={now - lastVolumeUpdate > 2000}>
|
<div class="volume" class:hidden={now - lastVolumeUpdate > config.autohide.volume}>
|
||||||
<div class="slider">
|
<div class="slider">
|
||||||
<div class="percent">
|
<div class="percent">
|
||||||
{Math.round(song.audio.volume * 100)}%
|
{Math.round(song.audio.volume * 100)}%
|
||||||
</div>
|
</div>
|
||||||
|
<svg class="progress-ring" width={volumeWidth} height={volumeWidth}>
|
||||||
|
<circle
|
||||||
|
stroke-width={volumeStroke}
|
||||||
|
fill="transparent"
|
||||||
|
stroke="blue"
|
||||||
|
stroke-dasharray={volumeRadius * 2 * Math.PI + " " + volumeRadius * 2 * Math.PI}
|
||||||
|
stroke-dashoffset={volumeRadius * 2 * Math.PI - song.audio.volume * volumeRadius * 2 * Math.PI}
|
||||||
|
r={volumeRadius - 1}
|
||||||
|
cx={volumeRadius - 1}
|
||||||
|
cy={volumeRadius + 1}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
<Options bind:config={config} bind:visible={settingsOpen} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -130,18 +196,53 @@
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
transition: opacity 0.6s;
|
transition: opacity 0.6s;
|
||||||
z-index: 1;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.volume {
|
.volume {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 2;
|
z-index: 5;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
color: black;
|
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
|
color: white;
|
||||||
|
background-color: black;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
.volume .slider {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.percent {
|
||||||
|
position: absolute;
|
||||||
|
top: 25px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.progress-ring {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.progress-ring circle {
|
||||||
|
transition: stroke-dashoffset 0.32s;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
position: absolute;
|
||||||
|
top: 1px;
|
||||||
|
left: 1px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
|
|
@ -176,4 +277,8 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
filter: invert(100%);
|
filter: invert(100%);
|
||||||
}
|
}
|
||||||
|
.info .controls .settings img {
|
||||||
|
height: 65%;
|
||||||
|
padding-top: 25%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const OsuDBParser = require("osu-db-parser");
|
const OsuDBParser = require("osu-db-parser");
|
||||||
const osuParser = require("osu-parser");
|
const osuParser = require("./lib/osu-parser.js");
|
||||||
export var osuData;
|
export var osuData;
|
||||||
export var songData;
|
export var songData;
|
||||||
|
export var config;
|
||||||
|
|
||||||
var wallpapers = [];
|
var wallpapers = [];
|
||||||
try {
|
try {
|
||||||
|
|
@ -25,7 +26,8 @@
|
||||||
song: v.song_title,
|
song: v.song_title,
|
||||||
song_u: v.song_title_unicode,
|
song_u: v.song_title_unicode,
|
||||||
id: v.beatmapset_id,
|
id: v.beatmapset_id,
|
||||||
dataFile: `${v.artist_name} - ${v.song_title} (${v.creator_name}) [${v.difficulty}].osu`
|
dataFile: `${v.artist_name} - ${v.song_title} (${v.creator_name}) [${v.difficulty}].osu`.replace(/\/|\*|"|:|\?/g, ""),
|
||||||
|
playing: true
|
||||||
})).filter((v, i, a) => a.findIndex(x => x.id === v.id) === i);
|
})).filter((v, i, a) => a.findIndex(x => x.id === v.id) === i);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error("Osu DB weren't found. You must have osu installed and started at least once.", e);
|
console.error("Osu DB weren't found. You must have osu installed and started at least once.", e);
|
||||||
|
|
@ -34,20 +36,43 @@
|
||||||
|
|
||||||
var wallpaper;
|
var wallpaper;
|
||||||
function shuffleWallpapers() {
|
function shuffleWallpapers() {
|
||||||
wallpaper = wallpapers[Math.floor(Math.random() * wallpapers.length)];
|
switch(config.backgrounds) {
|
||||||
|
case 0:
|
||||||
|
wallpaper = `${process.env.USERPROFILE.replace(/\\/g, "/")}/AppData/Local/osu!/Data/bg/${wallpapers[Math.floor(Math.random() * wallpapers.length)]}`;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(songData.beatmap) {
|
||||||
|
wallpaper = `${process.env.USERPROFILE.replace(/\\/g, "/")}/AppData/Local/osu!/Songs/${songData.folder}/${songData.beatmap.bgFilename}`;
|
||||||
|
} else {
|
||||||
|
wallpaper = `${process.env.USERPROFILE.replace(/\\/g, "/")}/AppData/Local/osu!/Data/bg/${wallpapers[Math.floor(Math.random() * wallpapers.length)]}`;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wallpaper = `${process.env.USERPROFILE.replace(/\\/g, "/")}/AppData/Local/osu!/Data/bg/${wallpapers[Math.floor(Math.random() * wallpapers.length)]}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
shuffleWallpapers();
|
||||||
|
|
||||||
var lastSong = null;
|
var lastSong = null;
|
||||||
|
var lastBackgroundOption = null;
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if(songData !== lastSong) {
|
if(songData !== lastSong) {
|
||||||
lastSong = songData;
|
lastSong = songData;
|
||||||
shuffleWallpapers();
|
shuffleWallpapers();
|
||||||
}
|
}
|
||||||
|
if(config.backgrounds !== lastBackgroundOption) {
|
||||||
|
lastBackgroundOption = config.backgrounds;
|
||||||
|
shuffleWallpapers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function fetchBeatmap() {
|
function fetchBeatmap() {
|
||||||
let file = fs.readFileSync(process.env.USERPROFILE + "/AppData/Local/osu!/Songs/" + songData.folder + "/" + songData.dataFile);
|
let file = fs.readFileSync(process.env.USERPROFILE + "/AppData/Local/osu!/Songs/" + songData.folder + "/" + songData.dataFile);
|
||||||
songData.beatmap = osuParser.parseContent(file);
|
songData.beatmap = osuParser.parseContent(file);
|
||||||
|
|
||||||
|
if(config.backgrounds === 1) {
|
||||||
|
wallpaper = `${process.env.USERPROFILE.replace(/\\/g, "/")}/AppData/Local/osu!/Songs/${songData.folder}/${songData.beatmap.bgFilename}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$: if(songData && songData.dataFile && !songData.beatmap) fetchBeatmap();
|
$: if(songData && songData.dataFile && !songData.beatmap) fetchBeatmap();
|
||||||
|
|
||||||
|
|
@ -56,9 +81,11 @@
|
||||||
y: 0.5
|
y: 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
const parallaxTreshold = 10;
|
var parallaxTreshold;
|
||||||
|
$: parallaxTreshold = config.parallax.treshold;
|
||||||
|
|
||||||
function updateMouse(e) {
|
function updateMouse(e) {
|
||||||
|
if(!config.parallax.enabled) return;
|
||||||
mouse = {
|
mouse = {
|
||||||
x: -(e.clientX / window.innerWidth) * parallaxTreshold - parallaxTreshold/2,
|
x: -(e.clientX / window.innerWidth) * parallaxTreshold - parallaxTreshold/2,
|
||||||
y: -(e.clientY / window.innerHeight) * parallaxTreshold - parallaxTreshold/2
|
y: -(e.clientY / window.innerHeight) * parallaxTreshold - parallaxTreshold/2
|
||||||
|
|
@ -78,7 +105,7 @@
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if(!songData) return;
|
if(!songData) return;
|
||||||
if(!songData.beatmap && songData.dataFile) fetchBeatmap();
|
if(!songData.beatmap && songData.dataFile) fetchBeatmap();
|
||||||
if(!songData.beatmap) return;
|
if(!songData.beatmap || !songData.audio) return;
|
||||||
|
|
||||||
var tp = null;
|
var tp = null;
|
||||||
for(var t of songData.beatmap.timingPoints) {
|
for(var t of songData.beatmap.timingPoints) {
|
||||||
|
|
@ -94,6 +121,25 @@
|
||||||
animDuration = tp.beatLength/2;
|
animDuration = tp.beatLength/2;
|
||||||
kiaiTime = tp.kiaiTimeActive;
|
kiaiTime = tp.kiaiTimeActive;
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if(!songData || !songData.beatmap || !songData.beatmap.video || !config.videoBackground) window.backgroundVideo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: console.log("Wallpaper", wallpaper);
|
||||||
|
|
||||||
|
$: console.log("Beatmap", songData.beatmap);
|
||||||
|
|
||||||
|
var backgroundVideo;
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if(backgroundVideo) {
|
||||||
|
songData.video = backgroundVideo;
|
||||||
|
if(songData && songData.audio && songData.video) {
|
||||||
|
songData.video.currentTime = songData.audio.currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:mousemove={updateMouse} on:resize={resize} />
|
<svelte:window on:mousemove={updateMouse} on:resize={resize} />
|
||||||
|
|
@ -101,13 +147,24 @@
|
||||||
<div
|
<div
|
||||||
class="main"
|
class="main"
|
||||||
style="
|
style="
|
||||||
background-image: url('{process.env.USERPROFILE.replace(/\\/g, "/")}/AppData/Local/osu!/Data/bg/{wallpaper}');
|
background-image: url('{wallpaper}');
|
||||||
background-size: {!isWidthSmaller ? `calc(100% + ${parallaxTreshold * 1.5}px) auto` : `auto calc(100% + ${parallaxTreshold * 1.5}px)`};
|
background-size: {!isWidthSmaller ? `calc(100% + ${parallaxTreshold * 1.5}px) auto` : `auto calc(100% + ${parallaxTreshold * 1.5}px)`};
|
||||||
background-position: {mouse.x}px {mouse.y}px;
|
background-position: {mouse.x}px {mouse.y}px;
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<img src="images/logo.svg" alt="logo" class="logo" style="animation-duration: {animDuration}ms;">
|
{#if songData && songData.beatmap && songData.beatmap.video && config.videoBackground}
|
||||||
<img src="images/logo.svg" alt="" class="shadow" style="animation-duration: {animDuration * 2}ms;">
|
<!-- svelte-ignore a11y-media-has-caption -->
|
||||||
|
<video bind:this={backgroundVideo} style="
|
||||||
|
width: {isWidthSmaller ? "auto" : `calc(100% + ${parallaxTreshold * 1.5}px)`};
|
||||||
|
height: {!isWidthSmaller ? "auto" : `calc(100% + ${parallaxTreshold * 1.5}px)`};
|
||||||
|
top: {mouse.y}px;
|
||||||
|
left: {mouse.x}px;
|
||||||
|
">
|
||||||
|
<source src="file:///{process.env.USERPROFILE.replace(/\\/g, "/")}/AppData/Local/osu!/Songs/{songData.folder}/{songData.beatmap.video}">
|
||||||
|
</video>
|
||||||
|
{/if}
|
||||||
|
<img src="images/logo.svg" alt="logo" class="logo" style="animation-duration: {animDuration}ms;" class:repeat={songData.playing}>
|
||||||
|
<img src="images/logo.svg" alt="" class="shadow" style="animation-duration: {animDuration * 2}ms;" class:repeat={songData.playing}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -154,24 +211,36 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 0;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
.main img {
|
.main img {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 500px;
|
width: 500px;
|
||||||
height: 500px;
|
height: 500px;
|
||||||
top: calc(50vh - 250px);
|
top: calc(50vh - 250px);
|
||||||
left: calc(50vw - 250px);
|
left: calc(50vw - 250px);
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .logo {
|
.main .logo {
|
||||||
animation-name: bpm;
|
animation-name: bpm;
|
||||||
animation-iteration-count: infinite;
|
|
||||||
animation-direction: alternate;
|
animation-direction: alternate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .shadow {
|
.main .shadow {
|
||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
animation-name: bpmShadow;
|
animation-name: bpmShadow;
|
||||||
animation-iteration-count: infinite;
|
|
||||||
animation-delay: 50ms;
|
animation-delay: 50ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main .repeat {
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
89
src/components/options.svelte
Normal file
89
src/components/options.svelte
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
<script>
|
||||||
|
export var config;
|
||||||
|
export var visible;
|
||||||
|
|
||||||
|
$: console.log("Config", config);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="options">
|
||||||
|
<div class="bg" class:visible={visible} on:click={() => visible = false}></div>
|
||||||
|
<nav class:visible={visible}>
|
||||||
|
<h2>Options</h2>
|
||||||
|
|
||||||
|
<div class="group">
|
||||||
|
<h3>Parallax</h3>
|
||||||
|
<div class="row">
|
||||||
|
<span>Enable parallax</span>
|
||||||
|
<input type="checkbox" bind:checked={config.parallax.enabled}>
|
||||||
|
</div>
|
||||||
|
<div class="row" class:enabled={config.parallax.enabled}>
|
||||||
|
<span>Parallax treshold</span>
|
||||||
|
<input type="range" min="1" max="30" bind:value={config.parallax.treshold}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="group">
|
||||||
|
<h3>Integrations</h3>
|
||||||
|
<div class="row">
|
||||||
|
<span>Discord Rich Presence</span>
|
||||||
|
<input type="checkbox" bind:checked={config.rpc}>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span>MediaSession (system-wide controls)</span>
|
||||||
|
<input type="checkbox" bind:checked={config.mediaSession}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="group">
|
||||||
|
<h3>Backgrounds</h3>
|
||||||
|
<select bind:value={config.backgrounds}>
|
||||||
|
<option value={0}>Osu!wallpapers</option>
|
||||||
|
<option value={1}>Beatmap wallpapers</option>
|
||||||
|
</select>
|
||||||
|
<div class="row">
|
||||||
|
<span>Video backgrounds</span>
|
||||||
|
<input type="checkbox" bind:checked={config.videoBackground}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="group">
|
||||||
|
<h3>UI</h3>
|
||||||
|
<div class="row">
|
||||||
|
<span>Song info hide timeout</span>
|
||||||
|
<input type="range" min="1000" max="15000" step="500" bind:value={config.autohide.info}>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span>Volume hide timeout</span>
|
||||||
|
<input type="range" min="1000" max="15000" step="500" bind:value={config.autohide.volume}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.bg {
|
||||||
|
position: fixed;
|
||||||
|
display: none;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
.bg.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
position: fixed;
|
||||||
|
height: 100vh;
|
||||||
|
width: 400px;
|
||||||
|
top: 0;
|
||||||
|
left: -400px;
|
||||||
|
opacity: 0;
|
||||||
|
background: rgba(0,0,0,0.4);
|
||||||
|
color: white;
|
||||||
|
z-index: 4;
|
||||||
|
transition: opacity 0.3s, left 0.3s;
|
||||||
|
}
|
||||||
|
nav.visible {
|
||||||
|
left: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
78
src/index.js
78
src/index.js
|
|
@ -1,38 +1,43 @@
|
||||||
const { app, BrowserWindow } = require('electron');
|
const { app, BrowserWindow } = require('electron');
|
||||||
const isDev = require('electron-is-dev');
|
const isDev = require('electron-is-dev');
|
||||||
|
const RPC = require("discord-rpc");
|
||||||
|
const rpc = new RPC.Client({ transport: "ipc" });
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||||
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
|
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isDev) require('update-electron-app')()
|
if (!isDev) require('update-electron-app')()
|
||||||
|
|
||||||
app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');
|
app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');
|
||||||
|
|
||||||
|
var mainWindow;
|
||||||
|
|
||||||
const createWindow = () => {
|
const createWindow = () => {
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
const mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true
|
nodeIntegration: true,
|
||||||
},
|
enableRemoteModule: true
|
||||||
autoHideMenuBar: true
|
},
|
||||||
});
|
autoHideMenuBar: true
|
||||||
mainWindow.setMenu(null);
|
});
|
||||||
|
mainWindow.setMenu(null);
|
||||||
|
|
||||||
// and load the index.html of the app.
|
// and load the index.html of the app.
|
||||||
mainWindow.loadFile(path.join(__dirname, '../public/index.html'));
|
mainWindow.loadFile(path.join(__dirname, '../public/index.html'));
|
||||||
|
|
||||||
// Open the DevTools.
|
// Open the DevTools.
|
||||||
mainWindow.webContents.openDevTools();
|
if(isDev) mainWindow.webContents.openDevTools();
|
||||||
};
|
};
|
||||||
|
|
||||||
require('electron-reload')(__dirname, {
|
require('electron-reload')(__dirname, {
|
||||||
electron: path.join(__dirname, '../node_modules', '.bin', 'electron'),
|
electron: path.join(__dirname, '../node_modules', '.bin', 'electron'),
|
||||||
awaitWriteFinish: true,
|
awaitWriteFinish: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// This method will be called when Electron has finished
|
// This method will be called when Electron has finished
|
||||||
|
|
@ -44,18 +49,39 @@ app.on('ready', createWindow);
|
||||||
// for applications and their menu bar to stay active until the user quits
|
// for applications and their menu bar to stay active until the user quits
|
||||||
// explicitly with Cmd + Q.
|
// explicitly with Cmd + Q.
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
// On OS X it's common to re-create a window in the app when the
|
// On OS X it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
if (BrowserWindow.getAllWindows().length === 0) {
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
createWindow();
|
createWindow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// In this file you can include the rest of your app's specific main process
|
// In this file you can include the rest of your app's specific main process
|
||||||
// code. You can also put them in separate files and import them here.
|
// code. You can also put them in separate files and import them here.
|
||||||
|
|
||||||
|
async function setActivity() {
|
||||||
|
if (!rpc || !mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const activity = await mainWindow.webContents.executeJavaScript('window.songActivity');
|
||||||
|
|
||||||
|
rpc.setActivity(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc.on('ready', () => {
|
||||||
|
setActivity();
|
||||||
|
|
||||||
|
// activity can only be set every 15 seconds
|
||||||
|
setInterval(() => {
|
||||||
|
setActivity();
|
||||||
|
}, 15e3);
|
||||||
|
});
|
||||||
|
|
||||||
|
rpc.login({ clientId: "756806736106618951" });
|
||||||
Loading…
Reference in a new issue