Compare commits
591 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41f4130e5d | ||
|
|
8e19f3fc0b | ||
|
|
c4b8ac8b0b | ||
|
|
0ac2df1297 | ||
|
|
251450fd50 | ||
|
|
85c5595f43 | ||
|
|
ca3188c930 | ||
|
|
2f47f82b0f | ||
|
|
0e09598b10 | ||
|
|
a705420528 | ||
|
|
4089887514 | ||
|
|
a3d02e5f39 | ||
|
|
6e09363832 | ||
|
|
1c58a64847 | ||
|
|
2a716e4d5a | ||
|
|
a2c613d380 | ||
|
|
aa4b09436c | ||
|
|
9521bba4ba | ||
|
|
55d10021f8 | ||
|
|
7fe35748d0 | ||
|
|
ff9efbd4ea | ||
|
|
23b8c325f4 | ||
|
|
ecfccb4c40 | ||
|
|
2472574cde | ||
|
|
bf81c8facc | ||
|
|
9bf0d69ab6 | ||
|
|
cf9d98d434 | ||
|
|
da8e67d4e5 | ||
|
|
d695cdef08 | ||
|
|
d7a7701c09 | ||
|
|
a31180260b | ||
|
|
f33947287c | ||
|
|
c054ceeab5 | ||
|
|
c8dce1bcb6 | ||
|
|
6195c10646 | ||
|
|
535cbbbd16 | ||
|
|
fa99f35bc0 | ||
|
|
5800f0e354 | ||
|
|
aa5e621184 | ||
|
|
283bdd6246 | ||
|
|
2884e67109 | ||
|
|
4542f9b2e3 | ||
|
|
9d08f91079 | ||
|
|
0704a4ad12 | ||
|
|
bb8509a21c | ||
|
|
f2e3d4a53d | ||
|
|
b8a221e67e | ||
|
|
f4147cce37 | ||
|
|
01f9fd502f | ||
|
|
5d20adc81e | ||
|
|
6a78f659e3 | ||
|
|
211f584bf8 | ||
|
|
fcfba8b12c | ||
|
|
85e4c7555a | ||
|
|
19dccffdde | ||
|
|
359514a83c | ||
|
|
90ea0dc857 | ||
|
|
ae18db45a4 | ||
|
|
4783c9be8d | ||
|
|
ff41fa9829 | ||
|
|
aa56dafd5f | ||
|
|
f2f2008d5d | ||
|
|
15d2589db8 | ||
|
|
47a8da49ca | ||
|
|
2250cac7f9 | ||
|
|
94e3063307 | ||
|
|
88691b3f18 | ||
|
|
3851880007 | ||
|
|
e5d2e089f4 | ||
|
|
bfe7f24a4b | ||
|
|
0d1e2c3349 | ||
|
|
bc6272a0ed | ||
|
|
56a752dc26 | ||
|
|
0fe443c92a | ||
|
|
74afdb2a46 | ||
|
|
ebd6ff36ed | ||
|
|
a5ec36bf89 | ||
|
|
c65802c1c3 | ||
|
|
784515e411 | ||
|
|
e859d39b2b | ||
|
|
62c4bfb9eb | ||
|
|
8ab1bdf30a | ||
|
|
c758066e25 | ||
|
|
06b7f69b3c | ||
|
|
c3c43a2645 | ||
|
|
343395a5de | ||
|
|
3c9bb74b61 | ||
|
|
c9cf30692f | ||
|
|
c979339c4e | ||
|
|
9393906eb9 | ||
|
|
1b4c910264 | ||
|
|
4db5d26b1e | ||
|
|
c09a4131db | ||
|
|
ce6f3f23c6 | ||
|
|
7b898c2d91 | ||
|
|
3da797a0ad | ||
|
|
517899cd03 | ||
|
|
1d6a14685e | ||
|
|
737d00f550 | ||
|
|
68798a9627 | ||
|
|
5b1dfee05c | ||
|
|
e75863e99d | ||
|
|
1c542a9b17 | ||
|
|
729ac5a0d7 | ||
|
|
ff8195df46 | ||
|
|
692ab6dacb | ||
|
|
128039d678 | ||
|
|
bb5de056d4 | ||
|
|
d927ac90e7 | ||
|
|
f61099ecad | ||
|
|
f96b663bbe | ||
|
|
f65213f8aa | ||
|
|
2e5adeb50c | ||
|
|
6de84d3b9b | ||
|
|
65ae08add6 | ||
|
|
3c970c24c1 | ||
|
|
93f3507dc8 | ||
|
|
e92e291409 | ||
|
|
4b4de8937e | ||
|
|
27a036bc00 | ||
|
|
1eb2540c67 | ||
|
|
3a5bd6029f | ||
|
|
249ff7f2d2 | ||
|
|
9afa965d5d | ||
|
|
28b7b5581d | ||
|
|
26aab15e50 | ||
|
|
92351049f1 | ||
|
|
47d3c50863 | ||
|
|
36ac3532e6 | ||
|
|
dee16f6943 | ||
|
|
3541b568c9 | ||
|
|
4dfa4d9525 | ||
|
|
5938f4e591 | ||
|
|
9ac26be65d | ||
|
|
5099ba9c96 | ||
|
|
bca5b13516 | ||
|
|
6ceb984393 | ||
|
|
17b29f376a | ||
|
|
36bef673d3 | ||
|
|
c2fa4e5220 | ||
|
|
ddf06d20c2 | ||
|
|
e51f640371 | ||
|
|
e302f53d5c | ||
|
|
b2058b9581 | ||
|
|
35501d328b | ||
|
|
cb746c64db | ||
|
|
e2f6d117bc | ||
|
|
9fd9449eca | ||
|
|
1f97af6ff1 | ||
|
|
f1a7862a9c | ||
|
|
8aeac3ed2e | ||
|
|
469832a598 | ||
|
|
e0e65e4374 | ||
|
|
66f78d6979 | ||
|
|
efc58f7dd1 | ||
|
|
bc301c27c2 | ||
|
|
82ea1935de | ||
|
|
226fb05337 | ||
|
|
be219f03d5 | ||
|
|
f10c1e923e | ||
|
|
66121e5ff3 | ||
|
|
478b71172d | ||
|
|
e7370f12ae | ||
|
|
b844a577c7 | ||
|
|
9bf33fdb25 | ||
|
|
8b988b227b | ||
|
|
8b2be019c6 | ||
|
|
4d7d92759f | ||
|
|
798b840472 | ||
|
|
48db75a995 | ||
|
|
7072541ba7 | ||
|
|
7119c915ec | ||
|
|
5e3035cc15 | ||
|
|
7cf2e4c4ed | ||
|
|
674a3a0a3f | ||
|
|
7486a99494 | ||
|
|
783d96bd7d | ||
|
|
64eea42092 | ||
|
|
8453ad0fb4 | ||
|
|
0acfeff006 | ||
|
|
a338b7ef39 | ||
|
|
e821660124 | ||
|
|
bad6045164 | ||
|
|
6779fd7ae5 | ||
|
|
04858cc42c | ||
|
|
916975b0a9 | ||
|
|
644db88e58 | ||
|
|
b025af45fa | ||
|
|
0f11731c01 | ||
|
|
ea1d21a3ef | ||
|
|
545ba6521b | ||
|
|
1fd3e6c9fa | ||
|
|
2913c0c7de | ||
|
|
a4c851899f | ||
|
|
df1c58e79b | ||
|
|
67edeab09b | ||
|
|
fe07ac025a | ||
|
|
fc72d99ab3 | ||
|
|
377f665361 | ||
|
|
4e458ec4cb | ||
|
|
6f4500f31a | ||
|
|
a363c5525b | ||
|
|
65027fceba | ||
|
|
2b0c75a649 | ||
|
|
bcc79541c1 | ||
|
|
081d6dc91e | ||
|
|
09a5111e36 | ||
|
|
253746843c | ||
|
|
5d2fac9247 | ||
|
|
3c2a1093a0 | ||
|
|
88b3d8ee4a | ||
|
|
d35a6f504f | ||
|
|
4965dad6a2 | ||
|
|
3ad4584159 | ||
|
|
5e291255bb | ||
|
|
205c99372e | ||
|
|
a05f3a969b | ||
|
|
3acc0931d8 | ||
|
|
05f6a953ea | ||
|
|
6253368f05 | ||
|
|
9483f2f178 | ||
|
|
8df6e7ef90 | ||
|
|
b09dba0a95 | ||
|
|
cfee4a0b24 | ||
|
|
34febf4949 | ||
|
|
6aed9dfb9f | ||
|
|
c7360993c9 | ||
|
|
34a072bada | ||
|
|
dda0d54f20 | ||
|
|
d710c31d48 | ||
|
|
02c74f7d96 | ||
|
|
5bdccba29e | ||
|
|
cdc819fbe8 | ||
|
|
4629d4cd3e | ||
|
|
ba3a70c524 | ||
|
|
52b985dd8e | ||
|
|
b51c8e1552 | ||
|
|
86f9c03707 | ||
|
|
e61c84ee08 | ||
|
|
2f39808275 | ||
|
|
f5aee4cbd0 | ||
|
|
9fd9bb4eef | ||
|
|
685cae8993 | ||
|
|
ec14aadec6 | ||
|
|
b934770e1e | ||
|
|
2f76433f34 | ||
|
|
535c63be2b | ||
|
|
53d4f08ee7 | ||
|
|
81b72fe72b | ||
|
|
e496794052 | ||
|
|
442b4fb30f | ||
|
|
9528b10d01 | ||
|
|
a9f9c887b5 | ||
|
|
6105a331aa | ||
|
|
0f0be95c12 | ||
|
|
d6ca9e4539 | ||
|
|
d3b5171237 | ||
|
|
cf501ac19e | ||
|
|
4fd4746ddf | ||
|
|
61c1476823 | ||
|
|
e28b8bb6e8 | ||
|
|
5eb9107adf | ||
|
|
83ddf74890 | ||
|
|
6aa7f2a0ee | ||
|
|
d801d55c3c | ||
|
|
491e644c3c | ||
|
|
5844232a00 | ||
|
|
abbf067625 | ||
|
|
806c882965 | ||
|
|
3fe5a85ffe | ||
|
|
95dae62bb3 | ||
|
|
f7edd54ea7 | ||
|
|
78ae89199e | ||
|
|
fc12a235f2 | ||
|
|
48fc96226c | ||
|
|
3534dd27dc | ||
|
|
a7e3c1a0c4 | ||
|
|
43c5051158 | ||
|
|
2f56a7090a | ||
|
|
13ffcfbbcd | ||
|
|
1aeb8e29e2 | ||
|
|
a3b844d2e3 | ||
|
|
5aa027f1a9 | ||
|
|
c12be6a1c8 | ||
|
|
c891ed81e1 | ||
|
|
c48921990d | ||
|
|
54bfd945e5 | ||
|
|
1d8c4db5eb | ||
|
|
055ab98d4c | ||
|
|
777551cb43 | ||
|
|
68827f7697 | ||
|
|
8e5b144f00 | ||
|
|
748a420b64 | ||
|
|
80fc43a075 | ||
|
|
0588f2846b | ||
|
|
8e4e7d9efa | ||
|
|
6df01edc7a | ||
|
|
996396c943 | ||
|
|
e3dddb9288 | ||
|
|
47ce71c959 | ||
|
|
8921aeb3f2 | ||
|
|
35be9739d4 | ||
|
|
f5ce46431b | ||
|
|
81ed70d291 | ||
|
|
4b0fdceb76 | ||
|
|
58e537732c | ||
|
|
02ad79b12a | ||
|
|
b179887efc | ||
|
|
0580b059fc | ||
|
|
bebd0e7258 | ||
|
|
6e96b2163e | ||
|
|
ca15ac987c | ||
|
|
6d3414caa9 | ||
|
|
85b80312e0 | ||
|
|
30d5f53c1d | ||
|
|
bad2e98757 | ||
|
|
45da396cb2 | ||
|
|
d195176a46 | ||
|
|
53078f79a6 | ||
|
|
dbb7f0c683 | ||
|
|
cb7703ecbb | ||
|
|
e63d7174bb | ||
|
|
31ab7a0493 | ||
|
|
c503f09529 | ||
|
|
f5bb9189af | ||
|
|
9ed8ba80c4 | ||
|
|
f9cce82a93 | ||
|
|
79d418d1a1 | ||
|
|
15d7f73aca | ||
|
|
4561870ece | ||
|
|
dbc8c9d07d | ||
|
|
d81a2029ec | ||
|
|
d04a5a2f92 | ||
|
|
5146f083ff | ||
|
|
57122c6eea | ||
|
|
ca748906c0 | ||
|
|
4d31bde98a | ||
|
|
3f98c332bd | ||
|
|
fb3eced1fb | ||
|
|
9641ea0b3a | ||
|
|
1df05a5529 | ||
|
|
a393bb02dd | ||
|
|
20518cbe2b | ||
|
|
9447034deb | ||
|
|
c7f0fcbe9f | ||
|
|
fce8719432 | ||
|
|
ce383769da | ||
|
|
342af62aea | ||
|
|
b3ab05cc86 | ||
|
|
36966e220c | ||
|
|
8ae3347c05 | ||
|
|
4f51a8ce31 | ||
|
|
1371bbe6fb | ||
|
|
94f4c9e334 | ||
|
|
c5c89f9d9e | ||
|
|
6a79f8ec0d | ||
|
|
aa940ef9f7 | ||
|
|
7a20f06cf4 | ||
|
|
b9596f2a6e | ||
|
|
bb2dfc269c | ||
|
|
684af4e7db | ||
|
|
1c946ac661 | ||
|
|
f8d06d38ab | ||
|
|
2a679c914b | ||
|
|
3f8d5ed570 | ||
|
|
028c2f9f03 | ||
|
|
b783c0c227 | ||
|
|
30787a372e | ||
|
|
b99169cc3b | ||
|
|
78cf146a92 | ||
|
|
b867167b78 | ||
|
|
d8dfbf6995 | ||
|
|
c2d6737796 | ||
|
|
dcfe055461 | ||
|
|
c86b1c259c | ||
|
|
400c16ba2d | ||
|
|
3ff0dbb7ef | ||
|
|
469a88f368 | ||
|
|
217ff27e72 | ||
|
|
e337f7121b | ||
|
|
665ac5ee99 | ||
|
|
f06c493458 | ||
|
|
f383e47344 | ||
|
|
e15518cd51 | ||
|
|
27ce62dd4f | ||
|
|
26202d8e56 | ||
|
|
d93b5a3374 | ||
|
|
e3acb7ce4e | ||
|
|
5b7c965c48 | ||
|
|
5f1e670dd7 | ||
|
|
ab1562ea33 | ||
|
|
2359a1444b | ||
|
|
9075b6629f | ||
|
|
583e8c43d6 | ||
|
|
26369dd14b | ||
|
|
9d40e7c004 | ||
|
|
267535844e | ||
|
|
0f5d2189e0 | ||
|
|
f76f4d9d29 | ||
|
|
2ba5e40012 | ||
|
|
1fe6ae4556 | ||
|
|
3d8a1894f6 | ||
|
|
70cfce833c | ||
|
|
96c3034a07 | ||
|
|
5aad81c696 | ||
|
|
b0e2f44f01 | ||
|
|
442e633800 | ||
|
|
5f1e788a25 | ||
|
|
3808e7e78f | ||
|
|
650edc1b1e | ||
|
|
cb5e1bd795 | ||
|
|
3282557769 | ||
|
|
dff18b6b9d | ||
|
|
2a64ead1c4 | ||
|
|
eb0a61d35b | ||
|
|
ddca70980e | ||
|
|
5aa3502ef5 | ||
|
|
3b02703805 | ||
|
|
f39d13c8f8 | ||
|
|
16a203227a | ||
|
|
b350f133b0 | ||
|
|
ec3a0e08c3 | ||
|
|
a96eea5e44 | ||
|
|
0dc7815e35 | ||
|
|
7f6e1c25e9 | ||
|
|
9291c35b00 | ||
|
|
90b67fc05c | ||
|
|
09afd2c6f8 | ||
|
|
1def571191 | ||
|
|
ef52f2465e | ||
|
|
845e5de43f | ||
|
|
b7433264eb | ||
|
|
60e606a413 | ||
|
|
9afafec9d6 | ||
|
|
c9cb84a28d | ||
|
|
8949383ade | ||
|
|
f732ea4dab | ||
|
|
162842415f | ||
|
|
07d200a752 | ||
|
|
822e1ea6c9 | ||
|
|
f79ae1541d | ||
|
|
2dfa93383f | ||
|
|
1ab5db8507 | ||
|
|
ccd951b5d3 | ||
|
|
6259690d12 | ||
|
|
8059d9cd73 | ||
|
|
c6635e554a | ||
|
|
d7ca662e70 | ||
|
|
b6f885b250 | ||
|
|
63141c4ac9 | ||
|
|
94e9f01e62 | ||
|
|
cffa74b1c2 | ||
|
|
1fb917941e | ||
|
|
08c6a4e2fb | ||
|
|
976be6d96f | ||
|
|
fe95b45820 | ||
|
|
47dffeee76 | ||
|
|
be7b06f5c8 | ||
|
|
3a371f8d75 | ||
|
|
fa97058895 | ||
|
|
df9289367b | ||
|
|
3a824b1d5e | ||
|
|
6f72da87b1 | ||
|
|
1b1c5ad6da | ||
|
|
f4777f787c | ||
|
|
6bcf45fba7 | ||
|
|
1e8a05e313 | ||
|
|
1cf0f2dd0b | ||
|
|
25a0439928 | ||
|
|
df20e97d60 | ||
|
|
fd764a28a4 | ||
|
|
81bd8fbb74 | ||
|
|
47ee572640 | ||
|
|
a0b9553158 | ||
|
|
7659a6cadf | ||
|
|
a65bae8243 | ||
|
|
421abac30a | ||
|
|
0b11e97427 | ||
|
|
fbe1ff73f1 | ||
|
|
68e831468b | ||
|
|
e382f0dba0 | ||
|
|
f0f92952d6 | ||
|
|
58f016ca00 | ||
|
|
faff0edb4a | ||
|
|
5e9a9e5b55 | ||
|
|
e182dde718 | ||
|
|
7dfc2e8736 | ||
|
|
b27a547fb8 | ||
|
|
379c752cf8 | ||
|
|
35abdc63d4 | ||
|
|
a386915b50 | ||
|
|
ab16bc849d | ||
|
|
90007127ba | ||
|
|
a1935cbdac | ||
|
|
7de91bd923 | ||
|
|
cdbcae21ac | ||
|
|
ea62033cf3 | ||
|
|
a48423944a | ||
|
|
b7fb3cd208 | ||
|
|
34825b5063 | ||
|
|
7737012103 | ||
|
|
3912a375c5 | ||
|
|
35ca6db1ee | ||
|
|
0d20869337 | ||
|
|
89d161268e | ||
|
|
5ae39ef8d3 | ||
|
|
e57696d4ff | ||
|
|
15c9a5468b | ||
|
|
30318b7c61 | ||
|
|
8b0fc9bf5f | ||
|
|
5fdba7720c | ||
|
|
ca12dc604d | ||
|
|
09f4d8ac0c | ||
|
|
254b82cc60 | ||
|
|
d4240006f1 | ||
|
|
68518e609d | ||
|
|
001eba6729 | ||
|
|
ff47a224c7 | ||
|
|
8810e25ea9 | ||
|
|
eb67d67a60 | ||
|
|
e12f95ff74 | ||
|
|
2fe213d060 | ||
|
|
b726ee42f7 | ||
|
|
6b71b4709e | ||
|
|
0701b78720 | ||
|
|
82d1ac1e83 | ||
|
|
8acf98631f | ||
|
|
0a31d19561 | ||
|
|
91279922f1 | ||
|
|
96804ae2e2 | ||
|
|
3ae8a89961 | ||
|
|
f8f13fd32c | ||
|
|
ae61d2c629 | ||
|
|
b1918e8b15 | ||
|
|
ce7bca5b36 | ||
|
|
51be62bc29 | ||
|
|
c1ff3971de | ||
|
|
57db286405 | ||
|
|
592b670e96 | ||
|
|
97fdcaac51 | ||
|
|
271d9ac13e | ||
|
|
b6cea110a7 | ||
|
|
4b5dae4779 | ||
|
|
a250317a28 | ||
|
|
431605e793 | ||
|
|
a4d3c06119 | ||
|
|
246412cb2c | ||
|
|
2fb013fb41 | ||
|
|
6f9d684b2d | ||
|
|
af6a2ec581 | ||
|
|
488b28921f | ||
|
|
4c23fc1011 | ||
|
|
db1c903f1b | ||
|
|
3fdf7411fc | ||
|
|
1da275ff3a | ||
|
|
bc5167f38d | ||
|
|
609b6f3123 | ||
|
|
fe35081e03 | ||
|
|
72df1a35a0 | ||
|
|
90ffcf5071 | ||
|
|
35f60cc536 | ||
|
|
31bb40c50b | ||
|
|
bc7b35f816 | ||
|
|
0c76612a4c | ||
|
|
ab86674aa3 | ||
|
|
8cd5a01dd5 | ||
|
|
4ef5bafcca | ||
|
|
2c783e0657 | ||
|
|
0c7ead5b21 | ||
|
|
57a8b7842e | ||
|
|
4b5a7b6a74 | ||
|
|
c09c31767d | ||
|
|
ecff04618b | ||
|
|
c377469dad | ||
|
|
ecb41382cb | ||
|
|
3150b12b99 | ||
|
|
364260b070 | ||
|
|
5ccf6f077d | ||
|
|
5b113c5c22 | ||
|
|
ff53900ea3 | ||
|
|
b0b0403d9a | ||
|
|
21c3b3ab57 | ||
|
|
e85709a341 | ||
|
|
04be42a4d6 | ||
|
|
8196e8a84d | ||
|
|
1f85492690 | ||
|
|
e15178150b | ||
|
|
d83aee2507 | ||
|
|
354a9904e9 | ||
|
|
fe3379ffbb | ||
|
|
50ddc8caa3 |
16
.babelrc
@@ -6,15 +6,15 @@
|
||||
"corejs": "3",
|
||||
"useBuiltIns": "usage"
|
||||
}
|
||||
],
|
||||
[
|
||||
"minify",
|
||||
{
|
||||
"builtIns": false,
|
||||
"evaluate": false,
|
||||
"mangle": false
|
||||
}
|
||||
]
|
||||
// [
|
||||
// "minify",
|
||||
// {
|
||||
// "builtIns": false,
|
||||
// "evaluate": false,
|
||||
// "mangle": false
|
||||
// }
|
||||
// ]
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
|
||||
17
.eslintrc
@@ -1,9 +1,15 @@
|
||||
{
|
||||
"extends": "standard",
|
||||
"extends": [
|
||||
// "plugin:vue/vue3-recommended",
|
||||
"standard"
|
||||
],
|
||||
"plugins": [
|
||||
"html"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"parser": "@babel/eslint-parser",
|
||||
"parserOptions": {
|
||||
"requireConfigFile": false
|
||||
},
|
||||
"rules": {
|
||||
"no-new": "off",
|
||||
"camelcase": "off",
|
||||
@@ -17,9 +23,12 @@
|
||||
"comma-dangle": [2, "always-multiline"],
|
||||
"standard/no-callback-literal": "off",
|
||||
"prefer-const": "off",
|
||||
"no-labels": "off"
|
||||
"no-labels": "off",
|
||||
"node/no-callback-literal": "off",
|
||||
"vue/multi-word-component-names": "off"
|
||||
},
|
||||
"settings": {
|
||||
"html/html-extensions": [".html", ".vue"]
|
||||
}
|
||||
},
|
||||
"ignorePatterns": ["vendors", "*.min.js", "dist", "node_modules"]
|
||||
}
|
||||
|
||||
25
.github/ISSUE_TEMPLATE/----.md
vendored
@@ -1,25 +0,0 @@
|
||||
---
|
||||
name: 功能请求(请先查看常见问题及搜索issue列表中有无你要提的问题)
|
||||
about: 为这个项目提出一个想法
|
||||
title: 例如:添加xxx功能、优化xxx功能
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**解决方案检查**
|
||||
<!-- 请确保你已从以下渠道寻找过解决方案,然后将 [ ] 替换成 [x] -->
|
||||
- [ ] 我已阅读常见问题(<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>)
|
||||
- [ ] 我已搜索issue列表(<https://github.com/lyswhut/lx-music-desktop/issues?utf8=✓&q=>)
|
||||
|
||||
**描述您想要的解决方案**
|
||||
<!-- 简洁明了地描述您要发生的事情。 -->
|
||||
|
||||
|
||||
**描述您考虑过的替代方案**
|
||||
<!-- 对您考虑过的所有替代解决方案或功能的简洁明了的描述。 -->
|
||||
|
||||
|
||||
**其他内容**
|
||||
<!-- 在此处添加有关功能请求的任何其他上下文或屏幕截图(直接把图片拖到编辑框即可添加图片)。 -->
|
||||
|
||||
40
.github/ISSUE_TEMPLATE/----.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: ✨功能请求
|
||||
description: 为这个项目提出一个想法,请先查看常见问题及搜索issue列表中有无你要提的问题
|
||||
title: "[Feature]: "
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: check-answer
|
||||
attributes:
|
||||
label: 解决方案检查
|
||||
description: 请确保你已完成以下所有操作
|
||||
options:
|
||||
- label: 我已阅读常见问题(<https://lyswhut.github.io/lx-music-doc/desktop/faq>),但没有找到解决方案
|
||||
required: true
|
||||
- label: 我已搜索issue列表(<https://github.com/lyswhut/lx-music-desktop/issues?utf8=✓&q=>),但没有发现类似的问题
|
||||
required: true
|
||||
- type: textarea
|
||||
id: problem-description
|
||||
attributes:
|
||||
label: 问题描述
|
||||
description: 请添加清晰简洁的描述,说明你希望通过此功能请求解决的问题
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: proposed-solution
|
||||
attributes:
|
||||
label: 描述你想要的解决方案
|
||||
description: 简洁明了地描述你要发生的事情
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives-considered
|
||||
attributes:
|
||||
label: 描述你考虑过的替代方案
|
||||
description: 对你考虑过的所有替代解决方案或功能的简洁明了的描述
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-information
|
||||
attributes:
|
||||
label: 附加信息
|
||||
description: 如果你的问题需要进一步解释,或者想要表达其他内容,请在此处添加更多信息。(直接把图片、视频拖到编辑框即可添加图片或视频)
|
||||
42
.github/ISSUE_TEMPLATE/--bug.md
vendored
@@ -1,42 +0,0 @@
|
||||
---
|
||||
name: 报告Bug(请先查看常见问题及搜索issue列表中有无你要提的问题)
|
||||
about: 创建报告以帮助我们改进
|
||||
title: 例如:音乐无法播放
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**解决方案检查**
|
||||
<!-- 请确保你已从以下渠道寻找过解决方案,然后将 [ ] 替换成 [x] -->
|
||||
- [ ] 我已阅读常见问题(<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>)
|
||||
- [ ] 我已搜索issue列表(<https://github.com/lyswhut/lx-music-desktop/issues?utf8=✓&q=>)
|
||||
|
||||
**描述错误**
|
||||
<!-- 清楚简洁地说明错误是什么。 -->
|
||||
|
||||
|
||||
**重现**
|
||||
重现行为的步骤:
|
||||
1.转到“ ...”
|
||||
2.点击“ ....”
|
||||
3.向下滚动到“ ....”
|
||||
4.看到错误
|
||||
|
||||
|
||||
**预期行为**
|
||||
<!-- 对您期望发生的事情的简洁明了的描述。 -->
|
||||
|
||||
|
||||
**截图**
|
||||
<!-- 如果适用,请添加屏幕截图以帮助解释您的问题(直接把图片拖到编辑框即可添加图片)。 -->
|
||||
|
||||
|
||||
**环境:**
|
||||
-操作系统及版本:[例如:Windows 10 64位 18362.156]
|
||||
-软件安装包及版本:[例如:1.0.0 安装版]
|
||||
|
||||
|
||||
**其他内容**
|
||||
<!-- 在此处添加有关该问题的任何其他上下文。 -->
|
||||
|
||||
55
.github/ISSUE_TEMPLATE/--bug.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: 🐞报告Bug
|
||||
description: 报告bug,请先查看常见问题及搜索issue列表中有无你要提的问题
|
||||
title: "[Bug]: "
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: check-answer
|
||||
attributes:
|
||||
label: 解决方案检查
|
||||
description: 请确保你已完成以下所有操作
|
||||
options:
|
||||
- label: 我已阅读常见问题(<https://lyswhut.github.io/lx-music-doc/desktop/faq>),并没有找到解决方案
|
||||
required: true
|
||||
- label: 我已搜索issue列表(<https://github.com/lyswhut/lx-music-desktop/issues?utf8=✓&q=>),并没有发现类似的问题
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: 预期行为
|
||||
description: 对期望发生的事情的清晰简明描述
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: 实际行为
|
||||
description: 对实际发生的事情的清晰简明描述
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Lx Music 版本
|
||||
description: 你使用什么版本的LX Music?
|
||||
placeholder: 1.15.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: last-known-working-version
|
||||
attributes:
|
||||
label: 最后正常的版本
|
||||
description: 如果有,请在此处填写最后正常的版本是多少?
|
||||
placeholder: 1.15.0
|
||||
- type: input
|
||||
id: operating-system-version
|
||||
attributes:
|
||||
label: 操作系统版本
|
||||
description: 您使用的是什么操作系统版本?在 Windows 上,单击开始按钮 > 设置 > 系统 > 关于;在 macOS 上,单击 Apple 菜单 > 关于本机;在 Linux 上,使用 lsb_release 或 uname -a
|
||||
placeholder: "例如 Windows 10 版本 1909、macOS Catalina 10.15.7 或 Ubuntu 20.04"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional-information
|
||||
attributes:
|
||||
label: 附加信息
|
||||
description: 如果你的问题需要进一步解释,或者你所遇到的问题不容易重现,请在此处添加更多信息。(直接把图片、视频拖到编辑框即可添加图片或视频)
|
||||
35
.github/workflows/beta-pack.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14.x'
|
||||
node-version: '16'
|
||||
|
||||
- name: Cache file
|
||||
uses: actions/cache@v2
|
||||
@@ -31,7 +31,9 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: |
|
||||
npm install npm@8.5 -g
|
||||
npm install
|
||||
|
||||
- name: Build src code
|
||||
run: npm run build:src
|
||||
@@ -92,6 +94,11 @@ jobs:
|
||||
name: lx-music-desktop-win_arm64-green
|
||||
path: build/*win_arm64 green.7z
|
||||
|
||||
- name: Generate file MD5
|
||||
run: |
|
||||
cd build
|
||||
Get-FileHash *.exe,*.7z -Algorithm MD5 | Format-List
|
||||
|
||||
Mac:
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
@@ -102,7 +109,7 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14.x'
|
||||
node-version: '16'
|
||||
|
||||
- name: Cache file
|
||||
uses: actions/cache@v2
|
||||
@@ -117,7 +124,9 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: |
|
||||
npm install npm@8.5 -g
|
||||
npm install
|
||||
|
||||
- name: Build src code
|
||||
run: npm run build:src
|
||||
@@ -143,12 +152,17 @@ jobs:
|
||||
name: lx-music-desktop-mac-dmg-arm64
|
||||
path: build/*-arm64.dmg
|
||||
|
||||
- name: Generate file MD5
|
||||
run: |
|
||||
cd build
|
||||
md5 *.dmg
|
||||
|
||||
Linux:
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install package
|
||||
run: sudo apt-get install -y rpm libarchive-tools
|
||||
run: sudo apt-get update && sudo apt-get install -y rpm libarchive-tools
|
||||
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v2
|
||||
@@ -156,7 +170,7 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14.x'
|
||||
node-version: '16'
|
||||
|
||||
- name: Cache file
|
||||
uses: actions/cache@v2
|
||||
@@ -171,7 +185,9 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: |
|
||||
npm install npm@8.5 -g
|
||||
npm install
|
||||
|
||||
- name: Build src code
|
||||
run: npm run build:src
|
||||
@@ -231,3 +247,8 @@ jobs:
|
||||
with:
|
||||
name: lx-music-desktop-x64-pacman
|
||||
path: build/* x64.pacman
|
||||
|
||||
- name: Generate file MD5
|
||||
run: |
|
||||
cd build
|
||||
md5sum *.deb *.rpm *.pacman *.AppImage
|
||||
|
||||
35
.github/workflows/release.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14.x'
|
||||
node-version: '16'
|
||||
|
||||
- name: Cache file
|
||||
uses: actions/cache@v2
|
||||
@@ -31,7 +31,9 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: |
|
||||
npm install npm@8.5 -g
|
||||
npm install
|
||||
|
||||
- name: Build src code
|
||||
run: npm run build:src
|
||||
@@ -49,6 +51,11 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
||||
|
||||
- name: Generate file MD5
|
||||
run: |
|
||||
cd build
|
||||
Get-FileHash *.exe,*.7z -Algorithm MD5 | Format-List
|
||||
|
||||
Mac:
|
||||
name: Mac
|
||||
runs-on: macos-latest
|
||||
@@ -59,7 +66,7 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14.x'
|
||||
node-version: '16'
|
||||
|
||||
- name: Cache file
|
||||
uses: actions/cache@v2
|
||||
@@ -74,7 +81,9 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: |
|
||||
npm install npm@8.5 -g
|
||||
npm install
|
||||
|
||||
- name: Build src code
|
||||
run: npm run build:src
|
||||
@@ -89,12 +98,17 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
||||
|
||||
- name: Generate file MD5
|
||||
run: |
|
||||
cd build
|
||||
md5 *.dmg
|
||||
|
||||
Linux:
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install package
|
||||
run: sudo apt-get install -y rpm libarchive-tools
|
||||
run: sudo apt-get update && sudo apt-get install -y rpm libarchive-tools
|
||||
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v2
|
||||
@@ -102,7 +116,7 @@ jobs:
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '14.x'
|
||||
node-version: '16'
|
||||
|
||||
- name: Cache file
|
||||
uses: actions/cache@v2
|
||||
@@ -117,7 +131,9 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
run: |
|
||||
npm install npm@8.5 -g
|
||||
npm install
|
||||
|
||||
- name: Build src code
|
||||
run: npm run build:src
|
||||
@@ -134,3 +150,8 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BT_TOKEN: ${{ secrets.BT_TOKEN }}
|
||||
|
||||
- name: Generate file MD5
|
||||
run: |
|
||||
cd build
|
||||
md5sum *.deb *.rpm *.pacman *.AppImage
|
||||
|
||||
14
.ncurc.js
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
upgrade: true,
|
||||
reject: [
|
||||
'electron',
|
||||
'chalk',
|
||||
'del',
|
||||
],
|
||||
// target: 'newest',
|
||||
// filter: [
|
||||
// /^vue/,
|
||||
// 'electron-builder',
|
||||
// 'electron-updater',
|
||||
// ],
|
||||
}
|
||||
19
.vscode/settings.json
vendored
@@ -1,19 +1,14 @@
|
||||
{
|
||||
"path-intellisense.mappings": {
|
||||
"@main/*": "${workspaceFolder}/src/main/*",
|
||||
"@renderer/*": "${workspaceFolder}/src/renderer/*",
|
||||
"@lyric/*": "${workspaceFolder}/src/renderer-lyric/*",
|
||||
"@static/*": "${workspaceFolder}/src/static/*",
|
||||
"@common/*": "${workspaceFolder}/src/common/*",
|
||||
},
|
||||
"i18n-ally.localesPaths": [
|
||||
"src/renderer/lang"
|
||||
"src/lang"
|
||||
],
|
||||
// "i18n-ally.fullReloadOnChanged": true,
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.displayLanguage": "zh-cn",
|
||||
"i18n-ally.sourceLanguage": "zh-cn",
|
||||
"i18n-ally.namespace": true,
|
||||
"i18n-ally.translate.engines": ["google-cn", "google"],
|
||||
"i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
|
||||
"i18n-ally.keystyle": "flat",
|
||||
"i18n-ally.translate.engines": [
|
||||
"google-cn",
|
||||
"google"
|
||||
],
|
||||
"i18n-ally.sortKeys": true
|
||||
}
|
||||
|
||||
409
CHANGELOG.md
@@ -6,6 +6,415 @@ Project versioning adheres to [Semantic Versioning](http://semver.org/).
|
||||
Commit convention is based on [Conventional Commits](http://conventionalcommits.org).
|
||||
Change log format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||
|
||||
## [1.22.2](https://github.com/lyswhut/lx-music-desktop/compare/v1.22.1...v1.22.2) - 2022-08-18
|
||||
|
||||
### 优化
|
||||
|
||||
- 为tx、kw源添加 Flac 24bit 音质显示,注:由于之前没有记录此音质,所以之前收藏的歌曲信息中不包含它
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复无法批量排序歌曲的问题
|
||||
- 修复某些缺失的繁体中文翻译
|
||||
- 修复企鹅音乐搜索失效的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 降级electron到v15.5.7
|
||||
|
||||
## [1.22.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.22.0...v1.22.1) - 2022-07-09
|
||||
|
||||
### 优化
|
||||
|
||||
- 歌单列表添加歌单内歌曲数量显示,注:目前只有kw、mg、wy、tx(部分)源支持显示
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复处于不支持的源时,歌单、排行榜的右键下载菜单没有禁用的问题
|
||||
- 修复若桌面歌词窗口与主窗口重叠时,鼠标划过重叠区域鼠标会闪烁的问题,注:此修复只对未启用“鼠标移入歌词区域时降低歌词透明度”时有效
|
||||
- 修复tx源搜索失效的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 升级Electron到 v17.4.10
|
||||
|
||||
## [1.22.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.21.0...v1.22.0) - 2022-06-19
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增设置-以全屏模式启动设置
|
||||
- 新增设置-桌面歌词设置-鼠标移入歌词区域时降低歌词透明度(#883),默认关闭,此设置不支持linux,注:此功能存在兼容性问题,若鼠标移出后无法恢复到正常透明度,可尝试再移入移出即可恢复
|
||||
|
||||
### 优化
|
||||
|
||||
- 添加歌曲到“我的列表”时,若按住`ctrl`键(Mac对应`Command`),则不会自动关闭添加窗口,这对想要将同一首(一批)歌曲添加到多个列表时会很有用
|
||||
- 支持mg源逐字歌词的播放,感谢 @mozbugbox 提供的帮助
|
||||
- 添加歌曲列表更新操作的二次确认
|
||||
- 添加导入文件错误时的指引提示
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复若配置了`http_proxy`环境变量时,会意外使用此代理配置的问题
|
||||
- 修复多选后切换列表后不会清空多选内容的问题
|
||||
- 修复设置快捷键时的处理逻辑问题
|
||||
- 修复在新建歌单输入框、歌单内歌曲搜索输入框会意外触发设置的全局快捷键的问题(#879)
|
||||
|
||||
### 文档
|
||||
|
||||
桌面版文档已迁移到:<https://lyswhut.github.io/lx-music-doc/desktop>
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新 Electron 到 v17.4.7
|
||||
|
||||
## [1.21.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.20.0...v1.21.0) - 2022-05-22
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增设置-播放设置-显示歌词罗马音,默认关闭,注:目前只有网易源能获取到罗马音歌词(得益于 Binaryify/NeteaseCloudMusicApi/pull/1523),如果你知道其他源的歌词罗马音获取方式,欢迎PR或开issue交流!
|
||||
|
||||
### 优化
|
||||
|
||||
- 同时删除一首歌以上时将需要二次确认删除
|
||||
- 禁用透明窗口时右侧不再偏移5px距离(在win7、Ubuntu等系统上测试发现不偏移也不影响滚动条的拖动了)
|
||||
- 删除未下载完成的任务时,只同时尝试删除已有下载进度的本地文件
|
||||
- 在全屏状态下使用`Esc`键可以退出全屏(#827)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复某些情况下歌曲播放出错时不会自动切歌的问题
|
||||
- 修复关闭“显示切换动画”设置后,在应用启动时该设置没有被应用的问题
|
||||
- 修复原始歌词存在偏移时,歌词偏移设置的重置未按预期工作的问题
|
||||
- 修复长度大于一行的歌词在使用歌词调整播放进度时的时间不准问题
|
||||
- 修复潜在歌单更新失败的问题
|
||||
|
||||
### 文档
|
||||
|
||||
- 将歌曲添加“稍后播放”后,它们会被放在一个优先级最高的特殊队列中,点击“下一曲”时会消耗该队列中的歌曲,并且无法通过“上一曲”功能播放该队列的上一首歌曲
|
||||
- 在切歌时若不是通过“上一曲”、“下一曲”功能切歌(例如直接点击“排行榜列表”、“我的列表”中的歌曲切歌),“稍后播放”队列将会被清空
|
||||
|
||||
## [1.20.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.19.0...v1.20.0) - 2022-04-17
|
||||
|
||||
特别说明:Scheme URL其实是支持Linux系统的,但好像需要deb之类的安装包创建出`.desktop`文件才行。
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增播放详情页歌词右键菜单,原来设置-播放详情页设置的字体重置已迁移到此菜单内
|
||||
- 新增歌词偏移设置,可以在播放详情页歌词右键菜单中使用
|
||||
- 新增设置-播放设置-播放错误时自动切换歌曲设置,默认开启(原来的行为),若你不想在遇到音频加载失败、url获取失败等错误时自动切歌可以关闭此设置
|
||||
- 新增设置-桌面歌词设置-自动刷新歌词置顶(当歌词置顶后仍被某些程序遮挡时可尝试启用此设置)
|
||||
- 新增列表更新管理,可以在鼠标移入“我的列表”标题时出现的按钮中进入,这可以用来设置启动软件时需要自动从原平台更新的列表
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化播放详情页背景显示,现在有背景图片的主题可以在播放详情页显示它的图片了
|
||||
- 播放详情页在全屏状态下仍会显示退出播放详情页按钮,同时在其旁边添加退出全屏按钮
|
||||
- 播放详情页在全屏状态下鼠标在空白处静止不动3秒后自动将其隐藏
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复Linux无法全屏的问题
|
||||
- 修复播放下载列表的歌曲时,使用Windows任务栏缩略图工具栏控制按钮的收藏按钮收藏歌曲时的异常问题
|
||||
- 修复启用搜索历史但不启用热门搜索时,搜索历史不显示的问题
|
||||
- 修复窗口尺寸设置对应的字体大小在启动后不生效的问题
|
||||
- 修复wy源搜索某些歌曲时第一页之后的歌曲无法加载的问题
|
||||
- 修复使用Scheme URL搜索歌曲时,不会自动关闭播放详情页(若处于打开状态)的问题
|
||||
- 修复换源失败时的处理问题
|
||||
- 修复启用代理时,https请求可能被挂起或被转为http的问题
|
||||
- 修复正在下载的歌曲暂停任务后,再开始会导致程序卡死的问题
|
||||
|
||||
### 变更
|
||||
|
||||
- 播放详情页的任意地方右键双击隐藏详情页的行为,“任意区域”改为在“非歌词区域”
|
||||
|
||||
### 移除
|
||||
|
||||
- 移除设置-播放详情页设置-歌词字体重置,此设置项已迁移到播放详情页的歌词菜单中
|
||||
- 移除播放详情页使用+-快捷键调整字体大小的功能,改用歌词右键菜单的字体大小调整功能
|
||||
|
||||
## [1.19.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.18.0...v1.19.0) - 2022-03-20
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增对播放详情页歌词大小、是否缩放、对齐方式的设置,可以去设置-播放详情页设置查看
|
||||
- 新增播放详情页通过歌词调整播放进度,默认关闭,需要到设置-播放详情页设置开启,开启后在播放详情页拖动歌词时将会出现跳转当前行歌词播放的按钮
|
||||
- 新增全屏状态,按F11可以进入、退出全屏状态,由于全屏时会隐藏控制栏按钮,所以需要使用鼠标右键双击(详情页的任意地方都可以)来关闭播放详情页
|
||||
- 新增动态主题“道法自然”,你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。注:鼠标 右击 此主题项即可打开亮、暗色主题设置窗口。
|
||||
- 新增对kw源卡拉OK歌词的支持
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化Windows任务栏缩略图工具栏控制按钮在浅色任务栏下的显示效果
|
||||
- 添加音频可视化与音频输出设备冲突的提示
|
||||
- 优化歌词的播放偏移
|
||||
- 优化托盘菜单操作(#686)
|
||||
- 优化播放下载列表时的切歌性能
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复“当前的声音输出设备被改变时暂停播放歌曲”设置无效的问题
|
||||
- 修复桌面歌词没有处理停止播放状态的问题
|
||||
- 修复AppImage包无法运行的问题
|
||||
- 修复Windows任务栏缩略图工具栏控制按钮的歌曲收藏按钮状态更新问题
|
||||
- 修复使用链接导入的歌单无法在我的列表打开原歌单详情页的问题
|
||||
- 修复播放下载列表的歌曲时增删下载任务导致正在的歌曲序号改变时,不会更新到新增序号的问题
|
||||
|
||||
### 文档
|
||||
|
||||
添加LX中定义的快捷操作汇总说明到常见问题中,这是目前可用的鼠标、键盘快捷操作,它们都可以在更新日志中找到
|
||||
|
||||
- 鼠标右击播放栏的歌曲图片封面可以定位当前播放的歌曲
|
||||
- 鼠标右击播放栏进度条上的LRC按钮可以锁定/解锁桌面歌词
|
||||
- 歌曲搜索框、歌单链接输入框内鼠标右击可以将当前剪贴板上的文字粘贴到输入框内
|
||||
- 鼠标右击搜索界面中的单条搜索历史可以将其移除
|
||||
- 歌曲列表内的文字在选中后,鼠标右击可以复制已选中的文字,此功能只对搜索、歌单、排行榜、我的列表中的列表有效
|
||||
- 鼠标在播放详情页内右键双击可以关闭播放详情页
|
||||
- 鼠标左击播放栏上的歌曲名字可以将它复制
|
||||
- 鼠标右击“道法自然(英文Auto)”主题可以打开亮、暗主题设置窗口
|
||||
- 歌曲搜索框的候选内容可以用键盘上下方向键选择,按回车键搜索已选内容
|
||||
- 在歌单详情页按退格键可以返回歌单列表
|
||||
- 歌曲列表中可以使用Ctrl、Shift键进行多选,这类似Windows下的文件选择,详情看常见问题列表多选部分
|
||||
- 在我的列表内可以使用Ctrl+f键打开搜索框进行列表内歌曲搜索,搜索框按Esc键可以关闭搜索框,搜索框内按上下方向键可以选择歌曲,按回车键跳转到已选歌曲,按Ctrl+回车可以跳转并播放已选歌曲
|
||||
- 在我的列表按住Ctrl键可以进入列表拖动模式,此时可以用鼠标拖动列表调整列表的位置
|
||||
- 编辑列表名时按Esc键可以取消编辑
|
||||
- 按F11可以进入、退出全屏状态
|
||||
|
||||
## [1.18.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.17.1...v1.18.0) - 2022-02-26
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增“双击列表里的歌曲时自动切换到当前列表播放”设置,此功能仅对歌单、排行榜有效,默认关闭
|
||||
- 新增打开收藏的在线列表的对应平台详情页功能,可以在我的列表-列表右键菜单中使用
|
||||
- 新增定时暂停播放功能,由于此功能大多数人可能不常用,所以将其放在设置-基本设置中
|
||||
- 新增任务栏缩略图工具栏控制按钮(此功能仅在Windows平台可用),按钮分别为收藏/取消收藏(将歌曲添加到“我的收藏”列表)、上一曲、播放/暂停、下一曲
|
||||
- 新增设置-基本设置-软件字体设置,此设置可用于设置主界面的字体(已知的问题:Windows 7 下可能会出现字体列表为空的情况,这是当前系统的 Powershell 版本小于5.1导致的,请自行尝试看常见解决)
|
||||
- 新增Scheme URL对音乐搜索的调用支持,详情看常见问题-Scheme URL支持
|
||||
- 新增Scheme URL以url传参的方式调用,详情看常见问题-Scheme URL支持
|
||||
- 自定义源新增更新弹窗方法,同时自定义源管理新增是否允许源显示更新弹窗设置(出于防止滥用考虑),当源作者想要通知用户源已更新时,可以调用此方法弹窗告诉用户,调用说明看常见问题-自定义源部分
|
||||
|
||||
### 优化
|
||||
|
||||
- 过滤tx源某些不支持播放的歌曲,解决播放此类内容会导致意外的问题
|
||||
- 把歌曲的热门评论与最新评论拆分成两个列表显示
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复排行榜名字右击菜单的播放功能在播放非激活的列表时的列表获取问题
|
||||
- 修复修改列表名时无法使用`Ctrl`键的问题
|
||||
- 修复wy源某些歌曲获取歌词翻译的问题处理
|
||||
- 修复下载功能的歌词换源时会进入死循环的问题
|
||||
- 修复某些歌曲无法下载的问题
|
||||
- 修复windows平台下软件目录存在`portable`文件夹时,仍会创建`C:\Users\<user>\AppData\Roaming\lx-music-desktop\Dictionaries\en-US-9-0.bdic`文件的问题,现在不会再创建文件,但仍会创建空目录(Electron的问题,目前暂无解决方法)
|
||||
- 修复播放器的停止逻辑问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到v13.6.9
|
||||
|
||||
## [1.17.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.17.0...v1.17.1) - 2022-01-28
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化kw源英文与翻译歌词的匹配
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复快捷键与默认按键行为冲突的问题,现在若将某些有默认行为的按键(如在列表中上、下箭头、Home、End等键可以使列表滚动)设置为快捷键时,将禁用其默认行为
|
||||
- 修复列表的聚焦问题,现在在列表中使用上、下箭头、空格等键滚动列表时不会导致滚动到一定距离后丢失焦点的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到v13.6.8
|
||||
|
||||
## [1.17.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.16.0...v1.17.0) - 2022-01-22
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增“便携”功能,在Windows平台下,若程序目录下存在 portable 目录,则自动使用此目录作为数据存储目录
|
||||
- 新增 Scheme URL 支持,同时发布lx-music-script项目配合使用(一个油猴脚本,可以在浏览器中的官方平台网页直接调用LX Music),Scheme URL的调用说明看Readme.md文档的Scheme URL支持部分
|
||||
- 新增启动参数`-proxy-server`与`-proxy-bypass-list`,详细介绍看Readme.md文档的启动参数部分
|
||||
- 新增桌面歌词是否延迟滚动设置,默认开启,若你不想要桌面歌词延迟滚动可以去设置-桌面歌词设置关掉
|
||||
|
||||
### 优化
|
||||
|
||||
- 为可视化音频的频谱整体添加频谱均值加成,使频谱显示更有节奏感
|
||||
- 优化程序初始化逻辑,修复无网络的情况下的初始化问题
|
||||
- 我的列表-列表名的右击菜单更新已收藏的在线列表时,将始终重新加载,不再使用缓存,解决在原平台更新歌单后,在LX点击更新可能看到的还是在原平台更新前的歌单的问题
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复代理不生效的问题
|
||||
- 修复`openDevTools`选项无效的问题
|
||||
- 修复播放状态的提示问题
|
||||
- 修复tx源无搜索结果的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新 Electron 到 v13.6.7
|
||||
|
||||
## [1.16.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.15.3...v1.16.0) - 2022-01-01
|
||||
|
||||
这算是一个大版本,对主窗口部分的代码逻辑做了较大改动,但由于界面的改动不大,所以没有更新大版本号。
|
||||
虽然经过一个月的测试与问题修复,但可能仍然存在未发现的问题,若你发现某些界面异常、某些行为与旧版本存在差异等问题,欢迎反馈!
|
||||
另外祝大家元旦快乐~!
|
||||
|
||||
### 新增
|
||||
|
||||
- 播放详情页新增音量控制条
|
||||
- 播放详情页新增桌面歌词切换按钮
|
||||
- 新增将我的列表保存为TXT、CSV格式,可以去设置-备份与恢复中使用(注意:此类格式的备份目前不支持恢复到LX Music中)
|
||||
- 新增根据歌曲名、歌手名等字段对列表自动排序的功能,可以在我的列表右击列表名弹出的菜单中使用
|
||||
- 新增将播放与下载的歌词转换为繁体中文选项,默认关闭,可在设置-播放设置中开启
|
||||
- 现在已允许进入临时播放列表,即:使用歌单详情页、排行榜名称右键菜单的“播放”按钮播放歌曲时,可右击播放封面进入此临时列表
|
||||
- 播放详情页新增音频可视化功能(实验性)
|
||||
- 我的列表新增拖动调整位置功能,按住Ctrl键(Mac上对应Command键)的时候将进入“拖动模式”,此时可以拖动列表的位置来调整顺序
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化列表性能,软件整体性能
|
||||
- 调整Mac平台下的图标大小
|
||||
- 同步功能添加对列表顺序调整的控制,确保手动调整位置后的列表与不同的电脑同步时,列表位置不会被还原
|
||||
- 优化歌单详情、排行榜名右键的播放按钮的播放机制,现在不用等待整个列表(多页时)加载完成才能播放了
|
||||
- 为播放详情页、桌面歌词添加延迟滚动,播放详情页略微减小已激活歌词的缩放大小及桌面歌词翻译大小
|
||||
- 修改右边控制按钮为windows风格
|
||||
- 更新了新年皮肤的背景与配色,欢迎体验~
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复kw源某些歌曲的歌词提取异常的问题
|
||||
|
||||
### 变更
|
||||
|
||||
- 现在使用繁体中文语言时将不再自动转换歌词,转换行为将由上面新增的转换开关控制
|
||||
|
||||
### 移除
|
||||
|
||||
- 移除我的列表右键菜单的“上移、下移列表”功能,调整改用新增的拖动功能去调整位置
|
||||
|
||||
### 其他
|
||||
|
||||
- 升级vue到 3.x
|
||||
|
||||
## [1.15.3](https://github.com/lyswhut/lx-music-desktop/compare/v1.15.2...v1.15.3) - 2021-11-21
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复设置-控制按钮位置选项与下载歌词编码格式选项命名冲突导致选项显示异常的问题
|
||||
- 修复播放下载列表时存在失效的歌曲会导致切歌不准确的问题
|
||||
- 修复潜在的音乐加载超时不会切歌的问题
|
||||
- 修复因kw源歌词接口停用导致该源歌词获取失败的问题
|
||||
|
||||
## [1.15.2](https://github.com/lyswhut/lx-music-desktop/compare/v1.15.3...v1.15.2) - 2021-11-09
|
||||
|
||||
### 其他
|
||||
|
||||
- 降级electron到v13.4.0(这修复了windows 7下播放歌曲时软件会崩溃的问题)
|
||||
|
||||
## [1.15.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.15.0...v1.15.1) - 2021-11-09
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化我的列表、下载列表等列表的滚动流畅度
|
||||
- 优化下载功能的批量添加、删除、暂停任务时的流畅度,现在进行这些操作应该不会再觉得卡顿了
|
||||
- 支持启动软件时恢复播放下载列表里的歌曲
|
||||
- 添加媒体播放进度条的信息设置
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复某些情况下获取URL失败时会意外切歌的问题
|
||||
- 修复了某些情况下会列表同步失败,导致连接断开无限重连或一直卡在 `syncing...` 的问题
|
||||
- 修复列表数据过大导致同步失败的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到v15.3.1(这修复了媒体控制失效的问题)
|
||||
|
||||
## [1.15.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.14.1...v1.15.0) - 2021-10-29
|
||||
|
||||
### 新增
|
||||
|
||||
- 添加黑色托盘图标
|
||||
- 自定义源新增`version`字段,新增`utils.buffer.bufToString`方法
|
||||
|
||||
### 优化
|
||||
|
||||
- 大幅优化我的列表、下载、歌单、排行榜列表性能,现在即使同一列表内的歌曲很多时也不会卡顿了
|
||||
- 优化列表同步代码逻辑
|
||||
- 优化开关评论时的动画性能
|
||||
- 优化进入、离开播放详情页的性能
|
||||
- 兼容桌面歌词以触摸的方式移动、调整大小
|
||||
- 调整图标尺寸
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复kg源的歌单链接无法打开的问题
|
||||
- 修复同一首歌的URL、歌词等同时需要换源时的处理问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新 Electron 到 v15.3.0
|
||||
|
||||
## [1.14.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.14.0...v1.14.1) - 2021-10-04
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复我的列表搜索无法搜索小括号、中括号等字符的问题
|
||||
- 修复v1.14.0出现的备份与恢复功能备份的数据无法恢复的问题,同时兼容使用v1.14.0导出的存在问题的数据
|
||||
|
||||
## [1.14.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.13.0...v1.14.0) - 2021-10-02
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增歌词简体中文转繁体中文,当软件语言被设置为繁体中文后,播放歌曲的歌词也将自动转成繁体中文显示
|
||||
- 新增单个列表导入/导出功能,可以方便分享歌曲列表,可在右击“我的列表”里的列表名后弹出的菜单中使用
|
||||
- 新增删除列表前的确认弹窗,防止误删列表
|
||||
- 新增歌词文本选择复制功能,可在详情页进度条上方的歌词文本选择按钮进入歌词文本选择模式,选择完成后可鼠标右击或者使用系统快捷键复制
|
||||
- 新增重复歌曲列表,可以方便移除我的列表中的重复歌曲,此列表会列出目标列表里歌曲名相同的歌曲,可在右击“我的列表”里的列表名后弹出的菜单中使用
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复mg排行榜无法加载的问题
|
||||
- 修复点击播放详情页的进度条跳进度时会出现偏移的问题
|
||||
- 修复在有提示信息的地方长按鼠标按键时提示信息会闪烁的问题
|
||||
- 修复下载歌曲时的歌词下载不尝试获取缓存歌词的问题
|
||||
- 修复GNOME等桌面下每次打开应用时需重新设置歌词窗口置顶的问题
|
||||
|
||||
## [1.13.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.12.2...v1.13.0) - 2021-09-05
|
||||
|
||||
如果你喜欢并经常使用洛雪音乐,并想要第一时间尝鲜洛雪的新功能,可以加入测试企鹅群768786588,
|
||||
注意:测试版的功可能会不稳定,打算潜水的勿加。
|
||||
|
||||
### 新增
|
||||
|
||||
- 歌曲搜索框新增清理按钮,点击此按钮可以清理搜索框并返回初始搜索界面
|
||||
- 新增“下载的歌词文件编码格式”设置,默认下载的歌词编码仍是`UTF-8`,对于某些在设备(如车机)上出现歌词中文乱码的用户可以尝试选择以`GBK`编码格式保存歌词文件
|
||||
- 新增设置-桌面歌词-歌词字体设置,此设置可用于设置桌面歌词的字体(已知的问题:Windows 7 下可能会出现字体列表为空的情况,这是当前系统的 Powershell 版本小于5.1导致的,请自行**尝试**看常见解决)
|
||||
|
||||
### 优化
|
||||
|
||||
- 支持网易源“我喜欢”歌单以注入token的方式打开。由于网易源的“我喜欢”歌单需要登录才能打开(若你看不懂后半句就去阅读 常见问题-无法打开外部歌单),现若想要打开此类歌单,需要在歌单链接后面拼上 `###` 再加上有效的token,拼接格式:`[id|url]###token`,例子(最后面的xxxxxx替换成你的token):`https://music.163.com/#/playlist?id=123456&userid=123456###xxxxxx`
|
||||
- 软件内快捷键的最小化触发时,如果已启用托盘,则隐藏程序,否则最小化程序
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复某些情况下同步功能会导致切歌混乱的问题
|
||||
- 修复从电脑浏览器复制的企鹅歌单链接无法打开的问题
|
||||
|
||||
## [1.12.2](https://github.com/lyswhut/lx-music-desktop/compare/v1.12.1...v1.12.2) - 2021-08-11
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复播放下载列表的歌曲时切歌的问题
|
||||
- 修复播放下载列表的歌曲时歌词无法显示的问题
|
||||
- 修复下载列表稍后播放功能无效的问题
|
||||
- 修复同步服务器启动失败时,关闭同步服务不会清空失败信息的问题
|
||||
|
||||
## [1.12.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.12.0...v1.12.1) - 2021-08-08
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复随机播放下无法切歌的问题
|
||||
|
||||
## [1.12.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.11.0...v1.12.0) - 2021-08-08
|
||||
|
||||
### 新增
|
||||
|
||||
311
FAQ.md
@@ -1,11 +1,45 @@
|
||||
# lx-music-desktop 常见问题
|
||||
|
||||
本文档已迁移到:<https://lyswhut.github.io/lx-music-doc/desktop/faq>
|
||||
|
||||
在阅读本常见问题后,仍然无法解决你的问题,请提交issue或者加企鹅群`830125506`反馈(无事勿加,入群先看群公告),反馈时请**注明**已阅读常见问题!
|
||||
|
||||
## ~~软件为什么没有桌面歌词与自定义列表功能~~
|
||||
|
||||
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用。
|
||||
|
||||
## 音乐播放列表机制
|
||||
|
||||
1. 默认情况下,播放搜索列表、歌单列表、排行榜列表的歌曲时会自动将该歌曲添加到“我的列表”的试听列表后再播放,这与手动将歌曲添加到试听列表,再去试听列表找到这首歌点播放是等价的
|
||||
2. 如果你想要播放多首歌曲,需要使用多选功能(若不知道如何多选请看常见问题)多选后,将这些歌曲添加到“我的列表”播放,或使用稍后播放功能播放
|
||||
3. 第2条适用于搜索列表、歌单列表、排行榜列表、我的列表中的歌曲
|
||||
4. 对于歌单详情列表,除了可以使用第2条的方式播放外,你可以点击详情页上面的播放按钮临时播放当前歌单,或点击收藏将当前歌单收藏到“我的列表”后再去播放
|
||||
5. 对于排行榜详情列表,除了可以使用第2条的方式播放外,你可以在右击排行榜名字后弹出的菜单中,播放或收藏整个排行榜,这与第四条的歌单中的播放、与收藏按钮功能一致
|
||||
6. v1.18.0及之后新增了“双击列表里的歌曲时自动切换到当前列表播放”设置,默认关闭,此功能仅对歌单、排行榜有效
|
||||
7. 将歌曲添加“稍后播放”后,它们会被放在一个优先级最高的特殊队列中,点击“下一曲”时会消耗该队列中的歌曲,并且无法通过“上一曲”功能播放该队列的上一首歌曲
|
||||
8. 在切歌时若不是通过“上一曲”、“下一曲”功能切歌(例如直接点击“排行榜列表”、“我的列表”中的歌曲切歌),“稍后播放”队列将会被清空
|
||||
|
||||
## 可用的鼠标、键盘快捷操作
|
||||
|
||||
- 鼠标右击播放栏的歌曲图片封面可以定位当前播放的歌曲
|
||||
- 鼠标右击播放栏进度条上的`LRC`按钮可以锁定/解锁桌面歌词
|
||||
- 歌曲搜索框、歌单链接输入框内鼠标右击可以将当前剪贴板上的文字粘贴到输入框内
|
||||
- 鼠标右击搜索界面中的单条搜索历史可以将其移除
|
||||
- 歌曲列表内的文字在选中后,鼠标右击可以复制已选中的文字,此功能只对搜索、歌单、排行榜、我的列表中的列表有效
|
||||
- 鼠标在播放详情页内右键双击可以关闭播放详情页
|
||||
- 鼠标左击播放栏上的歌曲名字可以将它复制
|
||||
- 鼠标右击设置-主题设置的“道法自然(英文Auto)”主题可以打开亮、暗主题设置窗口
|
||||
- 歌曲搜索框的候选内容可以用键盘上下方向键选择,按回车键搜索已选内容
|
||||
- 在歌单详情页按退格键可以返回歌单列表
|
||||
- 歌曲列表中可以使用`Ctrl`、`Shift`键进行多选,这类似Windows下的文件选择,详情看常见问题列表多选部分
|
||||
- 在我的列表内可以使用`Ctrl + f`键打开搜索框进行列表内歌曲搜索,搜索框按`Esc`键可以关闭搜索框,搜索框内按上下方向键可以选择歌曲,按`回车`键跳转到已选歌曲,按`Ctrl + 回车`可以跳转并播放已选歌曲
|
||||
- 在我的列表按住`Ctrl`键可以进入列表拖动模式,此时可以用鼠标拖动列表调整列表的位置
|
||||
- 编辑列表名时按`Esc`键可以取消编辑
|
||||
- 按`F11`可以进入、退出全屏状态(v1.19.0新增)
|
||||
- 在歌曲添加弹窗中,若按住`Ctrl`键后再点击列表名,将不会自动关闭添加窗口,这对想要将同一首(一批)歌曲添加到多个列表时会很有用(v1.22.0新增)
|
||||
|
||||
注:在macOS上`Ctrl`键对应`Command`键
|
||||
|
||||
## 歌曲无法试听与下载
|
||||
|
||||
### 所有歌曲都提示 `请求异常😮,可以多试几次,若还是不行就换一首吧。。。`
|
||||
@@ -19,7 +53,7 @@
|
||||
若网页无法打开或打开来不是404,则可能是DNS的问题,可以尝试以下办法:
|
||||
|
||||
1. 将DNS改成自动获取试试(注:改完可能需要清理下系统DNS缓存才生效)
|
||||
2. 手动把DNS改一下,不要用360的DNS,可以把DNS改成`114.114.114.114`、`8.8.8.8`(注:改完可能需要清理下系统DNS缓存才生效)
|
||||
2. 手动把DNS改一下,不要用360的DNS,可以把DNS改成`223.6.6.6`、`8.8.8.8`(注:改完可能需要清理下系统DNS缓存才生效)
|
||||
|
||||
改完DNS后可能需要重启软件才生效
|
||||
|
||||
@@ -38,7 +72,17 @@
|
||||
若网页无法打开或打来不是404,则应该是DNS的问题,可以尝试以下办法:
|
||||
|
||||
1. 将DNS改成自动获取试试
|
||||
2. 手动把DNS改一下,不要用360的DNS,可以把DNS改成`114.114.114.114`、`8.8.8.8`
|
||||
2. 手动把DNS改一下,不要用360的DNS,可以把DNS改成`223.6.6.6`、`8.8.8.8`
|
||||
|
||||
### Windows版所有歌曲都提示 `音频加载错误,5秒后切换下一首`
|
||||
|
||||
尝试关闭 Internet选项 的代理设置。
|
||||
|
||||
如果你不知道怎么做,可以尝试按以下步骤去做:
|
||||
|
||||
按<kbd>windows</kbd>+<kbd>r</kbd>键打开“运行”窗口,输入`inetcpl.cpl`后回车,在打开的 Internet选项 对话框中,切换到 连接 -> 局域网设置,在弹出的新窗口中把代理服务器下的勾去掉,如果自动配置下的勾也有被勾选,那么建议也去掉,最后按确定关闭所有弹窗。
|
||||
|
||||
> 来源:<https://github.com/lyswhut/lx-music-desktop/issues/873#issuecomment-1146945724>
|
||||
|
||||
## 列表多选
|
||||
|
||||
@@ -56,105 +100,44 @@
|
||||
|
||||
播放在线列表内的歌曲需要将它们都添加到我的列表才能播放,你可以全选列表内的歌曲然后添加到现有列表或者新创建的列表,然后去播放该列表内的歌曲。
|
||||
|
||||
从v1.10.0起,你可以右击排行榜名字的弹出菜单中直接播放或收藏整个排行榜的歌曲。
|
||||
|
||||
## 无法打开外部歌单
|
||||
|
||||
不支持垮源打开歌单,请**确认**你需要打开的歌单平台是否与软件标签所写的**歌单源**对应(不一样的话请通过右上角切换歌单源);<br>
|
||||
不支持跨源打开歌单,请**确认**你需要打开的歌单平台是否与软件标签所写的**歌单源**对应(不一样的话请通过右上角切换歌单源);<br>
|
||||
对于分享出来的歌单,若打开失败,可尝试先在浏览器中打开后,再从浏览器地址栏复制URL地址到软件打开;<br>
|
||||
或者如果你知道歌单 id 也可以直接输入歌单 id 打开。<br>
|
||||
|
||||
注:网易源的“我喜欢”歌单无法在未登录的情况下打开,所以你需要手动创建一个歌单后将“我喜欢”里的歌曲移动到该歌单打开
|
||||
|
||||
## 界面异常(界面显示不完整)
|
||||
### 打开网易源“我喜欢”歌单
|
||||
|
||||
### Windows 7 下界面异常
|
||||
由于网易源的“我喜欢”歌单需要登录才能打开,从v1.13.0起提供了可以以注入token的方式打开网易源“我喜欢”歌单的功能,现若想要打开此类歌单,需要在歌单链接或id后面拼上 `###` 再加上有效的token,拼接格式:`[id|url]###token`,例子(最后面的xxxxxx替换成你的token):
|
||||
- `https://music.163.com/#/playlist?id=11332&userid=123456###xxxxxx`
|
||||
- `11332###xxxxxx`
|
||||
|
||||
由于软件默认使用了透明窗口,根据Electron官方文档的[说明](https://electronjs.org/docs/api/frameless-window#%E5%B1%80%E9%99%90%E6%80%A7):
|
||||
> 在 windows 操作系统上, 当 DWM 被禁用时, 透明窗口将无法工作。
|
||||
即:将 `歌单链接或者歌单ID`、`###`、`token` 这三者拼到一起。
|
||||
|
||||
因此,当 win7 没有使用**AERO**主题时界面将会显示异常,开启AERO的方法请自行百度:`win7开启aero效果`(开启后可看到任务栏变透明)。<br>
|
||||
从`0.14.0`版本起不再强制要求开启透明效果,若你实在不想开启(若非电脑配置太低,墙裂建议开启!),可通过添加运行参数`-dt`来运行程序即可,例如:`.\lx-music-desktop.exe -dt`,添加方法可自行百度“给快捷方式加参数”,该参数的作用是用来控制程序是否使用非透明窗口运行。
|
||||
#### `token`的获取方法
|
||||
|
||||
注:启用**AERO**主题后,若软件出现黑边框,则重启软件即可恢复正常。
|
||||
**注:`token`是你账号的临时身份令牌,不要随便泄露给他人**<br>
|
||||
在浏览器打开登录网易云音乐并**登录**后,按`F12`,此时将会打开开发者窗口,然后按你使用的浏览器操作:
|
||||
|
||||
对于一些完全无法正常显示界面、开启了AERO后问题仍未解决的情况,请阅读下面的 **软件启动后,界面无法显示** 解决。
|
||||
##### Chrome、360、QQ等浏览器
|
||||
|
||||
这些浏览器打开此窗口时界面可能是中文也可能是英文,英文的话按括号里的来
|
||||
|
||||
# lx-music-mobile 常见问题
|
||||
1. 点击窗口顶部`应用程序(application)`(若找不到此选项,则可能是被折叠起来了,看看顶部菜单的`>>`)
|
||||
2. 展开左侧 `Cookies`
|
||||
3. 点击 `https://music.163.com`
|
||||
4. 在右侧窗口找到 `名称(Name)` 为 `MUSIC_U` 的这行,这行的第二列(`值(Value)`)内的那串内容就是`token`,双击它进入编辑状态,然后按`ctrl + c`键就可以将它复制
|
||||
|
||||
在阅读本常见问题后,仍然无法解决你的问题,请提交issue或者加企鹅群`830125506`反馈(无事勿加,入群先看群公告),反馈时请**注明**已阅读常见问题!
|
||||
##### 火狐浏览器
|
||||
|
||||
## 歌曲无法试听与下载
|
||||
|
||||
### 所有歌曲都提示 `请求异常😮,可以多试几次,若还是不行就换一首吧。。。`
|
||||
|
||||
尝试更换网络,如切换到移动网络,若移动网络还是不行则尝试开关下手机的飞行模式后再试,<br>
|
||||
若使用家庭网络的话,可尝试将光猫断电5分钟左右再通电联网后播放。
|
||||
|
||||
### 其他情况
|
||||
|
||||
尝试在在浏览器打开这个地址`http://ts.tempmusic.tk`,浏览器显示404是正常的,如果不是404那就证明所在网络无法访问接口服务器,对于此类情况请尝试切换其他网络。
|
||||
|
||||
### 通用解决方法
|
||||
|
||||
尝试按以下顺序解决:
|
||||
|
||||
1. 尝试更新到最新版本
|
||||
2. 尝试切换其他歌曲(或直接搜索该歌曲),若全部歌曲都无法试听与下载则进行下一步
|
||||
3. 尝试到 设置-音乐来源 切换到其他接口
|
||||
4. 尝试切换网络,比如用手机开热点(所有歌曲都提示请求异常时可通过此方法解决,或等一两天后再试)
|
||||
5. 若还不行请到这个链接查看详情:<https://github.com/lyswhut/lx-music-desktop/issues/5>
|
||||
6. 若没有在第5条链接中的第一条评论中看到接口无法使用的说明,则应该是你网络无法访问接口服务器的问题,如果接口有问题我会在那里说明。
|
||||
|
||||
想要知道是不是自己网络的问题可以看看`http://ts.tempmusic.tk`能不能在浏览器打开,浏览器显示404是正常的,如果不是404那就证明所在网络无法访问接口服务器。
|
||||
若网页无法打开或打来不是404,则应该是DNS的问题,可以尝试以下办法:
|
||||
|
||||
1. 将DNS改成自动获取试试
|
||||
2. 手动把DNS改一下,不要用360的DNS,可以把DNS改成`114.114.114.114`、`8.8.8.8`
|
||||
|
||||
## 列表多选
|
||||
|
||||
长按列表将会进入多选模式。
|
||||
|
||||
- 例子一:想要选中1-5项,进入多选模式后,取消所有选中的内容,切换到区间,点击第一项,再点击第五项即可完成选择;
|
||||
- 例子二:想要选中1项与第3项,进入多选模式后,点击第一项,再点击第三项即可完成选择;
|
||||
- 例子三:想要选中当前列表的全部内容,进入多选模式后,点击全选即可完成选择(注:由于**在线列表**使用分页加载,全选只会选择目前已加载的内容,若要完整选择整个在线列表的内容则需要往下滑动将列表加载完毕再进行全选)。
|
||||
|
||||
注:选完后可用歌曲列表三个点的菜单操作已选的内容
|
||||
|
||||
## 无法打开外部歌单
|
||||
|
||||
不支持垮源打开歌单,请**确认**你需要打开的歌单平台是否与软件标签所写的**歌单源**对应(不一样的话请通过右上角切换歌单源);<br>
|
||||
对于分享出来的歌单,若打开失败,可尝试先在浏览器中打开后,再从浏览器地址栏复制URL地址到软件打开;<br>
|
||||
或者如果你知道歌单 id 也可以直接输入歌单 id 打开。<br>
|
||||
|
||||
注:网易源的“我喜欢”歌单无法在未登录的情况下打开,所以你需要手动创建一个歌单后将“我喜欢”里的歌曲移动到该歌单打开
|
||||
|
||||
## 播放整个歌单或排行榜
|
||||
|
||||
播放在线列表内的歌曲需要将它们都添加到我的列表才能播放,你可以全选列表内的歌曲然后添加到现有列表或者新创建的列表,然后去播放该列表内的歌曲。
|
||||
|
||||
## 无法打开外部歌单
|
||||
|
||||
不支持垮源打开歌单,请**确认**你需要打开的歌单平台是否与软件标签所写的**歌单源**对应(不一样的话请通过右上角切换歌单源);<br>
|
||||
对于分享出来的歌单,若打开失败,可尝试先在浏览器中打开后,再从浏览器地址栏复制URL地址到软件打开;<br>
|
||||
或者如果你知道歌单 id 也可以直接输入歌单 id 打开。<br>
|
||||
|
||||
|
||||
## 同步功能的使用(实验性,首次使用前建议先备份一次列表)
|
||||
|
||||
**注意:由于同步传输时的数据是明文传输,请在受信任的网络下使用此功能!**<br>
|
||||
此功能需要配合PC端使用,移动端与PC端处在同一个局域网(路由器的网络)下时,可以多端实时同步歌曲列表,使用方法:
|
||||
|
||||
1. 在PC端的设置-数据同步开启同步功能(这时如果出现安全软件、防火墙等提示网络连接弹窗时需要点击允许)
|
||||
2. 在移动端的设置-同步-同步服务器地址输入PC端显示的同步服务器地址(如果显示可以多个,则输入与**移动端上显示的本机地址**最相似的那个),端口号与PC端的同步端口一致
|
||||
3. 输入完这两项后点击“启动同步”
|
||||
4. 若连接成功,对于首次同步时,若两边的设备的列表不为空,则PC端会弹出选择列表同步方式的弹窗,同步方式的说明弹窗下面有介绍
|
||||
|
||||
对于连接同步失败的可能原因:
|
||||
|
||||
- 此功能需要PC端与移动端都连接在同一个路由器下的网络才能使用
|
||||
- 路由器若开启了AP隔离,则此功能无法使用
|
||||
- 检查防火墙是否拦截了PC端的服务端口
|
||||
1. 点击窗口顶部`存储`
|
||||
2. 展开左侧 `Cookie`
|
||||
3. 点击 `https://music.163.com`
|
||||
4. 在右侧窗口找到 `名称` 为 `MUSIC_U` 的这行,这行的最后一列(`值`)内的那串内容就是`token`,双击它进入编辑状态,然后按`ctrl + c`键就可以将它复制
|
||||
|
||||
## 更新已收藏的在线歌单
|
||||
|
||||
@@ -162,14 +145,50 @@
|
||||
|
||||
需要注意的是:这将会覆盖本地的目标列表,歌曲将被替换成最新的在线列表。
|
||||
|
||||
## 杀毒软件提示有病毒或恶意行为
|
||||
## 调整我的列表的列表顺序
|
||||
|
||||
本人只能保证我写的代码不包含任何**恶意代码**、**收集用户信息**的行为,并且软件代码已开源,请自行查阅,软件安装包也是由CI拉取源代码构建,构建日志:[GitHub Actions](https://github.com/lyswhut/lx-music-mobile/actions)<br>
|
||||
尽管如此,但这不意味着软件是100%安全的,由于软件使用了第三方依赖,当这些依赖存在恶意行为时([供应链攻击](https://docs.microsoft.com/zh-cn/windows/security/threat-protection/intelligence/supply-chain-malware)),软件也将会受到牵连,所以我只能尽量选择使用较多人用、信任度较高的依赖。<br>
|
||||
当然,以上说明建立的前提是在你所用的安装包是从**本项目主页上写的链接**下载的,或者有相关能力者还可以下载源代码自己构建安装包。
|
||||
按住Ctrl键(Mac上对应Command键)的时候将进入“拖动模式”,此时可以拖动列表的位置来调整顺序。
|
||||
|
||||
最后,若出现杀毒软件报毒、存在恶意行为,请自行判断选择是否继续使用本软件!
|
||||
## 同步功能的使用(实验性,首次使用前建议先备份一次列表)
|
||||
|
||||
**注意:由于同步传输时的数据是明文传输,请在受信任的网络下使用此功能!**<br>
|
||||
此功能需要配合移动端使用,PC端与移动端处在同一个局域网(路由器的网络)下时,可以多端实时同步歌曲列表,使用方法:
|
||||
|
||||
1. 在PC端的设置-数据同步开启同步功能(这时如果出现安全软件、防火墙等提示网络连接弹窗时需要点击允许)
|
||||
2. 在移动端的设置-同步-同步服务器地址输入PC端显示的同步服务器地址(如果显示可以多个,则输入与**移动端上显示的本机地址**最相似的那个),端口号与PC端的同步端口一致(**输入完毕后需要按一下键盘上的回车键使输入的内容生效**)
|
||||
3. 输入完这两项后点击“启动同步”
|
||||
4. 若连接成功,对于首次同步时,若两边的设备的列表不为空,则PC端会弹出选择列表同步方式的弹窗,同步方式的说明弹窗下面有介绍
|
||||
|
||||
#### 关于同步弹窗的说明
|
||||
|
||||
对于首次同步时,若两边的设备的列表不为空,则PC端会弹出选择列表同步方式的弹窗,此弹窗内的同步方式仅针对**首次同步**,<br>
|
||||
第一次同步成功后,以后再同步时将会自动根据两边设备的列表内容合并同步,不信你可以在同步完成后断开两边的连接,然后在两边增删一些歌曲或列表后再同步试试看~😉
|
||||
|
||||
#### 连接同步服务失败的可能原因
|
||||
|
||||
- 此功能需要PC端与移动端都连接在同一个路由器下的网络才能使用
|
||||
- 检查防火墙是否拦截了PC端的服务端口
|
||||
- 路由器若开启了AP隔离,则此功能无法使用
|
||||
|
||||
#### 连接同步服务失败的检查
|
||||
|
||||
1. 确保PC端的同步服务已启用成功(若连接码、同步服务地址没有内容,则证明服务启动失败,此时看启用同步功能复选框后面的错误信息自行解决,另外若你不知道端口号是什么意思就不要乱改,或不要改得太大与太小)
|
||||
2. 在手机浏览器地址栏输入`http://x.x.x.x:23332/hello` **(注:将`x.x.x.x`换成PC端显示的同步服务地址,`23332`为PC端的端口号)** 后回车,若此地址可以打开并显示 `Hello~::^-^::`则证明移动端与PC端网络已互通,
|
||||
3. 若移动端无法打开第2步的地址,则在PC端的浏览器地址栏输入并打开该地址,若可以打开,则要么是被LX Music PC端被电脑防火墙拦截,要么PC端与移动端不在同一个网络下,或者路由器开启了AP隔离(一般在公共网络下会出现这种情况)
|
||||
|
||||
## 界面异常(界面显示不完整)
|
||||
|
||||
### Windows 7 下界面异常
|
||||
|
||||
由于软件默认使用了透明窗口,根据Electron官方文档的[说明](https://www.electronjs.org/docs/latest/tutorial/window-customization#limitations):
|
||||
> 在 windows 操作系统上, 当 DWM 被禁用时, 透明窗口将无法工作。
|
||||
|
||||
因此,当 win7 没有使用**Aero**主题时界面将会显示异常,开启AERO的方法请自行百度:`win7开启Aero效果`(开启后可看到任务栏变透明)。<br>
|
||||
从`0.14.0`版本起不再强制要求开启透明效果,若你实在不想开启(若非电脑配置太低,墙裂建议开启!),可通过添加运行参数`-dt`来运行程序即可,例如:`.\lx-music-desktop.exe -dt`,添加方法可自行百度“给快捷方式加参数”,该参数的作用是用来控制程序是否使用非透明窗口运行。
|
||||
|
||||
注:启用**Aero**主题后,若软件出现黑边框,则重启软件即可恢复正常。
|
||||
|
||||
对于一些完全无法正常显示界面、开启了AERO后问题仍未解决的情况,请阅读下面的 **Window 7 下软件启动后,界面无法显示** 解决。
|
||||
|
||||
### Linux 下界面异常
|
||||
|
||||
@@ -178,19 +197,25 @@
|
||||
|
||||
注:v1.6.0及之后的版本才支持`-dha`参数
|
||||
|
||||
## 软件启动后,界面无法显示
|
||||
## Windows 7 下软件启动后,界面无法显示
|
||||
|
||||
对于软件启动后,可以在任务栏看到软件,但软件界面在桌面上无任何显示,或者整个界面偶尔闪烁的情况。<br>
|
||||
原始问题看:<https://github.com/electron/electron/issues/19569#issuecomment-522231083><br>
|
||||
解决办法:下载`.NET Framework 4.7.1`或**更高**版本安装即可(建议安装最新版,若安装过程中遇到问题可尝试自行百度解决)。<br>
|
||||
微软官方下载地址:<https://dotnet.microsoft.com/download/dotnet-framework><br>
|
||||
下载`Runtime(运行时)`版即可,安装完成后可能需要重启才生效。
|
||||
下载`Runtime(运行时)`版即可,安装完成后可能需要重启才生效,**若出现闪烁的情况**,可阅读下面的**Windows 7 下整个界面闪烁**解决。
|
||||
|
||||
若还是不行可尝试以下操作:
|
||||
## Windows 7 下整个界面闪烁(消失又出现)
|
||||
|
||||
- 更新显卡驱动
|
||||
- 添加启动参数`-dha`运行(添加的方法请自行百度“给快捷方式加参数”)
|
||||
- 尝试将绿色版的软件放在**桌面**或**我的文档**运行
|
||||
可尝试在关掉软件后,在桌面空白处鼠标右击,在弹出的菜单中选择**个性化**,在弹出的窗口中**切换到系统内置的Aero主题**,然后再启动软件看是否解决。
|
||||
|
||||
## Windows 7 下桌面歌词字体列表为空
|
||||
|
||||
Windows 7 系统系统需要安装 Powershell 5.1及以上版本才可正常获取系统字体列表。
|
||||
|
||||
想要查看当前 Powershell 版本可以在 Powershell 窗口输入命令:`Get-Host`
|
||||
|
||||
最新 Powershell 安装包可以去官方 [Github releases](https://github.com/PowerShell/PowerShell/releases) 页下载,安装过程中若出现错误,请自行按照提示或者百度/Google解决。
|
||||
|
||||
## 安装版安装失败,提示安装程序并未成功地运行完成
|
||||
|
||||
@@ -247,9 +272,9 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看上面的
|
||||
|
||||
以 **`.dmg`** 结尾的文件为 MAC 版本;
|
||||
|
||||
以 **`.AppImage`**、**`.deb`** 结尾的为 Linux 版本。
|
||||
以 **`.AppImage`**、**`.deb`**、**`.rpm`**、**`.pacman`** 结尾的为 Linux 版本。
|
||||
|
||||
带有`x64`的为64位的系统版本,带`x86`的为32位的系统版本;若两个都带有的则为集合版,安装时会自动根据系统位数选择对应的版本安装。
|
||||
带有`x64`的为64位的系统版本,带`x86`的为32位的系统版本;若两个都带有的则为集合版,安装时会自动根据系统位数选择对应的版本安装;带有`arm`的为arm架构系统的版本。
|
||||
|
||||
## 软件更新
|
||||
|
||||
@@ -257,13 +282,13 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看上面的
|
||||
若下载未完成时软件被关闭,下次启动软件会再次自动下载。<br>
|
||||
若还是**更新失败**,可能是无法访问GitHub导致的,这时需要手动更新,即下载最新安装包直接覆盖安装即可。<br>
|
||||
注意:**绿色版**的软件自动更新功能**不可用**,建议使用安装版!!<br>
|
||||
注意:**Mac版**、**Linux deb**版不支持自动更新!
|
||||
注意:**Mac版**、**Linux**版不支持自动更新!
|
||||
|
||||
## 更新已收藏的在线歌单
|
||||
### Windows 安装版在升级后,卸载了旧版本,但没有安装新版本
|
||||
|
||||
该功能仅对直接从歌单详情页点“收藏”按钮收藏的歌单有效,可右击已收藏的列表名从弹出的菜单中选择“同步”使用该功能,
|
||||
出现这个问题的原因一般是你当初在安装本软件的时候是以管理员身份安装的,运行软件的时候没有以管理员身份运行,所以卸载后无法再装上。
|
||||
|
||||
需要注意的是:这将会覆盖本地的目标列表,歌曲将被替换成最新的在线列表。
|
||||
安装本软件时建议选择 `为当前用户安装`,并安装在当前用户目录或者安装在不需要管理员权限的目录(即其他分区下),不要选`为所有用户安装`。
|
||||
|
||||
## 缺少`xxx.dll`
|
||||
|
||||
@@ -272,6 +297,26 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看上面的
|
||||
- 以管理员权限打开`cmd`,输入`sfc /scannow`回车等待检查完成重启电脑
|
||||
- 若上面的方法**修复、重启**电脑后仍然不行,就自行百度弹出的**错误信息**看下别人是怎么解决的
|
||||
|
||||
## MAC OS无法启动软件,提示 lx-music-desktop 已损坏
|
||||
|
||||
这是因为软件没有签名,被系统阻止运行,<br>
|
||||
在终端里输入 `sudo xattr -rd com.apple.quarantine /Applications/lx-music-desktop.app`,然后输入你的电脑密码即可
|
||||
|
||||
还可以参考:
|
||||
|
||||
- <http://www.pc6.com/edu/168719.html>
|
||||
- <https://blog.csdn.net/for641/article/details/104811538>
|
||||
|
||||
## 数据存储路径
|
||||
|
||||
默认情况下,软件的数据存储在:
|
||||
|
||||
- Windows:`%APPDATA%/lx-music-desktop`
|
||||
- Linux:`$XDG_CONFIG_HOME/lx-music-desktop` 或 `~/.config/lx-music-desktop`
|
||||
- macOS:`~/Library/Application/lx-music-desktop`
|
||||
|
||||
在Windows平台下,若程序目录下存在`portable`目录,则自动使用此目录作为数据存储目录(v1.17.0新增)。
|
||||
|
||||
## 杀毒软件提示有病毒或恶意行为
|
||||
|
||||
本人只能保证我写的代码不包含任何**恶意代码**、**收集用户信息**的行为,并且软件代码已开源,请自行查阅,软件安装包也是由CI拉取源代码构建,构建日志:[GitHub Actions](https://github.com/lyswhut/lx-music-desktop/actions)<br>
|
||||
@@ -282,6 +327,58 @@ Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看上面的
|
||||
|
||||
最后,若出现杀毒软件报毒、存在恶意行为,请自行判断选择是否继续使用本软件!
|
||||
|
||||
## 启动参数
|
||||
|
||||
目前软件已支持的启动参数如下:
|
||||
|
||||
- `-search` 启动软件时自动在搜索框搜索指定的内容,例如:`-search="突然的自我 - 伍佰"`
|
||||
- `-dha` 禁用硬件加速启动(Disable Hardware Acceleration),窗口显示有问题时可以尝试添加此参数启动(v1.6.0起新增)
|
||||
- `-dt` 以非透明模式启动(Disable Transparent),对于未开启AERO效果的win7系统可加此参数启动以确保界面正常显示(注:该参数对桌面歌词无效),原来的`-nt`参数已重命名为`-dt`(v1.6.0起重命名)
|
||||
- `-dhmkh` 禁用硬件媒体密钥处理(Disable Hardware Media Key Handling),此选项将禁用Chromium的Hardware Media Key Handling特性(v1.9.0起新增)
|
||||
- `-proxy-server` 设置代理服务器,代理应用的所有流量,例:`-proxy-server="127.0.0.1:1081"`(不支持设置账号密码,v1.17.0起新增)。注:应用内“设置-网络-代理设置”仅代理接口请求的流量,优先级更高
|
||||
- `-proxy-bypass-list` 以分号分隔的主机列表绕过代理服务器,例:`-proxy-bypass-list="<local>;*.google.com;*foo.com;1.2.3.4:5678"`(与`-proxy-server`一起使用才有效,v1.17.0起新增)。注:此设置对应用内接口请求无效
|
||||
- `-play` 启动时播放指定列表的音乐,参数说明:
|
||||
- `type`:播放类型,目前固定为`songList`
|
||||
- `source`:播放源,可用值为`kw/kg/tx/wy/mg/myList`,其中`kw/kg/tx/wy/mg`对应各源的在线列表,`myList`为本地列表
|
||||
- `link`:要播放的在线列表歌单链接、或ID,source为`kw/kg/tx/wy/mg`之一(在线列表)时必传,举例:`./lx-music-desktop -play="type=songList&source=kw&link=歌单URL or ID"`,注意:如果传入URL时必须对URL进行编码后再传入
|
||||
- `name`:要播放的本地列表歌单名字,source为`myList`时必传,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表"`
|
||||
- `index`:从列表的哪个位置开始播放,选传,若不传默认播放第一首歌曲,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表&index=2"`
|
||||
|
||||
## Scheme URL支持
|
||||
|
||||
从v1.17.0起支持 Scheme URL,可以使用此功能从浏览器等场景下调用LX Music,我们开发了一个[油猴脚本](https://github.com/lyswhut/lx-music-script#readme)配套使用<br>
|
||||
脚本安装地址:<https://greasyfork.org/zh-CN/scripts/438148><br>
|
||||
以下是目前可用的Scheme URL调用方式:
|
||||
|
||||
- URL统一以`lxmusic://`开头
|
||||
- 若无特别说明,源的可用值为:`kw/kg/tx/wy/mg`
|
||||
- 若无特别说明,音质的可用值为:`128k/320k/flac/flac32bit`
|
||||
|
||||
目前支持两种传参方式:
|
||||
|
||||
- 通过`data`传参,以经过URL编码的JSON数据传参,例:`lxmusic://music/play?data=xxxx`,其中`xxxx`为经过URL编码后的JSON数据,支持复杂的参数调用
|
||||
- 通过`URL`传参,适用于简单传参的调用,不需要转成JSON格式,例:`lxmusic://music/search/xxxx`,但仍然需要对数据进行URL编码,只适应于简单参数调用(v1.18.0新增)
|
||||
|
||||
### `data`方式传参
|
||||
|
||||
以经过URL编码的JSON数据传参,例:`lxmusic://music/play?data=xxxx`,其中`xxxx`为经过URL编码后的JSON数据,JSON数据内容取决于下表的参数部分
|
||||
|
||||
| 描述 | URL | 参数
|
||||
| --- | --- | ---
|
||||
| 打开歌单 | `songlist/open` | `source<String>`(源,必须)<br>`id<String/Number>`(歌单ID,可选)<br>`url<String>`(歌单URL,可选)其中ID与URL必需传一个
|
||||
| 播放歌单 | `songlist/play` | `source<String>`(源,必须)<br>`id<String/Number>`(歌单ID,可选)<br>`url<String>`(歌单URL,可选)其中`id`与`url`必需传一个<br>`index<Number>`(播放第几首歌,可选,从0开始)
|
||||
| 搜索歌曲 | `music/search` | `keywords<String/Number>`(要搜索的内容,必须)<br>`source<String>`(源,可选)
|
||||
| 播放歌曲 | `music/play` | `name<String>`(歌曲名,必传)<br>`singer<String>`(艺术家名,必传)<br>`source<String>`(源,必传)<br>`songmid<String/Number>`(歌曲ID,必传)<br>`img<String>`(歌曲图片链接,选传)<br>`albumId<String/Number>`(歌曲专辑ID,选传)<br>`interval<String>`(格式化后的歌曲时长,选传,例:`03:55`)<br>`albumName<String>`(歌曲专辑名称,选传)<br>`types<Object>`(歌曲可用音质数组,必传,<br>数组格式:`[{"type": "<音质>", size: "<格式化后的文件大小,选传>", hash: "<kg源必传>"}]`,<br>例:`[{"type": "128k", size: "3.56M"}, {"type": "320k", size: null}]`)<br><br>以下为平台特定参数:<br>`hash<String>`(歌曲hash,kg源必传)<br>`strMediaMid<String>`(歌曲strMediaMid,tx源必传)<br>`albumMid<String>`(歌曲albumMid,tx源专用,选传)<br>`copyrightId<String>`(歌曲copyrightId,mg源必传)<br>`lrcUrl<String>`(歌曲lrcUrl,mg源专用,选传)
|
||||
|
||||
### `URL`方式传参
|
||||
|
||||
由于URL传参只适用于简单传参场景,所以目前只支持以下功能的调用:
|
||||
|
||||
| 描述 | URL | 参数
|
||||
| --- | --- | ---
|
||||
| 搜索歌曲 | `music/search/{source}/{keywords}` | `source`(源,可选)<br>`keywords`(要搜索的内容,必须)<br>例:`music/search/kw/xxx`、`music/search/xxx`
|
||||
| 打开歌单 | `songlist/open/{source}/{id/url}` | `source`(源,必须)<br>`id/url`(歌单ID或歌单URL,必须)<br>例:`songlist/open/kw/123456`
|
||||
|
||||
## 自定义源脚本编写说明
|
||||
|
||||
文件请使用UTF-8编码格式编写,脚本所用编程语言为JavaScript,可以使用ES6+语法,脚本与应用的交互是使用类似事件收发的方式进行,这是一个基本的脚本例子:
|
||||
@@ -372,8 +469,8 @@ send(EVENT_NAMES.inited, {
|
||||
|
||||
```
|
||||
|
||||
- `@name `:源的名字,建议不要过长,10个字符以内
|
||||
- `@description `:源的描述,建议不要过长,20个字符以内,可不填,不填时必须保留 @description
|
||||
- `@name `:源的名字,建议不要过长,24个字符以内
|
||||
- `@description `:源的描述,建议不要过长,36个字符以内,可不填,不填时必须保留 @description
|
||||
- `@version`:源的版本号,可不填,不填时可以删除 @version
|
||||
- `@author `:脚本作者名字,可不填,不填时可以删除 @author
|
||||
- `@homepage `:脚本主页,可不填,不填时可以删除 @homepage
|
||||
@@ -382,6 +479,10 @@ send(EVENT_NAMES.inited, {
|
||||
|
||||
应用为脚本暴露的API对象。
|
||||
|
||||
#### `window.lx.version`
|
||||
|
||||
自定义源API版本,API变更时此版本号将会更改(新增于v1.14.0之后)
|
||||
|
||||
#### `window.lx.EVENT_NAMES`
|
||||
|
||||
常量事件名称对象,发送、注册事件时传入事件名时使用,可用值:
|
||||
@@ -390,6 +491,7 @@ send(EVENT_NAMES.inited, {
|
||||
| --- | ---
|
||||
| `inited` | 脚本初始化完成后发送给应用的事件名,发送该事件时需要传入以下信息:`{status, sources, openDevTools}`<br>`status`:初始化结果(`true`成功,`false`失败)<br>`openDevTools`:是否打开DevTools,此选项可用于开发脚本时的调试<br>`sources`:支持的源信息对象,<br>`sources[kw/kg/tx/wy/mg].name`:源的名字(目前非必须)<br>`sources[kw/kg/tx/wy/mg].type`:源类型,目前固定值需为`music`<br>`sources[kw/kg/tx/wy/mg].actions`:支持的actions,由于目前只支持`musicUrl`,所以固定传`['musicUrl']`即可<br>`sources[kw/kg/tx/wy/mg].qualitys`:该源支持的音质列表,有效的值为`['128k', '320k', 'flac']`,该字段用于控制应用可用的音质类型
|
||||
| `request` | 应用API请求事件名,回调入参:`handler({ source, action, info})`,回调必须返回`Promise`对象<br>`source`:音乐源,可能的值取决于初始化时传入的`sources`对象的源key值<br>`info`:请求附加信息,内容根据`action`变化<br>`action`:请求操作类型,目前只有`musicUrl`,即获取音乐URL链接,需要在 Promise 返回歌曲 url,`info`的结构:`{type, musicInfo}`,`info.type`:音乐质量,可能的值有`128k` / `320k` / `flac`(取决于初始化时对应源传入的`qualitys`值中的一个),`info.musicInfo`:音乐信息对象,里面有音乐ID、名字等信息
|
||||
| `updateAlert` | 显示源更新弹窗,发送该事件时的参数:`{log, updateUrl}`<br>`log`:更新日志,必传,字符串类型,内容可以使用`\n`换行,最大长度1024,超过此长度后将被截取超出的部分<br>`updateUrl`:更新地址,用于引导用户去该地址更新源,选传,需为http协议的url地址,最大长度1024<br>此事件每次运行脚本只能调用一次(源版本v1.2.0新增)<br>例子:`lx.send(lx.EVENT_NAMES.updateAlert, { log: 'hello world', updateUrl: 'https://xxx.com' })`
|
||||
|
||||
|
||||
#### `window.lx.on`
|
||||
@@ -437,6 +539,7 @@ const cancelHttp = window.lx.request(url, options, callback)
|
||||
应用提供给脚本的工具方法:
|
||||
|
||||
- `window.lx.utils.buffer.from`:对应Node.js的 `Buffer.from`
|
||||
- `window.lx.utils.buffer.bufToString`:Buffer转字符串 `bufToString(buffer, format)`,`format`对应Node.js `Buffer.toString`的参数(v1.14.0之后新增)
|
||||
- `window.lx.utils.crypto.aesEncrypt`:AES加密 `aesEncrypt(buffer, mode, key, iv)`
|
||||
- `window.lx.utils.crypto.md5`:MD5加密 `md5(str)`
|
||||
- `window.lx.utils.crypto.randomBytes`:生成随机字符串 `randomBytes(size)`
|
||||
|
||||
58
README.md
@@ -36,8 +36,8 @@
|
||||
|
||||
所用技术栈:
|
||||
|
||||
- Electron 13
|
||||
- Vue 2
|
||||
- Electron 17
|
||||
- Vue 3
|
||||
|
||||
已支持的平台:
|
||||
|
||||
@@ -48,11 +48,43 @@
|
||||
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)<br>
|
||||
软件下载请转到:[发布页面](https://github.com/lyswhut/lx-music-desktop/releases)<br>
|
||||
或者到网盘下载(网盘内有MAC、windows版):`https://www.lanzoui.com/b0bf2cfa/` 密码:`glqw`(若链接无法打开请百度:蓝奏云链接打不开)<br>
|
||||
使用常见问题请转至:[常见问题](https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md)
|
||||
使用常见问题请转至:[常见问题](https://lyswhut.github.io/lx-music-doc/desktop/faq)<br>
|
||||
移动版项目地址:<https://github.com/lyswhut/lx-music-mobile>
|
||||
|
||||
#### Scheme URL支持
|
||||
|
||||
从v1.17.0起支持 Scheme URL,可以使用此功能从浏览器等场景下调用LX Music,我们开发了一个[油猴脚本](https://github.com/lyswhut/lx-music-script#readme)配套使用,<br>
|
||||
脚本安装地址:<https://greasyfork.org/zh-CN/scripts/438148><br>
|
||||
|
||||
若你想自己调用LX Music,可以看[Scheme URL支持](https://lyswhut.github.io/lx-music-doc/desktop/scheme-url)
|
||||
|
||||
#### 启动参数
|
||||
|
||||
目前软件已支持的启动参数如下:
|
||||
|
||||
- `-proxy-server` 设置代理服务器,代理应用的所有流量
|
||||
- `-proxy-bypass-list` 以分号分隔的主机列表绕过代理服务器
|
||||
- `-play` 启动时播放指定列表的音乐
|
||||
- `-search` 启动软件时自动在搜索框搜索指定的内容
|
||||
- `-dha` 禁用硬件加速启动(Disable Hardware Acceleration)
|
||||
- `-dt` 以非透明模式启动(Disable Transparent)
|
||||
- `-dhmkh` 禁用硬件媒体密钥处理(Disable Hardware Media Key Handling)
|
||||
|
||||
启动参数的详细说明请看[启动参数说明](https://lyswhut.github.io/lx-music-doc/desktop/run-params)
|
||||
|
||||
#### 数据存储路径
|
||||
|
||||
默认情况下,软件的数据存储在:
|
||||
|
||||
- Windows:`%APPDATA%/lx-music-desktop`
|
||||
- Linux:`$XDG_CONFIG_HOME/lx-music-desktop` 或 `~/.config/lx-music-desktop`
|
||||
- macOS:`~/Library/Application Support/lx-music-desktop`
|
||||
|
||||
在Windows平台下,若程序目录下存在`portable`目录,则自动使用此目录作为数据存储目录(v1.17.0新增)。
|
||||
|
||||
### 源码使用方法
|
||||
|
||||
环境要求:Node.js 14+
|
||||
环境要求:Node.js 16+
|
||||
|
||||
```bash
|
||||
# 开发模式
|
||||
@@ -76,25 +108,9 @@ npm run pack:linux
|
||||
|
||||
<p><a href="https://github.com/lyswhut/lx-music-desktop"><img width="100%" src="https://github.com/lyswhut/lx-music-desktop/blob/master/doc/images/app.png" alt="lx-music UI"></a></p>
|
||||
|
||||
### 启动参数
|
||||
|
||||
目前软件已支持的启动参数如下:
|
||||
|
||||
- `-search` 启动软件时自动在搜索框搜索指定的内容,例如:`-search="突然的自我 - 伍佰"`
|
||||
- `-dha` 禁用硬件加速启动(Disable Hardware Acceleration),窗口显示有问题时可以尝试添加此参数启动(v1.6.0起新增)
|
||||
- `-dt` 以非透明模式启动(Disable Transparent),对于未开启AERO效果的win7系统可加此参数启动以确保界面正常显示(注:该参数对桌面歌词无效),原来的`-nt`参数已重命名为`-dt`(v1.6.0起重命名)
|
||||
- `-dhmkh` 禁用硬件媒体密钥处理(Disable Hardware Media Key Handling),此选项将禁用Chromium的Hardware Media Key Handling特性(v1.9.0起新增)
|
||||
- `-play` 启动时播放指定列表的音乐,参数说明:
|
||||
- `type`:播放类型,目前固定为`songList`
|
||||
- `source`:播放源,可用值为`kw/kg/tx/wy/mg/myList`,其中`kw/kg/tx/wy/mg`对应各源的在线列表,`myList`为本地列表
|
||||
- `link`:要播放的在线列表歌单链接、或ID,source为`kw/kg/tx/wy/mg`之一(在线列表)时必传,举例:`./lx-music-desktop -play="type=songList&source=kw&link=歌单URL or ID"`,注意:如果传入URL时必须对URL进行编码后再传入
|
||||
- `name`:要播放的本地列表歌单名字,source为`myList`时必传,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表"`
|
||||
- `index`:从列表的哪个位置开始播放,选传,若不传默认播放第一首歌曲,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表&index=2"`
|
||||
|
||||
|
||||
### 常见问题
|
||||
|
||||
常见问题已移至:<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>
|
||||
常见问题已移至:<https://lyswhut.github.io/lx-music-doc/desktop/faq>
|
||||
|
||||
### 项目协议
|
||||
|
||||
|
||||
@@ -5,4 +5,5 @@ module.exports = {
|
||||
localIdentName: isDev ? '[path][name]__[local]--[hash:base64:5]' : '[hash:base64:5]',
|
||||
exportLocalsConvention: 'camelCase',
|
||||
},
|
||||
sourceMap: isDev,
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
const path = require('path')
|
||||
const ESLintPlugin = require('eslint-webpack-plugin')
|
||||
|
||||
module.exports = {
|
||||
target: 'electron-main',
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
path: path.join(__dirname, '../../dist'),
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
@@ -19,24 +20,12 @@ module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: {
|
||||
loader: 'eslint-loader',
|
||||
options: {
|
||||
formatter: require('eslint-formatter-friendly'),
|
||||
},
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
enforce: 'pre',
|
||||
test: /\.node$/,
|
||||
use: 'node-loader',
|
||||
},
|
||||
// {
|
||||
// test: /\.js$/,
|
||||
// loader: 'babel-loader',
|
||||
// exclude: /node_modules/,
|
||||
// },
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
},
|
||||
plugins: [
|
||||
new ESLintPlugin(),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const path = require('path')
|
||||
const { merge } = require('webpack-merge')
|
||||
const webpack = require('webpack')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
@@ -19,17 +18,9 @@ module.exports = merge(baseConfig, {
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
__userApi: `"${path.join(__dirname, '../../src/main/modules/userApi').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
new FriendlyErrorsPlugin({
|
||||
onErrors(severity, errors) { // Silent warning from electron-debug
|
||||
if (severity != 'warning') return
|
||||
|
||||
for (let i = errors.length - 1; i > -1; i--) {
|
||||
const error = errors[i]
|
||||
if (error.file == './node_modules/electron-debug/index.js') errors.splice(i, 1)
|
||||
}
|
||||
// You can listen to errors transformed and prioritized by the plugin
|
||||
// severity can be 'error' or 'warning'
|
||||
},
|
||||
}),
|
||||
],
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 50,
|
||||
maxAssetSize: 1024 * 1024 * 30,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ module.exports = merge(baseConfig, {
|
||||
},
|
||||
externals: [
|
||||
...Object.keys(dependencies || {}),
|
||||
// 'font-list',
|
||||
],
|
||||
node: {
|
||||
__dirname: false,
|
||||
@@ -25,11 +26,11 @@ module.exports = merge(baseConfig, {
|
||||
patterns: [
|
||||
{
|
||||
from: path.join(__dirname, '../../src/main/modules/userApi/renderer'),
|
||||
to: path.join(__dirname, '../../dist/electron/userApi/renderer'),
|
||||
to: path.join(__dirname, '../../dist/userApi/renderer'),
|
||||
},
|
||||
{
|
||||
from: path.join(__dirname, '../../src/main/modules/userApi/rendererEvent/name.js'),
|
||||
to: path.join(__dirname, '../../dist/electron/userApi/rendererEvent/name.js'),
|
||||
to: path.join(__dirname, '../../dist/userApi/rendererEvent/name.js'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -39,4 +40,11 @@ module.exports = merge(baseConfig, {
|
||||
},
|
||||
}),
|
||||
],
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 10,
|
||||
maxAssetSize: 1024 * 1024 * 20,
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -14,7 +14,7 @@ const okayLog = chalk.bgGreen.white(' OKAY ') + ' '
|
||||
|
||||
|
||||
function build() {
|
||||
del.sync(['dist/electron/**', 'build/**'])
|
||||
del.sync(['dist/**', 'build/**'])
|
||||
|
||||
const spinners = new Spinnies({ color: 'blue' })
|
||||
spinners.add('main', { text: 'main building' })
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const path = require('path')
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
const HTMLPlugin = require('html-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const CleanCSSPlugin = require('less-plugin-clean-css')
|
||||
const ESLintPlugin = require('eslint-webpack-plugin')
|
||||
|
||||
const vueLoaderConfig = require('../vue-loader.config')
|
||||
const { mergeCSSLoader } = require('../utils')
|
||||
@@ -17,11 +17,12 @@ module.exports = {
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
path: path.join(__dirname, '../../dist'),
|
||||
publicPath: 'auto',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.join(__dirname, '../../src'),
|
||||
'@main': path.join(__dirname, '../../src/main'),
|
||||
'@renderer': path.join(__dirname, '../../src/renderer'),
|
||||
'@lyric': path.join(__dirname, '../../src/renderer-lyric'),
|
||||
@@ -33,16 +34,8 @@ module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(vue|js)$/,
|
||||
use: {
|
||||
loader: 'eslint-loader',
|
||||
options: {
|
||||
formatter: require('eslint-formatter-friendly'),
|
||||
emitWarning: isDev,
|
||||
},
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
enforce: 'pre',
|
||||
test: /\.node$/,
|
||||
use: 'node-loader',
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
@@ -62,20 +55,6 @@ module.exports = {
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
lessOptions: {
|
||||
plugins: [
|
||||
new CleanCSSPlugin({ advanced: true }),
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl(:?us)?$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
@@ -97,6 +76,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
exclude: path.join(__dirname, '../../src/renderer/assets/svgs'),
|
||||
type: 'asset',
|
||||
parser: {
|
||||
dataUrlCondition: {
|
||||
@@ -107,6 +87,20 @@ module.exports = {
|
||||
filename: 'imgs/[name]-[contenthash:8][ext]',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
include: path.join(__dirname, '../../src/renderer/assets/svgs'),
|
||||
use: [
|
||||
{
|
||||
loader: 'svg-sprite-loader',
|
||||
options: {
|
||||
symbolId: 'icon-[name]',
|
||||
},
|
||||
},
|
||||
'svg-transform-loader',
|
||||
'svgo-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||
type: 'asset',
|
||||
@@ -133,16 +127,12 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
},
|
||||
plugins: [
|
||||
new HTMLPlugin({
|
||||
filename: 'lyric.html',
|
||||
template: path.join(__dirname, '../../src/renderer-lyric/index.pug'),
|
||||
isProd: process.env.NODE_ENV == 'production',
|
||||
browser: process.browser,
|
||||
scriptLoading: 'blocking',
|
||||
__dirname,
|
||||
}),
|
||||
new VueLoaderPlugin(),
|
||||
@@ -152,5 +142,9 @@ module.exports = {
|
||||
filename: isDev ? '[name].css' : '[name].[contenthash:8].css',
|
||||
chunkFilename: isDev ? '[id].css' : '[id].[contenthash:8].css',
|
||||
}),
|
||||
new ESLintPlugin({
|
||||
extensions: ['js', 'vue'],
|
||||
formatter: require('eslint-formatter-friendly'),
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
@@ -10,13 +9,13 @@ module.exports = merge(baseConfig, {
|
||||
mode: 'development',
|
||||
devtool: 'eval-source-map',
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new FriendlyErrorsPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"development"',
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
|
||||
},
|
||||
__VUE_OPTIONS_API__: 'true',
|
||||
__VUE_PROD_DEVTOOLS__: 'false',
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
const path = require('path')
|
||||
// const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
const { dependencies } = require('../../package.json')
|
||||
|
||||
let whiteListedModules = ['vue']
|
||||
// let whiteListedModules = ['vue']
|
||||
let whiteListedModules = ['vue', 'vue-router', 'vuex', 'vue-i18n']
|
||||
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
@@ -19,27 +19,24 @@ module.exports = merge(baseConfig, {
|
||||
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d)),
|
||||
],
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: path.join(__dirname, '../../src/static'),
|
||||
to: path.join(__dirname, '../../dist/electron/static'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"',
|
||||
},
|
||||
__VUE_OPTIONS_API__: 'true',
|
||||
__VUE_PROD_DEVTOOLS__: 'false',
|
||||
}),
|
||||
],
|
||||
optimization: {
|
||||
minimize: false,
|
||||
minimizer: [
|
||||
new TerserPlugin(),
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 10,
|
||||
maxAssetSize: 1024 * 1024 * 20,
|
||||
hints: 'warning',
|
||||
},
|
||||
node: {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const path = require('path')
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
const HTMLPlugin = require('html-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const CleanCSSPlugin = require('less-plugin-clean-css')
|
||||
const ESLintPlugin = require('eslint-webpack-plugin')
|
||||
|
||||
const vueLoaderConfig = require('../vue-loader.config')
|
||||
const { mergeCSSLoader } = require('../utils')
|
||||
@@ -17,11 +17,12 @@ module.exports = {
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
path: path.join(__dirname, '../../dist'),
|
||||
publicPath: 'auto',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.join(__dirname, '../../src'),
|
||||
'@main': path.join(__dirname, '../../src/main'),
|
||||
'@renderer': path.join(__dirname, '../../src/renderer'),
|
||||
'@lyric': path.join(__dirname, '../../src/renderer-lyric'),
|
||||
@@ -33,16 +34,8 @@ module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(vue|js)$/,
|
||||
use: {
|
||||
loader: 'eslint-loader',
|
||||
options: {
|
||||
formatter: require('eslint-formatter-friendly'),
|
||||
emitWarning: isDev,
|
||||
},
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
enforce: 'pre',
|
||||
test: /\.node$/,
|
||||
use: 'node-loader',
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
@@ -62,20 +55,6 @@ module.exports = {
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
lessOptions: {
|
||||
plugins: [
|
||||
new CleanCSSPlugin({ advanced: true }),
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl(:?us)?$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
@@ -97,6 +76,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
exclude: path.join(__dirname, '../../src/renderer/assets/svgs'),
|
||||
type: 'asset',
|
||||
parser: {
|
||||
dataUrlCondition: {
|
||||
@@ -107,6 +87,20 @@ module.exports = {
|
||||
filename: 'imgs/[name]-[contenthash:8][ext]',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
include: path.join(__dirname, '../../src/renderer/assets/svgs'),
|
||||
use: [
|
||||
{
|
||||
loader: 'svg-sprite-loader',
|
||||
options: {
|
||||
symbolId: 'icon-[name]',
|
||||
},
|
||||
},
|
||||
'svg-transform-loader',
|
||||
'svgo-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||
type: 'asset',
|
||||
@@ -133,16 +127,12 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
},
|
||||
plugins: [
|
||||
new HTMLPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.join(__dirname, '../../src/renderer/index.pug'),
|
||||
template: path.join(__dirname, '../../src/renderer/index.html'),
|
||||
isProd: process.env.NODE_ENV == 'production',
|
||||
browser: process.browser,
|
||||
scriptLoading: 'blocking',
|
||||
__dirname,
|
||||
}),
|
||||
new VueLoaderPlugin(),
|
||||
@@ -152,5 +142,9 @@ module.exports = {
|
||||
filename: isDev ? '[name].css' : '[name].[contenthash:8].css',
|
||||
chunkFilename: isDev ? '[id].css' : '[id].[contenthash:8].css',
|
||||
}),
|
||||
new ESLintPlugin({
|
||||
extensions: ['js', 'vue'],
|
||||
formatter: require('eslint-formatter-friendly'),
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
@@ -10,13 +9,14 @@ module.exports = merge(baseConfig, {
|
||||
mode: 'development',
|
||||
devtool: 'eval-source-map',
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new FriendlyErrorsPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"development"',
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
|
||||
},
|
||||
ENVIRONMENT: 'process.env',
|
||||
__VUE_OPTIONS_API__: 'true',
|
||||
__VUE_PROD_DEVTOOLS__: 'false',
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -9,7 +9,7 @@ const baseConfig = require('./webpack.config.base')
|
||||
|
||||
const { dependencies } = require('../../package.json')
|
||||
|
||||
let whiteListedModules = ['vue']
|
||||
let whiteListedModules = ['vue', 'vue-router', 'vuex', 'vue-i18n']
|
||||
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
@@ -23,7 +23,7 @@ module.exports = merge(baseConfig, {
|
||||
patterns: [
|
||||
{
|
||||
from: path.join(__dirname, '../../src/static'),
|
||||
to: path.join(__dirname, '../../dist/electron/static'),
|
||||
to: path.join(__dirname, '../../dist/static'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -31,15 +31,21 @@ module.exports = merge(baseConfig, {
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"',
|
||||
},
|
||||
ENVIRONMENT: 'process.env',
|
||||
__VUE_OPTIONS_API__: 'true',
|
||||
__VUE_PROD_DEVTOOLS__: 'false',
|
||||
}),
|
||||
],
|
||||
optimization: {
|
||||
minimize: false,
|
||||
minimizer: [
|
||||
new TerserPlugin(),
|
||||
new CssMinimizerPlugin(),
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 1024 * 1024 * 10,
|
||||
maxAssetSize: 1024 * 1024 * 20,
|
||||
hints: 'warning',
|
||||
},
|
||||
node: {
|
||||
|
||||
@@ -16,7 +16,8 @@ const rendererLyricConfig = require('./renderer-lyric/webpack.config.dev')
|
||||
|
||||
let electronProcess = null
|
||||
let manualRestart = false
|
||||
let hotMiddleware
|
||||
let hotMiddlewareRenderer
|
||||
let hotMiddlewareRendererLyric
|
||||
|
||||
|
||||
function startRenderer() {
|
||||
@@ -24,7 +25,7 @@ function startRenderer() {
|
||||
// rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
|
||||
// rendererConfig.mode = 'development'
|
||||
const compiler = webpack(rendererConfig)
|
||||
hotMiddleware = webpackHotMiddleware(compiler, {
|
||||
hotMiddlewareRenderer = webpackHotMiddleware(compiler, {
|
||||
log: false,
|
||||
heartbeat: 2500,
|
||||
})
|
||||
@@ -32,37 +33,36 @@ function startRenderer() {
|
||||
compiler.hooks.compilation.tap('compilation', compilation => {
|
||||
// console.log(Object.keys(compilation.hooks))
|
||||
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
hotMiddlewareRenderer.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
compiler.hooks.done.tap('done', stats => {
|
||||
// logStats('Renderer', 'Compile done')
|
||||
// logStats('Renderer', stats)
|
||||
})
|
||||
// compiler.hooks.done.tap('done', stats => {
|
||||
// // logStats('Renderer', 'Compile done')
|
||||
// // logStats('Renderer', stats)
|
||||
// })
|
||||
|
||||
const server = new WebpackDevServer(
|
||||
compiler,
|
||||
{
|
||||
contentBase: path.join(__dirname, '../'),
|
||||
quiet: true,
|
||||
hot: true,
|
||||
historyApiFallback: true,
|
||||
clientLogLevel: 'warning',
|
||||
overlay: {
|
||||
errors: true,
|
||||
},
|
||||
before(app, ctx) {
|
||||
app.use(hotMiddleware)
|
||||
ctx.middleware.waitUntilValid(() => {
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
const server = new WebpackDevServer({
|
||||
port: 9080,
|
||||
hot: true,
|
||||
historyApiFallback: true,
|
||||
// static: {
|
||||
// directory: path.join(__dirname, '../'),
|
||||
// },
|
||||
client: {
|
||||
logging: 'warn',
|
||||
overlay: true,
|
||||
},
|
||||
)
|
||||
setupMiddlewares(middlewares, devServer) {
|
||||
devServer.app.use(hotMiddlewareRenderer)
|
||||
devServer.middleware.waitUntilValid(resolve)
|
||||
|
||||
server.listen(9080)
|
||||
return middlewares
|
||||
},
|
||||
}, compiler)
|
||||
|
||||
server.start()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ function startRendererLyric() {
|
||||
// rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
|
||||
// rendererConfig.mode = 'development'
|
||||
const compiler = webpack(rendererLyricConfig)
|
||||
hotMiddleware = webpackHotMiddleware(compiler, {
|
||||
hotMiddlewareRendererLyric = webpackHotMiddleware(compiler, {
|
||||
log: false,
|
||||
heartbeat: 2500,
|
||||
})
|
||||
@@ -79,37 +79,35 @@ function startRendererLyric() {
|
||||
compiler.hooks.compilation.tap('compilation', compilation => {
|
||||
// console.log(Object.keys(compilation.hooks))
|
||||
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
hotMiddlewareRendererLyric.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
compiler.hooks.done.tap('done', stats => {
|
||||
// logStats('Renderer', 'Compile done')
|
||||
// logStats('Renderer', stats)
|
||||
})
|
||||
// compiler.hooks.done.tap('done', stats => {
|
||||
// // logStats('Renderer', 'Compile done')
|
||||
// // logStats('Renderer', stats)
|
||||
// })
|
||||
|
||||
const server = new WebpackDevServer(
|
||||
compiler,
|
||||
{
|
||||
contentBase: path.join(__dirname, '../'),
|
||||
quiet: true,
|
||||
hot: true,
|
||||
historyApiFallback: true,
|
||||
clientLogLevel: 'warning',
|
||||
overlay: {
|
||||
errors: true,
|
||||
},
|
||||
before(app, ctx) {
|
||||
app.use(hotMiddleware)
|
||||
ctx.middleware.waitUntilValid(() => {
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
const server = new WebpackDevServer({
|
||||
port: 9081,
|
||||
hot: true,
|
||||
historyApiFallback: true,
|
||||
// static: {
|
||||
// directory: path.join(__dirname, '../'),
|
||||
// },
|
||||
client: {
|
||||
logging: 'warn',
|
||||
overlay: true,
|
||||
},
|
||||
)
|
||||
setupMiddlewares(middlewares, devServer) {
|
||||
devServer.app.use(hotMiddlewareRenderer)
|
||||
devServer.middleware.waitUntilValid(resolve)
|
||||
return middlewares
|
||||
},
|
||||
}, compiler)
|
||||
|
||||
server.listen(9081)
|
||||
server.start()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -120,7 +118,8 @@ function startMain() {
|
||||
const compiler = webpack(mainConfig)
|
||||
|
||||
compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
|
||||
hotMiddleware.publish({ action: 'compiling' })
|
||||
hotMiddlewareRenderer.publish({ action: 'compiling' })
|
||||
hotMiddlewareRendererLyric.publish({ action: 'compiling' })
|
||||
done()
|
||||
})
|
||||
|
||||
@@ -152,7 +151,7 @@ function startElectron() {
|
||||
let args = [
|
||||
'--inspect=5858',
|
||||
// 'NODE_ENV=development',
|
||||
path.join(__dirname, '../dist/electron/main.js'),
|
||||
path.join(__dirname, '../dist/main.js'),
|
||||
]
|
||||
|
||||
// detect yarn or npm and process commandline args accordingly
|
||||
@@ -200,8 +199,14 @@ function init() {
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
startRenderer().then(() => handleSuccess('renderer')).catch(() => handleFail('renderer')),
|
||||
startRendererLyric().then(() => handleSuccess('renderer-lyric')).catch(() => handleFail('renderer-lyric')),
|
||||
startRenderer().then(() => handleSuccess('renderer')).catch((err) => {
|
||||
console.error(err.message)
|
||||
return handleFail('renderer')
|
||||
}),
|
||||
startRendererLyric().then(() => handleSuccess('renderer-lyric')).catch((err) => {
|
||||
console.error(err.message)
|
||||
return handleFail('renderer-lyric')
|
||||
}),
|
||||
startMain().then(() => handleSuccess('main')).catch(() => handleFail('main')),
|
||||
]).then(startElectron).catch(err => {
|
||||
console.error(err)
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"],
|
||||
"@main/*": ["src/main/*"],
|
||||
"@renderer/*": ["src/renderer/*"],
|
||||
"@lyric/*": ["src/renderer-lyric/*"],
|
||||
"@static/*": ["src/static/*"],
|
||||
"@common/*": ["src/common/*"],
|
||||
}
|
||||
},
|
||||
},
|
||||
"vueCompilerOptions": {
|
||||
"experimentalDisableTemplateSupport": true
|
||||
},
|
||||
"exclude": ["node_modules", "build", "dist"]
|
||||
}
|
||||
|
||||
29714
package-lock.json
generated
172
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "1.12.0",
|
||||
"version": "1.22.2",
|
||||
"description": "一个免费的音乐查找助手",
|
||||
"main": "./dist/electron/main.js",
|
||||
"main": "./dist/main.js",
|
||||
"productName": "lx-music-desktop",
|
||||
"scripts": {
|
||||
"pack": "node build-config/pack.js && npm run pack:win:setup:x64",
|
||||
@@ -57,43 +57,58 @@
|
||||
"publish:linux:rpm": "cross-env ARCH=x64 electron-builder -l=rpm --x64 -p onTagOrDraft",
|
||||
"publish:linux:pacman": "cross-env ARCH=x64 electron-builder -l=pacman --x64 -p onTagOrDraft",
|
||||
"dev": "node build-config/runner-dev.js",
|
||||
"clean:electron": "rimraf dist/electron",
|
||||
"clean:electron": "rimraf dist",
|
||||
"clean": "rimraf dist && rimraf build",
|
||||
"build:src": "node build-config/pack.js",
|
||||
"build:main": "cross-env NODE_ENV=production webpack --config build-config/main/webpack.config.prod.js --progress",
|
||||
"build:renderer": "cross-env NODE_ENV=production webpack --config build-config/renderer/webpack.config.prod.js --progress",
|
||||
"build:renderer-lyric": "cross-env NODE_ENV=production webpack --config build-config/renderer-lyric/webpack.config.prod.js --progress",
|
||||
"build": "npm run clean:electron && npm run build:main && npm run build:renderer && npm run build:renderer-lyric",
|
||||
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-formatter-friendly src",
|
||||
"lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-formatter-friendly --fix src",
|
||||
"lint": "eslint --ext .js,.vue -f node_modules/eslint-formatter-friendly src",
|
||||
"lint:fix": "eslint --ext .js,.vue -f node_modules/eslint-formatter-friendly --fix src",
|
||||
"dp": "cross-env ELECTRON_GET_USE_PROXY=true GLOBAL_AGENT_HTTPS_PROXY=http://localhost:1081 npm run pack",
|
||||
"up": "cross-env ELECTRON_GET_USE_PROXY=true GLOBAL_AGENT_HTTPS_PROXY=http://localhost:1081 npm i"
|
||||
},
|
||||
"browserslist": [
|
||||
"Electron 13.1.7"
|
||||
"Electron 15.5.7"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
"node": ">= 16",
|
||||
"npm": ">=8.5.2"
|
||||
},
|
||||
"build": {
|
||||
"appId": "cn.toside.music.desktop",
|
||||
"protocols": {
|
||||
"name": "lx-music-protocol",
|
||||
"schemes": [
|
||||
"lxmusic"
|
||||
]
|
||||
},
|
||||
"directories": {
|
||||
"buildResources": "./resources",
|
||||
"output": "./build"
|
||||
},
|
||||
"files": [
|
||||
"dist/electron/**/*"
|
||||
"dist/**/*"
|
||||
],
|
||||
"asar": {
|
||||
"smartUnpack": false
|
||||
},
|
||||
"extraResources": [
|
||||
"./licenses"
|
||||
],
|
||||
"win": {
|
||||
"icon": "./resources/icons/256x256.ico",
|
||||
"icon": "./resources/icons/icon.ico",
|
||||
"legalTrademarks": "lyswhut",
|
||||
"artifactName": "${productName} v${version} ${env.ARCH} ${env.TARGET}.${ext}"
|
||||
},
|
||||
"mac": {
|
||||
"icon": "./resources/icons/512x512.icns",
|
||||
"category": "public.app-category.music"
|
||||
"icon": "./resources/icons/icon.icns",
|
||||
"category": "public.app-category.music",
|
||||
"extendInfo": {
|
||||
"CFBundleName": "lx-music-desktop",
|
||||
"CFBundleDisplayName": "LX Music"
|
||||
}
|
||||
},
|
||||
"linux": {
|
||||
"maintainer": "lyswhut <lyswhut@qq.com>",
|
||||
@@ -163,91 +178,96 @@
|
||||
},
|
||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/core": "^7.18.10",
|
||||
"@babel/eslint-parser": "^7.18.9",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-modules-umd": "^7.14.5",
|
||||
"@babel/plugin-transform-runtime": "^7.15.0",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"browserslist": "^4.16.7",
|
||||
"cfonts": "^2.9.3",
|
||||
"@babel/plugin-transform-modules-umd": "^7.18.6",
|
||||
"@babel/plugin-transform-runtime": "^7.18.10",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-preset-minify": "^0.5.2",
|
||||
"browserslist": "^4.21.3",
|
||||
"chalk": "^4.1.2",
|
||||
"changelog-parser": "^2.8.0",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"core-js": "^3.16.0",
|
||||
"changelog-parser": "^2.8.1",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"core-js": "^3.24.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.2.0",
|
||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||
"del": "^6.0.0",
|
||||
"electron": "^13.1.8",
|
||||
"electron-builder": "^22.11.7",
|
||||
"css-loader": "^6.7.1",
|
||||
"css-minimizer-webpack-plugin": "^4.0.0",
|
||||
"del": "^6.1.1",
|
||||
"electron": "^15.5.7",
|
||||
"electron-builder": "^23.3.3",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-to-chromium": "^1.3.796",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-formatter-friendly": "^7.0.0",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-html": "^6.1.2",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"electron-to-chromium": "^1.4.224",
|
||||
"electron-updater": "^5.2.1",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-standard": "^17.0.0",
|
||||
"eslint-formatter-friendly": "git+https://github.com/lyswhut/eslint-friendly-formatter.git#2170d1320e2fad13615a9dcf229669f0bb473a53",
|
||||
"eslint-plugin-html": "^7.1.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"eslint-plugin-promise": "^6.0.0",
|
||||
"eslint-webpack-plugin": "^3.2.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"less": "^4.1.1",
|
||||
"less-loader": "^10.0.1",
|
||||
"less-plugin-clean-css": "^1.5.1",
|
||||
"markdown-it": "^12.2.0",
|
||||
"mini-css-extract-plugin": "^2.2.0",
|
||||
"postcss": "^8.3.6",
|
||||
"postcss-loader": "^6.1.1",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^11.0.0",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"node-loader": "^2.0.0",
|
||||
"postcss": "^8.4.16",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"postcss-pxtorem": "^6.0.0",
|
||||
"pug": "^3.0.2",
|
||||
"pug-loader": "^2.4.0",
|
||||
"pug-plain-loader": "^1.1.0",
|
||||
"raw-loader": "^4.0.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"spinnies": "^0.5.1",
|
||||
"stylus": "^0.54.8",
|
||||
"stylus-loader": "^6.1.0",
|
||||
"terser-webpack-plugin": "^5.1.4",
|
||||
"spinnies": "git+https://github.com/lyswhut/spinnies.git#233305c58694aa3b053e3ab9af9049993f918b9d",
|
||||
"svg-sprite-loader": "^6.0.11",
|
||||
"svg-transform-loader": "^2.0.13",
|
||||
"svgo-loader": "^3.0.1",
|
||||
"terser": "^5.14.2",
|
||||
"terser-webpack-plugin": "^5.3.5",
|
||||
"url-loader": "^4.1.1",
|
||||
"vue-loader": "^15.9.8",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"webpack": "^5.49.0",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
"vue-loader": "^17.0.0",
|
||||
"vue-template-compiler": "^2.7.8",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.10.0",
|
||||
"webpack-hot-middleware": "git+https://github.com/lyswhut/webpack-hot-middleware.git#329c4375134b89d39da23a56a94db651247c74a1",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bufferutil": "^4.0.6",
|
||||
"crypto-js": "^4.1.1",
|
||||
"electron-log": "^4.4.1",
|
||||
"bufferutil": "^4.0.3",
|
||||
"eiows": "^3.6.1",
|
||||
"electron-store": "^8.0.0",
|
||||
"electron-updater": "^4.3.9",
|
||||
"http-terminator": "^3.0.0",
|
||||
"electron-log": "^4.4.8",
|
||||
"electron-store": "^8.1.0",
|
||||
"font-list": "git+https://github.com/lyswhut/node-font-list.git#4edbb1933b49a9bac1eedd63a31da16b487fe57d",
|
||||
"http-terminator": "^3.2.0",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"image-size": "^1.0.0",
|
||||
"koa": "^2.13.1",
|
||||
"long": "^4.0.0",
|
||||
"lrc-file-parser": "^1.1.2",
|
||||
"needle": "^2.8.0",
|
||||
"image-size": "^1.0.2",
|
||||
"koa": "^2.13.4",
|
||||
"long": "^5.2.0",
|
||||
"mitt": "^3.0.0",
|
||||
"needle": "^3.1.0",
|
||||
"node-id3": "^0.2.3",
|
||||
"request": "^2.88.2",
|
||||
"socket.io": "^4.1.3",
|
||||
"utf-8-validate": "^5.0.5",
|
||||
"vue": "^2.6.14",
|
||||
"vue-i18n": "^8.25.0",
|
||||
"vue-router": "^3.5.2",
|
||||
"vuex": "^3.6.2",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
"socket.io": "^4.5.1",
|
||||
"sortablejs": "^1.15.0",
|
||||
"tunnel": "^0.0.6",
|
||||
"utf-8-validate": "^5.0.9",
|
||||
"vue": "^3.2.37",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.3",
|
||||
"vuex": "^4.0.2"
|
||||
},
|
||||
"overrides": {
|
||||
"async": "^2.3.0",
|
||||
"got": "^11.8.5",
|
||||
"svg-sprite-loader": {
|
||||
"postcss": "8.2.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ module.exports = {
|
||||
'*-height', '*-width',
|
||||
'flex', '::-webkit-scrollbar',
|
||||
'top', 'left', 'bottom', 'right',
|
||||
'border-radius',
|
||||
'border-radius', 'gap',
|
||||
],
|
||||
selectorBlackList: ['html', 'ignore-to-rem'],
|
||||
replace: true,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
### 新增
|
||||
|
||||
- 新增局域网同步功能(实验性,首次使用前建议先备份一次列表),此功能需要配合PC端使用,移动端与PC端处在同一个局域网(路由器的网络)下时,可以多端实时同步歌曲列表,使用问题请看"常见问题"。
|
||||
|
||||
### 优化
|
||||
|
||||
- 添加播放器对系统媒体控制与显示的兼容处理,现在在windows下的锁屏界面可以正确显示当前播放的音乐信息及切换歌曲了
|
||||
- 为tx、kw源添加 Flac 24bit 音质显示,注:由于之前没有记录此音质,所以之前收藏的歌曲信息中不包含它
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复导入kg歌单最多只能加载100、500首歌曲的问题。注:现在可以加载1000+首歌曲的歌单,但出于未知原因会导致部分歌曲无法加载(可能是无版权导致的),目前酷狗码仍然最多只能加载500首歌
|
||||
- 修复某些情况下所显示的歌词、封面图片与当前正在播放的歌曲不一致的问题
|
||||
- 修复无法批量排序歌曲的问题
|
||||
- 修复某些缺失的繁体中文翻译
|
||||
- 修复企鹅音乐搜索失效的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 降级electron到v15.5.7
|
||||
|
||||
@@ -9,12 +9,12 @@ const version_bak = JSON.stringify(version, null, 2)
|
||||
const parseChangelog = require('changelog-parser')
|
||||
const changelogPath = jp('../../CHANGELOG.md')
|
||||
|
||||
const md_renderer = markdownStr => new (require('markdown-it'))({
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
breaks: true,
|
||||
}).render(markdownStr)
|
||||
// const md_renderer = markdownStr => new (require('markdown-it'))({
|
||||
// html: true,
|
||||
// linkify: true,
|
||||
// typographer: true,
|
||||
// breaks: true,
|
||||
// }).render(markdownStr)
|
||||
|
||||
const getPrevVer = () => parseChangelog(changelogPath).then(res => {
|
||||
if (!res.versions.length) throw new Error('CHANGELOG 无法解析到版本号')
|
||||
@@ -28,7 +28,7 @@ const updateChangeLog = async(newVerNum, newChangeLog) => {
|
||||
fs.writeFileSync(changelogPath, changeLog.replace(new RegExp('(## [?0.1.1]?)'), log + '\n$1'), 'utf-8')
|
||||
}
|
||||
|
||||
const renderChangeLog = md => md_renderer(md)
|
||||
// const renderChangeLog = md => md_renderer(md)
|
||||
|
||||
|
||||
module.exports = async newVerNum => {
|
||||
@@ -38,7 +38,7 @@ module.exports = async newVerNum => {
|
||||
newVerNum = verArr.join('.')
|
||||
}
|
||||
const newMDChangeLog = fs.readFileSync(jp('../changeLog.md'), 'utf-8')
|
||||
const newChangeLog = renderChangeLog(newMDChangeLog)
|
||||
// const newChangeLog = renderChangeLog(newMDChangeLog)
|
||||
version.history.unshift({
|
||||
version: version.version,
|
||||
desc: version.desc,
|
||||
@@ -58,7 +58,7 @@ module.exports = async newVerNum => {
|
||||
return {
|
||||
pkg_bak,
|
||||
version_bak,
|
||||
changeLog: newChangeLog,
|
||||
// changeLog: newChangeLog,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
resources/icons/128x128.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
resources/icons/16x16.png
Normal file
|
After Width: | Height: | Size: 488 B |
|
Before Width: | Height: | Size: 7.4 KiB |
BIN
resources/icons/256x256.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
resources/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 901 B |
BIN
resources/icons/48x48.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
BIN
resources/icons/64x64.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
resources/icons/icon.icns
Normal file
BIN
resources/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
resources/icons/icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -53,4 +53,78 @@ module.exports = {
|
||||
navigationUrlWhiteList: [
|
||||
|
||||
],
|
||||
themes: [
|
||||
{
|
||||
id: 0,
|
||||
name: '绿意盎然',
|
||||
className: 'green',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: '蓝田生玉',
|
||||
className: 'blue',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '信口雌黄',
|
||||
className: 'yellow',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '橙黄橘绿',
|
||||
className: 'orange',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '热情似火',
|
||||
className: 'red',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: '粉装玉琢',
|
||||
className: 'pink',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '重斤球紫',
|
||||
className: 'purple',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '灰常美丽',
|
||||
className: 'grey',
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: '青出于黑',
|
||||
className: 'ming',
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: '青出于黑',
|
||||
className: 'blue2',
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: '黑灯瞎火',
|
||||
className: 'black',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: '月里嫦娥',
|
||||
className: 'mid_autumn',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: '木叶之村',
|
||||
className: 'naruto',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: '新年快乐',
|
||||
className: 'happy_new_year',
|
||||
},
|
||||
],
|
||||
themeLights: [0, 1, 2, 3, 4, 10, 5, 6, 11, 12, 7, 8, 9],
|
||||
themeDarks: [13, 7],
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
const defaultSetting = {
|
||||
version: '1.0.43',
|
||||
version: '1.0.59',
|
||||
player: {
|
||||
togglePlayMethod: 'listLoop',
|
||||
highQuality: false,
|
||||
@@ -12,29 +12,47 @@ const defaultSetting = {
|
||||
mediaDeviceId: 'default',
|
||||
isMediaDeviceRemovedStopPlay: false,
|
||||
isShowLyricTranslation: false,
|
||||
isShowLyricRoma: false,
|
||||
isS2t: false, // 是否将歌词从简体转换为繁体
|
||||
isPlayLxlrc: true,
|
||||
isSavePlayTime: false,
|
||||
audioVisualization: false,
|
||||
waitPlayEndStop: true,
|
||||
waitPlayEndStopTime: '',
|
||||
autoSkipOnError: true,
|
||||
},
|
||||
playDetail: {
|
||||
isZoomActiveLrc: true,
|
||||
isShowLyricProgressSetting: false,
|
||||
style: {
|
||||
fontSize: 100,
|
||||
align: 'center',
|
||||
},
|
||||
},
|
||||
desktopLyric: {
|
||||
enable: false,
|
||||
isLock: false,
|
||||
isAlwaysOnTop: false,
|
||||
width: 380,
|
||||
height: 420,
|
||||
isAlwaysOnTopLoop: false,
|
||||
width: 450,
|
||||
height: 300,
|
||||
x: null,
|
||||
y: null,
|
||||
theme: 0,
|
||||
isLockScreen: true,
|
||||
isDelayScroll: true,
|
||||
isHoverHide: false,
|
||||
style: {
|
||||
font: '',
|
||||
fontSize: 120,
|
||||
opacity: 95,
|
||||
isZoomActiveLrc: true,
|
||||
},
|
||||
},
|
||||
list: {
|
||||
isClickPlayList: false,
|
||||
isShowAlbumName: true,
|
||||
isShowSource: true,
|
||||
prevSelectListId: 'default',
|
||||
isSaveScrollLocation: true,
|
||||
addMusicLocationType: 'top',
|
||||
},
|
||||
@@ -44,6 +62,7 @@ const defaultSetting = {
|
||||
fileName: '歌名 - 歌手',
|
||||
maxDownloadNum: 3,
|
||||
isDownloadLrc: false,
|
||||
lrcFormat: 'utf8',
|
||||
isEmbedPic: true,
|
||||
isEmbedLyric: false,
|
||||
isUseOtherSource: false,
|
||||
@@ -90,11 +109,17 @@ const defaultSetting = {
|
||||
port: '23332',
|
||||
},
|
||||
windowSizeId: 2,
|
||||
themeId: 0,
|
||||
startInFullscreen: false,
|
||||
theme: {
|
||||
id: 0,
|
||||
lightId: 0,
|
||||
darkId: 13,
|
||||
},
|
||||
langId: null,
|
||||
sourceId: 'kw',
|
||||
apiSource: 'temp',
|
||||
sourceNameType: 'alias',
|
||||
font: '',
|
||||
isShowAnimation: true,
|
||||
randomAnimate: true,
|
||||
ignoreVersion: null,
|
||||
@@ -107,7 +132,10 @@ const overwriteSetting = {
|
||||
}
|
||||
|
||||
// 使用新年皮肤
|
||||
if (new Date().getMonth() < 2) defaultSetting.themeId = 9
|
||||
if (new Date().getMonth() < 2) {
|
||||
defaultSetting.theme.id = 9
|
||||
defaultSetting.desktopLyric.theme = 3
|
||||
}
|
||||
|
||||
|
||||
exports.defaultSetting = defaultSetting
|
||||
|
||||
@@ -65,6 +65,7 @@ const hotKey = {
|
||||
}
|
||||
|
||||
const keyName = {
|
||||
common: names.mainWindow.name,
|
||||
player: names.mainWindow.name,
|
||||
desktop_lyric: names.winLyric.name,
|
||||
}
|
||||
|
||||
@@ -4,10 +4,19 @@ const names = {
|
||||
close: 'close',
|
||||
min: 'min',
|
||||
max: 'max',
|
||||
fullscreen: 'fullscreen',
|
||||
set_app_name: 'set_app_name',
|
||||
clear_cache: 'clear_cache',
|
||||
get_cache_size: 'get_cache_size',
|
||||
get_env_params: 'get_env_params',
|
||||
clear_env_params_deeplink: 'clear_env_params_deeplink',
|
||||
wait: 'wait',
|
||||
wait_cancel: 'wait_cancel',
|
||||
interval: 'interval',
|
||||
interval_callback: 'interval_callback',
|
||||
interval_cancel: 'interval_cancel',
|
||||
open_dev_tools: 'open_dev_tools',
|
||||
system_theme_change: 'system_theme_change',
|
||||
|
||||
set_music_meta: 'set_music_meta',
|
||||
progress: 'progress',
|
||||
@@ -22,6 +31,7 @@ const names = {
|
||||
set_app_setting: 'set_app_setting',
|
||||
set_window_size: 'set_window_size',
|
||||
show_save_dialog: 'show_save_dialog',
|
||||
get_system_fonts: 'get_system_fonts',
|
||||
|
||||
handle_request: 'handle_request',
|
||||
cancel_request: 'cancel_request',
|
||||
@@ -32,6 +42,8 @@ const names = {
|
||||
|
||||
restart_window: 'restart_window',
|
||||
|
||||
lang_s2t: 'lang_s2t',
|
||||
|
||||
handle_kw_decode_lyric: 'handle_kw_decode_lyric',
|
||||
get_lyric_info: 'get_lyric_info',
|
||||
set_lyric_info: 'set_lyric_info',
|
||||
@@ -59,10 +71,18 @@ const names = {
|
||||
request_user_api_cancel: 'request_user_api_cancel',
|
||||
get_user_api_status: 'get_user_api_status',
|
||||
user_api_status: 'user_api_status',
|
||||
user_api_show_update_alert: 'user_api_show_update_alert',
|
||||
user_api_set_allow_update_alert: 'user_api_set_allow_update_alert',
|
||||
|
||||
get_lyric: 'get_lyric',
|
||||
save_lyric: 'save_lyric',
|
||||
clear_lyric: 'clear_lyric',
|
||||
get_lyric_raw: 'get_lyric_raw',
|
||||
save_lyric_raw: 'save_lyric_raw',
|
||||
clear_lyric_raw: 'clear_lyric_raw',
|
||||
get_lyric_edited: 'get_lyric_edited',
|
||||
save_lyric_edited: 'save_lyric_edited',
|
||||
remove_lyric_edited: 'remove_lyric_edited',
|
||||
get_music_url: 'get_music_url',
|
||||
save_music_url: 'save_music_url',
|
||||
clear_music_url: 'clear_music_url',
|
||||
@@ -73,6 +93,10 @@ const names = {
|
||||
sync_generate_code: 'sync_generate_code',
|
||||
sync_action_list: 'sync_action_list',
|
||||
sync_list: 'sync_list',
|
||||
|
||||
taskbar_set_thumbar_buttons: 'taskbar_set_thumbar_buttons',
|
||||
taskbar_set_thumbnail_clip: 'taskbar_set_thumbnail_clip',
|
||||
taskbar_on_thumbar_button_click: 'taskbar_on_thumbar_button_click',
|
||||
},
|
||||
winLyric: {
|
||||
close: 'close',
|
||||
|
||||
@@ -153,17 +153,10 @@ exports.initSetting = isShowErrorAlert => {
|
||||
// 迁移列表滚动位置设置 ~0.18.3
|
||||
if (setting.list.scroll) {
|
||||
let scroll = setting.list.scroll
|
||||
electronStore_list.set('defaultList.location', scroll.locations.default || 0)
|
||||
electronStore_list.set('loveList.location', scroll.locations.love || 0)
|
||||
electronStore_config.delete('setting.list.scroll')
|
||||
electronStore_config.set('setting.list.isSaveScrollLocation', scroll.enable)
|
||||
delete setting.list.scroll
|
||||
}
|
||||
|
||||
if (setting.player.isShowLyricTransition != null) { // 修正拼写问题 v1.8.2 及以前
|
||||
setting.player.isShowLyricTranslation = setting.player.isShowLyricTransition
|
||||
delete setting.player.isShowLyricTransition
|
||||
}
|
||||
}
|
||||
|
||||
// 从我的列表分离下载列表 v1.7.0 后
|
||||
@@ -175,6 +168,18 @@ exports.initSetting = isShowErrorAlert => {
|
||||
|
||||
const { version: settingVersion, setting: newSetting } = exports.mergeSetting(setting, electronStore_config.get('version'))
|
||||
|
||||
// 修正拼写问题 v1.8.2 及以前
|
||||
if (newSetting.player.isShowLyricTransition != null) {
|
||||
newSetting.player.isShowLyricTranslation = newSetting.player.isShowLyricTransition
|
||||
delete newSetting.player.isShowLyricTransition
|
||||
}
|
||||
|
||||
// 迁移v1.19.0之前的主题设置
|
||||
if (newSetting.themeId != null) {
|
||||
newSetting.theme.id = newSetting.themeId
|
||||
delete newSetting.themeId
|
||||
}
|
||||
|
||||
// 重置 ^0.18.2 排行榜ID
|
||||
if (!newSetting.leaderboard.tabId.includes('__')) newSetting.leaderboard.tabId = 'kw__16'
|
||||
|
||||
|
||||
478
src/lang/en-us.json
Normal file
@@ -0,0 +1,478 @@
|
||||
{
|
||||
"action": "Manage",
|
||||
"agree": "Accept",
|
||||
"alert_button_text": "All right",
|
||||
"audio_visualization": "Audio visualization (experimental)",
|
||||
"back": "Back",
|
||||
"cancel_button_text": "Cancel",
|
||||
"close": "Close",
|
||||
"comment__hot_load_error": "Hot comments failed to load, click to try to reload",
|
||||
"comment__hot_loading": "Hot comments are loading",
|
||||
"comment__hot_title": "Hot Comment",
|
||||
"comment__new_load_error": "The latest comment failed to load, click to try to reload",
|
||||
"comment__new_loading": "Latest comments are loading",
|
||||
"comment__new_title": "Latest comment",
|
||||
"comment__no_content": "No comments yet",
|
||||
"comment__refresh": "Refresh comments",
|
||||
"comment__show": "Song comments",
|
||||
"comment__title": "{name} comment",
|
||||
"confirm_button_text": "Yes",
|
||||
"copy_tip": " (Click to copy)",
|
||||
"date_format_hour": "{num} hours ago",
|
||||
"date_format_minute": "{num} minutes ago",
|
||||
"date_format_second": "{num} seconds ago",
|
||||
"deep_link__handle_error_tip": "Call failed: {message}",
|
||||
"default": "Default",
|
||||
"default_list": "Recently Played",
|
||||
"desktop_lyric__back": "Back",
|
||||
"desktop_lyric__close": "Close",
|
||||
"desktop_lyric__font_decrease": "Reduce font size (Right click to fine-tune)",
|
||||
"desktop_lyric__font_increase": "Increase font size (Right click to fine-tune)",
|
||||
"desktop_lyric__lock": "Lock Lyrics",
|
||||
"desktop_lyric__lrc_active_zoom_off": "Unzoom the currently playing lyrics",
|
||||
"desktop_lyric__lrc_active_zoom_on": "Zoom the currently playing lyrics",
|
||||
"desktop_lyric__opactiy_decrease": "Increase Transparency (Right click to fine-tune)",
|
||||
"desktop_lyric__opactiy_increase": "Decrease Transparency (Right click to fine-tune)",
|
||||
"desktop_lyric__theme": "Theme Color",
|
||||
"desktop_lyric__unlock": "Unlock Lyrics",
|
||||
"desktop_lyric__win_top_off": "Cancel the top lyrics interface",
|
||||
"desktop_lyric__win_top_on": "Top lyrics interface",
|
||||
"download": "Downloads",
|
||||
"download__all": "All Tasks",
|
||||
"download__error": "Error",
|
||||
"download__finished": "Download complete",
|
||||
"download__high_quality": "High Quality",
|
||||
"download__lossless": "Lossless",
|
||||
"download__multiple_tip": "{len} song selected",
|
||||
"download__multiple_tip2": "Select preferred download quality",
|
||||
"download__normal": "Normal",
|
||||
"download__not_available_tip": "The audio quality is not available",
|
||||
"download__paused": "Paused",
|
||||
"download__progress": "Progress",
|
||||
"download__quality": "Quality",
|
||||
"download__runing": "Downloading",
|
||||
"download__status": "Status",
|
||||
"export": "Export",
|
||||
"fullscreen_exit": "Exit Full Screen",
|
||||
"history_clear": "Clear History",
|
||||
"history_remove": "Right click to remove this entry",
|
||||
"history_search": "History Searches",
|
||||
"import": "Import",
|
||||
"leaderboard": "Charts",
|
||||
"list__add_to": "Add to ...",
|
||||
"list__collect": "Collect",
|
||||
"list__copy_name": "Copy name",
|
||||
"list__download": "Download",
|
||||
"list__export_part_desc": "Choose where to save the list file",
|
||||
"list__file": "Locate the file",
|
||||
"list__import_part_button_cancel": "Don't",
|
||||
"list__import_part_button_confirm": "Overwrite",
|
||||
"list__import_part_confirm": "The imported list ({importName}) has the same ID as the local list ({localName}). Do you want to overwrite the local list?",
|
||||
"list__import_part_desc": "Select List File",
|
||||
"list__load_failed": "Ah, the loading failed 😭",
|
||||
"list__loading": "List loading...⏳",
|
||||
"list__move_to": "Move to ...",
|
||||
"list__movedown": "Movedown",
|
||||
"list__moveup": "Move up",
|
||||
"list__new_list_btn": "New List",
|
||||
"list__new_list_input": "New list...",
|
||||
"list__pause": "Pause Task",
|
||||
"list__play": "Play",
|
||||
"list__play_later": "Play later",
|
||||
"list__remove": "Remove",
|
||||
"list__remove_tip": "Do you really want to remove {name}?",
|
||||
"list__remove_tip_button": "Yes, that's right",
|
||||
"list__rename": "Rename",
|
||||
"list__search": "Search",
|
||||
"list__sort": "Adjust position",
|
||||
"list__source_detail": "Song Page",
|
||||
"list__start": "Start Task",
|
||||
"list__sync": "Update",
|
||||
"list_add__btn_title": "Add the song(s) to {name}",
|
||||
"list_add__multiple_btn_title": "Add these song(s) to {name}",
|
||||
"list_add__multiple_title_add": "Add the selected {num} song(s) to ...",
|
||||
"list_add__multiple_title_move": "Move the selected {num} song(s) to ...",
|
||||
"list_add__title_first_add": "Add",
|
||||
"list_add__title_first_move": "Move",
|
||||
"list_add__title_last": "to...",
|
||||
"list_import_tip__alldata": "Import failed, this is an all data backup file, you need to go here to import: \nSettings -> Backup and Restore -> All Data -> Import",
|
||||
"list_import_tip__playlist": "Import failed, this is a list backup file, you need to go here to import: \nSettings -> Backup and Restore -> Import List",
|
||||
"list_import_tip__playlist_part": "The import failed, this is a single-list file, you need to go here to import: \nMy List -> Right-click on any list name -> Select Import in the pop-up menu",
|
||||
"list_import_tip__setting": "Import failed, this is a settings backup file, you need to go here to import: \nSettings -> Backup and Restore -> Partial Data -> Settings Import",
|
||||
"list_import_tip__unknown": "Import failed, unknown file type, please try to upgrade to the latest version and try again",
|
||||
"list_sort_modal_by_album": "Album name",
|
||||
"list_sort_modal_by_down": "Descending",
|
||||
"list_sort_modal_by_field": "Sort field",
|
||||
"list_sort_modal_by_name": "Song name",
|
||||
"list_sort_modal_by_singer": "Singer name",
|
||||
"list_sort_modal_by_source": "Song source",
|
||||
"list_sort_modal_by_time": "Duration",
|
||||
"list_sort_modal_by_type": "Sort categories",
|
||||
"list_sort_modal_by_up": "Ascending",
|
||||
"list_sort_modal_tip_confirm": "Are you sure you want to do this?",
|
||||
"list_update_modal__auto_update": "auto update",
|
||||
"list_update_modal__tips": "💡 The list with \"Automatic Updates\" checked will be automatically updated each time the software is launched",
|
||||
"list_update_modal__title": "List update management",
|
||||
"list_update_modal__update": "Sync",
|
||||
"lists__duplicate": "Duplicate song",
|
||||
"lists__export": "Export",
|
||||
"lists__export_part_desc": "Choose where to save the list file",
|
||||
"lists__import": "Import",
|
||||
"lists__import_part_button_cancel": "No",
|
||||
"lists__import_part_button_confirm": "Overwrite",
|
||||
"lists__import_part_confirm": "The imported list ({importName}) has the same ID as the local list ({localName}). Do you overwrite the local list?",
|
||||
"lists__import_part_desc": "Select list file",
|
||||
"lists__new_list_btn": "Create list",
|
||||
"lists__new_list_input": "New list...",
|
||||
"lists__remove": "Remove",
|
||||
"lists__remove music_tip": "Do you really want to remove the selected {len} songs?",
|
||||
"lists__remove_tip": "Do you really want to remove {name}?",
|
||||
"lists__remove_tip_button": "Yes, that's right",
|
||||
"lists__rename": "Rename",
|
||||
"lists__sort_list": "Sort songs",
|
||||
"lists__source_detail": "Playlist Page",
|
||||
"lists__sync": "Update",
|
||||
"lists__sync_confirm_tip": "This will replace the songs in {name} with the songs in the online list, are you sure you want to update?",
|
||||
"load_list_file_error_detail": "We have helped you back up the old list file to {path}\nIt is stored in JSON format, you can try to repair and restore it manually\n\nError details: {detail}",
|
||||
"load_list_file_error_title": "Error loading playlist data",
|
||||
"loding_list": "Loading...",
|
||||
"love_list": "Favorites",
|
||||
"lyric__load_error": "Failed to get lyrics",
|
||||
"lyric__select": "Lyric text selection",
|
||||
"lyric_menu__align": "Lyric Alignment",
|
||||
"lyric_menu__align_center": "Centered",
|
||||
"lyric_menu__align_left": "Left",
|
||||
"lyric_menu__lrc_size": "Font size [{size}]",
|
||||
"lyric_menu__offset": "Offset [ {offset}ms ]",
|
||||
"lyric_menu__offset_add_10": "10ms faster",
|
||||
"lyric_menu__offset_add_100": "100ms faster",
|
||||
"lyric_menu__offset_dec_10": "10ms slow down (right click slows down 5ms)",
|
||||
"lyric_menu__offset_dec_100": "slow down by 100ms",
|
||||
"lyric_menu__offset_reset": "Reset",
|
||||
"lyric_menu__size_add": "Increase font size (right click to fine-tune)",
|
||||
"lyric_menu__size_dec": "Decrease font (right click to fine tune)",
|
||||
"lyric_menu__size_reset": "Reset",
|
||||
"min": "Minimize",
|
||||
"music_album": "Album",
|
||||
"music_duplicate": "Duplicate song",
|
||||
"music_name": "Name",
|
||||
"music_singer": "Artist",
|
||||
"music_sort__btn_cancel": "Cancel",
|
||||
"music_sort__btn_confirm": "Confirm",
|
||||
"music_sort__input_tip": "Please input which position you want to adjust to",
|
||||
"music_sort__title": "Adjust the position of {name} to:",
|
||||
"music_sort__title_multiple": "Adjust the position of the selected {num} songs to:",
|
||||
"music_time": "Length",
|
||||
"my_list": "Your Library",
|
||||
"no_item": "Nothing's here...",
|
||||
"not_agree": "Not accept",
|
||||
"ok": "OK",
|
||||
"pagination__next": "Next page",
|
||||
"pagination__page": "Page {num}",
|
||||
"pagination__prev": "Previous page",
|
||||
"play_timeout": "Timed pause",
|
||||
"play_timeout_close": "Close",
|
||||
"play_timeout_confirm": "Confirm",
|
||||
"play_timeout_end": "Wait for the song to finish before pausing",
|
||||
"play_timeout_stop": "Cancel timer",
|
||||
"play_timeout_tip": "Pause after {time}",
|
||||
"play_timeout_unit": "minute",
|
||||
"play_timeout_update": "Update timing",
|
||||
"player__add_music_to": "Add the current song to...",
|
||||
"player__buffering": "Buffering...",
|
||||
"player__desktop_lyric_lock": "Right click to lock lyrics",
|
||||
"player__desktop_lyric_off": "Close Desktop Lyrics",
|
||||
"player__desktop_lyric_on": "Open Desktop Lyrics",
|
||||
"player__desktop_lyric_unlock": "Right click to unlock lyrics",
|
||||
"player__end": "Stopped",
|
||||
"player__error": "Error loading music. Switch to next song after 5 seconds",
|
||||
"player__geting_url": "Getting music link...",
|
||||
"player__hide_detail_tip": "Hide detail page (Right-click in the view to quickly hide the details page)",
|
||||
"player__loading": "Music loading...",
|
||||
"player__music_album": "Album: ",
|
||||
"player__music_name": "Name: ",
|
||||
"player__music_singer": "Artist: ",
|
||||
"player__next": "Next",
|
||||
"player__pause": "Pause",
|
||||
"player__pic_tip": "Play details page (right-click to locate the currently playing song in \"My List\")",
|
||||
"player__play": "Play",
|
||||
"player__play_toggle_mode_list": "Play in order",
|
||||
"player__play_toggle_mode_list_loop": "List Loop",
|
||||
"player__play_toggle_mode_off": "Disable",
|
||||
"player__play_toggle_mode_random": "List Random",
|
||||
"player__play_toggle_mode_single_loop": "Single Loop",
|
||||
"player__playing": "Now playing...",
|
||||
"player__prev": "Prev",
|
||||
"player__refresh_url": "Music URL expired, refreshing...",
|
||||
"player__stop": "Paused",
|
||||
"player__volume": "Volume: ",
|
||||
"search": "Search",
|
||||
"search__hot_search": "Top Searches",
|
||||
"search__welcome": "Search what I want to 😉",
|
||||
"setting": "Settings",
|
||||
"setting__about": "About lx-music-desktop",
|
||||
"setting__backup": "Backup and restore",
|
||||
"setting__backup_all": "All data (list data and setting data)",
|
||||
"setting__backup_all_export": "Export",
|
||||
"setting__backup_all_export_desc": "Select the backup to...",
|
||||
"setting__backup_all_import": "Import",
|
||||
"setting__backup_all_import_desc": "Select a backup file",
|
||||
"setting__backup_other": "Other backup formats (recovery of such backup files is not currently supported)",
|
||||
"setting__backup_other_export_dir": "Choose where to save the file",
|
||||
"setting__backup_other_export_list_csv": "Export list in CSV format",
|
||||
"setting__backup_other_export_list_text": "Export list in TXT format",
|
||||
"setting__backup_other_export_list_text_confirm": "Do you want to merge all the lists into one file?",
|
||||
"setting__backup_part": "Partial data (list data includes audition list, favorite list, user-defined list, setting data does not include shortcut key settings)",
|
||||
"setting__backup_part_export_list": "Export lists",
|
||||
"setting__backup_part_export_list_desc": "Save the list to...",
|
||||
"setting__backup_part_export_setting": "Export settings",
|
||||
"setting__backup_part_export_setting_desc": "Save the list to...",
|
||||
"setting__backup_part_import_list": "Import lists",
|
||||
"setting__backup_part_import_list_desc": "Select a list backup",
|
||||
"setting__backup_part_import_setting": "Import settings",
|
||||
"setting__backup_part_import_setting_desc": "Select the Settings file",
|
||||
"setting__basic": "General",
|
||||
"setting__basic_animation": "Random pop-up animation",
|
||||
"setting__basic_control_btn_position": "Control Button Position",
|
||||
"setting__basic_control_btn_position_left": "Left",
|
||||
"setting__basic_control_btn_position_right": "Right",
|
||||
"setting__basic_font": "Font",
|
||||
"setting__basic_lang": "Language",
|
||||
"setting__basic_lang_title": "The language displayed in the software",
|
||||
"setting__basic_show_animation": "Show switching animation",
|
||||
"setting__basic_source": "Music source",
|
||||
"setting__basic_source_status_failed": "Initialization failed",
|
||||
"setting__basic_source_status_initing": "Initializing",
|
||||
"setting__basic_source_status_success": "Initialization successful",
|
||||
"setting__basic_source_temp": "Temporary API (some features not available; workaround if Test API unavailable)",
|
||||
"setting__basic_source_test": "Test API (Available for most software features)",
|
||||
"setting__basic_source_title": "Choose a music source",
|
||||
"setting__basic_source_user_api_btn": "Custom Source Management",
|
||||
"setting__basic_sourcename": "Source name",
|
||||
"setting__basic_sourcename_alias": "Aliases",
|
||||
"setting__basic_sourcename_real": "Original",
|
||||
"setting__basic_sourcename_title": "Select the name of music source",
|
||||
"setting__basic_start_in_fullscreen": "Start in fullscreen mode",
|
||||
"setting__basic_theme": "Theme",
|
||||
"setting__basic_theme_auto_tip": "This is a dynamic theme, you can preset a light theme and a dark theme, and then it will automatically switch to the corresponding theme you preset according to the system's light and dark theme colors.\nNote: Right-click this theme item to open the light and dark theme setting window.",
|
||||
"setting__basic_to_tray": "Do not exit the software when closing the software and minimize it to the system tray",
|
||||
"setting__basic_window_size": "Window size",
|
||||
"setting__basic_window_size_big": "Large",
|
||||
"setting__basic_window_size_huge": "Huge",
|
||||
"setting__basic_window_size_larger": "Larger",
|
||||
"setting__basic_window_size_medium": "Medium",
|
||||
"setting__basic_window_size_oversized": "Oversized",
|
||||
"setting__basic_window_size_small": "Small",
|
||||
"setting__basic_window_size_smaller": "Smaller",
|
||||
"setting__basic_window_size_title": "Set the window size",
|
||||
"setting__click_copy": "Click to copy",
|
||||
"setting__click_open": "Click to open",
|
||||
"setting__desktop_lyric": "Desktop Lyric Settings",
|
||||
"setting__desktop_lyric_always_on_top": "Make the lyrics always above other windows",
|
||||
"setting__desktop_lyric_always_on_top_loop": "Automatically refresh the top of the lyrics (try to enable this setting when the lyrics are still blocked by some programs)",
|
||||
"setting__desktop_lyric_delay_scroll": "Delayed lyrics scroll",
|
||||
"setting__desktop_lyric_enable": "Display lyrics",
|
||||
"setting__desktop_lyric_font": "Lyric font",
|
||||
"setting__desktop_lyric_font_default": "Default",
|
||||
"setting__desktop_lyric_hover_hide": "Reduce the transparency of lyrics when the mouse moves into the lyrics area (this feature has platform compatibility issues)",
|
||||
"setting__desktop_lyric_lock": "Lock lyrics",
|
||||
"setting__desktop_lyric_lock_screen": "It is not allowed to drag the lyrics window out of the main screen",
|
||||
"setting__download": "Download",
|
||||
"setting__download_data_embed": "Whether to embed the following content in the audio file",
|
||||
"setting__download_embed_lyric": "Embedding lyric",
|
||||
"setting__download_embed_pic": "Embedding cover",
|
||||
"setting__download_enable": "Whether to enable download function",
|
||||
"setting__download_lyric": "Lyrics download",
|
||||
"setting__download_lyric_format": "Downloaded lyrics file encoding format",
|
||||
"setting__download_lyric_format_gbk": "GBK (Try to select this format when Chinese garbled characters appear on some devices)",
|
||||
"setting__download_lyric_format_utf8": "UTF-8",
|
||||
"setting__download_lyric_title": "Select whether to download the lyrics file",
|
||||
"setting__download_name": "Music file naming",
|
||||
"setting__download_name1": "Title - Artist",
|
||||
"setting__download_name2": "Artist - Title",
|
||||
"setting__download_name3": "Title only",
|
||||
"setting__download_name_title": "Select the music naming method for downloading",
|
||||
"setting__download_path": "Download path",
|
||||
"setting__download_path_change_btn": "Change",
|
||||
"setting__download_path_label": "Current: ",
|
||||
"setting__download_path_open_label": "Click to open this path",
|
||||
"setting__download_path_title": "Define the path to downloading",
|
||||
"setting__download_select_save_path": "Select the save path",
|
||||
"setting__download_use_other_source": "Auto source download",
|
||||
"setting__download_use_other_source_tip": "When the song cannot be downloaded from the original source, try to switch to another source to download. Note: This function does not 100% guarantee that the version of the song after changing the source is consistent with the original version",
|
||||
"setting__hot_key": "Shortcut Key Settings",
|
||||
"setting__hot_key_common_focus_search_input": "Focus Search Box",
|
||||
"setting__hot_key_common_min": "Minimize the program",
|
||||
"setting__hot_key_common_toggle_close": "Quit Program",
|
||||
"setting__hot_key_common_toggle_hide": "Show/Hide Program",
|
||||
"setting__hot_key_common_toggle_min": "Minimize/Restore Program",
|
||||
"setting__hot_key_desktop_lyric_toggle_always_top": "Top Desktop Lyrics Switch",
|
||||
"setting__hot_key_desktop_lyric_toggle_lock": "Desktop Lyric Lock Switch",
|
||||
"setting__hot_key_desktop_lyric_toggle_visible": "Turn on/off desktop lyrics",
|
||||
"setting__hot_key_global_title": "Global Shortcut Key",
|
||||
"setting__hot_key_local_title": "Shortcut Keys in Software",
|
||||
"setting__hot_key_player_next": "Next Song",
|
||||
"setting__hot_key_player_prev": "Previous Song",
|
||||
"setting__hot_key_player_toggle_play": "Play/Pause Control",
|
||||
"setting__hot_key_player_volume_down": "Reduce Volume",
|
||||
"setting__hot_key_player_volume_mute": "Mute Switch",
|
||||
"setting__hot_key_player_volume_up": "Increase Volume",
|
||||
"setting__hot_key_tip_input": "Please enter a new key",
|
||||
"setting__hot_key_unset_input": "Not Set",
|
||||
"setting__is_enable": "Enabled",
|
||||
"setting__is_show": "Showed",
|
||||
"setting__list": "List",
|
||||
"setting__list_add_music_location_type": "Position when adding a song to the list",
|
||||
"setting__list_add_music_location_type_bottom": "Bottom",
|
||||
"setting__list_add_music_location_type_top": "Top",
|
||||
"setting__list_click_action": "Automatically switch to the current list when double-clicking a song in the list (only valid for playlists and rankings)",
|
||||
"setting__list_scroll": "Remember the position of the scroll bar of the playlist (only valid for my music classification)",
|
||||
"setting__list_source": "Show song source (only valid for my music category)",
|
||||
"setting__network": "Network",
|
||||
"setting__network_proxy_host": "Host",
|
||||
"setting__network_proxy_password": "Password",
|
||||
"setting__network_proxy_port": "Port",
|
||||
"setting__network_proxy_title": "HTTP Proxy (False setting would block Internet connections)",
|
||||
"setting__network_proxy_username": "Username",
|
||||
"setting__odc": "Auto clear",
|
||||
"setting__odc_clear_search_input": "Clear the search box when you are not searching",
|
||||
"setting__odc_clear_search_list": "Clear the search list when you are not searching",
|
||||
"setting__other": "Extras",
|
||||
"setting__other_play_list_cache": "List cache management",
|
||||
"setting__other_play_list_cache_clear_btn": "Clear list cache information",
|
||||
"setting__other_play_list_cache_tip": "The cached song links and playback sources in my list need to be re-acquired when playing or downloading songs after cleaning. Do not clean up if there are no issues related to song playback",
|
||||
"setting__other_play_list_cache_tip_confirm": "In my list, the cached song links and play alternative sources need to be re-obtained when playing and downloading songs after cleaning. Do not clean up if there are no issues related to song playback. Are you sure to clean up?",
|
||||
"setting__other_resource_cache": "Resource cache management",
|
||||
"setting__other_resource_cache_clear_btn": "Clear resource cache",
|
||||
"setting__other_resource_cache_confirm": "I want to clear",
|
||||
"setting__other_resource_cache_label": "The software has used cache size: ",
|
||||
"setting__other_resource_cache_tip": "Picture, audio, and other caches. After cleaning, resources such as pictures will need to be downloaded again. It is not recommended to clean up. The software will dynamically manage the cache size according to the disk space.",
|
||||
"setting__other_resource_cache_tip_confirm": "Involving the cache of pictures, audios, etc., the pictures and other resources will need to be downloaded again after cleaning. It is not recommended to clean up. The software will dynamically manage the cache size according to the disk space. Do you still need to clean up?",
|
||||
"setting__other_tray_theme": "Tray Icon Style",
|
||||
"setting__other_tray_theme_black": "Black Color",
|
||||
"setting__other_tray_theme_native": "White",
|
||||
"setting__other_tray_theme_origin": "Primary Color",
|
||||
"setting__play": "Play",
|
||||
"setting__play_auto_skip_on_error": "Automatically switch songs on playback error",
|
||||
"setting__play_detail": "Play details page settings",
|
||||
"setting__play_detail_align": "Lyric Alignment",
|
||||
"setting__play_detail_align_center": "Centered",
|
||||
"setting__play_detail_align_left": "Left",
|
||||
"setting__play_detail_align_right": "Right",
|
||||
"setting__play_detail_font_size": "Lyrics font size (you can use the keyboard + - adjust the font size on the playback details page)",
|
||||
"setting__play_detail_font_size_current": "Current font size: {size}",
|
||||
"setting__play_detail_font_size_reset": "Reset",
|
||||
"setting__play_detail_font_zoom": "Zoom the currently playing lyrics",
|
||||
"setting__play_detail_lyric_progress": "Allows to adjust playback progress by lyrics",
|
||||
"setting__play_lyric_lxlrc": "Play with karaoke-style lyrics (if available)",
|
||||
"setting__play_lyric_roma": "Show lyrics roman",
|
||||
"setting__play_lyric_s2t": "Convert the playing and downloading lyrics to Traditional Chinese",
|
||||
"setting__play_lyric_transition": "Show lyrics translation",
|
||||
"setting__play_mediaDevice": "Audio output",
|
||||
"setting__play_mediaDevice_remove_stop_play": "Pause the song when the current sound output device is changed",
|
||||
"setting__play_mediaDevice_title": "Select a media device for audio output",
|
||||
"setting__play_media_device_error_tip": "This function conflicts with the audio visualization function. You have enabled audio visualization when you started the software this time. This setting is temporarily unavailable. Please restart the software and then modify this setting.",
|
||||
"setting__play_media_device_tip": "This feature conflicts with Audio Visualization, both cannot be enabled at the same time, would you like to turn Audio Visualization off and apply the selected audio output settings?",
|
||||
"setting__play_quality": "Priority playback of 320K quality songs (if available)",
|
||||
"setting__play_save_play_time": "Remember playback progress",
|
||||
"setting__play_task_bar": "Show playing progress on the taskbar",
|
||||
"setting__play_timeout": "Timed pause",
|
||||
"setting__player_audio_visualization_tip": "The custom audio output device will conflict with the audio visualization function. After the audio visualization is enabled, the audio output device will be reset to the default output device. At present, this problem cannot be solved. Do you still want to enable it?",
|
||||
"setting__search": "Search",
|
||||
"setting__search_focus_search_box": "Automatically focus the search box on startup",
|
||||
"setting__search_history": "Search history",
|
||||
"setting__search_hot": "Top Searches",
|
||||
"setting__sync": "Data synchronization",
|
||||
"setting__sync_address": "Synchronization service address: {address}",
|
||||
"setting__sync_auth_code": "Connection code: {code}",
|
||||
"setting__sync_device": "Connected devices: {devices}",
|
||||
"setting__sync_enable": "Enable the synchronization function (because the data is transmitted in clear text, please use it under a trusted network)",
|
||||
"setting__sync_port": "Sync port settings",
|
||||
"setting__sync_port_tip": "Please enter the synchronization service port number",
|
||||
"setting__sync_refresh_code": "Refresh the connection code",
|
||||
"setting__sync_tip": "For how to use it, please see the \"Sync function\" section of the FAQ",
|
||||
"setting__update": "Update",
|
||||
"setting__update_checking": "Checking for updates...",
|
||||
"setting__update_current_label": "Current version: ",
|
||||
"setting__update_downloading": "Update is found and being downloaded...⏳",
|
||||
"setting__update_init": "Processing update...",
|
||||
"setting__update_latest": "The software is up-to-date, enjoy yourself!🥂",
|
||||
"setting__update_latest_label": "Latest version: ",
|
||||
"setting__update_open_version_modal_btn": "Open the update window🚀",
|
||||
"setting__update_progress": "Download progress: ",
|
||||
"setting__update_unknown": "Unknown",
|
||||
"song_list": "Playlists",
|
||||
"songlist__import_input_tip": "Enter songlist link or songlist ID",
|
||||
"songlist__import_input_tip_1": "Cross-source playlists are not supported, please confirm whether the playlist to be opened corresponds to the current playlist source",
|
||||
"songlist__import_input_tip_2": "If you encounter a link to a playlist that cannot be opened, welcome feedback",
|
||||
"songlist__import_input_tip_3": "Kugou source does not support opening with playlist ID, but supports Kugou code opening",
|
||||
"songlist__open_list": "open {name} playlist",
|
||||
"source_alias_all": "Aggregated",
|
||||
"source_alias_bd": "BD Music",
|
||||
"source_alias_kg": "KG Music",
|
||||
"source_alias_kw": "KW Music",
|
||||
"source_alias_mg": "MG Music",
|
||||
"source_alias_tx": "TX Music",
|
||||
"source_alias_wy": "WY Music",
|
||||
"source_alias_xm": "XM Music",
|
||||
"source_all": "Aggregated",
|
||||
"source_bd": "Baidu",
|
||||
"source_kg": "Kugou",
|
||||
"source_kw": "Kuwo",
|
||||
"source_mg": "Migu",
|
||||
"source_tx": "Tencent",
|
||||
"source_wy": "Netease",
|
||||
"source_xm": "Xiami",
|
||||
"sync__merge_btn_local_remote": "Local list merge remote list",
|
||||
"sync__merge_btn_remote_local": "Remote list merge local list",
|
||||
"sync__merge_label": "Merge",
|
||||
"sync__merge_tip": "Merge:",
|
||||
"sync__merge_tip_desc": "Merge the two lists together, the same song will be removed (the song of the merged person is removed), and different songs will be added.",
|
||||
"sync__other_label": "Other",
|
||||
"sync__other_tip": "Other: ",
|
||||
"sync__other_tip_desc": "\"Only use real-time synchronization function\" will not modify the lists of both parties, only real-time synchronization operations; \"Cancel synchronization\" will directly disconnect the two parties.",
|
||||
"sync__overwrite": "Full coverage",
|
||||
"sync__overwrite_btn_cancel": "Cancel sync",
|
||||
"sync__overwrite_btn_local_remote": "Local list Overwrite remote list",
|
||||
"sync__overwrite_btn_none": "Only use real-time synchronization",
|
||||
"sync__overwrite_btn_remote_local": "Remote list Overwrite local list",
|
||||
"sync__overwrite_label": "Cover",
|
||||
"sync__overwrite_tip": "Cover: ",
|
||||
"sync__overwrite_tip_desc": "The list with the same ID of the covered person and the covered list will be deleted and replaced with the list of the covered person (lists with different list IDs will be merged together). If you check Complete coverage, all lists of the covered person will be moved. \nDivide, and then replace with a list of overriders.",
|
||||
"sync__title": "Choose how to synchronize the list with {name}",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
"tag__lossless_24bit": "24bit",
|
||||
"theme_auto": "Auto",
|
||||
"theme_auto_tip": "Right-click to open the light and dark theme settings window",
|
||||
"theme_black": "Black",
|
||||
"theme_blue": "Blue",
|
||||
"theme_blue2": "Purple Blue",
|
||||
"theme_green": "Green",
|
||||
"theme_grey": "Grey",
|
||||
"theme_happy_new_year": "New Year",
|
||||
"theme_mid_autumn": "Mid-Autumn",
|
||||
"theme_ming": "Ming",
|
||||
"theme_naruto": "Naruto",
|
||||
"theme_orange": "Orange",
|
||||
"theme_pink": "Pink",
|
||||
"theme_purple": "Purple",
|
||||
"theme_red": "Red",
|
||||
"theme_selector_modal__dark_title": "dark theme",
|
||||
"theme_selector_modal__light_title": "Bright theme",
|
||||
"theme_selector_modal__title": "Follow system theme settings",
|
||||
"theme_selector_modal__title_tip": "Note: You can set a light theme and a dark theme in advance, and then it will automatically switch to the corresponding theme you set in advance according to the light and dark theme colors of the system.",
|
||||
"theme_yellow": "Yellow",
|
||||
"user_api__allow_show_update_alert": "Allow update popup to show",
|
||||
"user_api__btn_export": "Export",
|
||||
"user_api__btn_import": "Import",
|
||||
"user_api__btn_remove": "Remove",
|
||||
"user_api__import_file": "Select music API script file",
|
||||
"user_api__max_tip": "There can only be a maximum of 20 sources at the same time🤪\nIf you want to continue importing, please remove some old sources to make room",
|
||||
"user_api__noitem": "There is nothing here...😲",
|
||||
"user_api__note": "Tip: Although we have isolated the script's running environment as much as possible, importing scripts containing malicious behaviors may still affect your system. Please import them carefully.",
|
||||
"user_api__readme": "Source writing instructions: ",
|
||||
"user_api__title": "Custom Source Management",
|
||||
"user_api__update_alert": "Custom source [{name}] found new version:",
|
||||
"user_api__update_alert_open_url": "Open update address"
|
||||
}
|
||||
43
src/lang/index.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import zh_cn from './zh-cn.json'
|
||||
import zh_tw from './zh-tw.json'
|
||||
import en_us from './en-us.json'
|
||||
|
||||
const langs = [
|
||||
{
|
||||
name: '简体中文',
|
||||
locale: 'zh-cn',
|
||||
alternate: 'zh-hans',
|
||||
country: 'cn',
|
||||
fallback: true,
|
||||
message: zh_cn,
|
||||
},
|
||||
{
|
||||
name: '繁体中文',
|
||||
locale: 'zh-tw',
|
||||
alternate: 'zh-hk',
|
||||
country: 'cn',
|
||||
message: zh_tw,
|
||||
},
|
||||
{
|
||||
name: 'English',
|
||||
locale: 'en-us',
|
||||
country: 'us',
|
||||
message: en_us,
|
||||
},
|
||||
]
|
||||
|
||||
const langList = []
|
||||
const messages = {}
|
||||
langs.forEach(item => {
|
||||
langList.push({
|
||||
name: item.name,
|
||||
locale: item.locale,
|
||||
alternate: item.alternate,
|
||||
})
|
||||
messages[item.locale] = item.message
|
||||
})
|
||||
|
||||
export {
|
||||
langList,
|
||||
messages,
|
||||
}
|
||||
478
src/lang/zh-cn.json
Normal file
@@ -0,0 +1,478 @@
|
||||
{
|
||||
"action": "操作",
|
||||
"agree": "接受",
|
||||
"alert_button_text": "好吧",
|
||||
"audio_visualization": "音频可视化(实验性)",
|
||||
"back": "返回",
|
||||
"cancel_button_text": "我不",
|
||||
"close": "关闭",
|
||||
"comment__hot_load_error": "热门评论加载失败,点击尝试重新加载",
|
||||
"comment__hot_loading": "热门评论加载中",
|
||||
"comment__hot_title": "热门评论",
|
||||
"comment__new_load_error": "最新评论加载失败,点击尝试重新加载",
|
||||
"comment__new_loading": "最新评论加载中",
|
||||
"comment__new_title": "最新评论",
|
||||
"comment__no_content": "暂无评论",
|
||||
"comment__refresh": "刷新评论",
|
||||
"comment__show": "歌曲评论",
|
||||
"comment__title": "{name} 的评论",
|
||||
"confirm_button_text": "是的",
|
||||
"copy_tip": "(点击复制)",
|
||||
"date_format_hour": "{num}小时前",
|
||||
"date_format_minute": "{num}分钟前",
|
||||
"date_format_second": "{num}秒前",
|
||||
"deep_link__handle_error_tip": "调用失败:{message}",
|
||||
"default": "默认",
|
||||
"default_list": "试听列表",
|
||||
"desktop_lyric__back": "返回",
|
||||
"desktop_lyric__close": "关闭",
|
||||
"desktop_lyric__font_decrease": "减小字体大小(右击可微调)",
|
||||
"desktop_lyric__font_increase": "增加字体大小(右击可微调)",
|
||||
"desktop_lyric__lock": "锁定歌词",
|
||||
"desktop_lyric__lrc_active_zoom_off": "取消缩放当前播放的歌词",
|
||||
"desktop_lyric__lrc_active_zoom_on": "缩放当前播放的歌词",
|
||||
"desktop_lyric__opactiy_decrease": "增加透明度(右击可微调)",
|
||||
"desktop_lyric__opactiy_increase": "减小透明度(右击可微调)",
|
||||
"desktop_lyric__theme": "主题配色",
|
||||
"desktop_lyric__unlock": "解锁歌词",
|
||||
"desktop_lyric__win_top_off": "取消置顶歌词界面",
|
||||
"desktop_lyric__win_top_on": "置顶歌词界面",
|
||||
"download": "下载",
|
||||
"download__all": "全部任务",
|
||||
"download__error": "出错",
|
||||
"download__finished": "下载完成",
|
||||
"download__high_quality": "高品音质",
|
||||
"download__lossless": "无损音质",
|
||||
"download__multiple_tip": "已选择 {len} 首歌曲",
|
||||
"download__multiple_tip2": "请选择要优先下载的音质",
|
||||
"download__normal": "普通音质",
|
||||
"download__not_available_tip": "该音质不可用",
|
||||
"download__paused": "已暂停",
|
||||
"download__progress": "进度",
|
||||
"download__quality": "品质",
|
||||
"download__runing": "正在下载",
|
||||
"download__status": "状态",
|
||||
"export": "导出",
|
||||
"fullscreen_exit": "退出全屏",
|
||||
"history_clear": "清空搜索历史",
|
||||
"history_remove": "右击移除该历史",
|
||||
"history_search": "历史搜索",
|
||||
"import": "导入",
|
||||
"leaderboard": "排行榜",
|
||||
"list__add_to": "添加到...",
|
||||
"list__collect": "收藏",
|
||||
"list__copy_name": "复制歌曲名",
|
||||
"list__download": "下载",
|
||||
"list__export_part_desc": "选择列表文件保存位置",
|
||||
"list__file": "定位文件",
|
||||
"list__import_part_button_cancel": "不要啊",
|
||||
"list__import_part_button_confirm": "覆盖掉",
|
||||
"list__import_part_confirm": "导入的列表({importName})与本地列表({localName})的ID相同,是否覆盖本地列表?",
|
||||
"list__import_part_desc": "选择列表文件",
|
||||
"list__load_failed": "啊,加载失败了😭",
|
||||
"list__loading": "列表加载中...⏳",
|
||||
"list__move_to": "移动到...",
|
||||
"list__movedown": "下移",
|
||||
"list__moveup": "上移",
|
||||
"list__new_list_btn": "新建列表",
|
||||
"list__new_list_input": "新列表...",
|
||||
"list__pause": "暂停任务",
|
||||
"list__play": "播放",
|
||||
"list__play_later": "稍后播放",
|
||||
"list__remove": "删除",
|
||||
"list__remove_tip": "你真的想要移除 {name} 吗?",
|
||||
"list__remove_tip_button": "是的 没错",
|
||||
"list__rename": "重命名",
|
||||
"list__search": "搜索",
|
||||
"list__sort": "调整位置",
|
||||
"list__source_detail": "歌曲详情页",
|
||||
"list__start": "开始任务",
|
||||
"list__sync": "更新",
|
||||
"list_add__btn_title": "把该歌曲添加到 {name}",
|
||||
"list_add__multiple_btn_title": "把这些歌曲添加到 {name}",
|
||||
"list_add__multiple_title_add": "添加已选的 {num} 首歌曲到...",
|
||||
"list_add__multiple_title_move": "移动已选的 {num} 首歌曲到...",
|
||||
"list_add__title_first_add": "添加",
|
||||
"list_add__title_first_move": "移动",
|
||||
"list_add__title_last": "到...",
|
||||
"list_import_tip__alldata": "导入失败,这是一个所有数据备份文件,你需要去这里导入:\n设置 -> 备份与恢复 -> 所有数据 -> 导入",
|
||||
"list_import_tip__playlist": "导入失败,这是一个列表备份文件,你需要去这里导入:\n设置 -> 备份与恢复 -> 部分数据 -> 导入列表",
|
||||
"list_import_tip__playlist_part": "导入失败,这是一个单列表文件,你需要去这里导入:\n我的列表 -> 右击任意一个列表名 -> 在弹出的菜单中选择导入",
|
||||
"list_import_tip__setting": "导入失败,这是一个设置备份文件,你需要去这里导入:\n设置 -> 备份与恢复 -> 部分数据 -> 设置导入",
|
||||
"list_import_tip__unknown": "导入失败,未知的文件类型,请尝试升级到最新版本后再试",
|
||||
"list_sort_modal_by_album": "专辑名",
|
||||
"list_sort_modal_by_down": "降序",
|
||||
"list_sort_modal_by_field": "排序字段",
|
||||
"list_sort_modal_by_name": "歌曲名",
|
||||
"list_sort_modal_by_singer": "歌手名",
|
||||
"list_sort_modal_by_source": "歌曲源",
|
||||
"list_sort_modal_by_time": "时长",
|
||||
"list_sort_modal_by_type": "排序类别",
|
||||
"list_sort_modal_by_up": "升序",
|
||||
"list_sort_modal_tip_confirm": "你确定要这么做吗?",
|
||||
"list_update_modal__auto_update": "自动更新",
|
||||
"list_update_modal__tips": "💡 每次启动软件时将会自动更新已勾选“自动更新”的列表",
|
||||
"list_update_modal__title": "列表更新管理",
|
||||
"list_update_modal__update": "立即更新",
|
||||
"lists__duplicate": "重复歌曲",
|
||||
"lists__export": "导出",
|
||||
"lists__export_part_desc": "选择列表文件保存位置",
|
||||
"lists__import": "导入",
|
||||
"lists__import_part_button_cancel": "不要啊",
|
||||
"lists__import_part_button_confirm": "覆盖掉",
|
||||
"lists__import_part_confirm": "导入的列表({importName})与本地列表({localName})的ID相同,是否覆盖本地列表?",
|
||||
"lists__import_part_desc": "选择列表文件",
|
||||
"lists__new_list_btn": "新建列表",
|
||||
"lists__new_list_input": "新列表...",
|
||||
"lists__remove": "删除",
|
||||
"lists__remove music_tip": "你真的要移除所选的 {len} 首歌曲吗?",
|
||||
"lists__remove_tip": "你真的想要移除 {name} 吗?",
|
||||
"lists__remove_tip_button": "是的 没错",
|
||||
"lists__rename": "重命名",
|
||||
"lists__sort_list": "排序歌曲",
|
||||
"lists__source_detail": "歌单详情页",
|
||||
"lists__sync": "更新",
|
||||
"lists__sync_confirm_tip": "这将会把 {name} 内的歌曲替换成在线列表的歌曲,你确认要更新吗?",
|
||||
"load_list_file_error_detail": "我们已经帮你把旧的列表文件备份到{path}\n它以 JSON 格式存储,你可以尝试手动修复并恢复它\n\n错误详情:{detail}",
|
||||
"load_list_file_error_title": "播放列表数据加载错误(建议到GitHub或加群反馈)",
|
||||
"loding": "加载中...",
|
||||
"love_list": "收藏",
|
||||
"lyric__load_error": "歌词获取失败",
|
||||
"lyric__select": "歌词文本选择",
|
||||
"lyric_menu__align": "歌词对齐方式",
|
||||
"lyric_menu__align_center": "居中",
|
||||
"lyric_menu__align_left": "居左",
|
||||
"lyric_menu__lrc_size": "字体大小 [ {size} ]",
|
||||
"lyric_menu__offset": "歌词偏移 [ {offset}ms ]",
|
||||
"lyric_menu__offset_add_10": "加快10毫秒",
|
||||
"lyric_menu__offset_add_100": "加快100毫秒",
|
||||
"lyric_menu__offset_dec_10": "减慢10毫秒",
|
||||
"lyric_menu__offset_dec_100": "减慢100毫秒",
|
||||
"lyric_menu__offset_reset": "重置",
|
||||
"lyric_menu__size_add": "加大字体(右击可微调)",
|
||||
"lyric_menu__size_dec": "减小字体(右击可微调)",
|
||||
"lyric_menu__size_reset": "重置",
|
||||
"min": "最小化",
|
||||
"music_album": "专辑名",
|
||||
"music_duplicate": "重复歌曲",
|
||||
"music_name": "歌曲名",
|
||||
"music_singer": "艺术家",
|
||||
"music_sort__btn_cancel": "取消",
|
||||
"music_sort__btn_confirm": "确定",
|
||||
"music_sort__input_tip": "请输入要调整到第几个位置",
|
||||
"music_sort__title": "将 {name} 的位置调整到:",
|
||||
"music_sort__title_multiple": "将已选的 {num} 首歌曲的位置调整到:",
|
||||
"music_time": "时长",
|
||||
"my_list": "我的列表",
|
||||
"no_item": "列表竟然是空的...",
|
||||
"not_agree": "不接受",
|
||||
"ok": "我知道了",
|
||||
"pagination__next": "下一页",
|
||||
"pagination__page": "第 {num} 页",
|
||||
"pagination__prev": "上一页",
|
||||
"play_timeout": "定时暂停",
|
||||
"play_timeout_close": "关闭",
|
||||
"play_timeout_confirm": "确认",
|
||||
"play_timeout_end": "等待歌曲播放完毕再暂停",
|
||||
"play_timeout_stop": "取消定时",
|
||||
"play_timeout_tip": "{time} 后暂停播放",
|
||||
"play_timeout_unit": "分钟",
|
||||
"play_timeout_update": "更新定时",
|
||||
"player__add_music_to": "添加当前歌曲到...",
|
||||
"player__buffering": "缓冲中...",
|
||||
"player__desktop_lyric_lock": "右击锁定歌词",
|
||||
"player__desktop_lyric_off": "关闭桌面歌词",
|
||||
"player__desktop_lyric_on": "开启桌面歌词",
|
||||
"player__desktop_lyric_unlock": "右击解锁歌词",
|
||||
"player__end": "播放完毕",
|
||||
"player__error": "音频加载出错,5 秒后切换下一首",
|
||||
"player__geting_url": "歌曲链接获取中...",
|
||||
"player__hide_detail_tip": "隐藏详情页(界面内右键双击可快速隐藏详情页)",
|
||||
"player__loading": "音乐加载中...",
|
||||
"player__music_album": "专辑名:",
|
||||
"player__music_name": "歌曲名:",
|
||||
"player__music_singer": "艺术家:",
|
||||
"player__next": "下一首",
|
||||
"player__pause": "暂停",
|
||||
"player__pic_tip": "播放详情页(右击在“我的列表”定位当前播放的歌曲)",
|
||||
"player__play": "播放",
|
||||
"player__play_toggle_mode_list": "顺序播放",
|
||||
"player__play_toggle_mode_list_loop": "列表循环",
|
||||
"player__play_toggle_mode_off": "禁用",
|
||||
"player__play_toggle_mode_random": "列表随机",
|
||||
"player__play_toggle_mode_single_loop": "单曲循环",
|
||||
"player__playing": "播放中...",
|
||||
"player__prev": "上一首",
|
||||
"player__refresh_url": "URL过期,正在刷新URL...",
|
||||
"player__stop": "暂停播放",
|
||||
"player__volume": "当前音量:",
|
||||
"search": "搜索",
|
||||
"search__hot_search": "热门搜索",
|
||||
"search__welcome": "搜我所想~~😉",
|
||||
"setting": "设置",
|
||||
"setting__about": "关于洛雪音乐",
|
||||
"setting__backup": "备份与恢复",
|
||||
"setting__backup_all": "所有数据(列表数据与设置数据)",
|
||||
"setting__backup_all_export": "导出",
|
||||
"setting__backup_all_export_desc": "选择备份保存位置",
|
||||
"setting__backup_all_import": "导入",
|
||||
"setting__backup_all_import_desc": "选择备份文件",
|
||||
"setting__backup_other": "其他备份格式(目前不支持恢复此类备份文件)",
|
||||
"setting__backup_other_export_dir": "选择文件保存位置",
|
||||
"setting__backup_other_export_list_csv": "导出 CSV 格式的列表",
|
||||
"setting__backup_other_export_list_text": "导出 TXT 格式的列表",
|
||||
"setting__backup_other_export_list_text_confirm": "是否将所有列表合并为一个文件?",
|
||||
"setting__backup_part": "部分数据(列表数据包括试听列表、收藏列表、用户自定义列表,设置数据不包括快捷键设置)",
|
||||
"setting__backup_part_export_list": "导出列表",
|
||||
"setting__backup_part_export_list_desc": "选择歌单保存位置",
|
||||
"setting__backup_part_export_setting": "导出设置",
|
||||
"setting__backup_part_export_setting_desc": "选择设置保存位置",
|
||||
"setting__backup_part_import_list": "导入列表",
|
||||
"setting__backup_part_import_list_desc": "选择列表文件",
|
||||
"setting__backup_part_import_setting": "导入设置",
|
||||
"setting__backup_part_import_setting_desc": "选择配置文件",
|
||||
"setting__basic": "基本设置",
|
||||
"setting__basic_animation": "弹出层随机动画",
|
||||
"setting__basic_control_btn_position": "控制按钮位置",
|
||||
"setting__basic_control_btn_position_left": "左边",
|
||||
"setting__basic_control_btn_position_right": "右边",
|
||||
"setting__basic_font": "字体",
|
||||
"setting__basic_lang": "语言",
|
||||
"setting__basic_lang_title": "软件显示的语言",
|
||||
"setting__basic_show_animation": "显示切换动画",
|
||||
"setting__basic_source": "音乐来源",
|
||||
"setting__basic_source_status_failed": "初始化失败",
|
||||
"setting__basic_source_status_initing": "初始化中",
|
||||
"setting__basic_source_status_success": "初始化成功",
|
||||
"setting__basic_source_temp": "临时接口(软件的某些功能不可用,建议测试接口不可用再使用本接口)",
|
||||
"setting__basic_source_test": "测试接口(几乎软件的所有功能都可用)",
|
||||
"setting__basic_source_title": "选择音乐来源",
|
||||
"setting__basic_source_user_api_btn": "自定义源管理",
|
||||
"setting__basic_sourcename": "音源名字",
|
||||
"setting__basic_sourcename_alias": "别名",
|
||||
"setting__basic_sourcename_real": "原名",
|
||||
"setting__basic_sourcename_title": "选择音源名字类型",
|
||||
"setting__basic_start_in_fullscreen": "以全屏模式启动",
|
||||
"setting__basic_theme": "主题颜色",
|
||||
"setting__basic_theme_auto_tip": "此乃动态主题,你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。\n注:鼠标 右击 此主题项即可打开亮、暗色主题设置窗口。",
|
||||
"setting__basic_to_tray": "关闭软件时不退出软件将其最小化到系统托盘",
|
||||
"setting__basic_window_size": "窗口尺寸",
|
||||
"setting__basic_window_size_big": "大",
|
||||
"setting__basic_window_size_huge": "巨大",
|
||||
"setting__basic_window_size_larger": "较大",
|
||||
"setting__basic_window_size_medium": "中",
|
||||
"setting__basic_window_size_oversized": "超大",
|
||||
"setting__basic_window_size_small": "小",
|
||||
"setting__basic_window_size_smaller": "较小",
|
||||
"setting__basic_window_size_title": "设置软件窗口尺寸",
|
||||
"setting__click_copy": "点击复制",
|
||||
"setting__click_open": "点击打开",
|
||||
"setting__desktop_lyric": "桌面歌词设置",
|
||||
"setting__desktop_lyric_always_on_top": "使歌词总是在其他窗口之上",
|
||||
"setting__desktop_lyric_always_on_top_loop": "自动刷新歌词置顶(当歌词置顶后仍被某些程序遮挡时可尝试启用此设置)",
|
||||
"setting__desktop_lyric_delay_scroll": "延迟歌词滚动",
|
||||
"setting__desktop_lyric_enable": "显示歌词",
|
||||
"setting__desktop_lyric_font": "歌词字体",
|
||||
"setting__desktop_lyric_font_default": "默认",
|
||||
"setting__desktop_lyric_hover_hide": "鼠标移入歌词区域时降低歌词透明度(此功能存在平台兼容性问题)",
|
||||
"setting__desktop_lyric_lock": "锁定歌词",
|
||||
"setting__desktop_lyric_lock_screen": "不允许歌词窗口拖出主屏幕之外",
|
||||
"setting__download": "下载设置",
|
||||
"setting__download_data_embed": "是否将以下内容嵌入到音频文件中",
|
||||
"setting__download_embed_lyric": "歌词嵌入",
|
||||
"setting__download_embed_pic": "封面嵌入",
|
||||
"setting__download_enable": "是否启用下载功能",
|
||||
"setting__download_lyric": "歌词下载",
|
||||
"setting__download_lyric_format": "下载的歌词文件编码格式",
|
||||
"setting__download_lyric_format_gbk": "GBK(在某些设备上出现中文乱码时可尝试选择此格式)",
|
||||
"setting__download_lyric_format_utf8": "UTF-8",
|
||||
"setting__download_lyric_title": "是否同时下载歌词文件",
|
||||
"setting__download_name": "文件命名方式",
|
||||
"setting__download_name1": "歌名 - 歌手",
|
||||
"setting__download_name2": "歌手 - 歌名",
|
||||
"setting__download_name3": "歌名",
|
||||
"setting__download_name_title": "下载歌曲时的命名方式",
|
||||
"setting__download_path": "下载路径",
|
||||
"setting__download_path_change_btn": "更改",
|
||||
"setting__download_path_label": "当前下载路径:",
|
||||
"setting__download_path_open_label": "点击打开当前路径",
|
||||
"setting__download_path_title": "下载歌曲保存的路径",
|
||||
"setting__download_select_save_path": "选择歌曲保存路径",
|
||||
"setting__download_use_other_source": "自动换源下载",
|
||||
"setting__download_use_other_source_tip": "当无法从歌曲的原始源下载时,尝试切换到其他源下载,注:此功能不100%保证换源后的歌曲版本与原版一致",
|
||||
"setting__hot_key": "快捷键设置",
|
||||
"setting__hot_key_common_focus_search_input": "聚焦搜索框",
|
||||
"setting__hot_key_common_min": "最小化程序",
|
||||
"setting__hot_key_common_toggle_close": "退出程序",
|
||||
"setting__hot_key_common_toggle_hide": "显示/隐藏程序",
|
||||
"setting__hot_key_common_toggle_min": "最小化/还原程序",
|
||||
"setting__hot_key_desktop_lyric_toggle_always_top": "桌面歌词置顶切换",
|
||||
"setting__hot_key_desktop_lyric_toggle_lock": "桌面歌词锁定切换",
|
||||
"setting__hot_key_desktop_lyric_toggle_visible": "开/关桌面歌词",
|
||||
"setting__hot_key_global_title": "全局快捷键",
|
||||
"setting__hot_key_local_title": "软件内快捷键",
|
||||
"setting__hot_key_player_next": "下一首歌曲",
|
||||
"setting__hot_key_player_prev": "上一首歌曲",
|
||||
"setting__hot_key_player_toggle_play": "播放/暂停控制",
|
||||
"setting__hot_key_player_volume_down": "减少音量",
|
||||
"setting__hot_key_player_volume_mute": "静音切换",
|
||||
"setting__hot_key_player_volume_up": "增加音量",
|
||||
"setting__hot_key_tip_input": "请输入新的按键",
|
||||
"setting__hot_key_unset_input": "未设置",
|
||||
"setting__is_enable": "是否启用",
|
||||
"setting__is_show": "是否显示",
|
||||
"setting__list": "列表设置",
|
||||
"setting__list_add_music_location_type": "添加歌曲到列表时的位置",
|
||||
"setting__list_add_music_location_type_bottom": "底部",
|
||||
"setting__list_add_music_location_type_top": "顶部",
|
||||
"setting__list_click_action": "双击列表里的歌曲时自动切换到当前列表播放(仅对歌单、排行榜有效)",
|
||||
"setting__list_scroll": "记住播放列表滚动条位置(仅对我的音乐分类有效)",
|
||||
"setting__list_source": "显示歌曲源(仅对我的音乐分类有效)",
|
||||
"setting__network": "网络设置",
|
||||
"setting__network_proxy_host": "主机",
|
||||
"setting__network_proxy_password": "密码",
|
||||
"setting__network_proxy_port": "端口",
|
||||
"setting__network_proxy_title": "HTTP代理设置(乱设置软件将无法联网)",
|
||||
"setting__network_proxy_username": "用户名",
|
||||
"setting__odc": "强迫症设置",
|
||||
"setting__odc_clear_search_input": "离开搜索界面时清空搜索框",
|
||||
"setting__odc_clear_search_list": "离开搜索界面时清空搜索列表",
|
||||
"setting__other": "其他",
|
||||
"setting__other_play_list_cache": "列表缓存管理",
|
||||
"setting__other_play_list_cache_clear_btn": "清理列表缓存信息",
|
||||
"setting__other_play_list_cache_tip": "我的列表中已缓存的歌曲链接、播放代替源,清理后播放、下载歌曲时需要重新获取,没有歌曲播放相关的问题不要清理",
|
||||
"setting__other_play_list_cache_tip_confirm": "我的列表中已缓存的歌曲链接、播放代替源,清理后播放、下载歌曲时需要重新获取,没有歌曲播放相关的问题不要清理,是否确认清理?",
|
||||
"setting__other_resource_cache": "资源缓存管理",
|
||||
"setting__other_resource_cache_clear_btn": "清理资源缓存",
|
||||
"setting__other_resource_cache_confirm": "我要清掉",
|
||||
"setting__other_resource_cache_label": "软件已使用缓存大小:",
|
||||
"setting__other_resource_cache_tip": "图片、音频等缓存,清理后图片等资源将需要重新下载,不建议清理,软件会根据磁盘空间动态管理缓存大小",
|
||||
"setting__other_resource_cache_tip_confirm": "涉及图片、音频等缓存,清理后图片等资源将需要重新下载,不建议清理,软件会根据磁盘空间动态管理缓存大小,是否仍要清理?",
|
||||
"setting__other_tray_theme": "托盘图标样式",
|
||||
"setting__other_tray_theme_black": "黑色",
|
||||
"setting__other_tray_theme_native": "白色",
|
||||
"setting__other_tray_theme_origin": "原色",
|
||||
"setting__play": "播放设置",
|
||||
"setting__play_auto_skip_on_error": "播放错误时自动切换歌曲",
|
||||
"setting__play_detail": "播放详情页设置",
|
||||
"setting__play_detail_align": "歌词对齐方式",
|
||||
"setting__play_detail_align_center": "居中",
|
||||
"setting__play_detail_align_left": "居左",
|
||||
"setting__play_detail_align_right": "居右",
|
||||
"setting__play_detail_font_size": "歌词字体大小(可以在播放详情页使用键盘的 + - 调整字体大小)",
|
||||
"setting__play_detail_font_size_current": "当前字体大小:{size}",
|
||||
"setting__play_detail_font_size_reset": "重置",
|
||||
"setting__play_detail_font_zoom": "缩放当前正在播放的歌词",
|
||||
"setting__play_detail_lyric_progress": "允许通过歌词调整播放进度",
|
||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌词播放(如果可用)",
|
||||
"setting__play_lyric_roma": "显示歌词罗马音(如果可用)",
|
||||
"setting__play_lyric_s2t": "将播放与下载的歌词转换为繁体中文",
|
||||
"setting__play_lyric_transition": "显示歌词翻译(如果可用)",
|
||||
"setting__play_mediaDevice": "音频输出",
|
||||
"setting__play_mediaDevice_remove_stop_play": "当前的声音输出设备被改变时暂停播放歌曲",
|
||||
"setting__play_mediaDevice_title": "选择声音输出的媒体设备",
|
||||
"setting__play_media_device_error_tip": "此功能与音频可视化功能冲突,你本次启动软件时已启用过音频可视化,此设置暂不可用,请 重启 软件后,再来修改此设置。",
|
||||
"setting__play_media_device_tip": "此功能与音频可视化功能冲突,两者无法同时启用,是否将音频可视化关闭 并 应用所选音频输出设置?",
|
||||
"setting__play_quality": "优先播放320K品质的歌曲(如果可用)",
|
||||
"setting__play_save_play_time": "记住播放进度",
|
||||
"setting__play_task_bar": "在任务栏上显示当前歌曲播放进度",
|
||||
"setting__play_timeout": "定时暂停",
|
||||
"setting__player_audio_visualization_tip": "自定义音频输出设备与音频可视化功能会冲突,启用了音频可视化后音频输出设备将会被重置为默认的输出设备,目前此问题暂无法解决,是否仍要开启?",
|
||||
"setting__search": "搜索设置",
|
||||
"setting__search_focus_search_box": "启动时自动聚焦搜索框",
|
||||
"setting__search_history": "显示历史搜索记录",
|
||||
"setting__search_hot": "显示热门搜索",
|
||||
"setting__sync": "数据同步",
|
||||
"setting__sync_address": "同步服务地址:{address}",
|
||||
"setting__sync_auth_code": "连接码:{code}",
|
||||
"setting__sync_device": "已连接的设备:{devices}",
|
||||
"setting__sync_enable": "启用同步功能(由于数据是明文传输,请在受信任的网络下使用)",
|
||||
"setting__sync_port": "同步端口设置",
|
||||
"setting__sync_port_tip": "请输入同步服务端口号",
|
||||
"setting__sync_refresh_code": "刷新连接码",
|
||||
"setting__sync_tip": "使用方式请看常见问题“同步功能”部分",
|
||||
"setting__update": "软件更新",
|
||||
"setting__update_checking": "检查更新中...",
|
||||
"setting__update_current_label": "当前版本:",
|
||||
"setting__update_downloading": "发现新版本并在努力下载中,请稍后...⏳",
|
||||
"setting__update_init": "处理更新中...",
|
||||
"setting__update_latest": "软件已是最新,尽情地体验吧~🥂",
|
||||
"setting__update_latest_label": "最新版本:",
|
||||
"setting__update_open_version_modal_btn": "打开更新窗口 🚀",
|
||||
"setting__update_progress": "下载进度:",
|
||||
"setting__update_unknown": "未知",
|
||||
"song_list": "歌单",
|
||||
"songlist__import_input_tip": "输入歌单链接或歌单ID",
|
||||
"songlist__import_input_tip_1": "不支持跨源打开歌单,请确认要打开的歌单与当前歌单源是否对应",
|
||||
"songlist__import_input_tip_2": "若遇到无法打开的歌单链接,欢迎反馈",
|
||||
"songlist__import_input_tip_3": "酷狗源不支持用歌单ID打开,但支持酷狗码打开",
|
||||
"songlist__open_list": "打开{name}歌单",
|
||||
"source_alias_all": "聚合大会",
|
||||
"source_alias_bd": "小杜音乐",
|
||||
"source_alias_kg": "小枸音乐",
|
||||
"source_alias_kw": "小蜗音乐",
|
||||
"source_alias_mg": "小蜜音乐",
|
||||
"source_alias_tx": "小秋音乐",
|
||||
"source_alias_wy": "小芸音乐",
|
||||
"source_alias_xm": "小霞音乐",
|
||||
"source_all": "聚合搜索",
|
||||
"source_bd": "百度音乐",
|
||||
"source_kg": "酷狗音乐",
|
||||
"source_kw": "酷我音乐",
|
||||
"source_mg": "咪咕音乐",
|
||||
"source_tx": "企鹅音乐",
|
||||
"source_wy": "网易音乐",
|
||||
"source_xm": "虾米音乐",
|
||||
"sync__merge_btn_local_remote": "本机列表 合并 远程列表",
|
||||
"sync__merge_btn_remote_local": "远程列表 合并 本机列表",
|
||||
"sync__merge_label": "合并",
|
||||
"sync__merge_tip": "合并:",
|
||||
"sync__merge_tip_desc": "将两边的列表合并到一起,相同的歌曲将被去掉(去掉的是被合并者的歌曲),不同的歌曲将被添加。",
|
||||
"sync__other_label": "其他",
|
||||
"sync__other_tip": "其他:",
|
||||
"sync__other_tip_desc": "“仅使用实时同步功能”将不修改双方的列表,仅实时同步操作;“取消同步”将直接断开双方的连接。",
|
||||
"sync__overwrite": "完全覆盖",
|
||||
"sync__overwrite_btn_cancel": "取消同步",
|
||||
"sync__overwrite_btn_local_remote": "本机列表 覆盖 远程列表",
|
||||
"sync__overwrite_btn_none": "仅使用实时同步功能",
|
||||
"sync__overwrite_btn_remote_local": "远程列表 覆盖 本机列表",
|
||||
"sync__overwrite_label": "覆盖",
|
||||
"sync__overwrite_tip": "覆盖:",
|
||||
"sync__overwrite_tip_desc": "被覆盖者与覆盖者列表ID相同的列表将被删除后替换成覆盖者的列表(列表ID不同的列表将被合并到一起),若勾选完全覆盖,则被覆盖者的所有列表将被移除,然后替换成覆盖者的列表。",
|
||||
"sync__title": "选择与 {name} 的列表同步方式",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
"tag__lossless_24bit": "24bit",
|
||||
"theme_auto": "道法自然",
|
||||
"theme_auto_tip": "鼠标 右击 可打开亮、暗主题设置窗口",
|
||||
"theme_black": "黑灯瞎火",
|
||||
"theme_blue": "蓝田生玉",
|
||||
"theme_blue2": "清热版蓝",
|
||||
"theme_green": "绿意盎然",
|
||||
"theme_grey": "灰常美丽",
|
||||
"theme_happy_new_year": "新年快乐",
|
||||
"theme_mid_autumn": "月里嫦娥",
|
||||
"theme_ming": "青出于黑",
|
||||
"theme_naruto": "木叶之村",
|
||||
"theme_orange": "橙黄橘绿",
|
||||
"theme_pink": "粉装玉琢",
|
||||
"theme_purple": "重斤球紫",
|
||||
"theme_red": "热情似火",
|
||||
"theme_selector_modal__dark_title": "暗色主题",
|
||||
"theme_selector_modal__light_title": "亮色主题",
|
||||
"theme_selector_modal__title": "跟随系统主题设置",
|
||||
"theme_selector_modal__title_tip": "注:你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。",
|
||||
"theme_yellow": "信口雌黄",
|
||||
"user_api__allow_show_update_alert": "允许显示更新弹窗",
|
||||
"user_api__btn_export": "导出",
|
||||
"user_api__btn_import": "导入",
|
||||
"user_api__btn_remove": "移除",
|
||||
"user_api__import_file": "选择音乐API脚本文件",
|
||||
"user_api__max_tip": "最多只能同时存在20个源哦🤪\n想要继续导入的话,请先移除一些旧的源腾出位置吧",
|
||||
"user_api__noitem": "这里竟然是空的 😲",
|
||||
"user_api__note": "提示:虽然我们已经尽可能地隔离了脚本的运行环境,但导入包含恶意行为的脚本仍可能会影响你的系统,请谨慎导入。",
|
||||
"user_api__readme": "源编写说明:",
|
||||
"user_api__title": "自定义源管理",
|
||||
"user_api__update_alert": "自定义源 [{name}] 发现新版本:",
|
||||
"user_api__update_alert_open_url": "打开更新地址"
|
||||
}
|
||||
478
src/lang/zh-tw.json
Normal file
@@ -0,0 +1,478 @@
|
||||
{
|
||||
"action": "操作",
|
||||
"agree": "接受",
|
||||
"alert_button_text": "好吧",
|
||||
"audio_visualization": "音頻可視化(實驗性)",
|
||||
"back": "返回",
|
||||
"cancel_button_text": "取消",
|
||||
"close": "關閉",
|
||||
"comment__hot_load_error": "熱門評論加載失敗,點擊嘗試重新加載",
|
||||
"comment__hot_loading": "熱門評論加載中",
|
||||
"comment__hot_title": "熱門評論",
|
||||
"comment__new_load_error": "最新評論加載失敗,點擊嘗試重新加載",
|
||||
"comment__new_loading": "最新評論加載中",
|
||||
"comment__new_title": "最新評論",
|
||||
"comment__no_content": "暫無評論",
|
||||
"comment__refresh": "刷新評論",
|
||||
"comment__show": "歌曲評論",
|
||||
"comment__title": "{name} 的評論",
|
||||
"confirm_button_text": "是的",
|
||||
"copy_tip": "(點擊複製)",
|
||||
"date_format_hour": "{num}小時前",
|
||||
"date_format_minute": "{num}分鐘前",
|
||||
"date_format_second": "{num}秒前",
|
||||
"deep_link__handle_error_tip": "調用失敗:{message}",
|
||||
"default": "默認",
|
||||
"default_list": "試聽列表",
|
||||
"desktop_lyric__back": "返回",
|
||||
"desktop_lyric__close": "關閉",
|
||||
"desktop_lyric__font_decrease": "減小字體大小(右擊可微調)",
|
||||
"desktop_lyric__font_increase": "增加字體大小(右擊可微調)",
|
||||
"desktop_lyric__lock": "鎖定歌詞",
|
||||
"desktop_lyric__lrc_active_zoom_off": "取消縮放當前播放的歌詞",
|
||||
"desktop_lyric__lrc_active_zoom_on": "縮放當前播放的歌詞",
|
||||
"desktop_lyric__opactiy_decrease": "增加透明度(右擊可微調)",
|
||||
"desktop_lyric__opactiy_increase": "減小透明度(右擊可微調)",
|
||||
"desktop_lyric__theme": "主題配色",
|
||||
"desktop_lyric__unlock": "解鎖歌詞",
|
||||
"desktop_lyric__win_top_off": "取消置頂歌詞界面",
|
||||
"desktop_lyric__win_top_on": "置頂歌詞界面",
|
||||
"download": "下載",
|
||||
"download__all": "全部任務",
|
||||
"download__error": "出錯",
|
||||
"download__finished": "下載完成",
|
||||
"download__high_quality": "高品音質",
|
||||
"download__lossless": "無損音質",
|
||||
"download__multiple_tip": "已選擇 {len} 首歌曲",
|
||||
"download__multiple_tip2": "請選擇要優先下載的音質",
|
||||
"download__normal": "普通音質",
|
||||
"download__not_available_tip": "該音質不可用",
|
||||
"download__paused": "已暫停",
|
||||
"download__progress": "進度",
|
||||
"download__quality": "品質",
|
||||
"download__runing": "正在下載",
|
||||
"download__status": "狀態",
|
||||
"export": "導出",
|
||||
"fullscreen_exit": "退出全屏",
|
||||
"history_clear": "清空搜索歷史",
|
||||
"history_remove": "右擊移除該歷史",
|
||||
"history_search": "歷史搜索",
|
||||
"import": "導入",
|
||||
"leaderboard": "排行榜",
|
||||
"list__add_to": "添加到...",
|
||||
"list__collect": "收藏",
|
||||
"list__copy_name": "複製歌曲名",
|
||||
"list__download": "下載",
|
||||
"list__export_part_desc": "選擇列表文件保存位置",
|
||||
"list__file": "定位文件",
|
||||
"list__import_part_button_cancel": "不要啊",
|
||||
"list__import_part_button_confirm": "覆蓋掉",
|
||||
"list__import_part_confirm": "導入的列表({importName})與本地列表({localName})的ID相同,是否覆蓋本地列表?",
|
||||
"list__import_part_desc": "選擇列表文件",
|
||||
"list__load_failed": "啊,加載失敗了😭",
|
||||
"list__loading": "列表加載中...⏳",
|
||||
"list__move_to": "移動到...",
|
||||
"list__movedown": "下移",
|
||||
"list__moveup": "上移",
|
||||
"list__new_list_btn": "新建列表",
|
||||
"list__new_list_input": "新列表...",
|
||||
"list__pause": "暫停任務",
|
||||
"list__play": "播放",
|
||||
"list__play_later": "稍後播放",
|
||||
"list__remove": "刪除",
|
||||
"list__remove_tip": "你真的想要移除 {name} 嗎?",
|
||||
"list__remove_tip_button": "是的 沒錯",
|
||||
"list__rename": "重命名",
|
||||
"list__search": "搜索",
|
||||
"list__sort": "調整位置",
|
||||
"list__source_detail": "歌曲詳情頁",
|
||||
"list__start": "開始任務",
|
||||
"list__sync": "更新",
|
||||
"list_add__btn_title": "把該歌曲添加到 {name}",
|
||||
"list_add__multiple_btn_title": "把這些歌曲添加到 {name}",
|
||||
"list_add__multiple_title_add": "添加已選的 {num} 首歌曲到...",
|
||||
"list_add__multiple_title_move": "移動已選的 {num} 首歌曲到...",
|
||||
"list_add__title_first_add": "添加",
|
||||
"list_add__title_first_move": "移動",
|
||||
"list_add__title_last": "到...",
|
||||
"list_import_tip__alldata": "導入失敗,這是一個所有數據備份文件,你需要去這裡導入:\n設置 -> 備份與恢復 -> 所有數據 -> 導入",
|
||||
"list_import_tip__playlist": "導入失敗,這是一個列表備份文件,你需要去這裡導入:\n設置 -> 備份與恢復 -> 部分數據 -> 導入列表",
|
||||
"list_import_tip__playlist_part": "導入失敗,這是一個單列表文件,你需要去這裡導入:\n我的列表 -> 右擊任意一個列表名 -> 在彈出的菜單中選擇導入",
|
||||
"list_import_tip__setting": "導入失敗,這是一個設置備份文件,你需要去這裡導入:\n設置 -> 備份與恢復 -> 部分數據 -> 設置導入",
|
||||
"list_import_tip__unknown": "導入失敗,未知的文件類型,請嘗試升級到最新版本後再試",
|
||||
"list_sort_modal_by_album": "專輯名",
|
||||
"list_sort_modal_by_down": "降序",
|
||||
"list_sort_modal_by_field": "排序字段",
|
||||
"list_sort_modal_by_name": "歌曲名",
|
||||
"list_sort_modal_by_singer": "歌手名",
|
||||
"list_sort_modal_by_source": "歌曲源",
|
||||
"list_sort_modal_by_time": "時長",
|
||||
"list_sort_modal_by_type": "排序類別",
|
||||
"list_sort_modal_by_up": "升序",
|
||||
"list_sort_modal_tip_confirm": "你確定要這麼做嗎?",
|
||||
"list_update_modal__auto_update": "自動更新",
|
||||
"list_update_modal__tips": "💡 每次啟動軟件時將會自動更新已勾選“自動更新”的列表",
|
||||
"list_update_modal__title": "列表更新管理",
|
||||
"list_update_modal__update": "立即更新",
|
||||
"lists__duplicate": "重複歌曲",
|
||||
"lists__export": "導出",
|
||||
"lists__export_part_desc": "選擇列表文件保存位置",
|
||||
"lists__import": "導入",
|
||||
"lists__import_part_button_cancel": "不要啊",
|
||||
"lists__import_part_button_confirm": "覆蓋掉",
|
||||
"lists__import_part_confirm": "導入的列表({importName})與本地列表({localName})的ID相同,是否覆蓋本地列表?",
|
||||
"lists__import_part_desc": "選擇列表文件",
|
||||
"lists__new_list_btn": "新建列表",
|
||||
"lists__new_list_input": "新列表...",
|
||||
"lists__remove": "刪除",
|
||||
"lists__remove music_tip": "你真的要移除所選的 {len} 首歌曲嗎?",
|
||||
"lists__remove_tip": "你真的想要移除 {name} 嗎?",
|
||||
"lists__remove_tip_button": "是的 沒錯",
|
||||
"lists__rename": "重命名",
|
||||
"lists__sort_list": "排序歌曲",
|
||||
"lists__source_detail": "歌單詳情頁",
|
||||
"lists__sync": "更新",
|
||||
"lists__sync_confirm_tip": "這將會把 {name} 內的歌曲替換成在線列表的歌曲,你確認要更新嗎?",
|
||||
"load_list_file_error_detail": "我們已經幫你把舊的列表文件備份到{path}\n它以 JSON 格式存儲,你可以嘗試手動修復並恢復它\n\n錯誤詳情:{detail}",
|
||||
"load_list_file_error_title": "播放列表數據加載錯誤(建議到GitHub或加群反饋)",
|
||||
"loding": "加載中...",
|
||||
"love_list": "收藏",
|
||||
"lyric__load_error": "歌詞獲取失敗",
|
||||
"lyric__select": "歌詞文本選擇",
|
||||
"lyric_menu__align": "歌詞對齊方式",
|
||||
"lyric_menu__align_center": "居中",
|
||||
"lyric_menu__align_left": "居左",
|
||||
"lyric_menu__lrc_size": "字體大小 [ {size} ]",
|
||||
"lyric_menu__offset": "歌詞偏移 [ {offset}ms ]",
|
||||
"lyric_menu__offset_add_10": "加快10毫秒",
|
||||
"lyric_menu__offset_add_100": "加快100毫秒",
|
||||
"lyric_menu__offset_dec_10": "減慢10毫秒",
|
||||
"lyric_menu__offset_dec_100": "減慢100毫秒",
|
||||
"lyric_menu__offset_reset": "重置",
|
||||
"lyric_menu__size_add": "加大字體(右擊可微調)",
|
||||
"lyric_menu__size_dec": "減小字體(右擊可微調)",
|
||||
"lyric_menu__size_reset": "重置",
|
||||
"min": "最小化",
|
||||
"music_album": "專輯名",
|
||||
"music_duplicate": "重複歌曲",
|
||||
"music_name": "歌曲名",
|
||||
"music_singer": "藝術家",
|
||||
"music_sort__btn_cancel": "取消",
|
||||
"music_sort__btn_confirm": "確定",
|
||||
"music_sort__input_tip": "請輸入要調整到第幾個位置",
|
||||
"music_sort__title": "將 {name} 的位置調整到:",
|
||||
"music_sort__title_multiple": "將已選的 {num} 首歌曲的位置調整到:",
|
||||
"music_time": "時長",
|
||||
"my_list": "我的列表",
|
||||
"no_item": "列表竟然是空的...",
|
||||
"not_agree": "不接受",
|
||||
"ok": "我知道了",
|
||||
"pagination__next": "下一頁",
|
||||
"pagination__page": "第 {num} 頁",
|
||||
"pagination__prev": "上一頁",
|
||||
"play_timeout": "定時暫停",
|
||||
"play_timeout_close": "關閉",
|
||||
"play_timeout_confirm": "確認",
|
||||
"play_timeout_end": "等待歌曲播放完畢再暫停",
|
||||
"play_timeout_stop": "取消定時",
|
||||
"play_timeout_tip": "{time} 後暫停播放",
|
||||
"play_timeout_unit": "分鐘",
|
||||
"play_timeout_update": "更新定時",
|
||||
"player__add_music_to": "添加當前歌曲到...",
|
||||
"player__buffering": "緩衝中...",
|
||||
"player__desktop_lyric_lock": "右擊鎖定歌詞",
|
||||
"player__desktop_lyric_off": "關閉桌面歌詞",
|
||||
"player__desktop_lyric_on": "開啟桌面歌詞",
|
||||
"player__desktop_lyric_unlock": "右擊解鎖歌詞",
|
||||
"player__end": "播放完畢",
|
||||
"player__error": "音頻加載出錯,5 秒後切換下一首",
|
||||
"player__geting_url": "歌曲鏈接獲取中...",
|
||||
"player__hide_detail_tip": "隱藏詳情頁(界面內右鍵雙擊可快速隱藏詳情頁)",
|
||||
"player__loading": "音樂加載中...",
|
||||
"player__music_album": "專輯名:",
|
||||
"player__music_name": "歌曲名:",
|
||||
"player__music_singer": "藝術家:",
|
||||
"player__next": "下一首",
|
||||
"player__pause": "暫停",
|
||||
"player__pic_tip": "播放詳情頁(右擊在“我的列表”定位當前播放的歌曲)",
|
||||
"player__play": "播放",
|
||||
"player__play_toggle_mode_list": "順序播放",
|
||||
"player__play_toggle_mode_list_loop": "列表循環",
|
||||
"player__play_toggle_mode_off": "禁用",
|
||||
"player__play_toggle_mode_random": "列表隨機",
|
||||
"player__play_toggle_mode_single_loop": "單曲循環",
|
||||
"player__playing": "播放中...",
|
||||
"player__prev": "上一首",
|
||||
"player__refresh_url": "URL過期,正在刷新URL...",
|
||||
"player__stop": "暫停播放",
|
||||
"player__volume": "當前音量:",
|
||||
"search": "搜索",
|
||||
"search__hot_search": "熱門搜索",
|
||||
"search__welcome": "搜我所想~~😉",
|
||||
"setting": "設置",
|
||||
"setting__about": "關於洛雪音樂",
|
||||
"setting__backup": "備份與恢復",
|
||||
"setting__backup_all": "所有數據(列表數據與設置數據)",
|
||||
"setting__backup_all_export": "導出",
|
||||
"setting__backup_all_export_desc": "選擇備份保存位置",
|
||||
"setting__backup_all_import": "導入",
|
||||
"setting__backup_all_import_desc": "選擇備份文件",
|
||||
"setting__backup_other": "其他備份格式(目前不支持恢復此類備份文件)",
|
||||
"setting__backup_other_export_dir": "選擇文件保存位置",
|
||||
"setting__backup_other_export_list_csv": "導出 CSV 格式的列表",
|
||||
"setting__backup_other_export_list_text": "導出 TXT 格式的列表",
|
||||
"setting__backup_other_export_list_text_confirm": "是否將所有列表合併為一個文件?",
|
||||
"setting__backup_part": "部分數據(列表數據包括試聽列表、收藏列表、用戶自定義列表,設置數據不包括快捷鍵設置)",
|
||||
"setting__backup_part_export_list": "導出列表",
|
||||
"setting__backup_part_export_list_desc": "選擇歌單保存位置",
|
||||
"setting__backup_part_export_setting": "導出設置",
|
||||
"setting__backup_part_export_setting_desc": "選擇設置保存位置",
|
||||
"setting__backup_part_import_list": "導入列表",
|
||||
"setting__backup_part_import_list_desc": "選擇列表文件",
|
||||
"setting__backup_part_import_setting": "導入設置",
|
||||
"setting__backup_part_import_setting_desc": "選擇配置文件",
|
||||
"setting__basic": "基本設置",
|
||||
"setting__basic_animation": "彈出層隨機動畫",
|
||||
"setting__basic_control_btn_position": "控制按鈕位置",
|
||||
"setting__basic_control_btn_position_left": "左邊",
|
||||
"setting__basic_control_btn_position_right": "右邊",
|
||||
"setting__basic_font": "字體",
|
||||
"setting__basic_lang": "語言",
|
||||
"setting__basic_lang_title": "軟件顯示的語言",
|
||||
"setting__basic_show_animation": "顯示切換動畫",
|
||||
"setting__basic_source": "音樂來源",
|
||||
"setting__basic_source_status_failed": "初始化失敗",
|
||||
"setting__basic_source_status_initing": "初始化中",
|
||||
"setting__basic_source_status_success": "初始化成功",
|
||||
"setting__basic_source_temp": "臨時接口(軟件的某些功能不可用,建議測試接口不可用再使用本接口)",
|
||||
"setting__basic_source_test": "測試接口(幾乎軟件的所有功能都可用)",
|
||||
"setting__basic_source_title": "選擇音樂來源",
|
||||
"setting__basic_source_user_api_btn": "自定義源管理",
|
||||
"setting__basic_sourcename": "音源名字",
|
||||
"setting__basic_sourcename_alias": "別名",
|
||||
"setting__basic_sourcename_real": "原名",
|
||||
"setting__basic_sourcename_title": "選擇音源名字類型",
|
||||
"setting__basic_start_in_fullscreen": "以全屏模式啟動",
|
||||
"setting__basic_theme": "主題顏色",
|
||||
"setting__basic_theme_auto_tip": "此乃動態主題,你可以預先設置一個亮色主題及暗色主題,此後將根據系統的亮、暗主題色自動切換為你預先設置的相應主題。\n注:鼠標 右擊 此主題項即可打開亮、暗色主題設置窗口。",
|
||||
"setting__basic_to_tray": "關閉軟件時不退出軟件將其最小化到系統托盤",
|
||||
"setting__basic_window_size": "窗口尺寸",
|
||||
"setting__basic_window_size_big": "大",
|
||||
"setting__basic_window_size_huge": "巨大",
|
||||
"setting__basic_window_size_larger": "較大",
|
||||
"setting__basic_window_size_medium": "中",
|
||||
"setting__basic_window_size_oversized": "超大",
|
||||
"setting__basic_window_size_small": "小",
|
||||
"setting__basic_window_size_smaller": "較小",
|
||||
"setting__basic_window_size_title": "設置軟件窗口尺寸",
|
||||
"setting__click_copy": "點擊複製",
|
||||
"setting__click_open": "點擊打開",
|
||||
"setting__desktop_lyric": "桌面歌詞設置",
|
||||
"setting__desktop_lyric_always_on_top": "使歌詞總是在其他窗口之上",
|
||||
"setting__desktop_lyric_always_on_top_loop": "自動刷新歌詞置頂(當歌詞置頂後仍被某些程序遮擋時可嘗試啟用此設置)",
|
||||
"setting__desktop_lyric_delay_scroll": "延遲歌詞滾動",
|
||||
"setting__desktop_lyric_enable": "顯示歌詞",
|
||||
"setting__desktop_lyric_font": "歌詞字體",
|
||||
"setting__desktop_lyric_font_default": "默認",
|
||||
"setting__desktop_lyric_hover_hide": "鼠標移入歌詞區域時降低歌詞透明度(此功能存在平台兼容性問題)",
|
||||
"setting__desktop_lyric_lock": "鎖定歌詞",
|
||||
"setting__desktop_lyric_lock_screen": "不允許歌詞窗口拖出主屏幕之外",
|
||||
"setting__download": "下載設置",
|
||||
"setting__download_data_embed": "是否將以下內容嵌入到音頻文件中",
|
||||
"setting__download_embed_lyric": "歌詞嵌入",
|
||||
"setting__download_embed_pic": "封面嵌入",
|
||||
"setting__download_enable": "是否啟用下載功能",
|
||||
"setting__download_lyric": "歌詞下載",
|
||||
"setting__download_lyric_format": "下載的歌詞文件編碼格式",
|
||||
"setting__download_lyric_format_gbk": "GBK(在某些設備上出現中文亂碼時可嘗試選擇此格式)",
|
||||
"setting__download_lyric_format_utf8": "UTF-8",
|
||||
"setting__download_lyric_title": "是否同時下載歌詞文件",
|
||||
"setting__download_name": "文件命名方式",
|
||||
"setting__download_name1": "歌名 - 歌手",
|
||||
"setting__download_name2": "歌手 - 歌名",
|
||||
"setting__download_name3": "歌名",
|
||||
"setting__download_name_title": "下載歌曲時的命名方式",
|
||||
"setting__download_path": "下載路徑",
|
||||
"setting__download_path_change_btn": "更改",
|
||||
"setting__download_path_label": "當前下載路徑:",
|
||||
"setting__download_path_open_label": "點擊打開當前路徑",
|
||||
"setting__download_path_title": "下載歌曲保存的路徑",
|
||||
"setting__download_select_save_path": "選擇歌曲保存路徑",
|
||||
"setting__download_use_other_source": "自動換源下載",
|
||||
"setting__download_use_other_source_tip": "當無法從歌曲的原始源下載時,嘗試切換到其他源下載,注:此功能不100%保證換源後的歌曲版本與原版一致",
|
||||
"setting__hot_key": "快捷鍵設置",
|
||||
"setting__hot_key_common_focus_search_input": "聚焦搜索框",
|
||||
"setting__hot_key_common_min": "最小化程序",
|
||||
"setting__hot_key_common_toggle_close": "退出程序",
|
||||
"setting__hot_key_common_toggle_hide": "顯示/隱藏程序",
|
||||
"setting__hot_key_common_toggle_min": "最小化/還原程序",
|
||||
"setting__hot_key_desktop_lyric_toggle_always_top": "桌面歌詞置頂切換",
|
||||
"setting__hot_key_desktop_lyric_toggle_lock": "桌面歌詞鎖定切換",
|
||||
"setting__hot_key_desktop_lyric_toggle_visible": "開/關桌面歌詞",
|
||||
"setting__hot_key_global_title": "全局快捷鍵",
|
||||
"setting__hot_key_local_title": "軟件內快捷鍵",
|
||||
"setting__hot_key_player_next": "下一首歌曲",
|
||||
"setting__hot_key_player_prev": "上一首歌曲",
|
||||
"setting__hot_key_player_toggle_play": "播放/暫停控制",
|
||||
"setting__hot_key_player_volume_down": "減少音量",
|
||||
"setting__hot_key_player_volume_mute": "靜音切換",
|
||||
"setting__hot_key_player_volume_up": "增加音量",
|
||||
"setting__hot_key_tip_input": "請輸入新的按鍵",
|
||||
"setting__hot_key_unset_input": "未設置",
|
||||
"setting__is_enable": "是否啟用",
|
||||
"setting__is_show": "是否顯示",
|
||||
"setting__list": "列表設置",
|
||||
"setting__list_add_music_location_type": "添加歌曲到列表時的位置",
|
||||
"setting__list_add_music_location_type_bottom": "底部",
|
||||
"setting__list_add_music_location_type_top": "頂部",
|
||||
"setting__list_click_action": "雙擊列表裡的歌曲時自動切換到當前列表播放(僅對歌單、排行榜有效)",
|
||||
"setting__list_scroll": "記住播放列表滾動條位置(僅對我的音樂分類有效)",
|
||||
"setting__list_source": "顯示歌曲源(僅對我的音樂分類有效)",
|
||||
"setting__network": "網絡設置",
|
||||
"setting__network_proxy_host": "主機",
|
||||
"setting__network_proxy_password": "密碼",
|
||||
"setting__network_proxy_port": "端口",
|
||||
"setting__network_proxy_title": "HTTP代理設置(亂設置軟件將無法聯網)",
|
||||
"setting__network_proxy_username": "用戶名",
|
||||
"setting__odc": "強迫症設置",
|
||||
"setting__odc_clear_search_input": "離開搜索界面時清空搜索框",
|
||||
"setting__odc_clear_search_list": "離開搜索界面時清空搜索列表",
|
||||
"setting__other": "其他",
|
||||
"setting__other_play_list_cache": "列表緩存管理",
|
||||
"setting__other_play_list_cache_clear_btn": "清理列表緩存信息",
|
||||
"setting__other_play_list_cache_tip": "我的列表中已緩存的歌曲鏈接、播放代替源,清理後播放、下載歌曲時需要重新獲取,沒有歌曲播放相關的問題不要清理",
|
||||
"setting__other_play_list_cache_tip_confirm": "我的列表中已緩存的歌曲鏈接、播放代替源,清理後播放、下載歌曲時需要重新獲取,沒有歌曲播放相關的問題不要清理,是否確認清理?",
|
||||
"setting__other_resource_cache": "資源緩存管理",
|
||||
"setting__other_resource_cache_clear_btn": "清理資源緩存",
|
||||
"setting__other_resource_cache_confirm": "我要清掉",
|
||||
"setting__other_resource_cache_label": "軟件已使用緩存大小:",
|
||||
"setting__other_resource_cache_tip": "圖片、音頻等緩存,清理後圖片等資源將需要重新下載,不建議清理,軟件會根據磁盤空間動態管理緩存大小",
|
||||
"setting__other_resource_cache_tip_confirm": "涉及圖片、音頻等緩存,清理後圖片等資源將需要重新下載,不建議清理,軟件會根據磁盤空間動態管理緩存大小,是否仍要清理?",
|
||||
"setting__other_tray_theme": "托盤圖標樣式",
|
||||
"setting__other_tray_theme_black": "黑色",
|
||||
"setting__other_tray_theme_native": "白色",
|
||||
"setting__other_tray_theme_origin": "原色",
|
||||
"setting__play": "播放設置",
|
||||
"setting__play_auto_skip_on_error": "播放錯誤時自動切換歌曲",
|
||||
"setting__play_detail": "播放詳情頁設置",
|
||||
"setting__play_detail_align": "歌詞對齊方式",
|
||||
"setting__play_detail_align_center": "居中",
|
||||
"setting__play_detail_align_left": "居左",
|
||||
"setting__play_detail_align_right": "居右",
|
||||
"setting__play_detail_font_size": "歌詞字體大小(可以在播放詳情頁使用鍵盤的 + - 調整字體大小)",
|
||||
"setting__play_detail_font_size_current": "當前字體大小:{size}",
|
||||
"setting__play_detail_font_size_reset": "重置",
|
||||
"setting__play_detail_font_zoom": "縮放當前正在播放的歌詞",
|
||||
"setting__play_detail_lyric_progress": "允許通過歌詞調整播放進度",
|
||||
"setting__play_lyric_lxlrc": "使用卡拉OK式歌詞播放(如果可用)",
|
||||
"setting__play_lyric_roma": "顯示歌詞羅馬音(如果可用)",
|
||||
"setting__play_lyric_s2t": "將播放與下載的歌詞轉換為繁體中文",
|
||||
"setting__play_lyric_transition": "顯示歌詞翻譯(如果可用)",
|
||||
"setting__play_mediaDevice": "音頻輸出",
|
||||
"setting__play_mediaDevice_remove_stop_play": "當前的聲音輸出設備被改變時暫停播放歌曲",
|
||||
"setting__play_mediaDevice_title": "選擇聲音輸出的媒體設備",
|
||||
"setting__play_media_device_error_tip": "此功能與音頻可視化功能衝突,你本次啟動軟件時已啟用過音頻可視化,此設置暫不可用,請 重啟 軟件後,再來修改此設置。",
|
||||
"setting__play_media_device_tip": "此功能與音頻可視化功能衝突,兩者無法同時啟用,是否將音頻可視化關閉 並 應用所選音頻輸出設置?",
|
||||
"setting__play_quality": "優先播放320K品質的歌曲(如果可用)",
|
||||
"setting__play_save_play_time": "記住播放進度",
|
||||
"setting__play_task_bar": "在任務欄上顯示當前歌曲播放進度",
|
||||
"setting__play_timeout": "定時暫停",
|
||||
"setting__player_audio_visualization_tip": "自定義音頻輸出設備與音頻可視化功能會衝突,啟用了音頻可視化後音頻輸出設備將會被重置為默認的輸出設備,目前此問題暫無法解決,是否仍要開啟?",
|
||||
"setting__search": "搜索設置",
|
||||
"setting__search_focus_search_box": "啟動時自動聚焦搜索框",
|
||||
"setting__search_history": "顯示歷史搜索記錄",
|
||||
"setting__search_hot": "顯示熱門搜索",
|
||||
"setting__sync": "數據同步",
|
||||
"setting__sync_address": "同步服務地址:{address}",
|
||||
"setting__sync_auth_code": "連接碼:{code}",
|
||||
"setting__sync_device": "已連接的設備:{devices}",
|
||||
"setting__sync_enable": "啟用同步功能(由於數據是明文傳輸,請在受信任的網絡下使用)",
|
||||
"setting__sync_port": "同步端口設置",
|
||||
"setting__sync_port_tip": "請輸入同步服務端口號",
|
||||
"setting__sync_refresh_code": "刷新連接碼",
|
||||
"setting__sync_tip": "使用方式請看常見問題“同步功能”部分",
|
||||
"setting__update": "軟件更新",
|
||||
"setting__update_checking": "檢查更新中...",
|
||||
"setting__update_current_label": "當前版本:",
|
||||
"setting__update_downloading": "發現新版本並在努力下載中,請稍後...⏳",
|
||||
"setting__update_init": "處理更新中...",
|
||||
"setting__update_latest": "軟件已是最新,盡情地體驗吧~🥂",
|
||||
"setting__update_latest_label": "最新版本:",
|
||||
"setting__update_open_version_modal_btn": "打開更新窗口 🚀",
|
||||
"setting__update_progress": "下載進度:",
|
||||
"setting__update_unknown": "未知",
|
||||
"song_list": "歌單",
|
||||
"songlist__import_input_tip": "輸入歌單鏈接或歌單ID",
|
||||
"songlist__import_input_tip_1": "不支持跨源打開歌單,請確認要打開的歌單與當前歌單源是否對應",
|
||||
"songlist__import_input_tip_2": "若遇到無法打開的歌單鏈接,歡迎反饋",
|
||||
"songlist__import_input_tip_3": "酷狗源不支持用歌單ID打開,但支持酷狗碼打開",
|
||||
"songlist__open_list": "打開{name}歌單",
|
||||
"source_alias_all": "聚合大會",
|
||||
"source_alias_bd": "小杜音樂",
|
||||
"source_alias_kg": "小枸音樂",
|
||||
"source_alias_kw": "小蝸音樂",
|
||||
"source_alias_mg": "小蜜音樂",
|
||||
"source_alias_tx": "小秋音樂",
|
||||
"source_alias_wy": "小芸音樂",
|
||||
"source_alias_xm": "小霞音樂",
|
||||
"source_all": "聚合搜索",
|
||||
"source_bd": "百度音樂",
|
||||
"source_kg": "酷狗音樂",
|
||||
"source_kw": "酷我音樂",
|
||||
"source_mg": "咪咕音樂",
|
||||
"source_tx": "企鵝音樂",
|
||||
"source_wy": "網易音樂",
|
||||
"source_xm": "蝦米音樂",
|
||||
"sync__merge_btn_local_remote": "本機列表 合併 遠程列表",
|
||||
"sync__merge_btn_remote_local": "遠程列表 合併 本機列表",
|
||||
"sync__merge_label": "合併",
|
||||
"sync__merge_tip": "合併:",
|
||||
"sync__merge_tip_desc": "將兩邊的列表合併到一起,相同的歌曲將被去掉(去掉的是被合併者的歌曲),不同的歌曲將被添加。",
|
||||
"sync__other_label": "其他",
|
||||
"sync__other_tip": "其他:",
|
||||
"sync__other_tip_desc": "“僅使用實時同步功能”將不修改雙方的列表,僅實時同步操作;“取消同步”將直接斷開雙方的連接。",
|
||||
"sync__overwrite": "完全覆蓋",
|
||||
"sync__overwrite_btn_cancel": "取消同步",
|
||||
"sync__overwrite_btn_local_remote": "本機列表 覆蓋 遠程列表",
|
||||
"sync__overwrite_btn_none": "僅使用實時同步功能",
|
||||
"sync__overwrite_btn_remote_local": "遠程列表 覆蓋 本機列表",
|
||||
"sync__overwrite_label": "覆蓋",
|
||||
"sync__overwrite_tip": "覆蓋:",
|
||||
"sync__overwrite_tip_desc": "被覆蓋者與覆蓋者列表ID相同的列表將被刪除後替換成覆蓋者的列表(列表ID不同的列表將被合併到一起),若勾選完全覆蓋,則被覆蓋者的所有列表將被移除,然後替換成覆蓋者的列表。",
|
||||
"sync__title": "選擇與 {name} 的列表同步方式",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
"tag__lossless_24bit": "24bit",
|
||||
"theme_auto": "道法自然",
|
||||
"theme_auto_tip": "鼠標 右擊 可打開亮、暗主題設置窗口",
|
||||
"theme_black": "黑燈瞎火",
|
||||
"theme_blue": "藍田生玉",
|
||||
"theme_blue2": "清熱版藍",
|
||||
"theme_green": "綠意盎然",
|
||||
"theme_grey": "灰常美麗",
|
||||
"theme_happy_new_year": "新年快樂",
|
||||
"theme_mid_autumn": "月裡嫦娥",
|
||||
"theme_ming": "青出於黑",
|
||||
"theme_naruto": "木葉之村",
|
||||
"theme_orange": "橙黃橘綠",
|
||||
"theme_pink": "粉裝玉琢",
|
||||
"theme_purple": "重斤球紫",
|
||||
"theme_red": "熱情似火",
|
||||
"theme_selector_modal__dark_title": "暗色主題",
|
||||
"theme_selector_modal__light_title": "亮色主題",
|
||||
"theme_selector_modal__title": "跟隨系統主題設置",
|
||||
"theme_selector_modal__title_tip": "注:你可以預先設置一個亮色主題及暗色主題,此後將根據系統的亮、暗主題色自動切換為你預先設置的相應主題。",
|
||||
"theme_yellow": "信口雌黃",
|
||||
"user_api__allow_show_update_alert": "允許顯示更新彈窗",
|
||||
"user_api__btn_export": "導出",
|
||||
"user_api__btn_import": "導入",
|
||||
"user_api__btn_remove": "移除",
|
||||
"user_api__import_file": "選擇音樂API腳本文件",
|
||||
"user_api__max_tip": "最多只能同時存在20個源哦🤪\n想要繼續導入的話,請先移除一些舊的源騰出位置吧",
|
||||
"user_api__noitem": "這裡竟然是空的 😲",
|
||||
"user_api__note": "提示:雖然我們已經盡可能地隔離了腳本的運行環境,但導入包含惡意行為的腳本仍可能會影響你的系統,請謹慎導入。",
|
||||
"user_api__readme": "源編寫說明:",
|
||||
"user_api__title": "自定義源管理",
|
||||
"user_api__update_alert": "自定義源 [{name}] 發現新版本:",
|
||||
"user_api__update_alert_open_url": "打開更新地址"
|
||||
}
|
||||
6
src/main/env/cmdParams.js
vendored
@@ -1,7 +1,13 @@
|
||||
const urlSchemeRxp = /^lxmusic:\/\//
|
||||
|
||||
const parseEnv = () => {
|
||||
const params = {}
|
||||
const rx = /^-\w+/
|
||||
for (let param of process.argv) {
|
||||
if (urlSchemeRxp.test(param)) {
|
||||
global.envParams.deeplink = param
|
||||
}
|
||||
|
||||
if (!rx.test(param)) continue
|
||||
param = param.substring(1)
|
||||
let index = param.indexOf('=')
|
||||
|
||||
@@ -26,6 +26,14 @@ class MainWindow extends EventEmitter {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.show)
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.focus)
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.blur)
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.hide)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ exports.mainWindow = {
|
||||
ready_to_show: 'ready_to_show',
|
||||
show: 'show',
|
||||
hide: 'hide',
|
||||
focus: 'focus',
|
||||
blur: 'blur',
|
||||
}
|
||||
|
||||
exports.tray = {
|
||||
|
||||
@@ -6,6 +6,7 @@ const Tray = require('./Tray')
|
||||
const WinLyric = require('./WinLyric')
|
||||
const HotKey = require('./HotKey')
|
||||
|
||||
const { Event: TaskBar } = require('../modules/taskbar')
|
||||
const { Event: UserApi } = require('../modules/userApi')
|
||||
const { Event: Sync } = require('../modules/sync')
|
||||
|
||||
@@ -15,5 +16,6 @@ if (!global.lx_event.tray) global.lx_event.tray = new Tray()
|
||||
if (!global.lx_event.winLyric) global.lx_event.winLyric = new WinLyric()
|
||||
if (!global.lx_event.hotKey) global.lx_event.hotKey = new HotKey()
|
||||
|
||||
if (!global.lx_event.taskbar) global.lx_event.taskbar = new TaskBar()
|
||||
if (!global.lx_event.userApi) global.lx_event.userApi = new UserApi()
|
||||
if (!global.lx_event.sync) global.lx_event.sync = new Sync()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const { app, BrowserWindow, shell, nativeTheme } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
const urlSchemeRxp = /^lxmusic:\/\//
|
||||
|
||||
// 单例应用程序
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
app.quit()
|
||||
@@ -8,6 +10,13 @@ if (!app.requestSingleInstanceLock()) {
|
||||
}
|
||||
if (!global.modules) global.modules = {}
|
||||
app.on('second-instance', (event, argv, cwd) => {
|
||||
for (const param of argv) {
|
||||
if (urlSchemeRxp.test(param)) {
|
||||
global.envParams.deeplink = param
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (global.modules.mainWindow) {
|
||||
if (global.modules.mainWindow.isMinimized()) {
|
||||
global.modules.mainWindow.restore()
|
||||
@@ -22,6 +31,18 @@ app.on('second-instance', (event, argv, cwd) => {
|
||||
}
|
||||
})
|
||||
|
||||
// windows平台下如果应用目录下存在 portable 文件夹则将数据存在此文件下
|
||||
if (process.platform === 'win32') {
|
||||
const fs = require('fs')
|
||||
const portablePath = path.join(path.dirname(app.getPath('exe')), '/portable')
|
||||
if (fs.existsSync(portablePath)) {
|
||||
app.setPath('appData', portablePath)
|
||||
const appDataPath = path.join(portablePath, '/userData')
|
||||
if (!fs.existsSync(appDataPath)) fs.mkdirSync(appDataPath)
|
||||
app.setPath('userData', appDataPath)
|
||||
}
|
||||
}
|
||||
|
||||
const isDev = global.isDev = process.env.NODE_ENV !== 'production'
|
||||
require('./env')
|
||||
// console.log(global.envParams.cmdParams)
|
||||
@@ -37,8 +58,40 @@ if (process.platform == 'linux') app.commandLine.appendSwitch('use-gl', 'desktop
|
||||
// https://github.com/electron/electron/issues/22691
|
||||
app.commandLine.appendSwitch('wm-window-animations-disabled')
|
||||
|
||||
// proxy
|
||||
if (global.envParams.cmdParams['proxy-server']) {
|
||||
app.commandLine.appendSwitch('proxy-server', global.envParams.cmdParams['proxy-server'])
|
||||
app.commandLine.appendSwitch('proxy-bypass-list', global.envParams.cmdParams['proxy-bypass-list'] ?? '<local>')
|
||||
}
|
||||
// if (global.envParams.cmdParams['proxy-pac-url']) app.commandLine.appendSwitch('proxy-pac-url', global.envParams.cmdParams['proxy-pac-url'])
|
||||
|
||||
const { navigationUrlWhiteList } = require('../common/config')
|
||||
// deep link
|
||||
app.on('open-url', (event, url) => {
|
||||
if (!urlSchemeRxp.test(url)) return
|
||||
event.preventDefault()
|
||||
global.envParams.deeplink = url
|
||||
if (global.modules.mainWindow) {
|
||||
if (global.modules.mainWindow.isMinimized()) {
|
||||
global.modules.mainWindow.restore()
|
||||
}
|
||||
if (global.modules.mainWindow.isVisible()) {
|
||||
global.modules.mainWindow.focus()
|
||||
} else {
|
||||
global.modules.mainWindow.show()
|
||||
}
|
||||
} else if (global.modules.mainWindow === null) {
|
||||
init()
|
||||
}
|
||||
})
|
||||
// if (isDev && process.platform === 'win32') {
|
||||
// // Set the path of electron.exe and your app.
|
||||
// // These two additional parameters are only available on windows.
|
||||
// // console.log(process.execPath, process.argv)
|
||||
// app.setAsDefaultProtocolClient('lxmusic', process.execPath, process.argv.slice(1))
|
||||
// }
|
||||
if (!isDev) app.setAsDefaultProtocolClient('lxmusic')
|
||||
|
||||
const { navigationUrlWhiteList, themes } = require('../common/config')
|
||||
const { getWindowSizeInfo, initSetting, updateSetting } = require('./utils')
|
||||
const { isMac, isLinux, initHotKey } = require('../common/utils')
|
||||
|
||||
@@ -46,7 +99,7 @@ const { isMac, isLinux, initHotKey } = require('../common/utils')
|
||||
// https://github.com/electron/electron/issues/18397
|
||||
// 开发模式下为true时 多次引入native模块会导致渲染进程卡死
|
||||
// https://github.com/electron/electron/issues/22791
|
||||
app.allowRendererProcessReuse = !isDev
|
||||
// app.allowRendererProcessReuse = !isDev
|
||||
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
@@ -75,6 +128,10 @@ app.on('web-contents-created', (event, contents) => {
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
// disable create dictionary
|
||||
// https://github.com/lyswhut/lx-music-desktop/issues/773
|
||||
contents.session.setSpellCheckerDictionaryDownloadURL('http://0.0.0.0')
|
||||
})
|
||||
|
||||
|
||||
@@ -102,7 +159,7 @@ function createWindow() {
|
||||
/**
|
||||
* Initial window options
|
||||
*/
|
||||
global.modules.mainWindow = new BrowserWindow({
|
||||
const options = {
|
||||
height: windowSizeInfo.height,
|
||||
useContentSize: true,
|
||||
width: windowSizeInfo.width,
|
||||
@@ -112,18 +169,32 @@ function createWindow() {
|
||||
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
fullscreenable: false,
|
||||
fullscreenable: true,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
contextIsolation: false,
|
||||
webSecurity: !isDev,
|
||||
nodeIntegration: true,
|
||||
spellcheck: false, // 禁用拼写检查器
|
||||
},
|
||||
})
|
||||
}
|
||||
if (global.appSetting.startInFullscreen) {
|
||||
options.fullscreen = true
|
||||
if (isLinux) options.resizable = true
|
||||
}
|
||||
global.modules.mainWindow = new BrowserWindow(options)
|
||||
|
||||
global.modules.mainWindow.loadURL(winURL)
|
||||
const shouldUseDarkColors = nativeTheme.shouldUseDarkColors
|
||||
const themeId = global.appSetting.theme.id == 'auto'
|
||||
? shouldUseDarkColors
|
||||
? global.appSetting.theme.darkId
|
||||
: global.appSetting.theme.lightId
|
||||
: global.appSetting.theme.id
|
||||
const themeClass = themes.find(t => t.id == themeId)?.className ?? themes[0].className
|
||||
global.modules.mainWindow.loadURL(winURL + `?dt=${!!global.envParams.cmdParams.dt}&dark=${shouldUseDarkColors}&theme=${themeClass}`)
|
||||
|
||||
winEvent(global.modules.mainWindow)
|
||||
if (global.envParams.cmdParams.odt) require('@main/utils').openDevTools(global.modules.mainWindow.webContents)
|
||||
// global.modules.mainWindow.webContents.openDevTools()
|
||||
|
||||
if (!isDev) autoUpdate()
|
||||
|
||||
@@ -2,4 +2,3 @@ require('./appMenu')
|
||||
require('./winLyric')
|
||||
require('./tray')
|
||||
require('./hotKey')
|
||||
require('./userApi')
|
||||
|
||||
@@ -3,8 +3,9 @@ const sio = require('socket.io')
|
||||
const { createHttpTerminator } = require('http-terminator')
|
||||
const modules = require('../modules')
|
||||
const { authCode, authConnect } = require('./auth')
|
||||
const { getAddress, getServerId, generateCode, getClientKeyInfo } = require('./utils')
|
||||
const syncList = require('./syncList')
|
||||
const { getAddress, getServerId, generateCode, getClientKeyInfo, setClientKeyInfo } = require('./utils')
|
||||
const { syncList, removeSnapshot } = require('./syncList')
|
||||
const { log } = require('@common/utils')
|
||||
|
||||
|
||||
let status = {
|
||||
@@ -71,7 +72,7 @@ const handleStartServer = (port = 9527) => new Promise((resolve, reject) => {
|
||||
serveClient: false,
|
||||
connectTimeout: 10000,
|
||||
pingTimeout: 30000,
|
||||
maxHttpBufferSize: 3e6,
|
||||
maxHttpBufferSize: 1e9, // 1G
|
||||
allowRequest: authConnection,
|
||||
transports: ['websocket'],
|
||||
})
|
||||
@@ -83,12 +84,15 @@ const handleStartServer = (port = 9527) => new Promise((resolve, reject) => {
|
||||
global.lx_event.sync.status(status)
|
||||
})
|
||||
const keyInfo = getClientKeyInfo(socket.handshake.query.i)
|
||||
keyInfo.connectionTime = Date.now()
|
||||
setClientKeyInfo(keyInfo)
|
||||
// socket.lx_keyInfo = keyInfo
|
||||
socket.data.keyInfo = keyInfo
|
||||
try {
|
||||
await syncList(io, socket)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
// console.log(err)
|
||||
log.warn(err)
|
||||
return
|
||||
}
|
||||
status.devices.push(keyInfo)
|
||||
@@ -120,7 +124,14 @@ const handleStopServer = async() => {
|
||||
}
|
||||
|
||||
exports.stopServer = async() => {
|
||||
if (!status.status) return
|
||||
if (!status.status) {
|
||||
status.status = false
|
||||
status.message = ''
|
||||
status.address = []
|
||||
status.code = ''
|
||||
global.lx_event.sync.status(status)
|
||||
return
|
||||
}
|
||||
console.log('stoping sync server...')
|
||||
return handleStopServer().then(() => {
|
||||
console.log('sync server stoped')
|
||||
@@ -163,3 +174,5 @@ exports.generateCode = async() => {
|
||||
global.lx_event.sync.status(status)
|
||||
return status.code
|
||||
}
|
||||
|
||||
exports.removeSnapshot = removeSnapshot
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const fsPromises = fs.promises
|
||||
const { app } = require('electron')
|
||||
const { encryptMsg, decryptMsg } = require('./utils')
|
||||
const { encryptMsg, decryptMsg, getSnapshotFilePath } = require('./utils')
|
||||
const SYNC_EVENT_NAMES = require('../event/name')
|
||||
const { common: COMMON_EVENT_NAME } = require('@main/events/_name')
|
||||
const { throttle } = require('@common/utils')
|
||||
@@ -11,6 +9,22 @@ let io
|
||||
let syncingId = null
|
||||
const wait = (time = 1000) => new Promise((resolve, reject) => setTimeout(resolve, time))
|
||||
|
||||
const patchListData = listData => {
|
||||
return Object.assign({}, {
|
||||
defaultList: {
|
||||
id: 'default',
|
||||
name: '试听列表',
|
||||
list: [],
|
||||
},
|
||||
loveList: {
|
||||
id: 'love',
|
||||
name: '我的收藏',
|
||||
list: [],
|
||||
},
|
||||
userList: [],
|
||||
}, listData)
|
||||
}
|
||||
|
||||
const getRemoteListData = socket => new Promise((resolve, reject) => {
|
||||
console.log('getRemoteListData')
|
||||
const handleError = reason => {
|
||||
@@ -23,7 +37,7 @@ const getRemoteListData = socket => new Promise((resolve, reject) => {
|
||||
const data = JSON.parse(decryptMsg(socket.data.keyInfo, enData))
|
||||
if (!data) return reject(new Error('Get remote list data failed'))
|
||||
if (data.action != 'getData') return
|
||||
resolve(data.data)
|
||||
resolve(patchListData(data.data))
|
||||
}
|
||||
|
||||
socket.on('disconnect', handleError)
|
||||
@@ -35,7 +49,7 @@ const getLocalListData = () => new Promise((resolve, reject) => {
|
||||
const handleSuccess = ({ action, data }) => {
|
||||
if (action !== 'getData') return
|
||||
global.lx_event.sync.off(SYNC_EVENT_NAMES.sync_handle_list, handleSuccess)
|
||||
resolve(data)
|
||||
resolve(patchListData(data))
|
||||
}
|
||||
global.lx_event.sync.on(SYNC_EVENT_NAMES.sync_handle_list, handleSuccess)
|
||||
global.lx_event.sync.sync_list({
|
||||
@@ -87,10 +101,10 @@ const updateSnapshot = (path, data) => {
|
||||
}
|
||||
|
||||
|
||||
const createListDataObj = listData => {
|
||||
const listDataObj = {}
|
||||
for (const list of listData.userList) listDataObj[list.id] = list
|
||||
return listDataObj
|
||||
const createUserListDataObj = listData => {
|
||||
const userListDataObj = {}
|
||||
for (const list of listData.userList) userListDataObj[list.id] = list
|
||||
return userListDataObj
|
||||
}
|
||||
|
||||
const handleMergeList = (sourceList, targetList, addMusicLocationType) => {
|
||||
@@ -137,17 +151,29 @@ const mergeList = (sourceListData, targetListData) => {
|
||||
newListData.defaultList = handleMergeList(sourceListData.defaultList, targetListData.defaultList, addMusicLocationType)
|
||||
newListData.loveList = handleMergeList(sourceListData.loveList, targetListData.loveList, addMusicLocationType)
|
||||
|
||||
const listDataObj = createListDataObj(sourceListData)
|
||||
const userListDataObj = createUserListDataObj(sourceListData)
|
||||
newListData.userList = [...sourceListData.userList]
|
||||
|
||||
for (const list of targetListData.userList) {
|
||||
const targetList = listDataObj[list.id]
|
||||
if (targetList) {
|
||||
targetList.list = handleMergeList(targetList, list, addMusicLocationType).list
|
||||
targetListData.userList.forEach((list, index) => {
|
||||
const targetUpdateTime = list?.locationUpdateTime ?? 0
|
||||
const sourceList = userListDataObj[list.id]
|
||||
if (sourceList) {
|
||||
sourceList.list = handleMergeList(sourceList, list, addMusicLocationType).list
|
||||
|
||||
const sourceUpdateTime = sourceList?.locationUpdateTime ?? 0
|
||||
if (targetUpdateTime >= sourceUpdateTime) return
|
||||
// 调整位置
|
||||
const [newList] = newListData.userList.splice(newListData.userList.findIndex(l => l.id == list.id), 1)
|
||||
newList.locationUpdateTime = targetUpdateTime
|
||||
newListData.userList.splice(index, 0, newList)
|
||||
} else {
|
||||
newListData.userList.push(list)
|
||||
if (targetUpdateTime) {
|
||||
newListData.userList.splice(index, 0, list)
|
||||
} else {
|
||||
newListData.userList.push(list)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return newListData
|
||||
}
|
||||
@@ -156,14 +182,17 @@ const overwriteList = (sourceListData, targetListData) => {
|
||||
newListData.defaultList = sourceListData.defaultList
|
||||
newListData.loveList = sourceListData.loveList
|
||||
|
||||
const listDataObj = createListDataObj(sourceListData)
|
||||
const userListDataObj = createUserListDataObj(sourceListData)
|
||||
newListData.userList = [...sourceListData.userList]
|
||||
|
||||
for (const list of targetListData.userList) {
|
||||
const targetList = listDataObj[list.id]
|
||||
if (targetList) continue
|
||||
newListData.userList.push(list)
|
||||
}
|
||||
targetListData.userList.forEach((list, index) => {
|
||||
if (userListDataObj[list.id]) return
|
||||
if (list?.locationUpdateTime) {
|
||||
newListData.userList.splice(index, 0, list)
|
||||
} else {
|
||||
newListData.userList.push(list)
|
||||
}
|
||||
})
|
||||
|
||||
return newListData
|
||||
}
|
||||
@@ -259,11 +288,10 @@ const mergeListDataFromSnapshot = (sourceList, targetList, snapshotList, addMusi
|
||||
const targetListItemIds = new Set()
|
||||
for (const m of sourceList.list) sourceListItemIds.add(m.songmid)
|
||||
for (const m of targetList.list) targetListItemIds.add(m.songmid)
|
||||
for (const m of snapshotList.list) {
|
||||
if (!sourceListItemIds.has(m.songmid)) removedListIds.add(m.songmid)
|
||||
}
|
||||
for (const m of snapshotList.list) {
|
||||
if (!targetListItemIds.has(m.songmid)) removedListIds.add(m.songmid)
|
||||
if (snapshotList) {
|
||||
for (const m of snapshotList.list) {
|
||||
if (!sourceListItemIds.has(m.songmid) || !targetListItemIds.has(m.songmid)) removedListIds.add(m.songmid)
|
||||
}
|
||||
}
|
||||
|
||||
let newList
|
||||
@@ -297,13 +325,12 @@ const mergeListDataFromSnapshot = (sourceList, targetList, snapshotList, addMusi
|
||||
const handleMergeListDataFromSnapshot = async(socket, snapshot) => {
|
||||
const addMusicLocationType = global.appSetting.list.addMusicLocationType
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalListData()])
|
||||
console.log('handleMergeListDataFromSnapshot', 'remoteListData, localListData')
|
||||
const newListData = {}
|
||||
newListData.defaultList = mergeListDataFromSnapshot(localListData.defaultList, remoteListData.defaultList, snapshot.defaultList, addMusicLocationType)
|
||||
newListData.loveList = mergeListDataFromSnapshot(localListData.loveList, remoteListData.loveList, snapshot.loveList, addMusicLocationType)
|
||||
const localUserListData = createListDataObj(localListData)
|
||||
const remoteUserListData = createListDataObj(remoteListData)
|
||||
const snapshotUserListData = createListDataObj(snapshot)
|
||||
const localUserListData = createUserListDataObj(localListData)
|
||||
const remoteUserListData = createUserListDataObj(remoteListData)
|
||||
const snapshotUserListData = createUserListDataObj(snapshot)
|
||||
const removedListIds = new Set()
|
||||
const localUserListIds = new Set()
|
||||
const remoteUserListIds = new Set()
|
||||
@@ -311,10 +338,7 @@ const handleMergeListDataFromSnapshot = async(socket, snapshot) => {
|
||||
for (const l of remoteListData.userList) remoteUserListIds.add(l.id)
|
||||
|
||||
for (const l of snapshot.userList) {
|
||||
if (!localUserListIds.has(l.id)) removedListIds.add(l.id)
|
||||
}
|
||||
for (const l of snapshot.userList) {
|
||||
if (!remoteUserListIds.has(l.id)) removedListIds.add(l.id)
|
||||
if (!localUserListIds.has(l.id) || !remoteUserListIds.has(l.id)) removedListIds.add(l.id)
|
||||
}
|
||||
|
||||
let newUserList = []
|
||||
@@ -329,10 +353,26 @@ const handleMergeListDataFromSnapshot = async(socket, snapshot) => {
|
||||
}
|
||||
newUserList.push(newList)
|
||||
}
|
||||
for (const list of remoteListData.userList) {
|
||||
if (removedListIds.has(list.id) || localUserListData[list.id]) continue
|
||||
newUserList.push({ ...list })
|
||||
}
|
||||
|
||||
remoteListData.userList.forEach((list, index) => {
|
||||
if (removedListIds.has(list.id)) return
|
||||
const remoteUpdateTime = list?.locationUpdateTime ?? 0
|
||||
if (localUserListData[list.id]) {
|
||||
const localUpdateTime = localUserListData[list.id]?.locationUpdateTime ?? 0
|
||||
if (localUpdateTime >= remoteUpdateTime) return
|
||||
// 调整位置
|
||||
const [newList] = newUserList.splice(newUserList.findIndex(l => l.id == list.id), 1)
|
||||
newList.locationUpdateTime = localUpdateTime
|
||||
newUserList.splice(index, 0, newList)
|
||||
} else {
|
||||
if (remoteUpdateTime) {
|
||||
newUserList.splice(index, 0, { ...list })
|
||||
} else {
|
||||
newUserList.push({ ...list })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
newListData.userList = newUserList
|
||||
setLocalList(newListData)
|
||||
setRemotelList(socket, newListData)
|
||||
@@ -353,7 +393,7 @@ const registerUpdateSnapshotTask = (socket, snapshot) => {
|
||||
if (loveList != null) snapshot.loveList = loveList
|
||||
if (userList != null) snapshot.userList = userList
|
||||
updateSnapshot(socket.data.snapshotFilePath, JSON.stringify(snapshot))
|
||||
}, 10000)
|
||||
}, 2000)
|
||||
global.lx_event.common.on(COMMON_EVENT_NAME.saveMyList, handleUpdateSnapshot)
|
||||
socket.on('disconnect', () => {
|
||||
global.lx_event.common.off(COMMON_EVENT_NAME.saveMyList, handleUpdateSnapshot)
|
||||
@@ -361,7 +401,7 @@ const registerUpdateSnapshotTask = (socket, snapshot) => {
|
||||
}
|
||||
|
||||
const syncList = async socket => {
|
||||
socket.data.snapshotFilePath = path.join(app.getPath('userData'), `snapshot-${Buffer.from(socket.data.keyInfo.clientId).toString('hex').substring(0, 10)}.json`)
|
||||
socket.data.snapshotFilePath = getSnapshotFilePath(socket.data.keyInfo)
|
||||
let fileData
|
||||
let isSyncRequired = false
|
||||
try {
|
||||
@@ -373,7 +413,7 @@ const syncList = async socket => {
|
||||
}
|
||||
console.log('isSyncRequired', isSyncRequired)
|
||||
if (isSyncRequired) return handleSyncList(socket)
|
||||
return handleMergeListDataFromSnapshot(socket, fileData)
|
||||
return handleMergeListDataFromSnapshot(socket, patchListData(fileData))
|
||||
}
|
||||
|
||||
const checkSyncQueue = async() => {
|
||||
@@ -381,7 +421,7 @@ const checkSyncQueue = async() => {
|
||||
await wait()
|
||||
return checkSyncQueue()
|
||||
}
|
||||
module.exports = async(_io, socket) => {
|
||||
exports.syncList = async(_io, socket) => {
|
||||
io = _io
|
||||
await checkSyncQueue()
|
||||
syncingId = socket.data.keyInfo.clientId
|
||||
@@ -392,3 +432,7 @@ module.exports = async(_io, socket) => {
|
||||
syncingId = null
|
||||
})
|
||||
}
|
||||
exports.removeSnapshot = keyInfo => {
|
||||
const filePath = getSnapshotFilePath(keyInfo)
|
||||
return fsPromises.unlink(filePath)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const { app } = require('electron')
|
||||
const { networkInterfaces } = require('os')
|
||||
const { randomBytes, createCipheriv, createDecipheriv } = require('crypto')
|
||||
const path = require('path')
|
||||
const getStore = require('@common/store')
|
||||
const STORE_NAME = 'sync'
|
||||
|
||||
@@ -91,3 +93,7 @@ exports.decryptMsg = (keyInfo, enMsg) => {
|
||||
// }
|
||||
// return msg
|
||||
}
|
||||
|
||||
exports.getSnapshotFilePath = keyInfo => {
|
||||
return path.join(app.getPath('userData'), `snapshot-${Buffer.from(keyInfo.clientId).toString('hex').substring(0, 10)}.json`)
|
||||
}
|
||||
|
||||
11
src/main/modules/taskbar/event/event.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const { EventEmitter } = require('events')
|
||||
const TASKBAR_EVENT_NAME = require('./name')
|
||||
|
||||
class TaskBar extends EventEmitter {
|
||||
thumbarButtonClick(type) {
|
||||
this.emit(TASKBAR_EVENT_NAME.thumbarButtonClick, type)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TaskBar
|
||||
|
||||
3
src/main/modules/taskbar/event/name.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
thumbarButtonClick: 'thumbarButtonClick',
|
||||
}
|
||||
92
src/main/modules/taskbar/index.js
Normal file
@@ -0,0 +1,92 @@
|
||||
const path = require('path')
|
||||
const Event = require('./event/event')
|
||||
const eventNames = require('./event/name')
|
||||
|
||||
exports.Event = Event
|
||||
exports.eventNames = eventNames
|
||||
|
||||
exports.setThumbnailClip = (region = { x: 0, y: 0, width: 0, height: 0 }) => {
|
||||
if (!global.modules.mainWindow) return
|
||||
return global.modules.mainWindow.setThumbnailClip(region)
|
||||
}
|
||||
|
||||
const getIconPath = name => {
|
||||
return path.join(global.__static, 'images/taskbar', name + '.png')
|
||||
}
|
||||
|
||||
const buttonsFlags = {
|
||||
empty: true,
|
||||
collect: false,
|
||||
play: false,
|
||||
next: true,
|
||||
prev: true,
|
||||
}
|
||||
const createButtons = ({ empty = false, collect = false, play = false, next = true, prev = true }) => {
|
||||
const buttons = [
|
||||
collect
|
||||
? {
|
||||
icon: getIconPath('collected'),
|
||||
click() {
|
||||
global.lx_event.taskbar.thumbarButtonClick('unCollect')
|
||||
},
|
||||
tooltip: '取消收藏',
|
||||
flags: ['nobackground'],
|
||||
}
|
||||
: {
|
||||
icon: getIconPath('collect'),
|
||||
click() {
|
||||
global.lx_event.taskbar.thumbarButtonClick('collect')
|
||||
},
|
||||
tooltip: '收藏',
|
||||
flags: ['nobackground'],
|
||||
},
|
||||
{
|
||||
icon: getIconPath('prev'),
|
||||
click() {
|
||||
global.lx_event.taskbar.thumbarButtonClick('prev')
|
||||
},
|
||||
tooltip: '上一曲',
|
||||
flags: prev ? ['nobackground'] : ['nobackground', 'disabled'],
|
||||
},
|
||||
play
|
||||
? {
|
||||
icon: getIconPath('pause'),
|
||||
click() {
|
||||
global.lx_event.taskbar.thumbarButtonClick('pause')
|
||||
},
|
||||
tooltip: '暂停',
|
||||
flags: ['nobackground'],
|
||||
}
|
||||
: {
|
||||
icon: getIconPath('play'),
|
||||
click() {
|
||||
global.lx_event.taskbar.thumbarButtonClick('play')
|
||||
},
|
||||
tooltip: '播放',
|
||||
flags: ['nobackground'],
|
||||
},
|
||||
{
|
||||
icon: getIconPath('next'),
|
||||
click() {
|
||||
global.lx_event.taskbar.thumbarButtonClick('next')
|
||||
},
|
||||
tooltip: '下一曲',
|
||||
flags: next ? ['nobackground'] : ['nobackground', 'disabled'],
|
||||
},
|
||||
]
|
||||
if (empty) {
|
||||
for (const button of buttons) {
|
||||
button.flags = ['nobackground', 'disabled']
|
||||
}
|
||||
}
|
||||
return buttons
|
||||
}
|
||||
exports.setThumbarButtons = ({ empty, collect, play, next, prev } = buttonsFlags) => {
|
||||
if (!global.modules.mainWindow) return
|
||||
buttonsFlags.empty = empty
|
||||
buttonsFlags.collect = collect
|
||||
buttonsFlags.play = play
|
||||
buttonsFlags.next = next
|
||||
buttonsFlags.prev = prev
|
||||
global.modules.mainWindow.setThumbarButtons(createButtons(buttonsFlags))
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
const { app, Tray, Menu } = require('electron')
|
||||
const { isWin } = require('../../common/utils')
|
||||
const { app, Tray, Menu, nativeImage } = require('electron')
|
||||
const { isWin } = require('@common/utils')
|
||||
const { tray: TRAY_EVENT_NAME, common: COMMON_EVENT_NAME, mainWindow: MAIN_WINDOW_NAME } = require('../events/_name')
|
||||
const path = require('path')
|
||||
let isEnableTray = null
|
||||
@@ -7,12 +7,17 @@ let themeId = null
|
||||
const themeList = [
|
||||
{
|
||||
id: 0,
|
||||
fileName: 'tray0Template',
|
||||
fileName: 'trayTemplate',
|
||||
isNative: true,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
fileName: 'tray1Template',
|
||||
fileName: 'tray_origin',
|
||||
isNative: false,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
fileName: 'tray_black',
|
||||
isNative: false,
|
||||
},
|
||||
]
|
||||
@@ -35,6 +40,14 @@ global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.ready_to_show, () => {
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.show, () => {
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
if (!isWin) {
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.focus, () => {
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.blur, () => {
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
}
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.hide, () => {
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
@@ -43,11 +56,11 @@ const createTray = () => {
|
||||
if ((global.modules.tray && !global.modules.tray.isDestroyed()) || !global.appSetting.tray || !global.appSetting.tray.isShow) return
|
||||
|
||||
themeId = global.appSetting.tray.themeId
|
||||
let themeName = (themeList.find(item => item.id === themeId) || themeList[0]).fileName
|
||||
const iconPath = path.join(global.__static, 'images/tray', isWin ? themeName + '@2x.ico' : themeName + '.png')
|
||||
let theme = themeList.find(item => item.id === themeId) || themeList[0]
|
||||
const iconPath = path.join(global.__static, 'images/tray', theme.fileName + '.png')
|
||||
|
||||
// 托盘
|
||||
global.modules.tray = new Tray(iconPath)
|
||||
global.modules.tray = new Tray(nativeImage.createFromPath(iconPath))
|
||||
|
||||
global.modules.tray.setToolTip('洛雪音乐助手')
|
||||
createMenu(global.modules.tray)
|
||||
@@ -70,55 +83,66 @@ const destroyTray = () => {
|
||||
const createMenu = tray => {
|
||||
if (!global.modules.tray) return
|
||||
let menu = []
|
||||
global.modules.mainWindow && menu.push(global.modules.mainWindow.isVisible() ? {
|
||||
label: '隐藏主界面',
|
||||
click() {
|
||||
global.modules.mainWindow.hide()
|
||||
},
|
||||
} : {
|
||||
label: '显示主界面',
|
||||
click() {
|
||||
if (!global.modules.mainWindow) return
|
||||
if (!global.modules.mainWindow.isVisible()) {
|
||||
global.modules.mainWindow.show()
|
||||
if (global.modules.mainWindow) {
|
||||
const isShow = global.modules.mainWindow.isVisible() && (isWin ? true : global.modules.mainWindow.isFocused())
|
||||
menu.push(isShow
|
||||
? {
|
||||
label: '隐藏主界面',
|
||||
click() {
|
||||
global.modules.mainWindow.hide()
|
||||
},
|
||||
}
|
||||
: {
|
||||
label: '显示主界面',
|
||||
click() {
|
||||
if (!global.modules.mainWindow) return
|
||||
if (!global.modules.mainWindow.isVisible()) {
|
||||
global.modules.mainWindow.show()
|
||||
}
|
||||
global.modules.mainWindow.restore()
|
||||
global.modules.mainWindow.focus()
|
||||
},
|
||||
})
|
||||
}
|
||||
menu.push(global.appSetting.desktopLyric.enable
|
||||
? {
|
||||
label: '关闭桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { enable: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
}
|
||||
global.modules.mainWindow.restore()
|
||||
global.modules.mainWindow.focus()
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.enable ? {
|
||||
label: '关闭桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { enable: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
} : {
|
||||
label: '开启桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { enable: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.isLock ? {
|
||||
label: '解锁桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isLock: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
} : {
|
||||
label: '锁定桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isLock: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.isAlwaysOnTop ? {
|
||||
label: '取消置顶',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isAlwaysOnTop: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
} : {
|
||||
label: '置顶歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isAlwaysOnTop: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
: {
|
||||
label: '开启桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { enable: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.isLock
|
||||
? {
|
||||
label: '解锁桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isLock: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
}
|
||||
: {
|
||||
label: '锁定桌面歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isLock: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.isAlwaysOnTop
|
||||
? {
|
||||
label: '取消置顶',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isAlwaysOnTop: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
}
|
||||
: {
|
||||
label: '置顶歌词',
|
||||
click() {
|
||||
global.lx_core.setAppConfig({ desktopLyric: { isAlwaysOnTop: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push({
|
||||
label: '退出',
|
||||
click() {
|
||||
@@ -132,7 +156,7 @@ const createMenu = tray => {
|
||||
|
||||
const setTrayImage = themeId => {
|
||||
if (!global.modules.tray) return
|
||||
let themeName = (themeList.find(item => item.id === themeId) || themeList[0]).fileName
|
||||
const iconPath = path.join(global.__static, 'images/tray', isWin ? themeName + '@2x.ico' : themeName + '.png')
|
||||
global.modules.tray.setImage(iconPath)
|
||||
let theme = themeList.find(item => item.id === themeId) || themeList[0]
|
||||
const iconPath = path.join(global.__static, 'images/tray', theme.fileName + '.png')
|
||||
global.modules.tray.setImage(nativeImage.createFromPath(iconPath))
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ class UserApi extends EventEmitter {
|
||||
status(info) {
|
||||
this.emit(USER_API_EVENT_NAME.status, info)
|
||||
}
|
||||
|
||||
showUpdateAlert(info) {
|
||||
this.emit(USER_API_EVENT_NAME.showUpdateAlert, info)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserApi
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
module.exports = {
|
||||
status: 'status',
|
||||
showUpdateAlert: 'showUpdateAlert',
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const Event = require('./event/event')
|
||||
const eventNames = require('./event/name')
|
||||
const { closeWindow } = require('./main')
|
||||
const { getUserApis, importApi, removeApi } = require('./utils')
|
||||
const { request, cancelRequest, getStatus, loadApi } = require('./rendererEvent/rendererEvent')
|
||||
const { getUserApis, importApi, removeApi, setAllowShowUpdateAlert: saveAllowShowUpdateAlert } = require('./utils')
|
||||
const { request, cancelRequest, getStatus, loadApi, setAllowShowUpdateAlert } = require('./rendererEvent/rendererEvent')
|
||||
|
||||
// const { getApiList, importApi, removeApi, setApi, getStatus, request, eventNames }
|
||||
let userApiId
|
||||
@@ -41,4 +41,7 @@ exports.setApi = async id => {
|
||||
await loadApi(id)
|
||||
}
|
||||
|
||||
|
||||
exports.setAllowShowUpdateAlert = (id, enable) => {
|
||||
saveAllowShowUpdateAlert(id, enable)
|
||||
setAllowShowUpdateAlert(id, enable)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ fs.readFile(path.join(dir, 'renderer/user-api.html'), 'utf8', (err, data) => {
|
||||
})
|
||||
|
||||
const denyEvents = [
|
||||
'new-window',
|
||||
'will-navigate',
|
||||
'will-redirect',
|
||||
'will-attach-webview',
|
||||
@@ -47,8 +46,18 @@ exports.createWindow = async userApi => {
|
||||
show: false,
|
||||
webPreferences: {
|
||||
contextIsolation: true,
|
||||
worldSafeExecuteJavaScript: true,
|
||||
// worldSafeExecuteJavaScript: true,
|
||||
nodeIntegration: false,
|
||||
nodeIntegrationInWorker: false,
|
||||
|
||||
spellcheck: false,
|
||||
autoplayPolicy: 'document-user-activation-required',
|
||||
enableWebSQL: false,
|
||||
disableDialogs: true,
|
||||
nativeWindowOpen: false,
|
||||
webgl: false,
|
||||
images: false,
|
||||
|
||||
preload: path.join(dir, 'renderer/preload.js'),
|
||||
},
|
||||
})
|
||||
@@ -58,8 +67,13 @@ exports.createWindow = async userApi => {
|
||||
event.preventDefault()
|
||||
})
|
||||
}
|
||||
global.modules.userApiWindow.webContents.session.setPermissionRequestHandler((webContents, permission, callback) => {
|
||||
callback(false)
|
||||
global.modules.userApiWindow.webContents.session.setPermissionRequestHandler((webContents, permission, resolve) => {
|
||||
if (webContents === global.modules.mainWindow.webContents) return resolve(true)
|
||||
|
||||
resolve(false)
|
||||
})
|
||||
global.modules.userApiWindow.webContents.setWindowOpenHandler(() => {
|
||||
return { action: 'deny' }
|
||||
})
|
||||
|
||||
winEvent(global.modules.userApiWindow)
|
||||
|
||||
@@ -3,14 +3,20 @@ const needle = require('needle')
|
||||
const { createCipheriv, publicEncrypt, constants, randomBytes, createHash } = require('crypto')
|
||||
const USER_API_RENDERER_EVENT_NAME = require('../rendererEvent/name')
|
||||
|
||||
const sendMessage = (action, status, data, message) => {
|
||||
ipcRenderer.send(action, { status, data, message })
|
||||
for (const key of Object.keys(process.env)) {
|
||||
if (/^(?:http_proxy|https_proxy|NO_PROXY)$/i.test(key)) delete process.env[key]
|
||||
}
|
||||
|
||||
const sendMessage = (action, data, status, message) => {
|
||||
ipcRenderer.send(action, { data, status, message })
|
||||
}
|
||||
|
||||
let isInitedApi = false
|
||||
let isShowedUpdateAlert = false
|
||||
const EVENT_NAMES = {
|
||||
request: 'request',
|
||||
inited: 'inited',
|
||||
updateAlert: 'updateAlert',
|
||||
}
|
||||
const eventNames = Object.values(EVENT_NAMES)
|
||||
const events = {
|
||||
@@ -35,7 +41,7 @@ const supportActions = {
|
||||
|
||||
const handleRequest = (context, { requestKey, data }) => {
|
||||
// console.log(data)
|
||||
if (!events.request) return sendMessage(USER_API_RENDERER_EVENT_NAME.response, false, { requestKey }, 'Request event is not defined')
|
||||
if (!events.request) return sendMessage(USER_API_RENDERER_EVENT_NAME.response, { requestKey }, false, 'Request event is not defined')
|
||||
try {
|
||||
events.request.call(context, { source: data.source, action: data.action, info: data.info }).then(response => {
|
||||
let sendData = {
|
||||
@@ -53,12 +59,12 @@ const handleRequest = (context, { requestKey, data }) => {
|
||||
}
|
||||
break
|
||||
}
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.response, true, sendData)
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.response, sendData, true)
|
||||
}).catch(err => {
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.response, false, { requestKey }, err.message)
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.response, { requestKey }, false, err.message)
|
||||
})
|
||||
} catch (err) {
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.response, false, { requestKey }, err.message)
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.response, { requestKey }, false, err.message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +72,7 @@ const handleRequest = (context, { requestKey, data }) => {
|
||||
*
|
||||
* @param {*} context
|
||||
* @param {*} info {
|
||||
* openDevTools: false,
|
||||
* status: true,
|
||||
* message: 'xxx',
|
||||
* sources: {
|
||||
@@ -79,7 +86,7 @@ const handleRequest = (context, { requestKey, data }) => {
|
||||
*/
|
||||
const handleInit = (context, info) => {
|
||||
if (!info) {
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, false, null, 'Init failed')
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, null, false, 'Init failed')
|
||||
// sendMessage(USER_API_RENDERER_EVENT_NAME.init, false, null, typeof info.message === 'string' ? info.message.substring(0, 100) : '')
|
||||
return
|
||||
}
|
||||
@@ -87,7 +94,7 @@ const handleInit = (context, info) => {
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.openDevTools)
|
||||
}
|
||||
if (!info.status) {
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, false, null, 'Init failed')
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, null, false, 'Init failed')
|
||||
// sendMessage(USER_API_RENDERER_EVENT_NAME.init, false, null, typeof info.message === 'string' ? info.message.substring(0, 100) : '')
|
||||
return
|
||||
}
|
||||
@@ -108,16 +115,28 @@ const handleInit = (context, info) => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, false, null, error.message)
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, null, false, error.message)
|
||||
return
|
||||
}
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, true, sourceInfo)
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.init, sourceInfo, true)
|
||||
|
||||
ipcRenderer.on(USER_API_RENDERER_EVENT_NAME.request, (event, data) => {
|
||||
handleRequest(context, data)
|
||||
})
|
||||
}
|
||||
|
||||
const handleShowUpdateAlert = (data, resolve, reject) => {
|
||||
if (!data || typeof data != 'object') return reject(new Error('parameter format error.'))
|
||||
if (!data.log || typeof data.log != 'string') return reject(new Error('log is required.'))
|
||||
if (data.updateUrl && !/^https?:\/\/[^\s$.?#].[^\s]*$/.test(data.updateUrl) && data.updateUrl.length > 1024) delete data.updateUrl
|
||||
if (data.log.length > 1024) data.log = data.log.substring(0, 1024) + '...'
|
||||
sendMessage(USER_API_RENDERER_EVENT_NAME.showUpdateAlert, {
|
||||
log: data.log,
|
||||
updateUrl: data.updateUrl,
|
||||
})
|
||||
resolve()
|
||||
}
|
||||
|
||||
contextBridge.exposeInMainWorld('lx', {
|
||||
EVENT_NAMES,
|
||||
request(url, { method = 'get', timeout, headers, body, form, formData }, callback) {
|
||||
@@ -150,7 +169,7 @@ contextBridge.exposeInMainWorld('lx', {
|
||||
headers: resp.headers,
|
||||
bytes: resp.bytes,
|
||||
raw: resp.raw,
|
||||
body: body,
|
||||
body,
|
||||
}, body)
|
||||
}).request
|
||||
|
||||
@@ -164,12 +183,18 @@ contextBridge.exposeInMainWorld('lx', {
|
||||
if (!eventNames.includes(eventName)) return reject(new Error('The event is not supported: ' + eventName))
|
||||
switch (eventName) {
|
||||
case EVENT_NAMES.inited:
|
||||
if (isInitedApi) return
|
||||
if (isInitedApi) return reject(new Error('Script is inited'))
|
||||
isInitedApi = true
|
||||
handleInit(this, data)
|
||||
resolve()
|
||||
break
|
||||
case EVENT_NAMES.updateAlert:
|
||||
if (isShowedUpdateAlert) return reject(new Error('The update alert can only be called once.'))
|
||||
isShowedUpdateAlert = true
|
||||
handleShowUpdateAlert(data, resolve, reject)
|
||||
break
|
||||
default:
|
||||
resolve(new Error('Unknown event name: ' + eventName))
|
||||
reject(new Error('Unknown event name: ' + eventName))
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -179,17 +204,19 @@ contextBridge.exposeInMainWorld('lx', {
|
||||
case EVENT_NAMES.request:
|
||||
events.request = handler
|
||||
break
|
||||
default: return Promise.reject(new Error('The event is not supported: ' + eventName))
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
utils: {
|
||||
crypto: {
|
||||
aesEncrypt(buffer, mode, key, iv) {
|
||||
const cipher = createCipheriv('aes-128-' + mode, key, iv)
|
||||
const cipher = createCipheriv(mode, key, iv)
|
||||
return Buffer.concat([cipher.update(buffer), cipher.final()])
|
||||
},
|
||||
rsaEncrypt(buffer, key) {
|
||||
buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer])
|
||||
return publicEncrypt({ key: key, padding: constants.RSA_NO_PADDING }, buffer)
|
||||
return publicEncrypt({ key, padding: constants.RSA_NO_PADDING }, buffer)
|
||||
},
|
||||
randomBytes(size) {
|
||||
return randomBytes(size)
|
||||
@@ -202,8 +229,12 @@ contextBridge.exposeInMainWorld('lx', {
|
||||
from(...args) {
|
||||
return Buffer.from(...args)
|
||||
},
|
||||
bufToString(buf, format) {
|
||||
return Buffer.from(buf, 'binary').toString(format)
|
||||
},
|
||||
},
|
||||
},
|
||||
version: '1.2.0',
|
||||
// removeEvent(eventName, handler) {
|
||||
// if (!eventNames.includes(eventName)) return Promise.reject(new Error('The event is not supported: ' + eventName))
|
||||
// let handlers
|
||||
|
||||
@@ -3,6 +3,7 @@ const names = {
|
||||
request: '',
|
||||
response: '',
|
||||
openDevTools: '',
|
||||
showUpdateAlert: '',
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ const { mainOn, mainSend } = require('@common/ipc')
|
||||
const USER_API_RENDERER_EVENT_NAME = require('../rendererEvent/name')
|
||||
const { createWindow } = require('../main')
|
||||
const { getUserApis } = require('../utils')
|
||||
const { openDevTools } = require('@main/utils')
|
||||
|
||||
let userApi
|
||||
let status = { status: true }
|
||||
@@ -32,12 +33,22 @@ const handleResponse = (event, { status, data: { requestKey, result }, message }
|
||||
}
|
||||
const handleOpenDevTools = () => {
|
||||
if (global.modules.userApiWindow) {
|
||||
global.modules.userApiWindow.webContents.openDevTools()
|
||||
openDevTools(global.modules.userApiWindow.webContents)
|
||||
}
|
||||
}
|
||||
const handleShowUpdateAlert = (event, { data }) => {
|
||||
if (!userApi.allowShowUpdateAlert) return
|
||||
global.lx_event.userApi.showUpdateAlert({
|
||||
name: userApi.name,
|
||||
description: userApi.description,
|
||||
log: data.log,
|
||||
updateUrl: data.updateUrl,
|
||||
})
|
||||
}
|
||||
mainOn(USER_API_RENDERER_EVENT_NAME.init, handleInit)
|
||||
mainOn(USER_API_RENDERER_EVENT_NAME.response, handleResponse)
|
||||
mainOn(USER_API_RENDERER_EVENT_NAME.openDevTools, handleOpenDevTools)
|
||||
mainOn(USER_API_RENDERER_EVENT_NAME.showUpdateAlert, handleShowUpdateAlert)
|
||||
|
||||
exports.loadApi = async apiId => {
|
||||
if (!apiId) return global.lx_event.userApi.status(status = { status: false, message: 'api id is null' })
|
||||
@@ -80,3 +91,8 @@ exports.request = ({ requestKey, data }) => new Promise((resolve, reject) => {
|
||||
})
|
||||
|
||||
exports.getStatus = () => status
|
||||
|
||||
exports.setAllowShowUpdateAlert = (id, enable) => {
|
||||
if (!userApi || userApi.id != id) return
|
||||
userApi.allowShowUpdateAlert = enable
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ exports.getUserApis = () => {
|
||||
userApis = defaultUserApis
|
||||
electronStore_userApi.set('userApis', userApis)
|
||||
}
|
||||
for (const api of userApis) {
|
||||
if (api.allowShowUpdateAlert == null) api.allowShowUpdateAlert = false
|
||||
}
|
||||
return userApis
|
||||
}
|
||||
|
||||
@@ -19,14 +22,15 @@ exports.importApi = script => {
|
||||
let name = scriptInfo[1] || ''
|
||||
let description = scriptInfo[2] || ''
|
||||
name = name.startsWith(' * @name ') ? name.replace(' * @name ', '').trim() : `user_api_${new Date().toLocaleString()}`
|
||||
if (name.length > 10) name = name.substring(0, 10) + '...'
|
||||
if (name.length > 24) name = name.substring(0, 24) + '...'
|
||||
description = description.startsWith(' * @description ') ? description.replace(' * @description ', '').trim() : ''
|
||||
if (description.length > 20) description = description.substring(0, 20) + '...'
|
||||
if (description.length > 36) description = description.substring(0, 36) + '...'
|
||||
const apiInfo = {
|
||||
id: `user_api_${Math.random().toString().substring(2, 5)}_${Date.now()}`,
|
||||
name,
|
||||
description,
|
||||
script,
|
||||
allowShowUpdateAlert: true,
|
||||
}
|
||||
userApis.push(apiInfo)
|
||||
getStore('userApi').set('userApis', userApis)
|
||||
@@ -42,3 +46,10 @@ exports.removeApi = ids => {
|
||||
}
|
||||
getStore('userApi').set('userApis', userApis)
|
||||
}
|
||||
|
||||
exports.setAllowShowUpdateAlert = (id, enable) => {
|
||||
const targetApi = userApis.find(api => api.id == id)
|
||||
if (!targetApi) return
|
||||
targetApi.allowShowUpdateAlert = enable
|
||||
getStore('userApi').set('userApis', userApis)
|
||||
}
|
||||
|
||||
@@ -2,11 +2,40 @@ const { common: COMMON_EVENT_NAME, winLyric: WIN_LYRIC_EVENT_NAME, hotKey: HOT_K
|
||||
const { mainSend, NAMES: { winLyric: ipcWinLyricNames } } = require('../../../common/ipc')
|
||||
const { desktop_lyric } = require('../../../common/hotKey')
|
||||
const { getLyricWindowBounds } = require('./utils')
|
||||
const { isLinux } = require('@common/utils')
|
||||
|
||||
let isLock = null
|
||||
let isEnable = null
|
||||
let isAlwaysOnTop = null
|
||||
let isAlwaysOnTopLoop = null
|
||||
let isLockScreen = null
|
||||
let isHoverHide = null
|
||||
|
||||
const alwaysOnTopTools = {
|
||||
timeout: null,
|
||||
alwaysOnTop: false,
|
||||
setAlwaysOnTop(flag, isLoop) {
|
||||
this.alwaysOnTop = flag
|
||||
this.clearLoop()
|
||||
global.modules.lyricWindow.setAlwaysOnTop(flag, 'screen-saver')
|
||||
console.log(isLoop)
|
||||
if (flag && isLoop) this.startLoop()
|
||||
},
|
||||
startLoop() {
|
||||
if (!this.alwaysOnTop) return
|
||||
this.timeout = setInterval(() => {
|
||||
if (!global.modules.lyricWindow) return this.clearLoop()
|
||||
global.modules.lyricWindow.setAlwaysOnTop(true, 'screen-saver')
|
||||
}, 1000)
|
||||
},
|
||||
clearLoop() {
|
||||
if (!this.timeout) return
|
||||
clearInterval(this.timeout)
|
||||
this.timeout = null
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
const setLrcConfig = () => {
|
||||
let desktopLyric = global.appSetting.desktopLyric
|
||||
if (global.modules.lyricWindow) {
|
||||
@@ -14,19 +43,34 @@ const setLrcConfig = () => {
|
||||
config: desktopLyric,
|
||||
languageId: global.appSetting.langId,
|
||||
isShowLyricTranslation: global.appSetting.player.isShowLyricTranslation,
|
||||
isShowLyricRoma: global.appSetting.player.isShowLyricRoma,
|
||||
isPlayLxlrc: global.appSetting.player.isPlayLxlrc,
|
||||
})
|
||||
if (isLock != desktopLyric.isLock) {
|
||||
isLock = desktopLyric.isLock
|
||||
if (desktopLyric.isLock) {
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(true, { forward: false })
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(true, { forward: !isLinux && global.appSetting.desktopLyric.isHoverHide })
|
||||
} else {
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(false)
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(false, { forward: !isLinux && global.appSetting.desktopLyric.isHoverHide })
|
||||
}
|
||||
}
|
||||
if (isHoverHide != desktopLyric.isHoverHide) {
|
||||
isHoverHide = desktopLyric.isHoverHide
|
||||
if (!isLinux) {
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(desktopLyric.isLock, { forward: global.appSetting.desktopLyric.isHoverHide })
|
||||
}
|
||||
}
|
||||
if (isAlwaysOnTop != desktopLyric.isAlwaysOnTop) {
|
||||
isAlwaysOnTop = desktopLyric.isAlwaysOnTop
|
||||
global.modules.lyricWindow.setAlwaysOnTop(desktopLyric.isAlwaysOnTop, 'screen-saver')
|
||||
alwaysOnTopTools.setAlwaysOnTop(desktopLyric.isAlwaysOnTop, desktopLyric.isAlwaysOnTopLoop)
|
||||
}
|
||||
if (isAlwaysOnTopLoop != desktopLyric.isAlwaysOnTopLoop) {
|
||||
isAlwaysOnTopLoop = desktopLyric.isAlwaysOnTopLoop
|
||||
if (isAlwaysOnTopLoop) {
|
||||
alwaysOnTopTools.startLoop()
|
||||
} else {
|
||||
alwaysOnTopTools.clearLoop()
|
||||
}
|
||||
}
|
||||
if (isLockScreen != desktopLyric.isLockScreen) {
|
||||
isLockScreen = desktopLyric.isLockScreen
|
||||
@@ -45,6 +89,7 @@ const setLrcConfig = () => {
|
||||
if (desktopLyric.enable) {
|
||||
global.lx_event.winLyric.create()
|
||||
} else {
|
||||
alwaysOnTopTools.clearLoop()
|
||||
global.lx_event.winLyric.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const path = require('path')
|
||||
const { BrowserWindow } = require('electron')
|
||||
const { winLyric: WIN_LYRIC_EVENT_NAME } = require('../../events/_name')
|
||||
const { debounce } = require('../../../common/utils')
|
||||
const { debounce, isLinux } = require('../../../common/utils')
|
||||
const { getLyricWindowBounds } = require('./utils')
|
||||
|
||||
require('./event')
|
||||
@@ -27,7 +27,7 @@ const setLyricsConfig = debounce(config => {
|
||||
const winEvent = lyricWindow => {
|
||||
// let bounds
|
||||
// lyricWindow.on('close', event => {
|
||||
// if (global.isQuitting || !global.appSetting.tray.isToTray || (!isWin && !global.isTrafficLightClose)) {
|
||||
// if (global.isQuitting || !global.appSetting.tray.isShow || (!isWin && !global.isTrafficLightClose)) {
|
||||
// lyricWindow.setProgressBar(-1)
|
||||
// return
|
||||
// }
|
||||
@@ -64,7 +64,11 @@ const winEvent = lyricWindow => {
|
||||
lyricWindow.once('ready-to-show', () => {
|
||||
lyricWindow.show()
|
||||
if (global.appSetting.desktopLyric.isLock) {
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(true, { forward: false })
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(true, { forward: !isLinux && global.appSetting.desktopLyric.isHoverHide })
|
||||
}
|
||||
// linux下每次重开时貌似要重新设置置顶
|
||||
if (isLinux && global.appSetting.desktopLyric.isAlwaysOnTop) {
|
||||
global.modules.lyricWindow.setAlwaysOnTop(global.appSetting.desktopLyric.isAlwaysOnTop, 'screen-saver')
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -112,6 +116,7 @@ const createWindow = () => {
|
||||
contextIsolation: false,
|
||||
webSecurity: !global.isDev,
|
||||
nodeIntegration: true,
|
||||
spellcheck: false, // 禁用拼写检查器
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ mainHandle(ipcWinLyricNames.get_lyric_config, async() => {
|
||||
config: global.appSetting.desktopLyric,
|
||||
languageId: global.appSetting.langId,
|
||||
isShowLyricTranslation: global.appSetting.player.isShowLyricTranslation,
|
||||
isShowLyricRoma: global.appSetting.player.isShowLyricRoma,
|
||||
isPlayLxlrc: global.appSetting.player.isPlayLxlrc,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { mainHandle, mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_env_params, async(event, options) => {
|
||||
return global.envParams.cmdParams
|
||||
return global.envParams
|
||||
})
|
||||
|
||||
mainOn(ipcMainWindowNames.clear_env_params_deeplink, () => {
|
||||
global.envParams.deeplink = null
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
const { isWin } = require('@common/utils')
|
||||
// require('./request')
|
||||
// require('./appName')
|
||||
require('./progressBar')
|
||||
@@ -19,8 +19,16 @@ require('./playList')
|
||||
require('./data')
|
||||
require('./lyric')
|
||||
require('./musicUrl')
|
||||
require('./systemFonts')
|
||||
require('./wait')
|
||||
require('./openDevtools')
|
||||
require('./nativeTheme')
|
||||
|
||||
if (isWin) require('./taskbar')
|
||||
|
||||
require('./kw_decodeLyric')
|
||||
|
||||
require('./userApi')
|
||||
require('./sync')
|
||||
require('./s2t')
|
||||
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
|
||||
const getStore = require('@common/store')
|
||||
|
||||
const LRC_RAW = 'lyrics'
|
||||
const LRC_EDITED = 'lyrics_edited'
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_lyric, async(event, id) => getStore('lyrics', true, false).get(id) || {})
|
||||
mainHandle(ipcMainWindowNames.get_lyric, async(event, id) => {
|
||||
return getStore(LRC_EDITED, true, false).get(id) || getStore(LRC_RAW, true, false).get(id) || {}
|
||||
})
|
||||
|
||||
|
||||
mainOn(ipcMainWindowNames.save_lyric, (event, { id, lyrics }) => getStore('lyrics', true, false).set(id, lyrics))
|
||||
// 原始歌词
|
||||
mainHandle(ipcMainWindowNames.get_lyric_raw, async(event, id) => getStore(LRC_RAW, true, false).get(id) || {})
|
||||
mainOn(ipcMainWindowNames.save_lyric_raw, (event, { id, lyrics }) => getStore(LRC_RAW, true, false).set(id, lyrics))
|
||||
mainOn(ipcMainWindowNames.clear_lyric_raw, () => getStore(LRC_RAW, true, false).clear())
|
||||
|
||||
mainOn(ipcMainWindowNames.clear_lyric, () => getStore('lyrics', true, false).clear())
|
||||
// 已编辑的歌词
|
||||
mainHandle(ipcMainWindowNames.get_lyric_edited, async(event, id) => getStore(LRC_EDITED, true, false).get(id) || {})
|
||||
mainOn(ipcMainWindowNames.save_lyric_edited, (event, { id, lyrics }) => getStore(LRC_EDITED, true, false).set(id, lyrics))
|
||||
mainOn(ipcMainWindowNames.remove_lyric_edited, async(event, id) => getStore(LRC_EDITED, true, false).delete(id))
|
||||
|
||||
11
src/main/rendererEvents/nativeTheme.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const { nativeTheme } = require('electron')
|
||||
|
||||
const { NAMES: { mainWindow: ipcMainWindowNames }, mainSend } = require('@common/ipc')
|
||||
|
||||
nativeTheme.addListener('updated', (event) => {
|
||||
// console.log(event.sender.shouldUseDarkColors)
|
||||
if (!global.modules.mainWindow) return
|
||||
mainSend(global.modules.mainWindow, ipcMainWindowNames.system_theme_change, event.sender.shouldUseDarkColors)
|
||||
// console.log(nativeTheme.themeSource)
|
||||
})
|
||||
|
||||
12
src/main/rendererEvents/openDevtools.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { openDevTools } = require('@main/utils')
|
||||
|
||||
mainOn(ipcMainWindowNames.open_dev_tools, event => {
|
||||
if (global.modules.mainWindow) {
|
||||
if (global.modules.mainWindow.isDevToolsOpened()) {
|
||||
global.modules.mainWindow.webContents.closeDevTools()
|
||||
} else {
|
||||
openDevTools(global.modules.mainWindow.webContents)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -8,19 +8,22 @@ mainHandle(ipcMainWindowNames.get_playlist, async(event, isIgnoredError = false)
|
||||
return {
|
||||
defaultList: electronStore_list.get('defaultList'),
|
||||
loveList: electronStore_list.get('loveList'),
|
||||
tempList: electronStore_list.get('tempList'),
|
||||
userList: electronStore_list.get('userList'),
|
||||
downloadList: getStore('downloadList').get('list'),
|
||||
}
|
||||
})
|
||||
|
||||
const handleSaveList = ({ defaultList, loveList, userList }) => {
|
||||
const handleSaveList = ({ defaultList, loveList, userList, tempList }) => {
|
||||
let data = {}
|
||||
if (defaultList != null) data.defaultList = defaultList
|
||||
if (loveList != null) data.loveList = loveList
|
||||
if (userList != null) data.userList = userList
|
||||
if (tempList != null) data.tempList = tempList
|
||||
getStore('playList').set(data)
|
||||
}
|
||||
mainOn(ipcMainWindowNames.save_playlist, (event, { type, data }) => {
|
||||
data = JSON.parse(data)
|
||||
switch (type) {
|
||||
case 'myList':
|
||||
handleSaveList(data)
|
||||
|
||||
9
src/main/rendererEvents/s2t.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { tranditionalize } = require('../utils/simplify-chinese-main')
|
||||
|
||||
|
||||
mainHandle(ipcMainWindowNames.lang_s2t, async(event, textBase64) => {
|
||||
if (!global.modules.mainWindow) throw new Error('mainWindow is undefined')
|
||||
const text = tranditionalize(Buffer.from(textBase64, 'base64').toString())
|
||||
return Buffer.from(text).toString('base64')
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
const { mainOn, mainSend, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { mainOn, mainSend, NAMES: { mainWindow: ipcMainWindowNames } } = require('@common/ipc')
|
||||
|
||||
|
||||
mainOn(ipcMainWindowNames.set_lyric_info, (event, info) => {
|
||||
|
||||
5
src/main/rendererEvents/systemFonts.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('@common/ipc')
|
||||
const { getFonts } = require('@main/utils/fontManage')
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_system_fonts, getFonts)
|
||||
|
||||
18
src/main/rendererEvents/taskbar.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { mainSend, mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('@common/ipc')
|
||||
const { setThumbnailClip, setThumbarButtons, eventNames } = require('../modules/taskbar')
|
||||
const { mainWindow: MAIN_WINDOW_EVENT_NAME } = require('@main/events/_name')
|
||||
|
||||
const handleThumbarButtonClick = action => {
|
||||
mainSend(global.modules.mainWindow, ipcMainWindowNames.taskbar_on_thumbar_button_click, action)
|
||||
}
|
||||
|
||||
global.lx_event.taskbar.on(eventNames.thumbarButtonClick, handleThumbarButtonClick)
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_EVENT_NAME.show, setThumbarButtons)
|
||||
|
||||
mainHandle(ipcMainWindowNames.taskbar_set_thumbnail_clip, (event, clip) => {
|
||||
return setThumbnailClip(clip)
|
||||
})
|
||||
|
||||
mainOn(ipcMainWindowNames.taskbar_set_thumbar_buttons, (event, buttons) => {
|
||||
setThumbarButtons(buttons)
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
const { app } = require('electron')
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { mainOn, mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { isLinux } = require('@common/utils')
|
||||
|
||||
mainOn(ipcMainWindowNames.min, event => {
|
||||
if (global.modules.mainWindow) {
|
||||
@@ -16,3 +17,18 @@ mainOn(ipcMainWindowNames.close, (event, isForce) => {
|
||||
global.isTrafficLightClose = true
|
||||
if (global.modules.mainWindow) global.modules.mainWindow.close()
|
||||
})
|
||||
mainHandle(ipcMainWindowNames.fullscreen, async(event, isFullscreen) => {
|
||||
if (!global.modules.mainWindow) return false
|
||||
if (isLinux) { // linux 需要先设置为可调整窗口大小才能全屏
|
||||
if (isFullscreen) {
|
||||
await global.modules.mainWindow.setResizable(isFullscreen)
|
||||
await global.modules.mainWindow.setFullScreen(isFullscreen)
|
||||
} else {
|
||||
await global.modules.mainWindow.setFullScreen(isFullscreen)
|
||||
await global.modules.mainWindow.setResizable(isFullscreen)
|
||||
}
|
||||
} else {
|
||||
await global.modules.mainWindow.setFullScreen(isFullscreen)
|
||||
}
|
||||
return isFullscreen
|
||||
})
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
const { mainSend, mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('@common/ipc')
|
||||
const { getApiList, importApi, removeApi, setApi, getStatus, request, cancelRequest, eventNames } = require('../modules/userApi')
|
||||
const { getApiList, importApi, removeApi, setApi, getStatus, request, cancelRequest, eventNames, setAllowShowUpdateAlert } = require('../modules/userApi')
|
||||
|
||||
const handleStatusChange = status => {
|
||||
mainSend(global.modules.mainWindow, ipcMainWindowNames.user_api_status, status)
|
||||
}
|
||||
const handleShowUpdateAlert = info => {
|
||||
mainSend(global.modules.mainWindow, ipcMainWindowNames.user_api_show_update_alert, info)
|
||||
}
|
||||
|
||||
global.lx_event.userApi.on(eventNames.status, handleStatusChange)
|
||||
global.lx_event.userApi.on(eventNames.showUpdateAlert, handleShowUpdateAlert)
|
||||
|
||||
mainHandle(ipcMainWindowNames.import_user_api, async(event, script) => {
|
||||
return importApi(script)
|
||||
@@ -27,6 +31,10 @@ mainHandle(ipcMainWindowNames.get_user_api_status, event => {
|
||||
return getStatus()
|
||||
})
|
||||
|
||||
mainHandle(ipcMainWindowNames.user_api_set_allow_update_alert, (event, { id, enable }) => {
|
||||
return setAllowShowUpdateAlert(id, enable)
|
||||
})
|
||||
|
||||
mainHandle(ipcMainWindowNames.request_user_api, (event, musicInfo) => {
|
||||
return request(musicInfo)
|
||||
})
|
||||
|
||||
46
src/main/rendererEvents/wait.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const { mainOn, mainHandle, mainSend, NAMES: { mainWindow: ipcMainWindowNames } } = require('@common/ipc')
|
||||
|
||||
const timeoutMap = new Map()
|
||||
|
||||
mainHandle(ipcMainWindowNames.wait, (event, { time, id }) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
if (timeoutMap.has(id)) timeoutMap.delete(id)
|
||||
resolve()
|
||||
}, time)
|
||||
timeoutMap.set(id, {
|
||||
timeout,
|
||||
resolve,
|
||||
reject,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
mainOn(ipcMainWindowNames.wait_cancel, (event, id) => {
|
||||
if (!timeoutMap.has(id)) return
|
||||
const timeout = timeoutMap.get(id)
|
||||
timeoutMap.delete(id)
|
||||
clearTimeout(timeout.timeout)
|
||||
timeout.reject('cancelled')
|
||||
})
|
||||
|
||||
mainOn(ipcMainWindowNames.interval, (event, { time, id }) => {
|
||||
if (timeoutMap.has(id)) return
|
||||
const timeout = setInterval(() => {
|
||||
if (global.modules.mainWindow) mainSend(global.modules.mainWindow, ipcMainWindowNames.interval_callback, id)
|
||||
}, time)
|
||||
|
||||
timeoutMap.set(id, {
|
||||
timeout,
|
||||
type: 'interval',
|
||||
time,
|
||||
})
|
||||
})
|
||||
|
||||
mainOn(ipcMainWindowNames.interval_cancel, (event, id) => {
|
||||
if (!timeoutMap.has(id)) return
|
||||
const timeout = timeoutMap.get(id)
|
||||
timeoutMap.delete(id)
|
||||
if (timeout.type != 'interval') return
|
||||
clearInterval(timeout.timeout)
|
||||
})
|
||||
@@ -1,11 +1,12 @@
|
||||
const { isWin } = require('../../common/utils')
|
||||
const { openDevTools } = require('@main/utils')
|
||||
const { mainSend, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
global.isQuitting = false
|
||||
global.isTrafficLightClose = false // 是否点击软件上的关闭按钮关闭
|
||||
|
||||
module.exports = mainWindow => {
|
||||
mainWindow.on('close', event => {
|
||||
if (global.isQuitting || !global.appSetting.tray.isToTray || (!isWin && !global.isTrafficLightClose)) {
|
||||
if (global.isQuitting || !global.appSetting.tray.isShow || (!isWin && !global.isTrafficLightClose)) {
|
||||
mainWindow.setProgressBar(-1)
|
||||
global.lx_event.winLyric.close()
|
||||
return
|
||||
@@ -25,11 +26,17 @@ module.exports = mainWindow => {
|
||||
// })
|
||||
mainWindow.on('focus', () => {
|
||||
mainSend(mainWindow, ipcMainWindowNames.focus)
|
||||
global.lx_event.mainWindow.focus()
|
||||
})
|
||||
|
||||
mainWindow.on('blur', () => {
|
||||
global.lx_event.mainWindow.blur()
|
||||
})
|
||||
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show()
|
||||
global.lx_event.mainWindow.readyToShow()
|
||||
if (global.envParams.cmdParams.debug) openDevTools(global.modules.mainWindow.webContents)
|
||||
})
|
||||
|
||||
mainWindow.on('show', () => {
|
||||
|
||||
9
src/main/utils/fontManage.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// const { getAvailableFontFamilies } = require('electron-font-manager')
|
||||
|
||||
|
||||
// exports.getAvailableFontFamilies = getAvailableFontFamilies
|
||||
|
||||
|
||||
const fontList = require('font-list')
|
||||
|
||||
exports.getFonts = fontList.getFonts
|
||||
@@ -41,3 +41,9 @@ exports.initSetting = (isShowErrorAlert = true) => {
|
||||
global.appSetting = info.setting
|
||||
global.appSettingVersion = info.version
|
||||
}
|
||||
|
||||
exports.openDevTools = webContents => {
|
||||
webContents.openDevTools({
|
||||
mode: 'undocked',
|
||||
})
|
||||
}
|
||||
|
||||
18
src/main/utils/simplify-chinese-main/.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
todo.md
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-debug.log
|
||||
yarn-error.log
|
||||
package-lock.json
|
||||
tsconfig.tsbuildinfo
|
||||
report.*.json
|
||||
|
||||
.eslintcache
|
||||
.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
.yarn
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
22
src/main/utils/simplify-chinese-main/LICENSE.md
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 Shigma
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
10
src/main/utils/simplify-chinese-main/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# simplify-chinese
|
||||
|
||||
Convert chinese characters between simplified form and tranditional form / 汉字简繁体转换工具。
|
||||
|
||||
```js
|
||||
const { simplify, tranditionalize } = require('simplify-chinese')
|
||||
|
||||
console.log(simplify('窩窩頭')) // 窝窝头
|
||||
console.log(tranditionalize('窝窝头')) // 窩窩頭
|
||||
```
|
||||
2
src/main/utils/simplify-chinese-main/chinese.js
Normal file
2
src/main/utils/simplify-chinese-main/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export function simplify(source: string): string
|
||||
export function tranditionalize(source: string): string
|
||||