mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/lyswhut/lx-music-desktop.git
synced 2026-09-20 08:04:00 +08:00
Compare commits
744 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0709aa56a4 | ||
|
|
684d90d0e7 | ||
|
|
227c05a696 | ||
|
|
8cf1a4a790 | ||
|
|
75e3976bfa | ||
|
|
e9791fd493 | ||
|
|
f9f445489c | ||
|
|
10e5460e39 | ||
|
|
f1049169b5 | ||
|
|
2056bdb43d | ||
|
|
785bf3ce3a | ||
|
|
c29bf61e59 | ||
|
|
a98c0516a3 | ||
|
|
a6989a2aba | ||
|
|
30e43170f8 | ||
|
|
d8feb3e794 | ||
|
|
99bdf6d173 | ||
|
|
8424a9e4de | ||
|
|
4c0cbe3253 | ||
|
|
462dc5da51 | ||
|
|
40fad5f785 | ||
|
|
c0791acbf6 | ||
|
|
3cb0a56647 | ||
|
|
95f38e8048 | ||
|
|
a3493a6c74 | ||
|
|
3535bb4e4e | ||
|
|
3be6242cb5 | ||
|
|
64a53830e4 | ||
|
|
b3e3860b23 | ||
|
|
4db560fb4b | ||
|
|
b00de4d976 | ||
|
|
ac162103a7 | ||
|
|
16876502d1 | ||
|
|
4cdd2110a6 | ||
|
|
b820adf0bf | ||
|
|
1cee2febf4 | ||
|
|
43f8d9d72b | ||
|
|
66ffe03224 | ||
|
|
5c96c83f98 | ||
|
|
6d1ddece92 | ||
|
|
897107ca23 | ||
|
|
0baaffdad8 | ||
|
|
784d2fda6d | ||
|
|
19817249db | ||
|
|
240260e598 | ||
|
|
fcf92f06ef | ||
|
|
fe1c2a1896 | ||
|
|
d55c65e275 | ||
|
|
93064bb18b | ||
|
|
dec1b24c86 | ||
|
|
8c76c3d81c | ||
|
|
8d8cabd5b3 | ||
|
|
aa948b0149 | ||
|
|
a25ef6e2a0 | ||
|
|
c404d3ac8d | ||
|
|
8eb71495a1 | ||
|
|
db824c4601 | ||
|
|
029886cc87 | ||
|
|
42604ec737 | ||
|
|
caaa62db30 | ||
|
|
0f135e0587 | ||
|
|
dae6826cc1 | ||
|
|
ddf2ac7ece | ||
|
|
5e011356f2 | ||
|
|
82e047dc66 | ||
|
|
7720b416d5 | ||
|
|
c40dc0fa50 | ||
|
|
36ed7bca66 | ||
|
|
1fa015704a | ||
|
|
7e2097ba6d | ||
|
|
3a630edaa5 | ||
|
|
1b561bbf4c | ||
|
|
37de0b59c3 | ||
|
|
2f528d2a03 | ||
|
|
686d55a672 | ||
|
|
07c58e2ce7 | ||
|
|
6fe794fdf5 | ||
|
|
d0ec90130c | ||
|
|
f7806d9781 | ||
|
|
63219b49f2 | ||
|
|
320e84627c | ||
|
|
fc9e697249 | ||
|
|
a68c626fa2 | ||
|
|
66f17cf05b | ||
|
|
5949e8fb3f | ||
|
|
3bb0fcc4cd | ||
|
|
d32d5d0eb8 | ||
|
|
5ee2c030ec | ||
|
|
58ca7df105 | ||
|
|
fc77dbc73b | ||
|
|
8aedde2422 | ||
|
|
526b5fe140 | ||
|
|
1c4e9ed474 | ||
|
|
21cbb441e2 | ||
|
|
01fedc59e2 | ||
|
|
b3d13c3a90 | ||
|
|
24ee42e0c7 | ||
|
|
3a18eccdd6 | ||
|
|
a3b763ecc9 | ||
|
|
822c74ad2f | ||
|
|
0a71e34459 | ||
|
|
25b68081ea | ||
|
|
ac0e1e7698 | ||
|
|
4be5bcc979 | ||
|
|
f3c2d7e43a | ||
|
|
9fa0700f72 | ||
|
|
868da542ab | ||
|
|
04c810e292 | ||
|
|
86478c0268 | ||
|
|
b453a8934f | ||
|
|
669c1fe490 | ||
|
|
c15895ab45 | ||
|
|
44acc7d5ac | ||
|
|
341df0dab7 | ||
|
|
8df3ff3536 | ||
|
|
85c683b714 | ||
|
|
6606edafb9 | ||
|
|
91ff7b658a | ||
|
|
27c500e950 | ||
|
|
078245cb96 | ||
|
|
e54597b944 | ||
|
|
1af9b3a018 | ||
|
|
315d041fc7 | ||
|
|
f7f1cdab34 | ||
|
|
597f0da42f | ||
|
|
497add09b3 | ||
|
|
ff05225b56 | ||
|
|
ac053e9ac9 | ||
|
|
9aeae1e460 | ||
|
|
d710f204b3 | ||
|
|
be016aa4bb | ||
|
|
04e62cba24 | ||
|
|
4d476dc641 | ||
|
|
85c3a812da | ||
|
|
e985e70303 | ||
|
|
9dbf96c259 | ||
|
|
6eba7c9a2f | ||
|
|
c1966e9301 | ||
|
|
a6fb72f1de | ||
|
|
a695a69f0f | ||
|
|
a8632297eb | ||
|
|
ca4218b309 | ||
|
|
65df71239a | ||
|
|
fdd8f3b214 | ||
|
|
1887573301 | ||
|
|
1efd56f48b | ||
|
|
bcd13b6f27 | ||
|
|
e4e880edd9 | ||
|
|
75da9c2e73 | ||
|
|
7a933dbd5e | ||
|
|
4b097b83b1 | ||
|
|
b3f9a691f5 | ||
|
|
50cd94a280 | ||
|
|
82982b3cda | ||
|
|
a5243ff58c | ||
|
|
3b25e0a112 | ||
|
|
d94d880569 | ||
|
|
8eec07b5bd | ||
|
|
9f72a51458 | ||
|
|
9fd181ee06 | ||
|
|
f18875682b | ||
|
|
897a17e303 | ||
|
|
c9d0aafbfa | ||
|
|
fbd2a57a35 | ||
|
|
ccd5c91283 | ||
|
|
c78b9f07a2 | ||
|
|
ffc3300fe4 | ||
|
|
b02d32929c | ||
|
|
e29d3e3eaa | ||
|
|
5d91643637 | ||
|
|
9eec1adf77 | ||
|
|
9cebaa0d97 | ||
|
|
48cfebd5ae | ||
|
|
0c3899840b | ||
|
|
93bab6bbdd | ||
|
|
69368b884f | ||
|
|
f59b2d26ad | ||
|
|
32ffe33e1a | ||
|
|
cc5d119ba4 | ||
|
|
637727faa0 | ||
|
|
9b82cdfe53 | ||
|
|
2424c76c50 | ||
|
|
f0dc76c7a4 | ||
|
|
798f5cd0a6 | ||
|
|
a904896269 | ||
|
|
be482bd683 | ||
|
|
e9a624c896 | ||
|
|
b3a13a25f0 | ||
|
|
30e55f5acb | ||
|
|
7a67263cf9 | ||
|
|
b811906bae | ||
|
|
2a81d41c2c | ||
|
|
51d0037a4b | ||
|
|
25fc0226aa | ||
|
|
cfef06a15b | ||
|
|
5ce6aafc07 | ||
|
|
fe833033df | ||
|
|
a47be148c8 | ||
|
|
af426d28c1 | ||
|
|
0332b81d58 | ||
|
|
88b416c949 | ||
|
|
66c4e62d9b | ||
|
|
9091c2c346 | ||
|
|
e29ca2e79c | ||
|
|
afc3f48f51 | ||
|
|
eed8b36dc1 | ||
|
|
b20942d254 | ||
|
|
e707beffd6 | ||
|
|
747c75fb18 | ||
|
|
42f0a9df4b | ||
|
|
10ee6bcc7f | ||
|
|
bcba194a31 | ||
|
|
8605f63ac6 | ||
|
|
a02827a7ac | ||
|
|
16903b0f5a | ||
|
|
26bdf25423 | ||
|
|
3c0f4be533 | ||
|
|
ecf9dce758 | ||
|
|
90e40d5245 | ||
|
|
b76424ba9b | ||
|
|
ded75563e9 | ||
|
|
1eb9920bcf | ||
|
|
7e029b5495 | ||
|
|
37f9491d5e | ||
|
|
6aec78e153 | ||
|
|
685e34bc83 | ||
|
|
fb828788df | ||
|
|
eff49af00c | ||
|
|
7f02b85eb8 | ||
|
|
1de84c66d6 | ||
|
|
e382ccff9b | ||
|
|
33e6202835 | ||
|
|
bd8b8d5b64 | ||
|
|
db9dc18118 | ||
|
|
7cc373c07f | ||
|
|
aa87640687 | ||
|
|
6724912c73 | ||
|
|
2cabe6e58e | ||
|
|
33383cd3bd | ||
|
|
78c5250f1b | ||
|
|
9797d98fac | ||
|
|
43c2dc3dec | ||
|
|
50e140e606 | ||
|
|
3f88701751 | ||
|
|
7d89d53b1b | ||
|
|
09f7989cab | ||
|
|
6255cfd401 | ||
|
|
e7e4897dcd | ||
|
|
9639143893 | ||
|
|
3be3b0ca36 | ||
|
|
afc81b6308 | ||
|
|
36d140d4bd | ||
|
|
edff998be9 | ||
|
|
5a856e468e | ||
|
|
d2845f91b5 | ||
|
|
9040c13c3f | ||
|
|
7ed95ff523 | ||
|
|
aed9889a2e | ||
|
|
0090f484d8 | ||
|
|
0c576c65a8 | ||
|
|
b94cde5fbe | ||
|
|
df2582d1de | ||
|
|
f237a9aab5 | ||
|
|
12c370d7cb | ||
|
|
015c17e2dc | ||
|
|
d8a3466914 | ||
|
|
05d2ffe8fa | ||
|
|
a62d8304e2 | ||
|
|
e51ee8c1ad | ||
|
|
6d0f668f88 | ||
|
|
ed5e590859 | ||
|
|
346fa2c004 | ||
|
|
db04b0c285 | ||
|
|
07800bdb83 | ||
|
|
ad8b338bd9 | ||
|
|
031c0c263d | ||
|
|
d54053003e | ||
|
|
adb453c216 | ||
|
|
ef04e43323 | ||
|
|
9ff5147418 | ||
|
|
cdbedf3d64 | ||
|
|
3d52fa059e | ||
|
|
ef46d1a308 | ||
|
|
d57cfa90fc | ||
|
|
7aece7dd7e | ||
|
|
ccf362db41 | ||
|
|
7bd4002f09 | ||
|
|
9460b12cf9 | ||
|
|
8cac592182 | ||
|
|
83b25b0c33 | ||
|
|
1832ec753c | ||
|
|
0c4f943d72 | ||
|
|
116ee25e28 | ||
|
|
6149c2a8a8 | ||
|
|
b2e475b857 | ||
|
|
f7e4e98b01 | ||
|
|
c4a9919652 | ||
|
|
5c1fb7d4e8 | ||
|
|
b1d0a4e7ad | ||
|
|
75db995342 | ||
|
|
c318856534 | ||
|
|
cf42e1846e | ||
|
|
56a5ebbb9d | ||
|
|
7431e1e605 | ||
|
|
4b6a460e69 | ||
|
|
f6f0c2f1dc | ||
|
|
90357ae386 | ||
|
|
bdc6b08234 | ||
|
|
1ba68d67ba | ||
|
|
d0518e6dfe | ||
|
|
3be6a78568 | ||
|
|
a6b8881e30 | ||
|
|
23c057ac08 | ||
|
|
07460ba06f | ||
|
|
bcbedbe053 | ||
|
|
ba26037c7f | ||
|
|
60243215a0 | ||
|
|
9c3ab28da9 | ||
|
|
2b1076f09e | ||
|
|
241859232b | ||
|
|
456fdc0fca | ||
|
|
be84bd27d3 | ||
|
|
2e84788d53 | ||
|
|
76b3b3b23d | ||
|
|
426c88c4ed | ||
|
|
d625b0d567 | ||
|
|
e350c5f070 | ||
|
|
1e481edc67 | ||
|
|
12f02dda98 | ||
|
|
ef50d90a18 | ||
|
|
25ae72cd26 | ||
|
|
eb8f83786c | ||
|
|
cd7b075016 | ||
|
|
19068dc6b0 | ||
|
|
93ba0bd807 | ||
|
|
15a76486ef | ||
|
|
f01e367785 | ||
|
|
9b536f8dc1 | ||
|
|
664a0e4ad8 | ||
|
|
9ed64354fc | ||
|
|
f59a160249 | ||
|
|
cdd7774a73 | ||
|
|
a10777d598 | ||
|
|
a4c5670409 | ||
|
|
343c53b41c | ||
|
|
4c97bc34ce | ||
|
|
83f0ca918a | ||
|
|
bc7c3968b6 | ||
|
|
1aba217b1a | ||
|
|
a95e87a08f | ||
|
|
b75e299b2f | ||
|
|
3e63b49c3c | ||
|
|
1eaf2372bb | ||
|
|
8b8400e5be | ||
|
|
c6551c9ea3 | ||
|
|
b04c676288 | ||
|
|
01e2a2bdb2 | ||
|
|
670533807a | ||
|
|
9d1270374e | ||
|
|
353e8bd0de | ||
|
|
9ca0ec82a8 | ||
|
|
bb5fd44750 | ||
|
|
1e435b0ff8 | ||
|
|
bb080c2d18 | ||
|
|
91063075d3 | ||
|
|
ccaf485c91 | ||
|
|
125207226b | ||
|
|
393affbd90 | ||
|
|
4f06fe45d3 | ||
|
|
ba1a981c87 | ||
|
|
6d51240a27 | ||
|
|
527143405f | ||
|
|
2808fdd3c0 | ||
|
|
a2c84392f4 | ||
|
|
3fdff4e6eb | ||
|
|
dd41e00691 | ||
|
|
29bcaa9558 | ||
|
|
3be3e8546f | ||
|
|
0bbb760e61 | ||
|
|
4f238f4f62 | ||
|
|
a244c6d5e3 | ||
|
|
aa5765971e | ||
|
|
2a66edd1c5 | ||
|
|
a6e86e8d6b | ||
|
|
f30cb9da59 | ||
|
|
e94d17a922 | ||
|
|
53f5c168ad | ||
|
|
4533f7b1d5 | ||
|
|
b9398e882a | ||
|
|
66f19d72da | ||
|
|
35e85cfdcb | ||
|
|
6d6b63cce1 | ||
|
|
a7d5e77a1c | ||
|
|
0332b22c4a | ||
|
|
09a7974818 | ||
|
|
66d2f0d550 | ||
|
|
d2556fed20 | ||
|
|
49cd8536a7 | ||
|
|
b8f15bcca9 | ||
|
|
a17ba9f62c | ||
|
|
a9aa9a2e20 | ||
|
|
43da07ca4c | ||
|
|
1b22abcd50 | ||
|
|
f85c83169d | ||
|
|
ecff344473 | ||
|
|
cde380782f | ||
|
|
d557149326 | ||
|
|
ecdcb040ee | ||
|
|
e58471fe37 | ||
|
|
30e66473db | ||
|
|
5357ed3746 | ||
|
|
337f443cbf | ||
|
|
e7ad1b8496 | ||
|
|
aea01de449 | ||
|
|
b7fb75a49e | ||
|
|
57752d09cd | ||
|
|
bd395f557a | ||
|
|
2d865d8fed | ||
|
|
5bff74e7a9 | ||
|
|
a9e3723764 | ||
|
|
b811227c41 | ||
|
|
4896c4dda5 | ||
|
|
b4ee1ade2d | ||
|
|
a6e2308282 | ||
|
|
f56c42f353 | ||
|
|
5edf51810d | ||
|
|
81985b0e31 | ||
|
|
163830f1bd | ||
|
|
867ae2991c | ||
|
|
ee3d04ba23 | ||
|
|
71dd8c14f8 | ||
|
|
88dc9c2a74 | ||
|
|
98f012de4d | ||
|
|
c85a036ac6 | ||
|
|
1f8b632d95 | ||
|
|
59dd56e542 | ||
|
|
1bfa8dcb3f | ||
|
|
1b381af7a7 | ||
|
|
2bc4912416 | ||
|
|
474f0d8291 | ||
|
|
231fe54408 | ||
|
|
78bef70735 | ||
|
|
ce7247e209 | ||
|
|
1d807e2a89 | ||
|
|
749141c10e | ||
|
|
e2c7c0596c | ||
|
|
392cd72f83 | ||
|
|
340a9d937b | ||
|
|
5d7ad836db | ||
|
|
f8e449b017 | ||
|
|
bb0b59080a | ||
|
|
95b08c2406 | ||
|
|
3ef5e0e55a | ||
|
|
ae9b4bc2f5 | ||
|
|
914e738931 | ||
|
|
e4c19c0f2a | ||
|
|
54354518d0 | ||
|
|
d36e21ab56 | ||
|
|
b496e3c667 | ||
|
|
d10434285f | ||
|
|
d6c8886fdb | ||
|
|
51e3c8605c | ||
|
|
d4d6b9c9aa | ||
|
|
0c9c3c61fc | ||
|
|
0228850d6d | ||
|
|
529078dc67 | ||
|
|
aadb68ba08 | ||
|
|
c81171a39e | ||
|
|
a50ecff189 | ||
|
|
73321829ae | ||
|
|
e88c837482 | ||
|
|
2b263cae87 | ||
|
|
e93052f0cb | ||
|
|
9539083f7e | ||
|
|
8f26eb1c69 | ||
|
|
a126e5b4c8 | ||
|
|
033c3cd8e9 | ||
|
|
50d029c671 | ||
|
|
6a3f7e6150 | ||
|
|
aadfbefbe9 | ||
|
|
edbcaf0f90 | ||
|
|
207427e993 | ||
|
|
e109dd876a | ||
|
|
64ac69c48b | ||
|
|
652b06c116 | ||
|
|
654035a469 | ||
|
|
cd50e0086b | ||
|
|
66a119e9dc | ||
|
|
14ec7d48f6 | ||
|
|
5ad5b211e9 | ||
|
|
aac4b6ccfe | ||
|
|
cfc6967fdc | ||
|
|
8a0b960985 | ||
|
|
bd260c3dc5 | ||
|
|
203dff8d98 | ||
|
|
ca56089a3e | ||
|
|
a012d1b927 | ||
|
|
0af322a3a8 | ||
|
|
8d743803c8 | ||
|
|
63fed77c5b | ||
|
|
f2077dca04 | ||
|
|
cccfb6a08a | ||
|
|
fa6dead83d | ||
|
|
605418d750 | ||
|
|
8aa869b2e4 | ||
|
|
558b6e0ccf | ||
|
|
6a695368da | ||
|
|
ce89f29aeb | ||
|
|
6d935d8589 | ||
|
|
967093328f | ||
|
|
48e1da128d | ||
|
|
369de684a6 | ||
|
|
d5f65eea06 | ||
|
|
8e5deb5bf4 | ||
|
|
df653258bb | ||
|
|
ed28a59fcb | ||
|
|
adc46411b2 | ||
|
|
fcc4d666ec | ||
|
|
9d89f5d48d | ||
|
|
88c62e01ad | ||
|
|
1823598a8b | ||
|
|
3fd22988c1 | ||
|
|
a3ade4cde2 | ||
|
|
55c2286eca | ||
|
|
1afa050698 | ||
|
|
dfa15c6952 | ||
|
|
a2af321c5e | ||
|
|
fddfaf23ce | ||
|
|
ae0ee2048a | ||
|
|
6659d1fe43 | ||
|
|
f601e61f8d | ||
|
|
f8ed7a112a | ||
|
|
b0d6181bd7 | ||
|
|
82843b14b4 | ||
|
|
0df3ca3c5f | ||
|
|
c881f8e886 | ||
|
|
f1bf274de1 | ||
|
|
91e4e9c2d5 | ||
|
|
63a5f94a67 | ||
|
|
1bd8694262 | ||
|
|
501231adff | ||
|
|
3a033b66c4 | ||
|
|
46aacba037 | ||
|
|
10ef80da75 | ||
|
|
75b7897ad6 | ||
|
|
14423e0eb3 | ||
|
|
fe44581a61 | ||
|
|
0d612bd6df | ||
|
|
b7eba95ab2 | ||
|
|
59091a5ea9 | ||
|
|
31e8b466cf | ||
|
|
c97bc5edfc | ||
|
|
74f8e9544b | ||
|
|
0a5e7c44ff | ||
|
|
5c32160a58 | ||
|
|
2fc81c03ec | ||
|
|
cc485df42f | ||
|
|
d575dd24ca | ||
|
|
e47586cea3 | ||
|
|
1ce63c7550 | ||
|
|
36d69da3b7 | ||
|
|
529be08420 | ||
|
|
ffe11c7015 | ||
|
|
76b796bde7 | ||
|
|
f81715f07f | ||
|
|
ec3f667b75 | ||
|
|
87f0b4fd17 | ||
|
|
c7e95c5166 | ||
|
|
6ea0837cce | ||
|
|
59627e048f | ||
|
|
45fea5726b | ||
|
|
e539f29f6d | ||
|
|
1d2810e98f | ||
|
|
1cbafc9750 | ||
|
|
e675f7ac06 | ||
|
|
9dc9d3b1b7 | ||
|
|
a104ce688e | ||
|
|
2dd1ceb0b9 | ||
|
|
9379328d96 | ||
|
|
d8969c327c | ||
|
|
c3624fb7d6 | ||
|
|
b2de230100 | ||
|
|
9d0bf50931 | ||
|
|
843e453b21 | ||
|
|
f7546b0090 | ||
|
|
ed12aac7d8 | ||
|
|
15f4053241 | ||
|
|
7a334f0099 | ||
|
|
4a510393ab | ||
|
|
52b0638258 | ||
|
|
b198b1945d | ||
|
|
10784e95bb | ||
|
|
f4c65516d0 | ||
|
|
6498305ec8 | ||
|
|
7a91e6efef | ||
|
|
4204b62f8f | ||
|
|
70b718d372 | ||
|
|
2b5d6f3592 | ||
|
|
8e48d5ba68 | ||
|
|
3cec62d1a9 | ||
|
|
b1650bcbee | ||
|
|
492e3d8965 | ||
|
|
6d7be78b70 | ||
|
|
bac9439f8e | ||
|
|
5b612bfa0f | ||
|
|
1f77b3dd4b | ||
|
|
b0d7a53d15 | ||
|
|
c029eccdd3 | ||
|
|
7236f8929c | ||
|
|
aa114f86e3 | ||
|
|
95db349973 | ||
|
|
2acef590b4 | ||
|
|
29855b2b6e | ||
|
|
ea10dd68a3 | ||
|
|
e1942c66ac | ||
|
|
6bd18e8078 | ||
|
|
f3dd306f54 | ||
|
|
3cf39ea48b | ||
|
|
d57f212c62 | ||
|
|
b273c52124 | ||
|
|
ce0a9afc33 | ||
|
|
8437fe1716 | ||
|
|
f63f645696 | ||
|
|
f7267806df | ||
|
|
bebf1906a2 | ||
|
|
58e61e0bda | ||
|
|
42aa62cff0 | ||
|
|
bcf7b3fccb | ||
|
|
ff09378c6d | ||
|
|
99b0595e50 | ||
|
|
5321469c1d | ||
|
|
ef9eb83a75 | ||
|
|
c12bbc7f0f | ||
|
|
a16c4c3657 | ||
|
|
c8240448c6 | ||
|
|
d19569131c | ||
|
|
37eec4c971 | ||
|
|
65fe679ee2 | ||
|
|
a16b825c3b | ||
|
|
b9aedc9165 | ||
|
|
8bdbbc562c | ||
|
|
696f6c096c | ||
|
|
d0ef6aef1c | ||
|
|
7204b51439 | ||
|
|
6075a9d22f | ||
|
|
b15cfa1892 | ||
|
|
955375f423 | ||
|
|
2aa13a499a | ||
|
|
fb0e61f3b0 | ||
|
|
16149fdd38 | ||
|
|
a432080141 | ||
|
|
73072daa46 | ||
|
|
2f57345bd2 | ||
|
|
06075d561d | ||
|
|
db8ad7cde5 | ||
|
|
cacf39da69 | ||
|
|
4dc7937321 | ||
|
|
1c462ce152 | ||
|
|
2014d2495e | ||
|
|
dc5493f39f | ||
|
|
67ff5e5a4a | ||
|
|
22d56d31a9 | ||
|
|
785427674a | ||
|
|
581f6c6e1c | ||
|
|
7d0be85e84 | ||
|
|
04e75ab540 | ||
|
|
c117e33d24 | ||
|
|
cafdad6f9f | ||
|
|
05e212682c | ||
|
|
3f876202c1 | ||
|
|
57c75799a9 | ||
|
|
5cbf2d8047 | ||
|
|
3dd9ad9ead | ||
|
|
864bef483f | ||
|
|
9ea9fefe1d | ||
|
|
0b953a1517 | ||
|
|
80db293aca | ||
|
|
809be41e64 | ||
|
|
8a6ee68e58 | ||
|
|
da764721d9 | ||
|
|
0586639e07 | ||
|
|
0aeab00289 | ||
|
|
9564097f46 | ||
|
|
d4750f4c6e | ||
|
|
f1cc2fe72e | ||
|
|
6d90539e89 | ||
|
|
21f5ed6afd | ||
|
|
4cbbf2ac81 | ||
|
|
a035a2525a | ||
|
|
9727601752 | ||
|
|
9e9053c0eb | ||
|
|
507d495f3f | ||
|
|
a2f7547cdb | ||
|
|
d48308d913 | ||
|
|
78c0badd95 | ||
|
|
c81c33a430 | ||
|
|
1786376a9e | ||
|
|
aa973ea984 | ||
|
|
67aeeb0b2f | ||
|
|
ee2b01673b | ||
|
|
c392f7ee8d | ||
|
|
4adc950e29 | ||
|
|
78db5b55ec | ||
|
|
ad40fdcb55 | ||
|
|
c5ca510a75 | ||
|
|
13c64a95fa | ||
|
|
5d74a78bb7 | ||
|
|
d638bae7c4 | ||
|
|
9faf8ed55e | ||
|
|
3aa23b0f9d | ||
|
|
063bbc9f06 | ||
|
|
16bb23b8a7 | ||
|
|
a26bef6317 | ||
|
|
21c41d5af1 | ||
|
|
b270096591 | ||
|
|
be689f088d | ||
|
|
2410409342 | ||
|
|
a24d682747 | ||
|
|
2ada44a2fc | ||
|
|
d6c7fb8dcc | ||
|
|
bb40a8612a | ||
|
|
1182a6eba4 | ||
|
|
0d303889ef | ||
|
|
2b3aab2faf | ||
|
|
893d20b4e9 | ||
|
|
32e421356f | ||
|
|
9858170e61 | ||
|
|
16711e33e8 | ||
|
|
f534e11acb | ||
|
|
2ff0f4b102 | ||
|
|
5b2a44e3bd | ||
|
|
0b06206d34 | ||
|
|
cb93dfa218 | ||
|
|
c92517960e | ||
|
|
3a615a4a87 | ||
|
|
78d2541c14 | ||
|
|
b8d07b365b | ||
|
|
2d5848db94 | ||
|
|
d4c88edb8b | ||
|
|
90288da36d | ||
|
|
601e1a67a1 | ||
|
|
8817318a53 | ||
|
|
153836ea01 | ||
|
|
24c88b828c |
@@ -4,14 +4,15 @@ platform:
|
||||
cache:
|
||||
- node_modules
|
||||
- '%APPDATA%\npm-cache'
|
||||
# - '%USERPROFILE%\.electron'
|
||||
- '%LOCALAPPDATA%\electron\Cache'
|
||||
- '%LOCALAPPDATA%\electron-builder\Cache'
|
||||
|
||||
install:
|
||||
- ps: Install-Product node 12 x64
|
||||
- npm install
|
||||
|
||||
build_script:
|
||||
- npm run pub:gh
|
||||
- npm run publish:gh
|
||||
|
||||
test: off
|
||||
|
||||
4
.babelrc
4
.babelrc
@@ -17,6 +17,8 @@
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-syntax-dynamic-import"
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"@babel/plugin-transform-modules-umd",
|
||||
"@babel/plugin-transform-runtime"
|
||||
]
|
||||
}
|
||||
|
||||
25
.github/ISSUE_TEMPLATE/----.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/----.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
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=>)
|
||||
|
||||
**描述您想要的解决方案**
|
||||
<!-- 简洁明了地描述您要发生的事情。 -->
|
||||
|
||||
|
||||
**描述您考虑过的替代方案**
|
||||
<!-- 对您考虑过的所有替代解决方案或功能的简洁明了的描述。 -->
|
||||
|
||||
|
||||
**其他内容**
|
||||
<!-- 在此处添加有关功能请求的任何其他上下文或屏幕截图(直接把图片拖到编辑框即可添加图片)。 -->
|
||||
|
||||
42
.github/ISSUE_TEMPLATE/--bug.md
vendored
Normal file
42
.github/ISSUE_TEMPLATE/--bug.md
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
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]
|
||||
-软件安装包及版本:[例如:Windows 64位绿色版 1.0.0]
|
||||
|
||||
|
||||
**其他内容**
|
||||
<!-- 在此处添加有关该问题的任何其他上下文。 -->
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -34,6 +34,7 @@ build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
node_modules.bak*/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
@@ -68,3 +69,5 @@ dist
|
||||
publish/assets
|
||||
|
||||
publish/utils/githubToken.js
|
||||
|
||||
src/**/*-internal.js
|
||||
|
||||
49
.travis.yml
Normal file
49
.travis.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
language: node_js
|
||||
node_js: 12
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
env:
|
||||
- ELECTRON_CACHE=$HOME/.cache/electron
|
||||
- ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
sudo: required
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- rpm
|
||||
- bsdtar
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- $HOME/.cache/electron
|
||||
- $HOME/.cache/electron-builder
|
||||
- $HOME/.npm/_prebuilds
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
script:
|
||||
- node --version
|
||||
- npm --version
|
||||
- |
|
||||
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||
npm install && npm run publish:gh:linux
|
||||
else
|
||||
npm run publish:gh:mac
|
||||
fi
|
||||
|
||||
before_cache:
|
||||
- rm -rf $HOME/.cache/electron-builder/wine
|
||||
|
||||
# only run this script on pull requests and merges into
|
||||
# the 'master' and 'prod' branches
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- dev
|
||||
833
CHANGELOG.md
833
CHANGELOG.md
@@ -6,6 +6,839 @@ 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.5.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.4.1...v1.5.0) - 2020-12-13
|
||||
|
||||
### 新增
|
||||
|
||||
- 直接从歌单详情收藏的列表新增同步功能。注意:这将会覆盖本地的目标列表,歌曲将被替换成最新的在线列表
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化软件启动时恢复上一次播放的歌曲进度功能
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复MAC平台上下载歌曲封面嵌入无法显示的问题
|
||||
- 修复MAC平台首次运行软件最小化、关闭控制按钮默认在右边的问题
|
||||
- 修复酷狗源的某些歌曲没有专辑字段导致的列表加载失败问题
|
||||
- 修复某些酷狗源歌单链接无法打开的问题
|
||||
|
||||
## [1.4.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.4.0...v1.4.1) - 2020-11-25
|
||||
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复有歌词翻译与无歌词的音乐间切换会导致歌词翻译残留显示的问题
|
||||
- 修复歌曲URL过期时,等待刷新URL的自动切换歌曲时间间隔太短的问题
|
||||
- 修复某些电脑上的某些歌曲没有声音的问题(升级Electron9.3.4导致的,现降级到9.3.3)
|
||||
|
||||
## [1.4.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.3.0...v1.4.0) - 2020-11-21
|
||||
|
||||
### 新增
|
||||
|
||||
- 托盘菜单新增显示、隐藏主界面选项,为Linux、MAC版添加托盘菜单
|
||||
- 新增播放进度信息保存
|
||||
|
||||
### 优化
|
||||
|
||||
- 移除kg源的歌词文件开头的空白字符串
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复专辑图片无法嵌入的问题
|
||||
- 修复播放状态栏切换“上一首”歌曲按钮提示错误的问题
|
||||
- 修复移动单首歌曲时,如果目标列表存在该歌曲,会导致将源列表与目标列表里的目标歌曲移除
|
||||
- 修复kg源歌曲信息带有单引号等特殊字符被转义的问题
|
||||
|
||||
## [1.3.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.2.2...v1.3.0) - 2020-11-01
|
||||
|
||||
### 新增
|
||||
|
||||
- 播放详情页新增歌曲评论加载显示(某些平台暂不支持显示子评论)
|
||||
|
||||
### 优化
|
||||
|
||||
- 修改播放详情页的歌曲图片的显示效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复小芸源音乐搜索结果最多只有20条搜索结果的问题
|
||||
|
||||
## [1.2.2](https://github.com/lyswhut/lx-music-desktop/compare/v1.2.1...v1.2.2) - 2020-10-18
|
||||
|
||||
### 修复
|
||||
|
||||
- 降级 Electron 到 9.x.x 版本修复 Linux 版桌面歌词窗口变白的问题
|
||||
|
||||
## [1.2.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.2.0...v1.2.1) - 2020-10-18
|
||||
|
||||
### 优化
|
||||
|
||||
- Linux版的软件界面默认使用圆角与阴影,顺便修复了桌面歌词窗口变白的问题,已在Ubuntu 18.10测试正常,若显示异常可尝试添加`-nt`参数启动
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复聚合搜索的分页问题
|
||||
- 修复代理输入框输入的内容不生效的问题
|
||||
|
||||
## [1.2.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.1.1...v1.2.0) - 2020-09-30
|
||||
|
||||
提前祝大家中秋&国庆快乐~
|
||||
|
||||
### 新增
|
||||
|
||||
- 播放控制栏开启/关闭桌面歌词按钮 新增右击按钮时锁定/解锁桌面歌词功能
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化我的列表滚动条位置的保存逻辑
|
||||
- 更新设置-备份与恢复功能的描述
|
||||
- 优化软件内鼠标悬停的提示界面
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复桌面歌词窗口不允许拖出桌面之外的位置计算偏移Bug
|
||||
- 修复网易云KTV嗨榜无法加载的问题
|
||||
- 修复初始化搜索历史列表功能
|
||||
- 修复重启软件后试听列表与收藏列表无法恢复上次的滚动位置的问题
|
||||
- 修复歌曲封面无法嵌入的Bug
|
||||
- 修复酷狗歌词格式问题
|
||||
- 修复关闭切换动画时从搜索候选列表点击内容无效的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新 Electron 到 v10.1.3
|
||||
|
||||
## [1.1.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.1.0...v1.1.1) - 2020-09-19
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复某些情况下桌面歌词不会播放的问题
|
||||
|
||||
## [1.1.0](https://github.com/lyswhut/lx-music-desktop/compare/v1.0.1...v1.1.0) - 2020-09-18
|
||||
|
||||
### 新增
|
||||
|
||||
- 在歌单详情界面新增播放当前歌单按钮、收藏歌单按钮,注:播放歌单不会将歌曲添加到试听列表
|
||||
- 新增`不允许将歌词窗口拖出主屏幕之外`的设置项,默认开启,在连接多个屏幕时想要拖动到其他屏幕时可关闭此设置
|
||||
- 新增大部分平台的歌词翻译,感谢 @InoriHimea 提供的[krc解码算法](https://github.com/lyswhut/lx-music-desktop/issues/296#issuecomment-683285784)
|
||||
- 新增`显示歌词翻译`设置,默认开启,仅支持某些平台,注:无论该设置是否开启,嵌入或下载歌词时都不会带上翻译
|
||||
- 新增`显示切换动画`设置,默认开启,关闭时将基本禁用软件内的所有切换动画
|
||||
- 播放状态栏新增桌面歌词的开关、播放模式的切换、歌曲的收藏按钮,Thanks to @andylow for the [icon](https://github.com/lyswhut/lx-music-desktop/pull/309)!
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复使用全局快捷键还原窗口时,窗口没有获取焦点的问题
|
||||
- 修复我的列表搜索对最后一个字符的匹配问题
|
||||
- 修复窗口在`较小`模式下最小化/关闭按钮不居中的问题
|
||||
|
||||
### 优化
|
||||
|
||||
- 桌面歌词当前播放行改为上下居中
|
||||
- 为区分静音状态,静音时音量条会变淡,调整音量条时将会取消静音
|
||||
- 优化随机播放机制,现在通过`下一曲`切换歌曲时,直到播放完整个列表之前将不会再随机到之前播放过的歌曲,并且通过`上一曲`可以正确播放上一首歌曲
|
||||
- 当下载目录没有写入权限时将显示没有写入权限的提示
|
||||
|
||||
### 移除
|
||||
|
||||
- 移除默认的全局声音媒体快捷键接管
|
||||
- 移除对百度音乐的支持,因百度音乐原有的大部分API失效,而且该平台相对其他平台来说音乐太少了,可有可无,以后再看情况恢复
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到 10.1.2
|
||||
|
||||
## [1.0.1](https://github.com/lyswhut/lx-music-desktop/compare/v1.0.0...v1.0.1) - 2020-07-25
|
||||
|
||||
### 优化
|
||||
|
||||
- 对我的列表歌曲搜索结果进行相似度排序
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复在 Windows 系统下缩放比非100%时,拖动桌面歌词会自动加大桌面歌词窗口的问题
|
||||
|
||||
## [1.0.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.18.2...v1.0.0) - 2020-07-24
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增`rpm`、`pacman`包的构建(未测试可用性)
|
||||
- 新增因系统音频设备列表改变导致的当前音频输出设备改变时是否暂停播放的设置,默认关闭
|
||||
- 新增歌曲列表右击菜单
|
||||
- 新增自定义列表,创建列表的按钮在表头`#`左侧,鼠标移上去才会显示;编辑列表名字时,按`ESC`键可快速取消编辑,按回车键或使输入框失去焦点即可保存列表名字,右击列表可编辑已创建的列表,“试听列表”与“我的收藏”两个列表固定不可编辑
|
||||
- 改变排行榜布局,新增更多排行榜
|
||||
- 新增我的列表右键菜单复制歌曲名选项
|
||||
- 新增桌面歌词,默认关闭,可到设置或者托盘菜单开启(建议使用全局快捷键控制);调整字体大小、透明度时,鼠标左击按钮正常调整,右击微调;**Windows 7未开启Aero效果时桌面歌词会有问题**,详情看常见问题解决;Linux版桌面歌词有问题,以后再尝试优化;
|
||||
- 新增“清热板蓝”皮肤
|
||||
- 新增软件最小化、关闭按钮位置设置,MAC版默认为左边,非MAC为右边,不想用默认的可到设置修改
|
||||
- 新增快捷键设置,软件内快捷键默认开启,全局快捷键默认关闭(注:若想开启蓝牙耳机切歌需开启全局快捷键,当快捷键被中划线划掉时,表示当前快捷键被其他程序占用导致注册失败)
|
||||
- 新增首次运行时自动根据当前系统使用的语言设置软件显示的语言
|
||||
- 新增歌词区域的触摸板、鼠标滚轮等对歌词滚动的支持
|
||||
- 为了方便支持正版资源,歌曲列表右击菜单新增跳转到当前歌曲源官方详情页菜单(注意:在本版本之前添加的虾米源歌曲无法跳转详情页,需要移除后重新搜索添加)
|
||||
- 新增我的列表内歌曲搜索,在我的列表按`ctrl+f`将显示搜索框;鼠标滑过或键盘上下方向键选择搜索结果;鼠标点击或按回车键定位选中的歌曲;按`ctrl`键的情况下鼠标点击或按回车键确认定位歌曲时,将会在定位歌曲结束后播放该歌曲(搜索框激活的情况下按`esc`可快速清空搜索框/关闭搜索框)
|
||||
- 新增托盘图标样式设置,可到设置-其他切换
|
||||
- 新增开关下载功能控制,默认关闭,可到设置-下载设置开启
|
||||
- 新增将歌词嵌入音频文件中,默认关闭,可到设置-下载设置开启
|
||||
- 新增当列表文件损坏时对损坏文件的备份,若出现该情况可打开`%HOMEPATH%\AppData\Roaming\lx-music-desktop`找到`playList.json.bak`尝试手动修复列表文件,列表文件以`JSON`格式存储
|
||||
- 新增在歌单详情列表按退格(Backspace)键可快速返回歌单列表
|
||||
|
||||
### 优化
|
||||
|
||||
- 改进歌曲切换时的歌词滚动效果
|
||||
- 优化批量添加、删除播放列表的歌曲操作逻辑,大幅提升批量添加、删除列表歌曲的流畅度
|
||||
- 改进歌单列表展示
|
||||
- **改进聚合搜索的搜索结果排序**,修复当某些源搜索失败时导致其他源无法显示结果的问题,现在聚合搜索已达到最初的理想效果,为了使排序更精确,**建议同时输入 歌曲名 歌手名 搜索**(歌曲名在前歌手名在后),欢迎体验~!
|
||||
- 压缩备份数据文件大小
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复按住`Ctrl`等键触发多选机制时不松开按键的情况下切换到其他窗口后再松开按键,这时切回软件不按按键都处在多选模式的问题
|
||||
- 修复Linux版开启托盘无法退出的问题
|
||||
- 修复某些情况下可能导致的音源输出问题
|
||||
- 修复某些情况下无法开始下载任务的问题
|
||||
- 修复 tab 组件边框溢出问题
|
||||
- 修复错误更新试听列表外的歌曲时间的问题
|
||||
- 修复网易音乐源歌单、排行榜歌曲列表加载显示的数量与实际不对的问题,同时支持加载大于1000首歌的歌单(歌曲大于1000首会分页),注意:目前软件一下子显示太多歌曲时会卡顿,不建议在同一列表内添加太多歌曲
|
||||
- 修复歌曲图片链接没有扩展名的情况下无法嵌入图片的问题
|
||||
- 修复无法检测最新版本时弹窗提示的显示
|
||||
- 修复某些情况下从托盘还原窗口后无法操作的问题
|
||||
- 修复Linux下无法`ctrl+a`全选的问题
|
||||
- 修复主题背景图片覆盖不全的问题
|
||||
- 修复聚合搜索音源标签的皮肤配色问题
|
||||
|
||||
### 更变
|
||||
|
||||
- 修改设置-列表-是否显示歌曲源的默认设置为选中(该变更不影响之前的设置)
|
||||
- 移除浮动按钮,现在在多选完成后可鼠标右击随意一项在弹出的右键菜单中进行原来悬浮按钮的操作
|
||||
- 为了避免出现误会,现在下载弹窗中不可用的音质将直接隐藏
|
||||
- 更改初始设置的搜索设置为聚合搜索(该变更不影响之前的设置)
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新 Electron 到 9.1.1
|
||||
|
||||
## [0.18.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.18.1...v0.18.2) - 2020-05-02
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复开启托盘时,可能导致无法自动更新的问题
|
||||
|
||||
## [0.18.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.18.0...v0.18.1) - 2020-05-02
|
||||
|
||||
### 优化
|
||||
|
||||
- win下的托盘图标使用更大的图片
|
||||
- 加长软件协议的强制停留时间
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复导入设置某些设置未立即生效的问题
|
||||
|
||||
## [0.18.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.17.0...v0.18.0) - 2020-05-01
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增FLAC格式音乐标签信息写入与封面嵌入(因128k以外的音质已失效,目前该功能用不上了)
|
||||
- 添加软件启动时是否自动聚焦搜索框的设置
|
||||
- 新增托盘设置,默认关闭,可到设置开启,感谢 @LasyIsLazy 提交的PR
|
||||
- 新增打开酷狗源用户歌单
|
||||
- 新增使用协议
|
||||
- 新增虾米音源
|
||||
- 新增新皮肤“粉妆玉琢”、“青出于黑”,可去体验下~
|
||||
- 新增“超大”、“巨大”窗口尺寸
|
||||
- 新增播放详情页(退出详情页可点击右上角退出按钮或者在播放详情页任意地方**鼠标快速右击两次**)
|
||||
|
||||
### 优化
|
||||
|
||||
- 略微加深音量条底色
|
||||
- 优化其他界面细节
|
||||
- 优化英语翻译,感谢 @CPCer
|
||||
- 优化程序的流畅度
|
||||
|
||||
### 更变
|
||||
|
||||
- 下载列表的歌曲下载、播放将随设置中的保存路径改变而改变,不再固定指向其初始位置
|
||||
- 移除列表多选框,现在多选需要键盘配合,想要多选前需按下`Shift`或`Ctrl`键然后再鼠标点击想要选中的内容即可触发多选机制,其中`Shift`键用于连续选择,`Ctrl`键用于不连续选择,`Ctrl+a`用于快速全选。例子一:想要选中1-5项,则先按下`Shift`键后,鼠标点击第一项,再点击第五项即可完成选择;例子二:想要选中1项与第3项,则先按下`Ctrl`键后,鼠标点击第一项,再点击第三项即可完成选择;例子三:想要选中当前列表的全部内容,键盘先按下`Ctrl`键不放,然后按`a`键,即可完成选择。用`Shift`或`Ctrl`选择时,鼠标点击未选中的内容会将其选中,点击已选择的内容会将其取消选择,若想全部取消选择,在不按`Shift`或`Alt`键的情况下,随意点击列表里的一项内容即可全部取消选择。(P.S:`Ctrl`键对应Mac OS上的`Command`键)
|
||||
- 现在进度条的封面图左击改为打开播放详情页,在列表定位歌曲改为右击
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复网易源某些歌曲提示没有可播放的音质的问题
|
||||
- 修复下载管理刷新URL失败时不标记任务下载失败的问题
|
||||
- 修复列表导出的文字描述,感谢 @CPCer
|
||||
- 修复歌曲切换方式无法取消勾选的问题
|
||||
- 修复打开歌单详情的情况下切到其他界面再切回来报错的问题
|
||||
- 修正播放列表浮动按钮错误的文字提示
|
||||
|
||||
### 移除
|
||||
|
||||
- 因128k以外的音质失效,So 禁止所有128k外的音质下载
|
||||
|
||||
### 其他
|
||||
|
||||
更新 Electron 到 8.2.5
|
||||
|
||||
|
||||
## [0.17.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.16.0...v0.17.0) - 2020-03-15
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增多语言设置,目前软件内置了简体中文、繁体中文、英语三种语言,欢迎提交PR翻译更多语言!
|
||||
- 新增无法打开外部歌单FAQ
|
||||
- 新增启动参数`search`,使用例子:`.\lx-music-desktop.exe -search="突然的自我 - 伍佰"`
|
||||
- 新增音频输出设置
|
||||
- 新增软件内的包括字体在内的界面内容大小调整,现在当窗口大小切换到“较小/大/较大”时,软件内的元素将会适当减小或加大,窗口大小的“小”与“中”内的元素将保持之前的大小暂不做改变
|
||||
- 新增音源别名,默认将显示别名,想要显示回原名可到设置切换(免责声明:别名仅是本软件用于描述各音源的标签,其名字归版权方所有)
|
||||
- 新增发现新版本更新失败弹窗的忽略提醒按钮,忽略提醒后,以后同一个版本再失败时将不会弹窗提醒,但仍可到设置-版本更新手动点开更新弹窗查看或恢复提醒
|
||||
- 新增热搜词,默认关闭,可到设置开启
|
||||
- 新增历史搜索记录,默认关闭,可到设置开启(右击单个历史记录标签可移除所点击的记录)
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化月里嫦娥皮肤侧栏鼠标悬浮颜色
|
||||
- 优化播放进度条的动画效果
|
||||
- 现在添加下载任务时,后面添加的任务会在列表顶部插入
|
||||
- 优化歌单打开机制,现在歌单加载失败时会提示加载失败了,并且支持直接打开企鹅、酷我手机分享出来的歌单了
|
||||
- 优化右上角最小化/关闭按钮布局
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复歌单详情处于加载状态时无法返回的问题
|
||||
- 修复鼠标右击复制列表内容时会复制音质标签的问题
|
||||
- 修复`0.6.2`及以前的版本导出的“所有数据”内的歌曲列表无法导入的问题
|
||||
- 修复下载列表在某些情况下无法取消全选的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新Electron到 8.1.1
|
||||
|
||||
## [0.16.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.15.0...v0.16.0) - 2020-02-16
|
||||
|
||||
### 新增
|
||||
|
||||
- 允许选中列表内歌曲名、歌手名、专辑名内的文字,选中后可使用键盘快捷键进行复制
|
||||
- 新增在列表可选内容区域**鼠标右击**时自动复制列表已选文字的功能
|
||||
- 新增在搜索框**鼠标右击**时自动粘贴剪贴板的文本到搜索框中
|
||||
- 任务下载失败时将显示搜索按钮,方便在其他源搜索该歌曲
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化木叶之村主题翻页器背景颜色
|
||||
- 优化各个主题音质标签颜色
|
||||
- 优化其他一些界面细节及用户交互效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复启用透明窗口鼠标不穿透的bug
|
||||
- 修复大窗口时设置的音乐来源选项不换行的问题
|
||||
- 修复某些情况下暂停任务会自动开始任务的问题
|
||||
- 修复移除暂停、错误的任务时不删除未下载完成的文件的问题
|
||||
- 修复酷狗源歌单热门标签歌单列表无法加载问题
|
||||
- 修复QQ源歌单热门标签歌单列表无法加载问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到 8.0.1
|
||||
|
||||
## [0.15.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.14.1...v0.15.0) - 2020-01-23
|
||||
|
||||
洛雪提前祝大家新年快乐、身体健康、阖家幸福!
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复歌曲下载列表无法加载的问题
|
||||
- 修复歌曲下载任务数大于最大下载任务数的问题
|
||||
- 修复某些情况下歌曲下载错误的问题
|
||||
- 修复下载列表数据没有被迁移直接被丢弃的问题
|
||||
|
||||
## [0.14.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.14.0...v0.14.1) - 2020-01-22
|
||||
|
||||
洛雪提前祝大家新年快乐、身体健康、阖家幸福!
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复由于旧版配置文件迁移出错导致的软件界面无法显示的问题
|
||||
|
||||
## [0.14.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.13.1...v0.14.0) - 2020-01-22
|
||||
|
||||
洛雪提前祝大家新年快乐、身体健康、阖家幸福!
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增各大平台歌单热门标签显示(显示在歌单界面的第一个下拉标签菜单中)
|
||||
- 恢复QQ音乐源128k音质试听
|
||||
- 新增不强制win7开启透明效果即可使用,但要配置运行参数`-nt`,例如:`.\lx-music-desktop.exe -nt`,添加方法可自行百度“给快捷方式加参数”
|
||||
- 新增“新年快乐”主题,可自行切换体验
|
||||
|
||||
### 优化
|
||||
|
||||
- 减淡各个主题的歌曲列表分隔线颜色
|
||||
- 在线音乐列表音质标签优化,当歌曲有无损音质时隐藏高品质标签
|
||||
- 更新改进的歌词播放插件,现在歌词的播放显示将更准确
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复咪咕源无法搜索的问题
|
||||
- 修复更新弹窗底部文字颜色没有适配当前主题颜色的问题
|
||||
- 修复导入设置窗口大小、代理设置不立即生效的问题
|
||||
- 修复在线音乐列表获取失败时无限循环请求的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 将软件设置与播放列表分离存储成两个文件
|
||||
- 更新 Electron 到 7.1.9
|
||||
|
||||
## [0.13.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.13.0...v0.13.1) - 2019-12-16
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复全局更新弹窗无法遮盖搜索框的问题
|
||||
|
||||
### 其他
|
||||
|
||||
- 由于electron 7.1.3 - 7.1.5 的自动更新功能存在Bug,现降级到7.1.2
|
||||
|
||||
## [0.13.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.12.1...v0.13.0) - 2019-12-15
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增搜索框搜索建议键盘上下方向键选择功能
|
||||
- 聚合搜索新增音源显示
|
||||
- 新增“离开搜索界面时清空搜索列表”设置选项,默认关闭,可到设置-强迫症设置开启
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化“信口雌黄”皮肤配色
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复存在弹出层时,搜索建议列表被弹出层覆盖的问题
|
||||
- 修复搜索、排行榜、歌单列表多选框从不定状态到选中的Bug
|
||||
|
||||
### 移除
|
||||
|
||||
- 因Q音接口失效,移除Q音源的试听与下载
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到7.1.5
|
||||
- 更新vue到2.6.11
|
||||
|
||||
## [0.12.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.12.0...v0.12.1) - 2019-12-01
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化定位歌曲时的列表滚动机制
|
||||
- 优化链接点击效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复使用酷我源下载歌曲时,当歌曲无封面时下载报错的问题
|
||||
- 修复酷我源排行榜、歌单详情列表里的歌曲音质匹配问题(原来无论歌曲有无高品、无损都会显示有)
|
||||
- 禁止外部链接在软件内打开,将所有外部链接从默认浏览器打开
|
||||
|
||||
### 其他
|
||||
|
||||
- 更新electron到7.1.2
|
||||
|
||||
## [0.12.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.11.0...v0.12.0) - 2019-11-17
|
||||
|
||||
由于新下载库仍然没有完成,但下载功能已经可用,so 移除之前使用的第三方下载库,暂时把新下载库的下载模块直接加入本程序,若出现下载问题欢迎反馈!
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增下载功能对代理设置的支持,现在若在软件设置了代理服务器,下载功能也将会走代理网络了
|
||||
|
||||
### 优化
|
||||
|
||||
- 新下载模块将对恢复下载的任务进行字节校验,用于解决下载进度超过100%后仍然下载的问题
|
||||
- 注意:目前仍然无法暂停处于**链接获取**状态中的任务
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复Linux deb版本`.desktop`桌面文件缺少图标的问题,新增中文名称显示、软件分类,感谢@lowy的反馈!
|
||||
- 修复下载列表歌曲状态分类列表操作Bug
|
||||
- 修复歌曲封面下载失败时仍然执行嵌入封面操作导致报错的问题
|
||||
- 跳过重复添加**相同歌曲名与扩展名的歌曲**,例如你之前下载了A歌曲的128k音质,现在想要下载它的320k音质,但由于两者都是MP3格式,会因为重名导致之前的128k音质被覆盖但列表中仍然显示两种音质的问题(但实际上都是指向后面的320k音质)
|
||||
|
||||
## [0.11.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.10.0...v0.11.0) - 2019-11-10
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增歌曲缓冲定时器,尝试用于解决网络正常但是歌曲缓冲过久的问题
|
||||
- 新增下载管理的任务状态分类
|
||||
- 添加**杀毒软件提示有病毒或恶意行为**的说明,可到**常见问题**拉到最后查看(常见问题可在开源地址找到)
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化更新弹窗机制及其内容描述,对于可以自动更新的版本,现在可以看到软件的下载进度了
|
||||
|
||||
## [0.10.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.9.1...v0.10.0) - 2019-11-02
|
||||
|
||||
#### 优化
|
||||
|
||||
- 大幅减少程序**播放时**对CPU与GPU的使用,经测试CPU使用减少60%以上,GPU使用减少90%以上,这应该能解决MAC系统上的温度上涨的问题
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复酷我源**搜索提示**、**排行榜**无法获取的问题
|
||||
- 修复咪咕源无法播放的问题
|
||||
|
||||
## [0.9.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.9.0...v0.9.1) - 2019-10-27
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复没有配置文件时程序启动出错的问题
|
||||
|
||||
## [0.9.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.8.2...v0.9.0) - 2019-10-27
|
||||
|
||||
#### 新增
|
||||
|
||||
- 新增窗口大小设置,若觉得软件窗口小可以到设置页调大点
|
||||
- 新增定位当前播放歌曲,点击播放栏左侧的**歌曲图片**可在播放列表定位当前播放的歌曲(该功能对播放下载列表的歌曲无效)
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复搜索提示失效的问题
|
||||
- 修复从歌单或列表点击搜索按钮搜索目标歌曲时,搜索框未聚焦仍然弹出候选搜索列表的问题
|
||||
|
||||
## [0.8.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.8.1...v0.8.2) - 2019-10-20
|
||||
|
||||
#### 修复
|
||||
|
||||
- 兼容旧版酷我源搜索列表过滤128k音质的bug(注:0.8.1版本仅修复了酷我源的歌曲过滤问题,该修复仅对以后添加的歌曲有效,如果是之前添加的歌曲仍会出现这个问题,现修复对之前旧列表数据的兼容处理)
|
||||
|
||||
## [0.8.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.8.0...v0.8.1) - 2019-10-20
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复酷我源搜索歌曲结果未添加128k音质导致播放128k音质时显示“该歌曲没有可播放的音频”的问题
|
||||
|
||||
## [0.8.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.7.0...v0.8.0) - 2019-10-19
|
||||
|
||||
#### 新增
|
||||
|
||||
- 新增网易云源歌曲搜索
|
||||
- 新增网易云源歌单
|
||||
- 新增各平台通过输入歌单链接或歌单ID打开歌单详情列表,目前只适配了**网页版歌单链接**,其他方式的歌单链接可能无法解析,但你可想办法获取歌单ID后输入打开。注:各平台歌单ID均为纯数字,若遇到链接里存在歌单ID但无法解析的歌单链接,可以到GitHub提交issue或发送邮件或加群830125506反馈!
|
||||
- 新增音量调整滑动功能,现在支持鼠标左右拖动调整音量了
|
||||
|
||||
#### 优化
|
||||
|
||||
- 优化搜索框搜索体验
|
||||
- 优化音量条交互视觉效果
|
||||
- 缓存歌单详情列表数据
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复QQ源歌单无法翻页Bug
|
||||
- 修复默认列表没有创建时无法显示收藏列表的Bug
|
||||
- 修复网易云128k直接试听
|
||||
- 修复歌曲音质不存在时仍然播放或下载的Bug
|
||||
- 修复调整音量时,调整的位置与鼠标点击的位置不一致的问题
|
||||
|
||||
## [0.7.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.6.2...v0.7.0) - 2019-10-07
|
||||
|
||||
#### 新增
|
||||
|
||||
- 新增“我的收藏”本地播放列表
|
||||
- 新增缓存清理功能,可到**设置-其他**查看与清理软件缓存
|
||||
- 新增QQ音乐源搜索
|
||||
- 新增咪咕源搜索
|
||||
- 新增咪咕源歌单
|
||||
- 新增咪咕源排行榜
|
||||
- 新增我的音乐列表歌曲源显示,默认关闭,可到**设置-列表设置**开启
|
||||
|
||||
#### 优化
|
||||
|
||||
- 优化选择框动画效果
|
||||
- 尝试优化选我的音乐列表内容很多时多选的卡顿问题
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修复列表延迟显示的Bug
|
||||
- 修复QQ音源128k音质试听
|
||||
|
||||
## [0.6.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.6.1...v0.6.2) - 2019-10-01
|
||||
|
||||
祝贺祖国成立70周年~!
|
||||
|
||||
#### 新增
|
||||
|
||||
- 新增QQ音乐源歌单
|
||||
|
||||
#### 修复
|
||||
|
||||
- 修正火影皮肤名字
|
||||
- 修复当试听列表为空时,无法切到其他界面的Bug
|
||||
- 修复百度源搜索结果为空时的接口处理Bug
|
||||
- 恢复**酷狗**其他音质播放
|
||||
|
||||
## [0.6.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.6.0...v0.6.1) - 2019-09-28
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增试听列表**滚动条位置恢复**设置(可自动恢复到上次离开时的列表滚动位置),本功能默认开启,若不需要可到设置-列表设置将其关闭
|
||||
- 新增 **《海贼王》** 皮肤,喜欢个性化的可以试试~
|
||||
|
||||
### 优化
|
||||
|
||||
- 新增DNS解析缓存,加快请求速度
|
||||
- 优化代码逻辑,减少软件对系统资源的占用
|
||||
- 优化新版本信息检测,尽量减少弹出版本获取失败弹窗弹出的概率
|
||||
- 优化下拉列表动画效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复请求超时的逻辑处理Bug,尝试修复请求无法取消导致的正在播放的歌曲与界面显示的信息不一致的问题
|
||||
- 修复其他一些小Bug
|
||||
|
||||
### 移除
|
||||
|
||||
- 移除 `192k` 音质
|
||||
- 移除酷我音源 `ape` 音质,无损推荐 `flac` 格式
|
||||
|
||||
## [0.6.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.5...v0.6.0) - 2019-09-21
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增音乐**聚合搜索**,目前支持酷我、酷狗、百度源搜索
|
||||
- 新增代理功能
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化从《梦里嫦娥》皮肤切换到其他皮肤时侧栏动画的切换效果
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复试听列表没有歌曲时会显示列表加载中的Bug
|
||||
- 修复切换歌单列表详情时的UI Bug
|
||||
|
||||
## [0.5.5](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.4...v0.5.5) - 2019-09-13
|
||||
|
||||
### 新增
|
||||
|
||||
- 月是故乡明,祝大家中秋快乐🥮~~新增个性皮肤 **《月里嫦娥》**,时间仓促,皮肤还不是很完善,可以试试喜不喜欢~😉
|
||||
- 新增 MAC 版本退出快捷键支持
|
||||
- 新增点击播放器中的歌曲标题可以复制标题的功能(遇到好听的歌曲方便分享)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复 MAC 系统下软件关闭时再次从 dock 打开时报错的Bug
|
||||
- 修复下载的歌曲文件名中包含命名规则不允许的符号时下载失败的问题(若歌曲名包含这些符号会自动将其移除)
|
||||
- 修复 MAC 版本不能复制粘贴的问题
|
||||
|
||||
## [0.5.4](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.3...v0.5.4) - 2019-09-09
|
||||
|
||||
### 移除
|
||||
|
||||
- 下载的FLAC文件在修改歌曲信息后,软件无法播放,但使用本地播放器可以播放
|
||||
- 为了稳妥起见,暂时移除FLAC格式的meta信息修改
|
||||
- MP3格式无此问题
|
||||
|
||||
## [0.5.3](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.2...v0.5.3) - 2019-09-09
|
||||
|
||||
### 优化
|
||||
|
||||
- 更新所有依赖包到最新
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复试听酷狗源的音乐仍然获取320k音质导致获取失败的Bug
|
||||
|
||||
## [0.5.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.1...v0.5.2) - 2019-09-09
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增强迫症设置-离开搜索界面时是否清空搜索框
|
||||
- 设置-关于板块新增常见问题链接
|
||||
- 歌单左上角的分类按钮添加一个**向下图标**,方便识别该按钮为下拉框(该按钮可选择歌单类型,请自行尝试)
|
||||
|
||||
### 优化
|
||||
|
||||
- 略微优化最小化按钮字符
|
||||
- 优化试听列表的加载体验,当歌曲数过多时列表将延迟加载
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复下载管理的一些Bug
|
||||
|
||||
### 移除
|
||||
|
||||
- 因接口失效,移除网易云音源,酷狗音源仅支持播放128k音质
|
||||
|
||||
## [0.5.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.5.0...v0.5.1) - 2019-09-05
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增右上角最小化/关闭按钮鼠标滑过符号
|
||||
- 新增下载列表定位文件按钮
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复百度源歌单全部分类无法加载的问题
|
||||
- 修复更新弹窗无法弹出的问题
|
||||
|
||||
## [0.5.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.4.0...v0.5.0) - 2019-09-05
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**封面嵌入**(默认开启,可到设置-下载设置关闭)
|
||||
- 新增**歌词下载**(默认关闭,可到设置-下载设置开启)
|
||||
- 新增单例应用功能(实现软件单开功能,禁止软件多开)
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化歌单列表动画
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复歌单无法翻页的问题
|
||||
- 修复在某些情况下,添加下载歌曲导致下载列表崩溃的问题
|
||||
- 修复版本更新弹窗Bug
|
||||
- 修复酷狗歌单推荐歌单出现在其他分类中的Bug
|
||||
|
||||
## [0.4.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.5...v0.4.0) - 2019-09-04
|
||||
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**歌单**功能,目前支持酷我、酷狗、百度源歌单
|
||||
- 在设置界面-关于洛雪音乐说明部分新增**最新版网盘下载地址**与**打赏地址**
|
||||
- 新增酷狗 电音热歌榜、DJ热歌榜
|
||||
- 新增版本更新超时功能,对于部分无法访问GitHub的用户做更新超时提醒
|
||||
|
||||
### 移除
|
||||
|
||||
- **注意**:0.4.0以前的版本即将失效,请更新到0.4.0版本
|
||||
|
||||
## [0.3.5](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.4...v0.3.5) - 2019-08-30
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**测试接口**,该接口同样速度较慢,但软件的大部分功能可用,**请自行切换到该接口**,找接口辛苦,且用且珍惜!
|
||||
|
||||
### 优化
|
||||
|
||||
- 取消需要刷新URL时windows任务栏进度显示错误状态(现显示为暂停状态)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复使用临时接口时在试听列表双击灰色歌曲仍然会进行播放的Bug
|
||||
- 修复歌词加载Bug
|
||||
|
||||
## [0.3.4](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.3...v0.3.4) - 2019-08-29
|
||||
|
||||
### 优化
|
||||
|
||||
- 减少接口不稳定带来的影响,适当增加请求等待时间
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复播放过程中URL过期不会刷新URL的问题
|
||||
|
||||
## [0.3.3](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.2...v0.3.3) - 2019-08-29
|
||||
|
||||
### 修复
|
||||
|
||||
- **messoer**的接口已经关闭,暂时切换到临时接口使用,部分功能受限。。。
|
||||
- 修复设置界面更新出错时仍然显示更新下载中的问题
|
||||
- 修复手动定位播放进度条时存在偏差的问题
|
||||
- 屏蔽播放器中没有歌曲时对进度条的点击
|
||||
|
||||
|
||||
## [0.3.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.1...v0.3.2) - 2019-08-24
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增酷狗排行榜其他音质下载
|
||||
|
||||
## [0.3.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.3.0...v0.3.1) - 2019-08-24
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复音量条主题适配
|
||||
|
||||
## [0.3.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.3...v0.3.0) - 2019-08-24
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**MAC**及**Linux**版本(需要的可自行下载)
|
||||
- 新增音量调整
|
||||
- 新增任务栏播放进度条控制选项(现在可在设置界面关闭在任务栏显示的播放进度)
|
||||
- 新增更新出错时的弹窗提示
|
||||
- 从该版本起,非安装版也会有更新弹窗提醒了,但仍然需要手动下载新版本更新,版本信息可到设置页面查看
|
||||
|
||||
### 修复
|
||||
|
||||
- 强制把临时接口设置回 `messoer` 接口
|
||||
|
||||
## [0.2.3](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.2...v0.2.3) - 2019-08-22
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增任务栏程序标题改变功能(播放歌曲时任务栏标题将显示当前播放的歌曲)
|
||||
|
||||
### 修复
|
||||
|
||||
- 使用临时接口时,试听列表中的下载按钮仍然能点击的Bug
|
||||
- 修复某些情况下歌曲链接未能缓存的问题
|
||||
|
||||
### 移除
|
||||
|
||||
- 移除临时接口(因服务器被攻击,本接口已关闭)
|
||||
- 移除列表栏设置的隐藏专辑栏选项(感觉这个设置并没有什么luan用,并且还会打破布局)
|
||||
|
||||
## [0.2.2](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.1...v0.2.2) - 2019-08-21
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复下载过程中出错重试5次都失败后不会自动开始下一个任务的Bug
|
||||
- 修复播放到一半URL过期时不会刷新URL直接播放下一首的问题
|
||||
|
||||
## [0.2.1](https://github.com/lyswhut/lx-music-desktop/compare/v0.2.0...v0.2.1) - 2019-08-20
|
||||
|
||||
### 优化
|
||||
|
||||
- 新增歌曲URL存储,当URL无效时才重新获取,以减少接口不稳定的影响
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复歌曲加载无法加载时自动切换混乱的Bug
|
||||
- 修复移除列表最后一首歌曲时播放器不停止播放的问题
|
||||
|
||||
## [0.2.0](https://github.com/lyswhut/lx-music-desktop/compare/v0.1.6...v0.2.0) - 2019-08-20
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增**百度音乐**排行榜及其音乐直接试听与下载
|
||||
- 新增网易云排行榜音乐直接试听与下载(目前仅支持128k音质)
|
||||
- 新增酷狗排行榜音乐直接试听与下载(目前仅支持128k音质)
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复更新弹窗历史版本描述多余的换行问题
|
||||
- 修复歌曲无法播放的情况下歌词仍会播放的问题
|
||||
|
||||
## [0.1.6](https://github.com/lyswhut/lx-music-desktop/compare/v0.1.5...v0.1.6) - 2019-08-19
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复列表多选音源限制Bug
|
||||
|
||||
## [0.1.5](https://github.com/lyswhut/lx-music-desktop/compare/v0.1.4...v0.1.5) - 2019-08-19
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增搜索列表批量试听与下载功能
|
||||
- 新增排行榜列表批量试听与下载功能
|
||||
- 新增试听列表批量移除与下载功能
|
||||
- 新增下载列表批量开始、暂停与移除功能
|
||||
|
||||
### 优化
|
||||
|
||||
- 优化歌曲切换机制
|
||||
|
||||
## [0.1.4](https://github.com/lyswhut/lx-music-desktop/compare/v0.1.3...v0.1.4) - 2019-08-18
|
||||
|
||||
### 新增
|
||||
|
||||
143
FAQ.md
Normal file
143
FAQ.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# lx-music-desktop 常见问题
|
||||
|
||||
在阅读本常见问题后,仍然无法解决你的问题,请提交issue或者加企鹅群`830125506`反馈(无事勿加,入群先看群公告),反馈时请**注明**已阅读常见问题!
|
||||
|
||||
## ~~软件为什么没有桌面歌词与自定义列表功能~~
|
||||
|
||||
洛雪音乐的最初定位不是作为播放器开发的,它主要用于**查找歌曲**,软件的播放功能仅用于试听,不建议用作为常用播放器使用。
|
||||
|
||||
## 歌曲无法试听与下载
|
||||
|
||||
该问题解决顺序如下:
|
||||
|
||||
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`
|
||||
|
||||
## 列表多选
|
||||
|
||||
从v0.18.0起,列表多选需要键盘配合,想要多选前需按下`Shift`或`Ctrl`键然后再鼠标点击想要选中的内容即可触发多选机制,其中`Shift`键用于连续选择,`Ctrl`键用于不连续选择,`Ctrl+a`用于快速全选。
|
||||
|
||||
- 例子一:想要选中1-5项,则先按下`Shift`键后,鼠标点击第一项,再点击第五项即可完成选择;
|
||||
- 例子二:想要选中1项与第3项,则先按下`Ctrl`键后,鼠标点击第一项,再点击第三项即可完成选择;
|
||||
- 例子三:想要选中当前列表的全部内容,键盘先按下`Ctrl`键不放,然后按`a`键,即可完成选择。
|
||||
|
||||
用`Shift`或`Ctrl`选择时,鼠标点击未选中的内容会将其选中,点击已选择的内容会将其取消选择,若想全部取消选择,在不按`Shift`或`Alt`键的情况下,随意点击列表里的一项内容即可全部取消选择。(P.S:`Ctrl`键对应Mac OS上的`Command`键)
|
||||
|
||||
注:选完后可用鼠标右击弹出右键菜单操作已选的内容
|
||||
|
||||
## 播放整个歌单或排行榜
|
||||
|
||||
播放在线列表内的歌曲需要将它们都添加到我的列表才能播放,你可以全选列表内的歌曲然后添加到现有列表或者新创建的列表,然后去播放该列表内的歌曲。
|
||||
|
||||
## 无法打开外部歌单
|
||||
|
||||
不支持垮源打开歌单,请**确认**你需要打开的歌单平台是否与软件标签所写的**歌单源**对应(不一样的话请通过右上角切换歌单源);<br>
|
||||
对于分享出来的歌单,若打开失败,可尝试先在浏览器中打开后,再从浏览器地址栏复制URL地址到软件打开;<br>
|
||||
或者如果你知道歌单 id 也可以直接输入歌单 id 打开。<br>
|
||||
|
||||
## Windows 7 下界面异常(界面显示不完整)
|
||||
|
||||
由于软件默认使用了透明窗口,根据Electron官方文档的[说明](https://electronjs.org/docs/api/frameless-window#%E5%B1%80%E9%99%90%E6%80%A7):
|
||||
> 在 windows 操作系统上, 当 DWM 被禁用时, 透明窗口将无法工作。
|
||||
|
||||
因此,当 win7 没有使用**AERO**主题时界面将会显示异常,开启AERO的方法请自行百度:`win7开启aero效果`(开启后可看到任务栏变透明)。<br>
|
||||
从`0.14.0`版本起不再强制要求开启透明效果,若你实在不想开启(若非电脑配置太低,墙裂建议开启!),可通过添加运行参数`-nt`来运行程序即可,例如:`.\lx-music-desktop.exe -nt`,添加方法可自行百度“给快捷方式加参数”,该参数的作用是用来控制程序是否使用非透明窗口运行。
|
||||
|
||||
对于一些完全无法正常显示界面、开启了AERO后问题仍未解决的情况,请阅读下面的 **软件启动后,界面无法显示** 解决
|
||||
|
||||
## 软件启动后,界面无法显示
|
||||
|
||||
对于软件启动后,可以在任务栏看到软件,但软件界面在桌面上无任何显示,或者整个界面偶尔闪烁的情况。<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(运行时)`版即可,安装完成后可能需要重启才生效。
|
||||
|
||||
若还是不行可尝试以下操作:
|
||||
|
||||
- 更新显卡驱动
|
||||
- 尝试将绿色版的软件放在**桌面**或**我的文档**运行
|
||||
|
||||
## 安装版安装失败,提示安装程序并未成功地运行完成
|
||||
|
||||
对于部分电脑出现安装失败的问题,可以做出以下尝试:
|
||||
|
||||
- 若你之前可以安装成功,但现在安装失败,就去**控制面板-程序和功能**或用第三方卸载工具看下有没有之前的版本残留,若同时在不同路径下安装了多个版本就可能会出现该问题,这种情况卸载掉所有版本重新安装即可
|
||||
- 清理安装路径下的残留文件
|
||||
- 清理注册表(建议用清理工具清理)
|
||||
|
||||
## 软件无法联网
|
||||
|
||||
软件的排行榜、歌单、搜索列表**都**无法加载:
|
||||
|
||||
- 检查是否在设置界面开启了代理(当代理乱设置时软件将无法联网)
|
||||
- 检查软件是否被第三方软件/防火墙阻止联网
|
||||
|
||||
## 桌面歌词显示异常
|
||||
|
||||
### Windows 7 系统桌面歌词显示异常
|
||||
|
||||
Windows 7 未开启 Aero 效果时桌面歌词会有问题,详情看下面的 **Windows 7 下界面异常(界面显示不完整)** 方法解决。
|
||||
|
||||
### MAC OS 系统、桌面歌词有残留阴影
|
||||
|
||||
此问题似乎是Electron的Bug,翻阅electron的issue列表发现该Bug以存在很久了,遗憾的是没有一直都没有修复,由于我没有装MAC平台的电脑,没法重现,就没再去electron提issue,更多信息看:
|
||||
|
||||
- <https://github.com/electron/electron/issues/21173>
|
||||
- <https://github.com/electron/electron/issues/14304>
|
||||
|
||||
### Linux 系统下桌面歌词窗口异常
|
||||
|
||||
目前在 Ubuntu 18.10 下第一次开启桌面歌词时歌词窗口会变白,需要关闭后再开启,
|
||||
|
||||
其他 Linux 系统未测试,如有异常也是意料之中,目前不打算去处理 Linux 平台的桌面歌词问题。
|
||||
|
||||
|
||||
## 软件安装包说明
|
||||
|
||||
软件发布页及网盘中有多个类型的安装文件,以下是对这些类型文件的说明:
|
||||
|
||||
文件名带 `win_` 的是在Windows系统上运行的版本,<br>
|
||||
其中安装版(Setup)可自动更新软件,<br>
|
||||
绿色版(green)为免安装版,自动更新功能不可用;
|
||||
|
||||
以 **`.dmg`** 结尾的文件为 MAC 版本;
|
||||
|
||||
以 **`.AppImage`**、**`.deb`** 结尾的为 Linux 版本。
|
||||
|
||||
带有`x64`的为64位的系统版本,带`x86`的为32位的系统版本;若两个都带有的则为集合版,安装时会自动根据系统位数选择对应的版本安装。
|
||||
|
||||
## 软件更新
|
||||
|
||||
软件启动时若发现新版本时会自动从本仓库下载安装包,下载完毕会弹窗提示更新。<br>
|
||||
若下载未完成时软件被关闭,下次启动软件会再次自动下载。<br>
|
||||
若还是**更新失败**,可能是无法访问GitHub导致的,这时需要手动更新,即下载最新安装包直接覆盖安装即可。<br>
|
||||
注意:**绿色版**的软件自动更新功能**不可用**,建议使用安装版!!<br>
|
||||
注意:**Mac版**、**Linux deb**版不支持自动更新!
|
||||
|
||||
## 缺少`xxx.dll`
|
||||
|
||||
这个是电脑缺少某些dll导致的,正常的系统是没有这个问题的,可以尝试如下几个解决办法:
|
||||
|
||||
- 以管理员权限打开`cmd`,输入`sfc /scannow`回车等待检查完成重启电脑
|
||||
- 若上面的方法**修复、重启**电脑后仍然不行,就自行百度弹出的**错误信息**看下别人是怎么解决的
|
||||
|
||||
## 杀毒软件提示有病毒或恶意行为
|
||||
|
||||
本人只能保证我写的代码不包含任何**恶意代码**、**收集用户信息**的行为,并且软件代码已开源,请自行查阅,软件安装包也是由CI拉取源代码构建,构建日志:[windows包](https://ci.appveyor.com/project/lyswhut/lx-music-desktop)、[Mac/Linux包](https://travis-ci.com/github/lyswhut/lx-music-desktop)<br>
|
||||
尽管如此,但这不意味着软件是100%安全的,由于软件使用了第三方依赖,当这些依赖存在恶意行为时([供应链攻击](https://docs.microsoft.com/zh-cn/windows/security/threat-protection/intelligence/supply-chain-malware)),软件也将会受到牵连,所以我只能尽量选择使用较多人用、信任度较高的依赖。<br>
|
||||
当然,以上说明建立的前提是在你所用的安装包是从**本项目主页上写的链接**下载的,或者有相关能力者还可以下载源代码自己构建安装包。
|
||||
|
||||
从`v0.17.0`起,由于加入了音频输出设备切换功能,该功能调用了 [MediaDevices.enumerateDevices()](https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/enumerateDevices),可能导致安全软件提示洛雪要访问摄像头(目前发现卡巴斯基会提示),但实际上没有用到摄像头,并且摄像头的提示灯也不会亮,你可以选择阻止访问。
|
||||
|
||||
最后,若出现杀毒软件报毒、存在恶意行为,请自行判断选择是否继续使用本软件!
|
||||
88
README.md
88
README.md
@@ -1,35 +1,58 @@
|
||||
# 洛雪音乐助手桌面版
|
||||
<p align="center"><a href="https://github.com/lyswhut/lx-music-desktop"><img width="200" src="https://github.com/lyswhut/lx-music-desktop/blob/master/doc/images/icon.png" alt="lx-music logo"></a></p>
|
||||
|
||||
[![GitHub release][1]][2]
|
||||
<p align="center">
|
||||
<a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/release/lyswhut/lx-music-desktop" alt="Release version"></a>
|
||||
<a href="https://ci.appveyor.com/project/lyswhut/lx-music-desktop"><img src="https://ci.appveyor.com/api/projects/status/flrsqd5ymp8fnte5?svg=true" alt="Build status"></a>
|
||||
<a href="https://travis-ci.com/lyswhut/lx-music-desktop"><img src="https://travis-ci.com/lyswhut/lx-music-desktop.svg?branch=master" alt="Build status"></a>
|
||||
<a href="https://electronjs.org/releases/stable"><img src="https://img.shields.io/github/package-json/dependency-version/lyswhut/lx-music-desktop/dev/electron/master" alt="Electron version"></a>
|
||||
<!-- <a href="https://github.com/lyswhut/lx-music-desktop/releases"><img src="https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/latest/total" alt="Downloads"></a> -->
|
||||
<a href="https://github.com/lyswhut/lx-music-desktop/tree/dev"><img src="https://img.shields.io/github/package-json/v/lyswhut/lx-music-desktop/dev" alt="Dev branch version"></a>
|
||||
<!-- <a href="https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE"><img src="https://img.shields.io/github/license/lyswhut/lx-music-desktop" alt="License"></a> -->
|
||||
</p>
|
||||
|
||||
<!-- [![GitHub release][1]][2]
|
||||
[![Build status][3]][4]
|
||||
[![GitHub All Releases Download][5]][6]
|
||||
[![GitHub Releases Download][5]][6]
|
||||
[![dev branch][7]][8]
|
||||
[![GitHub license][9]][10] -->
|
||||
|
||||
[1]: https://img.shields.io/github/release/lyswhut/lx-music-desktop
|
||||
<!-- [1]: https://img.shields.io/github/release/lyswhut/lx-music-desktop
|
||||
[2]: https://github.com/lyswhut/lx-music-desktop/releases
|
||||
[3]: https://ci.appveyor.com/api/projects/status/flrsqd5ymp8fnte5?svg=true
|
||||
[4]: https://ci.appveyor.com/project/lyswhut/lx-music-desktop
|
||||
[5]: https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/latest/total
|
||||
[5]: https://img.shields.io/github/downloads/lyswhut/lx-music-desktop/total
|
||||
[6]: https://github.com/lyswhut/lx-music-desktop/releases
|
||||
[7]: https://img.shields.io/github/package-json/v/lyswhut/lx-music-desktop/dev
|
||||
[8]: https://github.com/lyswhut/lx-music-desktop/tree/dev
|
||||
[9]: https://img.shields.io/github/license/lyswhut/lx-music-desktop
|
||||
[10]: https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE -->
|
||||
|
||||
## 说明
|
||||
<h2 align="center">洛雪音乐助手桌面版</h2>
|
||||
|
||||
一个基于 Electron + Vue 开发的 Windows 版音乐软件。
|
||||
### 说明
|
||||
|
||||
一个基于 Electron + Vue 开发的音乐软件。
|
||||
|
||||
所用技术栈:
|
||||
|
||||
- Electron 6.x
|
||||
- Vue 2.x
|
||||
- Electron 9
|
||||
- Vue 2
|
||||
|
||||
其他说明:TODO
|
||||
已支持的平台:
|
||||
|
||||
软件变化请查看:[更新日志](https://github.com/lyswhut/lx-music-desktop/blob/master/CHANGELOG.md)
|
||||
- Windows 7 及以上
|
||||
- Mac OS
|
||||
- Linux
|
||||
|
||||
感谢 <https://github.com/messoer> 提供的部分音乐API!
|
||||
软件变化请查看:[更新日志](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.lanzoux.com/b0bf2cfa/` 密码:`glqw`<br>
|
||||
使用常见问题请转至:[常见问题](https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md)
|
||||
|
||||
## 使用方法
|
||||
### 源码使用方法
|
||||
|
||||
环境要求:Node.js 12.x+
|
||||
|
||||
```bash
|
||||
# 开发模式
|
||||
@@ -38,11 +61,46 @@ npm run dev
|
||||
# 构建免安装版
|
||||
npm run pack:dir
|
||||
|
||||
# 构建安装包
|
||||
# 构建安装包(Windows版)
|
||||
npm run pack
|
||||
|
||||
# 构建安装包(Mac版)
|
||||
npm run pack:mac
|
||||
|
||||
# 构建安装包(Linux版)
|
||||
npm run pack:linux
|
||||
|
||||
```
|
||||
|
||||
## License
|
||||
### UI界面
|
||||
|
||||
Apache License 2.0
|
||||
<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="突然的自我 - 伍佰"`
|
||||
- `-nt` 以非透明模式启动,对于未开启AERO效果的win7系统可加此参数启动以确保界面正常显示
|
||||
|
||||
### 常见问题
|
||||
|
||||
常见问题已移至:<https://github.com/lyswhut/lx-music-desktop/blob/master/FAQ.md>
|
||||
|
||||
### 项目协议
|
||||
|
||||
本项目基于 [Apache License 2.0](https://github.com/lyswhut/lx-music-desktop/blob/master/LICENSE) 许可证发行,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。
|
||||
|
||||
词语约定:本协议中的“本项目”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本项目内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。
|
||||
|
||||
1. 本项目的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本项目不对数据的准确性负责。
|
||||
2. 使用本项目的过程中可能会产生版权数据,对于这些版权数据,本项目不拥有它们的所有权,为了避免造成侵权,使用者务必在**24小时**内清除使用本项目的过程中所产生的版权数据。
|
||||
3. 本项目内的官方音乐平台别名为本项目内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本项目更改或移除。
|
||||
4. 本项目内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本项目移除。
|
||||
5. 由于使用本项目产生的包括由于本协议或由于使用或无法使用本项目而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。
|
||||
6. 本项目完全免费,且开源发布于 GitHub 面向全世界人用作对技术的学习交流,本项目不对项目内的技术可能存在违反当地法律法规的行为作保证,**禁止在违反当地法律法规的情况下使用本项目**,对于使用者在明知或不知当地法律法规不允许的情况下使用本项目所造成的任何违法违规行为由使用者承担,本项目不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。
|
||||
|
||||
若你使用了本项目,将代表你接受以上协议。
|
||||
|
||||
音乐平台不易,请尊重版权,支持正版。<br>
|
||||
若对此有疑问请 mail to: lyswhut+qq.com (请将`+`替换成`@`)
|
||||
|
||||
@@ -3,6 +3,6 @@ const isDev = process.env.NODE_ENV === 'development'
|
||||
module.exports = {
|
||||
modules: {
|
||||
localIdentName: isDev ? '[folder]-[name]--[local]--[hash:base64:5]' : '[hash:base64:5]',
|
||||
exportLocalsConvention: 'camelCase',
|
||||
},
|
||||
localsConvention: 'camelCase',
|
||||
}
|
||||
|
||||
@@ -7,14 +7,12 @@ module.exports = {
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
},
|
||||
externals: [
|
||||
// suppress electron-debug warning
|
||||
// see https://github.com/SimulatedGREG/electron-vue/issues/498
|
||||
{ 'electron-debug': 'electron-debug' },
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
common: path.join(__dirname, '../../src/common'),
|
||||
'@main': path.join(__dirname, '../../src/main'),
|
||||
'@renderer': path.join(__dirname, '../../src/renderer'),
|
||||
'@lyric': path.join(__dirname, '../../src/renderer-lyric'),
|
||||
'@common': path.join(__dirname, '../../src/common'),
|
||||
},
|
||||
extensions: ['*', '.js', '.json', '.node'],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const path = require('path')
|
||||
const merge = require('webpack-merge')
|
||||
const { merge } = require('webpack-merge')
|
||||
const webpack = require('webpack')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
@@ -18,5 +19,17 @@ module.exports = merge(baseConfig, {
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
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'
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const path = require('path')
|
||||
const merge = require('webpack-merge')
|
||||
const { merge } = require('webpack-merge')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
@@ -3,52 +3,67 @@ process.env.NODE_ENV = 'production'
|
||||
const chalk = require('chalk')
|
||||
const del = require('del')
|
||||
const webpack = require('webpack')
|
||||
const Multispinner = require('multispinner')
|
||||
const Spinnies = require('spinnies')
|
||||
|
||||
const mainConfig = require('./main/webpack.config.prod')
|
||||
const rendererConfig = require('./renderer/webpack.config.prod')
|
||||
const rendererLyricConfig = require('./renderer-lyric/webpack.config.prod')
|
||||
|
||||
const errorLog = chalk.bgRed.white(' ERROR ') + ' '
|
||||
const okayLog = chalk.bgGreen.white(' OKAY ') + ' '
|
||||
|
||||
|
||||
function build() {
|
||||
del.sync(['dist/electron', 'build'])
|
||||
|
||||
const tasks = ['main', 'renderer']
|
||||
const m = new Multispinner(tasks, {
|
||||
preText: 'building',
|
||||
postText: 'process',
|
||||
})
|
||||
del.sync(['dist/electron/**', 'build/**'])
|
||||
|
||||
const spinners = new Spinnies({ color: 'blue' })
|
||||
spinners.add('main', { text: 'main building' })
|
||||
spinners.add('renderer', { text: 'renderer building' })
|
||||
spinners.add('renderer-lyric', { text: 'renderer-lyric building' })
|
||||
let results = ''
|
||||
|
||||
m.on('success', () => {
|
||||
// m.on('success', () => {
|
||||
// process.stdout.write('\x1B[2J\x1B[0f')
|
||||
// console.log(`\n\n${results}`)
|
||||
// console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
|
||||
// process.exit()
|
||||
// })
|
||||
function handleSuccess() {
|
||||
process.stdout.write('\x1B[2J\x1B[0f')
|
||||
console.log(`\n\n${results}`)
|
||||
console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
|
||||
process.exit()
|
||||
})
|
||||
}
|
||||
|
||||
pack(mainConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
m.success('main')
|
||||
}).catch(err => {
|
||||
m.error('main')
|
||||
console.log(`\n ${errorLog}failed to build main process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
pack(rendererConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
m.success('renderer')
|
||||
}).catch(err => {
|
||||
m.error('renderer')
|
||||
console.log(`\n ${errorLog}failed to build renderer process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
})
|
||||
Promise.all([
|
||||
pack(mainConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
spinners.succeed('main', { text: 'main build success!' })
|
||||
}).catch(err => {
|
||||
spinners.fail('main', { text: 'main build fail :(' })
|
||||
console.log(`\n ${errorLog}failed to build main process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
}),
|
||||
pack(rendererConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
spinners.succeed('renderer', { text: 'renderer build success!' })
|
||||
}).catch(err => {
|
||||
spinners.fail('renderer', { text: 'renderer build fail :(' })
|
||||
console.log(`\n ${errorLog}failed to build renderer process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
}),
|
||||
pack(rendererLyricConfig).then(result => {
|
||||
results += result + '\n\n'
|
||||
spinners.succeed('renderer-lyric', { text: 'renderer-lyric build success!' })
|
||||
}).catch(err => {
|
||||
spinners.fail('renderer-lyric', { text: 'renderer-lyric build fail :(' })
|
||||
console.log(`\n ${errorLog}failed to build renderer-lyric process`)
|
||||
console.error(`\n${err}\n`)
|
||||
process.exit(1)
|
||||
}),
|
||||
]).then(handleSuccess)
|
||||
}
|
||||
|
||||
function pack(config) {
|
||||
|
||||
136
build-config/renderer-lyric/webpack.config.base.js
Normal file
136
build-config/renderer-lyric/webpack.config.base.js
Normal file
@@ -0,0 +1,136 @@
|
||||
const path = require('path')
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
const HTMLPlugin = require('html-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
|
||||
const vueLoaderConfig = require('../vue-loader.config')
|
||||
const { mergeCSSLoader } = require('../utils')
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
module.exports = {
|
||||
target: 'electron-renderer',
|
||||
entry: {
|
||||
'renderer-lyric': path.join(__dirname, '../../src/renderer-lyric/main.js'),
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.join(__dirname, '../../dist/electron'),
|
||||
publicPath: './',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@main': path.join(__dirname, '../../src/main'),
|
||||
'@renderer': path.join(__dirname, '../../src/renderer'),
|
||||
'@lyric': path.join(__dirname, '../../src/renderer-lyric'),
|
||||
'@static': path.join(__dirname, '../../src/static'),
|
||||
'@common': path.join(__dirname, '../../src/common'),
|
||||
},
|
||||
extensions: ['*', '.js', '.json', '.vue', '.node'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(vue|js)$/,
|
||||
use: {
|
||||
loader: 'eslint-loader',
|
||||
options: {
|
||||
formatter: require('eslint-formatter-friendly'),
|
||||
},
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
enforce: 'pre',
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: vueLoaderConfig,
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
oneOf: mergeCSSLoader(),
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl(:?us)?$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.pug$/,
|
||||
oneOf: [
|
||||
// Use pug-plain-loader handle .vue file
|
||||
{
|
||||
resourceQuery: /vue/,
|
||||
use: ['pug-plain-loader'],
|
||||
},
|
||||
// Use pug-loader handle .pug file
|
||||
{
|
||||
use: ['pug-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'imgs/[name]--[folder].[ext]',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'media/[name]--[folder].[ext]',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'fonts/[name]--[folder].[ext]',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
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,
|
||||
__dirname,
|
||||
}),
|
||||
new VueLoaderPlugin(),
|
||||
new MiniCssExtractPlugin({
|
||||
// Options similar to the same options in webpackOptions.output
|
||||
// both options are optional
|
||||
filename: isDev ? '[name].css' : '[name].[contenthash:8].css',
|
||||
chunkFilename: isDev ? '[id].css' : '[id].[contenthash:8].css',
|
||||
}),
|
||||
],
|
||||
}
|
||||
28
build-config/renderer-lyric/webpack.config.dev.js
Normal file
28
build-config/renderer-lyric/webpack.config.dev.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: 'development',
|
||||
devtool: 'eval-source-map',
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
new FriendlyErrorsPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"development"',
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
|
||||
},
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
],
|
||||
performance: {
|
||||
hints: false,
|
||||
},
|
||||
})
|
||||
|
||||
52
build-config/renderer-lyric/webpack.config.prod.js
Normal file
52
build-config/renderer-lyric/webpack.config.prod.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-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']
|
||||
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: 'production',
|
||||
devtool: false,
|
||||
externals: [
|
||||
...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"',
|
||||
},
|
||||
}),
|
||||
],
|
||||
optimization: {
|
||||
chunkIds: 'named',
|
||||
minimizer: [
|
||||
new TerserPlugin(),
|
||||
new OptimizeCSSAssetsPlugin({}),
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
hints: 'warning',
|
||||
},
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false,
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
const path = require('path')
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
const HTMLPlugin = require('html-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
|
||||
const vueLoaderConfig = require('../vue-loader.config')
|
||||
const { mergeCSSLoader } = require('../utils')
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
module.exports = {
|
||||
target: 'electron-renderer',
|
||||
@@ -18,8 +21,11 @@ module.exports = {
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.join(__dirname, '../../src/renderer'),
|
||||
common: path.join(__dirname, '../../src/common'),
|
||||
'@main': path.join(__dirname, '../../src/main'),
|
||||
'@renderer': path.join(__dirname, '../../src/renderer'),
|
||||
'@lyric': path.join(__dirname, '../../src/renderer-lyric'),
|
||||
'@static': path.join(__dirname, '../../src/static'),
|
||||
'@common': path.join(__dirname, '../../src/common'),
|
||||
},
|
||||
extensions: ['*', '.js', '.json', '.vue', '.node'],
|
||||
},
|
||||
@@ -46,6 +52,28 @@ module.exports = {
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
oneOf: mergeCSSLoader(),
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl(:?us)?$/,
|
||||
oneOf: mergeCSSLoader({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.pug$/,
|
||||
oneOf: [
|
||||
@@ -92,11 +120,17 @@ module.exports = {
|
||||
plugins: [
|
||||
new HTMLPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.join(__dirname, '../../src/index.pug'),
|
||||
template: path.join(__dirname, '../../src/renderer/index.pug'),
|
||||
isProd: process.env.NODE_ENV == 'production',
|
||||
browser: process.browser,
|
||||
__dirname,
|
||||
}),
|
||||
new VueLoaderPlugin(),
|
||||
new MiniCssExtractPlugin({
|
||||
// Options similar to the same options in webpackOptions.output
|
||||
// both options are optional
|
||||
filename: isDev ? '[name].css' : '[name].[contenthash:8].css',
|
||||
chunkFilename: isDev ? '[id].css' : '[id].[contenthash:8].css',
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -2,41 +2,13 @@ const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const merge = require('webpack-merge')
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
const { mergeCSSLoaderDev } = require('../utils')
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: 'development',
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
oneOf: mergeCSSLoaderDev(),
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoaderDev({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl(:?us)?$/,
|
||||
oneOf: mergeCSSLoaderDev({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
devtool: 'eval-source-map',
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
@@ -46,7 +18,7 @@ module.exports = merge(baseConfig, {
|
||||
NODE_ENV: '"development"',
|
||||
ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
|
||||
},
|
||||
'__static': `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
__static: `"${path.join(__dirname, '../../src/static').replace(/\\/g, '\\\\')}"`,
|
||||
}),
|
||||
],
|
||||
performance: {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const merge = require('webpack-merge')
|
||||
const { merge } = require('webpack-merge')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
const { mergeCSSLoaderProd } = require('../utils')
|
||||
const { dependencies } = require('../../package.json')
|
||||
|
||||
let whiteListedModules = ['vue']
|
||||
@@ -20,57 +18,25 @@ module.exports = merge(baseConfig, {
|
||||
externals: [
|
||||
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d)),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
oneOf: mergeCSSLoaderProd(),
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoaderProd({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl(:?us)?$/,
|
||||
oneOf: mergeCSSLoaderProd({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.join(__dirname, '../../src/static'),
|
||||
to: path.join(__dirname, '../../dist/electron/static'),
|
||||
ignore: ['.*'],
|
||||
},
|
||||
]),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: path.join(__dirname, '../../src/static'),
|
||||
to: path.join(__dirname, '../../dist/electron/static'),
|
||||
},
|
||||
],
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"',
|
||||
},
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].css',
|
||||
}),
|
||||
new webpack.NamedChunksPlugin(),
|
||||
],
|
||||
optimization: {
|
||||
chunkIds: 'named',
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
sourceMap: false, // set to true if you want JS source maps
|
||||
}),
|
||||
new TerserPlugin(),
|
||||
new OptimizeCSSAssetsPlugin({}),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -7,12 +7,12 @@ const path = require('path')
|
||||
const { spawn } = require('child_process')
|
||||
const webpack = require('webpack')
|
||||
const WebpackDevServer = require('webpack-dev-server')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware')
|
||||
|
||||
const mainConfig = require('./main/webpack.config.dev')
|
||||
const rendererConfig = require('./renderer/webpack.config.dev')
|
||||
|
||||
const { logStats } = require('./utils')
|
||||
const rendererLyricConfig = require('./renderer-lyric/webpack.config.dev')
|
||||
|
||||
let electronProcess = null
|
||||
let manualRestart = false
|
||||
@@ -31,7 +31,7 @@ function startRenderer() {
|
||||
|
||||
compiler.hooks.compilation.tap('compilation', compilation => {
|
||||
// console.log(Object.keys(compilation.hooks))
|
||||
compilation.hooks.htmlWebpackPluginAfterEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
hotMiddleware.publish({ action: 'reload' })
|
||||
cb()
|
||||
})
|
||||
@@ -59,13 +59,60 @@ function startRenderer() {
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
server.listen(9080)
|
||||
})
|
||||
}
|
||||
|
||||
function startRendererLyric() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
|
||||
// rendererConfig.mode = 'development'
|
||||
const compiler = webpack(rendererLyricConfig)
|
||||
hotMiddleware = webpackHotMiddleware(compiler, {
|
||||
log: false,
|
||||
heartbeat: 2500,
|
||||
})
|
||||
|
||||
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' })
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
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()
|
||||
})
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
server.listen(9081)
|
||||
})
|
||||
}
|
||||
|
||||
function startMain() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
|
||||
@@ -73,7 +120,6 @@ function startMain() {
|
||||
const compiler = webpack(mainConfig)
|
||||
|
||||
compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
|
||||
logStats('Main', chalk.white.bold('compiling...'))
|
||||
hotMiddleware.publish({ action: 'compiling' })
|
||||
done()
|
||||
})
|
||||
@@ -137,34 +183,26 @@ function electronLog(data, color) {
|
||||
}
|
||||
}
|
||||
|
||||
function greeting() {
|
||||
/* const cols = process.stdout.columns
|
||||
let text = ''
|
||||
|
||||
if (cols > 104) text = 'electron-vue'
|
||||
else if (cols > 76) text = 'electron-|vue'
|
||||
else text = false
|
||||
|
||||
if (text) {
|
||||
say(text, {
|
||||
colors: ['yellow'],
|
||||
font: 'simple3d',
|
||||
space: false,
|
||||
})
|
||||
} else console.log(chalk.yellow.bold('\n electron-vue')) */
|
||||
console.log(chalk.blue('getting ready...') + '\n')
|
||||
}
|
||||
|
||||
function init() {
|
||||
greeting()
|
||||
const Spinnies = require('spinnies')
|
||||
const spinners = new Spinnies({ color: 'blue' })
|
||||
spinners.add('main', { text: 'main compiling' })
|
||||
spinners.add('renderer', { text: 'renderer compiling' })
|
||||
spinners.add('renderer-lyric', { text: 'renderer-lyric compiling' })
|
||||
function handleSuccess(name) {
|
||||
spinners.succeed(name, { text: name + ' compile success!' })
|
||||
}
|
||||
function handleFail(name) {
|
||||
spinners.fail(name, { text: name + ' compile fail!' })
|
||||
}
|
||||
|
||||
Promise.all([startRenderer(), startMain()])
|
||||
.then(() => {
|
||||
startElectron()
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
Promise.all([
|
||||
startRenderer().then(() => handleSuccess('renderer')).catch(() => handleFail('renderer')),
|
||||
startRendererLyric().then(() => handleSuccess('renderer-lyric')).catch(() => handleFail('renderer-lyric')),
|
||||
startMain().then(() => handleSuccess('main')).catch(() => handleFail('main')),
|
||||
]).then(startElectron).catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
init()
|
||||
|
||||
@@ -2,62 +2,21 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const cssLoaderConfig = require('./css-loader.config')
|
||||
const chalk = require('chalk')
|
||||
|
||||
// merge css-loader in development
|
||||
exports.mergeCSSLoaderDev = beforeLoader => {
|
||||
const loader = [
|
||||
// 这里匹配 `<style module>`
|
||||
{
|
||||
resourceQuery: /module/,
|
||||
use: [
|
||||
'vue-style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: Object.assign({
|
||||
sourceMap: true,
|
||||
}, cssLoaderConfig),
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// 这里匹配普通的 `<style>` 或 `<style scoped>`
|
||||
{
|
||||
use: [
|
||||
'vue-style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
if (beforeLoader) {
|
||||
loader[0].use.push(beforeLoader)
|
||||
loader[1].use.push(beforeLoader)
|
||||
}
|
||||
return loader
|
||||
}
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
|
||||
// merge css-loader in production
|
||||
exports.mergeCSSLoaderProd = beforeLoader => {
|
||||
// merge css-loader
|
||||
exports.mergeCSSLoader = beforeLoader => {
|
||||
const loader = [
|
||||
// 这里匹配 `<style module>`
|
||||
{
|
||||
resourceQuery: /module/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: {
|
||||
hmr: isDev,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: cssLoaderConfig,
|
||||
@@ -68,7 +27,12 @@ exports.mergeCSSLoaderProd = beforeLoader => {
|
||||
// 这里匹配普通的 `<style>` 或 `<style scoped>`
|
||||
{
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: {
|
||||
hmr: isDev,
|
||||
},
|
||||
},
|
||||
'css-loader',
|
||||
'postcss-loader',
|
||||
],
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const HTMLPlugin = require('html-webpack-plugin')
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
|
||||
const vueLoaderConfig = require('../vue-loader.config')
|
||||
|
||||
module.exports = {
|
||||
target: 'web',
|
||||
entry: path.join(__dirname, '../../src/renderer/main.js'),
|
||||
output: {
|
||||
path: path.join(__dirname, '../../dist/web'),
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.join(__dirname, '../../src/renderer'),
|
||||
common: path.join(__dirname, '../../src/common'),
|
||||
},
|
||||
extensions: ['*', '.js', '.vue', '.json', '.css'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(vue|js)$/,
|
||||
use: {
|
||||
loader: 'eslint-loader',
|
||||
options: {
|
||||
formatter: require('eslint-formatter-friendly'),
|
||||
},
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
enforce: 'pre',
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: vueLoaderConfig,
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.pug$/,
|
||||
oneOf: [
|
||||
// Use pug-plain-loader handle .vue file
|
||||
{
|
||||
resourceQuery: /vue/,
|
||||
use: ['pug-plain-loader'],
|
||||
},
|
||||
// Use pug-loader handle .pug file
|
||||
{
|
||||
use: ['pug-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'imgs/[name].[ext]',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
use: {
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'fonts/[name].[ext]',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new HTMLPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.resolve(__dirname, '../../src/index.pug'),
|
||||
nodeModules: false,
|
||||
isProd: process.env.NODE_ENV == 'production',
|
||||
browser: process.browser,
|
||||
__dirname,
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.IS_WEB': 'true',
|
||||
}),
|
||||
],
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const merge = require('webpack-merge')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
const { mergeCSSLoaderDev } = require('../utils')
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: 'development',
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.join(__dirname, '../../dist/web'),
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
oneOf: mergeCSSLoaderDev(),
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoaderDev({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl$/,
|
||||
oneOf: mergeCSSLoaderDev({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"development"',
|
||||
},
|
||||
}),
|
||||
new FriendlyErrorsPlugin(),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin(),
|
||||
],
|
||||
performance: {
|
||||
hints: false,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const merge = require('webpack-merge')
|
||||
const TerserPlugin = require('terser-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
const baseConfig = require('./webpack.config.base')
|
||||
|
||||
const { mergeCSSLoaderProd } = require('../utils')
|
||||
|
||||
|
||||
module.exports = merge(baseConfig, {
|
||||
mode: 'production',
|
||||
devtool: false,
|
||||
output: {
|
||||
filename: '[name].[chunkhash:8].js',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
oneOf: mergeCSSLoaderProd(),
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
oneOf: mergeCSSLoaderProd({
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
test: /\.styl$/,
|
||||
oneOf: mergeCSSLoaderProd({
|
||||
loader: 'stylus-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.join(__dirname, '../../src/static'),
|
||||
to: path.join(__dirname, '../dist/web/static'),
|
||||
ignore: ['.*'],
|
||||
},
|
||||
]),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: '"production"',
|
||||
},
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].[contentHash:8].css',
|
||||
}),
|
||||
new webpack.NamedChunksPlugin(),
|
||||
],
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
sourceMap: false, // set to true if you want JS source maps
|
||||
}),
|
||||
new OptimizeCSSAssetsPlugin({}),
|
||||
],
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
// chunks: 'all',
|
||||
vendors: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: 'vendors',
|
||||
enforce: true,
|
||||
chunks: 'all',
|
||||
},
|
||||
styles: {
|
||||
name: 'styles',
|
||||
test: /\.(css|less)$/,
|
||||
chunks: 'all',
|
||||
enforce: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
runtimeChunk: true,
|
||||
},
|
||||
performance: {
|
||||
hints: 'warning',
|
||||
},
|
||||
})
|
||||
BIN
doc/images/app.png
Normal file
BIN
doc/images/app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
BIN
doc/images/icon.png
Normal file
BIN
doc/images/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
19
jsconfig.json
Normal file
19
jsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
// This is the line you want to add
|
||||
"allowSyntheticDefaultImports": true,
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@main": ["src/main"],
|
||||
"@renderer": ["src/renderer"],
|
||||
"@lyric": ["src/renderer-lyric"],
|
||||
"@static": ["src/static"],
|
||||
"@common": ["src/common"],
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules/**/*"]
|
||||
}
|
||||
@@ -1,45 +1,49 @@
|
||||
{\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}
|
||||
{\rtf1\adeflang1025\ansi\ansicpg936\uc2\adeff0\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi0\deflang1033\deflangfe2052\themelang1033\themelangfe2052\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}
|
||||
{\f13\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'cb\'ce\'cc\'e5{\*\falt SimSun};}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}
|
||||
{\f44\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}@\'cb\'ce\'cc\'e5;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\f44\fbidi \fnil\fcharset134\fprq2{\*\panose 00000000000000000000}@\'cb\'ce\'cc\'e5;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\fdbmajor\f31501\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df Light;}{\fhimajor\f31502\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df Light;}
|
||||
{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\fdbminor\f31505\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df{\*\falt DengXian};}{\fhiminor\f31506\fbidi \fnil\fcharset134\fprq2{\*\panose 02010600030101010101}\'b5\'c8\'cf\'df{\*\falt DengXian};}
|
||||
{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f65\fbidi \fmodern\fcharset238\fprq1 Courier New CE;}{\f66\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;}
|
||||
{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f45\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f46\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\f48\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f49\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f50\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f51\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\f52\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f53\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f65\fbidi \fmodern\fcharset238\fprq1 Courier New CE;}{\f66\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;}
|
||||
{\f68\fbidi \fmodern\fcharset161\fprq1 Courier New Greek;}{\f69\fbidi \fmodern\fcharset162\fprq1 Courier New Tur;}{\f70\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f71\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);}
|
||||
{\f72\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f73\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);}{\f177\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f487\fbidi \fnil\fcharset0\fprq2 @SimSun Western;}
|
||||
{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31520\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}
|
||||
{\fdbmajor\f31518\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}{\fdbmajor\f31519\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}{\fdbmajor\f31521\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}
|
||||
{\fhimajor\f31530\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}{\fhimajor\f31528\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}{\fhimajor\f31529\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}
|
||||
{\fhimajor\f31531\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||
{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31560\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}
|
||||
{\fdbminor\f31558\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}{\fdbminor\f31559\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}{\fdbminor\f31561\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}
|
||||
{\fhiminor\f31570\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}{\fhiminor\f31568\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}{\fhiminor\f31569\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}
|
||||
{\fhiminor\f31571\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||
{\f45\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f46\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f48\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f49\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\f50\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f51\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f52\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\f53\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;
|
||||
\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;}
|
||||
{\*\defchp \fs21\kerning2\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
|
||||
\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
{\f72\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f73\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);}{\f177\fbidi \fnil\fcharset0\fprq2 SimSun Western{\*\falt SimSun};}{\f385\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}
|
||||
{\f386\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f388\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f389\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f392\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}
|
||||
{\f393\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f487\fbidi \fnil\fcharset0\fprq2 @SimSun Western;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
|
||||
{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31520\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}{\fdbmajor\f31518\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}
|
||||
{\fdbmajor\f31519\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}{\fdbmajor\f31521\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}{\fhimajor\f31530\fbidi \fnil\fcharset0\fprq2 DengXian Light Western;}
|
||||
{\fhimajor\f31528\fbidi \fnil\fcharset238\fprq2 DengXian Light CE;}{\fhimajor\f31529\fbidi \fnil\fcharset204\fprq2 DengXian Light Cyr;}{\fhimajor\f31531\fbidi \fnil\fcharset161\fprq2 DengXian Light Greek;}
|
||||
{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
|
||||
{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31560\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}{\fdbminor\f31558\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}
|
||||
{\fdbminor\f31559\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}{\fdbminor\f31561\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}{\fhiminor\f31570\fbidi \fnil\fcharset0\fprq2 DengXian Western{\*\falt DengXian};}
|
||||
{\fhiminor\f31568\fbidi \fnil\fcharset238\fprq2 DengXian CE{\*\falt DengXian};}{\fhiminor\f31569\fbidi \fnil\fcharset204\fprq2 DengXian Cyr{\*\falt DengXian};}{\fhiminor\f31571\fbidi \fnil\fcharset161\fprq2 DengXian Greek{\*\falt DengXian};}
|
||||
{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
|
||||
\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
|
||||
\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;\chyperlink\ctint255\cshade255\red5\green99\blue193;\red96\green94\blue92;\red225\green223\blue221;\cfollowedhyperlink\ctint255\cshade255\red149\green79\blue114;}{\*\defchp
|
||||
\fs21\kerning2\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
|
||||
\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
|
||||
\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv
|
||||
\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs21\alang1025 \ltrch\fcs0 \fs21\lang1033\langfe2052\kerning2\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp2052
|
||||
\snext11 \ssemihidden \sunhideused Normal Table;}{\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af2\afs22\alang1025 \ltrch\fcs0
|
||||
\fs21\lang1033\langfe2052\kerning2\loch\f31505\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp2052 \sbasedon0 \snext15 \slink16 \sunhideused Plain Text;}{\*\cs16 \additive \rtlch\fcs1 \af2 \ltrch\fcs0 \loch\f31505\hich\af2 \sbasedon10 \slink15 \slocked
|
||||
\'b4\'bf\'ce\'c4\'b1\'be \'d7\'d6\'b7\'fb;}}{\*\rsidtbl \rsid927107\rsid3950508\rsid11081282\rsid12910709\rsid13643782\rsid14384001}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0
|
||||
\mnaryLim1}{\info{\author lysyw}{\operator lysyw}{\creatim\yr2019\mo8\dy17\hr10\min22}{\revtim\yr2019\mo8\dy17\hr10\min22}{\version2}{\edmins0}{\nofpages1}{\nofwords8}{\nofchars49}{\nofcharsws56}{\vern111}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.co
|
||||
m/office/word/2003/wordml}}\paperw11906\paperh16838\margl2253\margr2253\margt1440\margb1440\gutter0\ltrsect
|
||||
\'b4\'bf\'ce\'c4\'b1\'be \'d7\'d6\'b7\'fb;}{\*\cs17 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf19 \sbasedon10 \sunhideused \styrsid9533173 Hyperlink;}{\*\cs18 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \cf20\chshdng0\chcfpat0\chcbpat21
|
||||
\sbasedon10 \ssemihidden \sunhideused \styrsid9533173 Unresolved Mention;}{\*\cs19 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf22 \sbasedon10 \ssemihidden \sunhideused \styrsid9533173 FollowedHyperlink;}}{\*\pgptbl {\pgp\ipgp0\itap0\li0\ri0\sb0\sa0}}
|
||||
{\*\rsidtbl \rsid927107\rsid1398824\rsid2109456\rsid3950508\rsid4133944\rsid4355753\rsid9533173\rsid10447395\rsid11081282\rsid12910709\rsid13643782\rsid14384001\rsid15226681}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0
|
||||
\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author lysyw}{\operator lysyw}{\creatim\yr2019\mo8\dy17\hr10\min22}{\revtim\yr2020\mo4\dy28\hr13\min46}{\version8}{\edmins3}{\nofpages1}{\nofwords135}{\nofchars772}{\nofcharsws906}{\vern1}}
|
||||
{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\margl2253\margr2253\margt1440\margb1440\gutter0\ltrsect
|
||||
\deftab420\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\formshade\horzdoc\dgmargin\dghspace180\dgvspace156
|
||||
\dghorigin2253\dgvorigin1440\dghshow0\dgvshow2\jcompress\lnongrid
|
||||
\viewkind1\viewscale100\splytwnine\ftnlytwnine\htmautsp\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\rsidroot3950508\newtblstyruls
|
||||
\viewkind1\viewscale120\splytwnine\ftnlytwnine\htmautsp\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct\asianbrkrule\rsidroot3950508\newtblstyruls
|
||||
\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat {\upr{\*\fchars
|
||||
!%),.:\'3b>?]\'7d\'a1\'e9\'a1\'a7\'a1\'e3\'a1\'a4\'a1\'a6\'a1\'a5\'a8\'44\'a1\'ac\'a1\'af\'a1\'b1\'a1\'ad\'a1\'eb\'a1\'e4\'a1\'e5?\'a1\'e6\'a1\'c3\'a1\'a2\'a1\'a3\'a1\'a8\'a1\'b5\'a1\'b7\'a1\'b9\'a1\'bb\'a1\'bf\'a1\'b3\'a1\'bd\'a8\'95\'a6\'e1\'a6\'e3\'a6\'e7\'a6\'e5\'a6\'eb\'a9\'77\'a9\'79\'a9\'7b\'a3\'a1\'a3\'a2\'a3\'a5\'a3\'a7\'a3\'a9\'a3\'ac\'a3\'ae\'a3\'ba\'a3\'bb\'a3\'bf\'a3\'dd\'a3\'e0\'a3\'fc\'a3\'fd\'a1\'ab\'a1\'e9
|
||||
}{\*\ud\uc0{\*\fchars
|
||||
@@ -49,18 +53,67 @@ $([\'7b{\uc2\u163 \'a1\'ea\u165 \'a3\'a4\'a1\'a4\'a1\'ae\'a1\'b0\'a1\'b4\'a1\'b6
|
||||
\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery851\footery992\colsx425\endnhere\sectlinegrid312\sectspecifyl\sectrsid2109456\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang
|
||||
{\pntxta \dbch .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta \dbch .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta \dbch )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl6
|
||||
\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}{\*\pnseclvl9
|
||||
\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}\pard\plain \ltrpar\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid12910709 \rtlch\fcs1 \af2\afs22\alang1025 \ltrch\fcs0
|
||||
\fs21\lang1033\langfe2052\kerning2\loch\af31505\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'b3\'cc\'d0\'f2
|
||||
\'bd\'f6\'d3\'c3\'d3\'da\'d1\'a7\'cf\'b0\'bd\'bb\'c1\'f7\'ca\'b9\'d3\'c3\'a3\'a1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'c7\'eb\'ce\'f0\'d3\'c3\'d3\'da\'c9\'cc\'d2\'b5\'d3\'c3\'cd\'be\'a3\'a1\'a3\'a1}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'d4\'ec\'b3\'c9\'b5\'c4\'d2\'bb\'c7\'d0\'ba\'f3\'b9\'fb\'d3\'c9\'ca\'b9\'d3\'c3\'d5\'df
|
||||
\'b3\'d0\'b5\'a3\'a3\'a1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par
|
||||
\par \hich\af13\dbch\af13\loch\f13 By: }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'c2\'e4\'d1\'a9\'ce\'de\'ba\'db}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
\par
|
||||
\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb \dbch (}{\pntxta \dbch )}}\pard\plain \ltrpar\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid1398824 \rtlch\fcs1 \af2\afs22\alang1025 \ltrch\fcs0
|
||||
\fs21\lang1033\langfe2052\kerning2\loch\af31505\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp2052 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'b1\'be\'cf\'ee\'c4\'bf\'a3\'a8
|
||||
\'c8\'ed\'bc\'fe\'a3\'a9\'bb\'f9\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid4133944 \hich\af13\dbch\af13\loch\f13 Apache License 2.0}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'d0\'ed\'bf\'c9\'d6\'a4\'b7\'a2
|
||||
\'d0\'d0\'a3\'ac\'d4\'da\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'c7\'b0\'a3\'ac\'c4\'e3\'a3\'a8\'ca\'b9\'d3\'c3\'d5\'df\'a3\'a9\'d0\'e8\'c7\'a9\'ca\'f0\'b1\'be\'d0\'ad\'d2\'e9\'b2\'c5\'bf\'c9\'bc\'cc\'d0\'f8\'ca\'b9\'d3\'c3\'a3\'ac\'d2\'d4\'cf\'c2
|
||||
\'d0\'ad\'d2\'e9\'ca\'c7\'b6\'d4\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 Apache Li\hich\af13\dbch\af13\loch\f13 cense 2.0 }{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'b5\'c4\'b2\'b9\'b3\'e4\'a3\'ac\'c8\'e7\'d3\'d0\'b3\'e5\'cd\'bb\'a3\'ac\'d2\'d4\'d2\'d4\'cf\'c2\'d0\'ad\'d2\'e9\'ce\'aa\'d7\'bc\'a1\'a3}{\rtlch\fcs1 \af13
|
||||
\ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid10447395\charrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'b4\'ca\'d3\'ef\'d4\'bc\'b6\'a8\'a3\'ba\'b1\'be\'d0\'ad\'d2\'e9\'d6\'d0\'b5\'c4\'a1\'b0\'b1\'be\'c8\'ed\'bc\'fe\'a1\'b1\'d6\'b8
|
||||
\'c2\'e5\'d1\'a9\'d2\'f4\'c0\'d6\'d7\'c0\'c3\'e6\'b0\'e6\'cf\'ee\'c4\'bf\'a3\'bb\'a1\'b0\'ca\'b9\'d3\'c3\'d5\'df\'a1\'b1\'d6\'b8\'c7\'a9\'ca\'f0\'b1\'be\'d0\'ad\'d2\'e9\'b5\'c4\'ca\'b9\'d3\'c3\'d5\'df\'a3\'bb\'a1\'b0\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6
|
||||
\'c6\'bd\'cc\'a8\'a1\'b1\'d6\'b8\'b6\'d4\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'d6\'c3\'b5\'c4\'b0\'fc\'c0\'a8\'bf\'e1\'ce\'d2\'a1\'a2\'bf\'e1\'b9\'b7\'a1\'a2\'df\'e4\'b9\'be\'b5\'c8\'d2\'f4\'c0\'d6\'d4\'b4\'b5\'c4\'b9\'d9\'b7\'bd\'c6\'bd\'cc\'a8\'cd\'b3
|
||||
\'b3\'c6\'a3\'bb\'a1\'b0\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a1\'b1\'d6\'b8\'b0\'fc\'c0\'a8\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'cd\'bc\'cf\'f1\'a1\'a2\'d2\'f4\'c6\'b5\'a1\'a2\'c3\'fb\'d7\'d6\'b5\'c8\'d4\'da\'c4\'da\'b5\'c4\'cb\'fb\'c8\'cb\'d3\'b5\'d3\'d0
|
||||
\'cb\'f9\'ca\'f4\'b0\'e6\'c8\'a8\'b5\'c4\'ca\'fd\'be\'dd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par
|
||||
\par \hich\af13\dbch\af13\loch\f13 1}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'ca\'fd\'be\'dd\'c0\'b4\'d4\'b4\'d4\'ad\'c0\'ed\'ca\'c7
|
||||
\'b4\'d3\'b8\'f7\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b5\'c4\'b9\'ab\'bf\'aa\'b7\'fe\'ce\'f1\'c6\'f7\'d6\'d0\'c0\'ad\'c8\'a1\'ca\'fd\'be\'dd\'a3\'ac\'be\'ad\'b9\'fd\'b6\'d4\'ca\'fd\'be\'dd\'bc\'f2\'b5\'a5\'b5\'d8\'c9\'b8\'d1\'a1\'d3\'eb
|
||||
\'ba\'cf\'b2\'a2\'ba\'f3\'bd\'f8\'d0\'d0\'d5\'b9\'ca\'be\'a3\'ac\'d2\'f2\'b4\'cb\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'b6\'d4\'ca\'fd\'be\'dd\'b5\'c4\'d7\'bc\'c8\'b7\'d0\'d4\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 2}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'b9\'fd\'b3\'cc\'d6\'d0\'bf\'c9\'c4\'dc
|
||||
\'bb\'e1\'b2\'fa\'c9\'fa\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a3\'ac\'b6\'d4\'d3\'da\'d5\'e2\'d0\'a9\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a3\'ac\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'d3\'b5\'d3\'d0\'cb\'fc\loch\af13\hich\af13\dbch\f13 \'c3\'c7\'b5\'c4\'cb\'f9\'d3\'d0
|
||||
\'c8\'a8\'a3\'ac\'ce\'aa\'c1\'cb\'b1\'dc\'c3\'e2\'d4\'ec\'b3\'c9\'c7\'d6\'c8\'a8\'a3\'ac\'ca\'b9\'d3\'c3\'d5\'df\'ce\'f1\'b1\'d8\'d4\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\hich\af13\dbch\af13\loch\f13 24}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'d0\'a1\'ca\'b1\'c4\'da\'c7\'e5\'b3\'fd\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'b9\'fd
|
||||
\'b3\'cc\'d6\'d0\'cb\'f9\'b2\'fa\'c9\'fa\'b5\'c4\'b0\'e6\'c8\'a8\'ca\'fd\'be\'dd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'b5\'c4\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8
|
||||
\'b1\'f0\'c3\'fb\'ce\'aa\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'b6\'d4\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b5\'c4\'d2\'bb\'b8\'f6\'b3\'c6\'ba\'f4\'a3\'ac\'b2\'bb\'b0\'fc\'ba\'ac\'b6\'f1\'d2\'e2\'a3\'ac\'c8\'e7\'b9\'fb\'b9\'d9\'b7\'bd\'d2\'f4
|
||||
\'c0\'d6\'c6\'bd\'cc\'a8\'be\'f5\'b5\'c3\'b2\'bb\'cd\'d7\'a3\'ac\'bf\'c9\'c1\'aa\'cf\'b5\'b1\'be\'c8\'ed\'bc\'fe\'b8\'fc\'b8\'c4\'bb\'f2\'d2\'c6\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
|
||||
\par \hich\af13\dbch\af13\loch\f13 4}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'c8\'ed\'bc\'fe\'c4\'da\'ca\'b9\'d3\'c3\'b5\'c4\'b2\'bf\'b7\'d6\'b0\'fc\'c0\'a8
|
||||
\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'d7\'d6\'cc\'e5\'a1\'a2\'cd\'bc\'c6\'ac\'b5\'c8\'d7\'ca\'d4\'b4\'c0\'b4\'d4\'b4\'d3\'da\'bb\'a5\'c1\'aa\'cd\'f8\'a3\'ac\'c8\'e7\'b9\'fb\'b3\'f6\'cf\'d6\'c7\'d6\'c8\'a8\'bf\'c9\'c1\'aa\'cf\'b5\'b1\'be\'c8\'ed\'bc\'fe
|
||||
\'d2\'c6\'b3\'fd\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 5}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'d3\'c9\'d3\'da\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b2\'fa\'c9\'fa\'b5\'c4\'b0\'fc
|
||||
\'c0\'a8\'d3\'c9\'d3\'da\'b1\'be\'d0\'ad\'d2\'e9\'bb\'f2\'d3\'c9\'d3\'da\'ca\'b9\'d3\'c3\'bb\'f2\'ce\'de\'b7\'a8\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'b6\'f8\'d2\'fd\'c6\'f0\'b5\'c4\'c8\'ce\'ba\'ce\'d0\'d4\'d6\'ca\'b5\'c4\'c8\'ce\'ba\'ce\'d6\'b1
|
||||
\'bd\'d3\'a1\'a2\'bc\'e4\'bd\'d3\'a1\'a2\'cc\'d8\'ca\'e2\'a1\'a2\'c5\'bc\'c8\'bb\'bb\'f2\'bd\'e1\'b9\'fb\'d0\'d4\'cb\'f0\'ba\'a6\'a3\'a8\'b0\'fc\'c0\'a8\'b5\'ab\'b2\'bb\'cf\'de\'d3\'da\'d2\'f2\'c9\'cc\'d3\'fe\'cb\'f0\'ca\'a7\'a1\'a2\'cd\'a3\'b9\'a4
|
||||
\'a1\'a2\'bc\'c6\'cb\'e3\'bb\'fa\'b9\'ca\'d5\'cf\'bb\'f2\'b9\'ca\'d5\'cf\'d2\'fd\'c6\'f0\'b5\'c4\'cb\'f0\'ba\'a6\'c5\'e2\'b3\'a5\'a3\'ac\'bb\'f2\'c8\'ce\'ba\'ce\'bc\'b0\loch\af13\hich\af13\dbch\f13 \'cb\'f9\'d3\'d0\'c6\'e4\'cb\'fb\'c9\'cc\'d2\'b5\'cb\'f0
|
||||
\'ba\'a6\'bb\'f2\'cb\'f0\'ca\'a7\'a3\'a9\'d3\'c9\'ca\'b9\'d3\'c3\'d5\'df\'b8\'ba\'d4\'f0\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\par \hich\af13\dbch\af13\loch\f13 6}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13 \'a1\'a2\'b1\'be\'cf\'ee\'c4\'bf\'cd\'ea\'c8\'ab\'c3\'e2\'b7\'d1\'a3\'ac\'c7\'d2\'bf\'aa\'d4\'b4
|
||||
\'b7\'a2\'b2\'bc\'d3\'da}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 GitHub }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824
|
||||
\loch\af13\hich\af13\dbch\f13 \'c3\'e6\'cf\'f2\'c8\'ab\'ca\'c0\'bd\'e7\'c8\'cb\'d3\'c3\'d7\'f7\'b6\'d4\'bc\'bc\'ca\'f5\'b5\'c4\'d1\'a7\'cf\'b0\'bd\'bb\'c1\'f7\'a3\'ac\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'b6\'d4\'cf\'ee\'c4\'bf\'c4\'da\'b5\'c4\'bc\'bc\'ca\'f5
|
||||
\'bf\'c9\'c4\'dc\'b4\'e6\'d4\'da\'ce\'a5\'b7\'b4\'b5\'b1\'b5\'d8\'b7\'a8\'c2\'c9\'b7\'a8\'b9\'e6\'b5\'c4\'d0\'d0\'ce\'aa\'d7\'f7\'b1\'a3\'d6\'a4\'a3\'ac\'bd\'fb\'d6\'b9\'d4\'da\'ce\'a5\'b7\'b4\'b5\'b1\'b5\'d8\'b7\'a8\'c2\'c9\'b7\'a8\'b9\'e6\'b5\'c4
|
||||
\'c7\'e9\'bf\'f6\'cf\'c2\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'a3\'ac\'b6\'d4\'d3\'da\'ca\'b9\'d3\'c3\'d5\'df\'d4\'da\'c3\'f7\'d6\'aa\'bb\'f2\'b2\'bb\'d6\'aa\'b5\'b1\'b5\'d8\'b7\'a8\'c2\'c9\'b7\'a8\'b9\'e6\'b2\'bb\'d4\'ca\'d0\'ed\'b5\'c4\'c7\'e9
|
||||
\'bf\'f6\'cf\'c2\'ca\'b9\'d3\'c3\'b1\'be\'c8\'ed\'bc\'fe\'cb\'f9\'d4\'ec\'b3\'c9\'b5\'c4\'c8\'ce\'ba\'ce\'ce\'a5\'b7\'a8\'ce\'a5\'b9\'e6\'d0\'d0\'ce\'aa\'d3\'c9\'ca\'b9\'d3\'c3\'d5\'df\'b3\'d0\'b5\'a3\'a3\'ac\'b1\'be\'c8\'ed\'bc\'fe\'b2\'bb\'b3\'d0
|
||||
\'b5\'a3\'d3\'c9\'b4\'cb\'d4\'ec\'b3\'c9\'b5\'c4\'c8\'ce\'ba\'ce\'d6\'b1\'bd\'d3\'a1\'a2\'bc\'e4\'bd\'d3\'a1\'a2\'cc\'d8\'ca\'e2\'a1\'a2\'c5\'bc\'c8\'bb\'bb\'f2\'bd\'e1\'b9\'fb\'d0\'d4\'d4\'f0\'c8\'ce\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid10447395\charrsid1398824
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13
|
||||
\'c8\'f4\'d0\'ad\'d2\'e9\'b8\'fc\'d0\'c2\'a3\'ac\'cb\'a1\'b2\'bb\'c1\'ed\'d0\'d0\'cd\'a8\'d6\'aa\'a3\'ac\'bf\'c9\'b5\'bd\'bf\'aa\'d4\'b4\'b5\'d8\'d6\'b7\'b2\'e9\'bf\'b4\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13
|
||||
\'b1\'be\'c8\'ed\'bc\'fe\'b5\'c4\'b3\'f5\'d6\'d4\'ca\'c7\'b0\'ef\'d6\'fa\'b9\'d9\'b7\'bd\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'bc\'f2\'bb\'af\'ca\'fd\'be\'dd\'ba\'f3\'b4\'fa\'ce\'aa\'d5\'b9\'ca\'be\'a3\'ac\'b0\'ef\'d6\'fa\'ca\'b9\'d3\'c3\'d5\'df\'b8\'f9
|
||||
\'be\'dd\'b8\'e8\'c7\'fa\loch\af13\hich\af13\dbch\f13 \'c3\'fb\'a1\'a2\'d2\'d5\'ca\'f5\'bc\'d2\'b5\'c8\'b9\'d8\'bc\'fc\'d7\'d6\'bf\'ec\'cb\'d9\'b5\'d8\'b6\'a8\'ce\'bb\'cb\'f9\'d0\'e8\'c4\'da\'c8\'dd\'cb\'f9\'d4\'da\'b5\'c4\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8
|
||||
\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid15226681
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \hich\af13\dbch\af13\loch\f13 * }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid1398824\charrsid1398824 \loch\af13\hich\af13\dbch\f13
|
||||
\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'b2\'bb\'d2\'d7\'a3\'ac\'bd\'a8\'d2\'e9\'b5\'bd\'b6\'d4\'d3\'a6\'d2\'f4\'c0\'d6\'c6\'bd\'cc\'a8\'d6\'a7\'b3\'d6\'d5\'fd\'b0\'e6\'d7\'ca\'d4\'b4\'a1\'a3}{\rtlch\fcs1 \af13 \ltrch\fcs0
|
||||
\loch\af13\hich\af13\dbch\af13\insrsid12910709
|
||||
\par }{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid9533173\charrsid15226681
|
||||
\par }\pard \ltrpar\s15\qj \li0\ri0\nowidctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid12910709 {\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \hich\af13\dbch\af13\loch\f13 By: }{
|
||||
\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709 \loch\af13\hich\af13\dbch\f13 \'c2\'e4\'d1\'a9\'ce\'de\'ba\'db}{\rtlch\fcs1 \af13 \ltrch\fcs0 \loch\af13\hich\af13\dbch\af13\insrsid12910709\charrsid12910709
|
||||
|
||||
\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a
|
||||
9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad
|
||||
5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6
|
||||
@@ -114,7 +167,7 @@ e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8
|
||||
617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
|
||||
6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
|
||||
656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
|
||||
{\*\latentstyles\lsdstimax377\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
|
||||
{\*\latentstyles\lsdstimax376\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;
|
||||
@@ -143,18 +196,8 @@ e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 2;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 4;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 7;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 7;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Contemporary;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Elegant;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Professional;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;
|
||||
\lsdpriority39 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;
|
||||
\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;
|
||||
\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;
|
||||
\lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;
|
||||
@@ -202,8 +245,8 @@ e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8
|
||||
\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5;
|
||||
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6;
|
||||
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link Error;}}{\*\datastore 0105000002000000180000004d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link;}}{\*\datastore 01050000
|
||||
02000000180000004d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000
|
||||
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
@@ -212,8 +255,8 @@ fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000908a
|
||||
0599a254d501feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
|
||||
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000b026
|
||||
8d59201dd601feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000105000000000000}}
|
||||
18
licenses/license_en.txt
Normal file
18
licenses/license_en.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
This project (software) is issued based on the Apache License 2.0 license. Before using this software, you (users) need to sign this agreement before you can continue to use it. The following agreement is a supplement to the Apache License 2.0. In case of conflict, use the following agreement Shall prevail.
|
||||
|
||||
|
||||
Terms agreed: "this software" in this agreement refers to the Luo Xue Music desktop version of the project; "user" refers to the user who signed this agreement; "official music platform" refers to the built-in software including Kuwo, Kugou, Migu The official platforms of music sources, etc. are collectively referred to; "copyright data" refers to data including but not limited to images, audio, names, etc. that others own the copyright.
|
||||
|
||||
1. The principle of the data source of this software is to pull data from the public servers of each official music platform. After simply filtering and merging the data for display, this software is not responsible for the accuracy of the data.
|
||||
2. Copyright data may be generated during the use of this software. For this copyright data, the software does not own their ownership. In order to avoid infringement, users must clear the copyright generated during the use of this software within 24 hours data.
|
||||
3. The alias of the official music platform in this software is a name for the official music platform in the software. It does not contain maliciousness. If the official music platform feels inappropriate, you can contact the software to change or remove it.
|
||||
4. The parts used in this software include but are not limited to fonts, pictures and other resources from the Internet. If there is infringement, you can contact this software to remove it.
|
||||
5. Any direct, indirect, special, accidental or consequential damage of any nature arising from the use of this software, including this agreement or the use or inability to use this software (including but not limited to due to loss of goodwill, work stoppage, Compensation for computer failure or damage caused by the failure, or any and all other commercial damage or loss) is the responsibility of the user.
|
||||
6. This project is completely free, and the open source is published on GitHub. It is used by people all over the world to learn and exchange technology. This software does not guarantee that the technology in the project may violate local laws and regulations. It is prohibited to violate local laws and regulations. Using this software, the user shall be responsible for any violations caused by the user's use of the software without knowing or not permitted by local laws and regulations. The software shall not be responsible for any direct, indirect, special, accidental Or consequential responsibility.
|
||||
|
||||
|
||||
* If the agreement is updated without prior notice, you can check it at the open source address.
|
||||
* The original intention of this software is to help the official music platform to simplify the data generation for display, and to help users quickly locate the music platform where the desired content is based on the song title, artist and other keywords.
|
||||
* Music platform is not easy, it is recommended to support genuine resources to the corresponding music platform.
|
||||
|
||||
By: lyswhut
|
||||
18
licenses/license_zh.txt
Normal file
18
licenses/license_zh.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
本项目(软件)基于Apache License 2.0 许可证发行,在使用本软件前,你(使用者)需签署本协议才可继续使用,以下协议是对于 Apache License 2.0 的补充,如有冲突,以以下协议为准。
|
||||
|
||||
|
||||
词语约定:本协议中的“本软件”指洛雪音乐桌面版项目;“使用者”指签署本协议的使用者;“官方音乐平台”指对本软件内置的包括酷我、酷狗、咪咕等音乐源的官方平台统称;“版权数据”指包括但不限于图像、音频、名字等在内的他人拥有所属版权的数据。
|
||||
|
||||
1、本软件的数据来源原理是从各官方音乐平台的公开服务器中拉取数据,经过对数据简单地筛选与合并后进行展示,因此本软件不对数据的准确性负责。
|
||||
2、使用本软件的过程中可能会产生版权数据,对于这些版权数据,本软件不拥有它们的所有权,为了避免造成侵权,使用者务必在24小时内清除使用本软件的过程中所产生的版权数据。
|
||||
3、本软件内的官方音乐平台别名为本软件内对官方音乐平台的一个称呼,不包含恶意,如果官方音乐平台觉得不妥,可联系本软件更改或移除。
|
||||
4、本软件内使用的部分包括但不限于字体、图片等资源来源于互联网,如果出现侵权可联系本软件移除。
|
||||
5、由于使用本软件产生的包括由于本协议或由于使用或无法使用本软件而引起的任何性质的任何直接、间接、特殊、偶然或结果性损害(包括但不限于因商誉损失、停工、计算机故障或故障引起的损害赔偿,或任何及所有其他商业损害或损失)由使用者负责。
|
||||
6、本项目完全免费,且开源发布于 GitHub 面向全世界人用作对技术的学习交流,本软件不对项目内的技术可能存在违反当地法律法规的行为作保证,禁止在违反当地法律法规的情况下使用本软件,对于使用者在明知或不知当地法律法规不允许的情况下使用本软件所造成的任何违法违规行为由使用者承担,本软件不承担由此造成的任何直接、间接、特殊、偶然或结果性责任。
|
||||
|
||||
|
||||
* 若协议更新,恕不另行通知,可到开源地址查看。
|
||||
* 本软件的初衷是帮助官方音乐平台简化数据后代为展示,帮助使用者根据歌曲名、艺术家等关键字快速地定位所需内容所在的音乐平台。
|
||||
* 音乐平台不易,建议到对应音乐平台支持正版资源。
|
||||
|
||||
By: 落雪无痕
|
||||
15989
package-lock.json
generated
15989
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
281
package.json
281
package.json
@@ -1,27 +1,67 @@
|
||||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "0.1.4",
|
||||
"version": "1.5.0",
|
||||
"description": "一个免费的音乐下载助手",
|
||||
"main": "./dist/electron/main.js",
|
||||
"productName": "lx-music-desktop",
|
||||
"scripts": {
|
||||
"pack": "node build-config/pack.js && npm run pack:win",
|
||||
"pack:win": "npm run pack:win:setup:x86_64 && npm run pack:win:7z",
|
||||
"pack:win:setup:x86_64": "cross-env TARGET=win_安装版 ARCH=x86_64 electron-builder -w=nsis --x64 --ia32",
|
||||
"pack:win:setup:x64": "cross-env TARGET=win_安装版 ARCH=x64 electron-builder -w=nsis --x64",
|
||||
"pack:win:setup:x86": "cross-env TARGET=win_安装版 ARCH=x86 electron-builder -w=nsis --ia32",
|
||||
"pack:win:portable": "npm run pack:win:portable:x86_64 && npm run pack:win:portable:x64 && npm run pack:win:portable:x86",
|
||||
"pack:win:portable:x86_64": "cross-env TARGET=便携版 ARCH=x86_64 electron-builder -w=portable --x64 --ia32",
|
||||
"pack:win:portable:x64": "cross-env TARGET=便携版 ARCH=x64 electron-builder -w=portable --x64",
|
||||
"pack:win:portable:x86": "cross-env TARGET=便携版 ARCH=x86 electron-builder -w=portable --ia32",
|
||||
"pack:win:7z": "npm run pack:win:7z:x64 && npm run pack:win:7z:x86",
|
||||
"pack:win:7z:x64": "cross-env TARGET=win_绿色版 ARCH=x64 electron-builder -w=7z --x64",
|
||||
"pack:win:7z:x86": "cross-env TARGET=win_绿色版 ARCH=x86 electron-builder -w=7z --ia32",
|
||||
"publish": "node publish",
|
||||
"pub:gh": "node build-config/pack.js && electron-builder --win -p always",
|
||||
"pack": "node build-config/pack.js && electron-builder -w",
|
||||
"pack:linux": "node build-config/pack.js && electron-builder -l",
|
||||
"publish:gh": "node build-config/pack.js && npm run publish:win",
|
||||
"publish:win": "npm run publish:win:7z && npm run publish:win:setup",
|
||||
"publish:win:setup": "cross-env TARGET=Setup ARCH=x86_64 electron-builder -w=nsis --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:portable": "npm run publish:win:portable:x86_64 && npm run publish:win:portable:x64 && npm run publish:win:portable:x86",
|
||||
"publish:win:portable:x86_64": "cross-env TARGET=portable ARCH=x86_64 electron-builder -w=portable --x64 --ia32 -p onTagOrDraft",
|
||||
"publish:win:portable:x64": "cross-env TARGET=portable ARCH=x64 electron-builder -w=portable --x64 -p onTagOrDraft",
|
||||
"publish:win:portable:x86": "cross-env TARGET=portable ARCH=x86 electron-builder -w=portable --ia32 -p onTagOrDraft",
|
||||
"publish:win:7z": "npm run publish:win:7z:x64 && npm run publish:win:7z:x86",
|
||||
"publish:win:7z:x64": "cross-env TARGET=green ARCH=win_x64 electron-builder -w=7z --x64 -p always",
|
||||
"publish:win:7z:x86": "cross-env TARGET=green ARCH=win_x86 electron-builder -w=7z --ia32 -p onTagOrDraft",
|
||||
"publish:gh:mac": "node build-config/pack.js && npm run publish:mac",
|
||||
"publish:mac": "npm run publish:mac:dmg",
|
||||
"publish:mac:dmg": "electron-builder -m=dmg -p onTagOrDraft",
|
||||
"publish:gh:linux": "node build-config/pack.js && npm run publish:linux",
|
||||
"publish:linux": "npm run publish:linux:deb && npm run publish:linux:appImage && npm run publish:linux:rpm && npm run publish:linux:pacman",
|
||||
"publish:linux:appImage": "cross-env ARCH=x64 electron-builder -l=AppImage -p onTagOrDraft",
|
||||
"publish:linux:deb": "npm run publish:linux:deb:x64 && npm run publish:linux:deb:x86 && npm run publish:linux:deb:arm64",
|
||||
"publish:linux:deb:x64": "cross-env ARCH=x64 electron-builder -l=deb --x64 -p onTagOrDraft",
|
||||
"publish:linux:deb:x86": "cross-env ARCH=x86 electron-builder -l=deb --ia32 -p onTagOrDraft",
|
||||
"publish:linux:deb:arm64": "cross-env ARCH=arm64 electron-builder -l=deb --arm64 -p onTagOrDraft",
|
||||
"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",
|
||||
"pack:linux": "node build-config/pack.js && npm run pack:linux:deb && npm run pack:linux:appImage && npm run pack:linux:rpm && npm run pack:linux:pacman",
|
||||
"pack:linux:appImage": "cross-env ARCH=x64 electron-builder -l=AppImage",
|
||||
"pack:linux:deb": "npm run pack:linux:deb:x64 && npm run pack:linux:deb:x86 && npm run pack:linux:deb:arm64",
|
||||
"pack:linux:deb:x64": "cross-env ARCH=x64 electron-builder -l=deb --x64",
|
||||
"pack:linux:deb:x86": "cross-env ARCH=x86 electron-builder -l=deb --ia32",
|
||||
"pack:linux:deb:arm64": "cross-env ARCH=arm64 electron-builder -l=deb --arm64",
|
||||
"pack:linux:rpm": "cross-env ARCH=x64 electron-builder -l=rpm --x64",
|
||||
"pack:linux:pacman": "cross-env ARCH=x64 electron-builder -l=pacman --x64",
|
||||
"pack:mac": "node build-config/pack.js && electron-builder -m=dmg",
|
||||
"pack:dir": "node build-config/pack.js && electron-builder --dir",
|
||||
"dev": "node build-config/runner-dev.js",
|
||||
"clean:electron": "rimraf dist/electron",
|
||||
"clean:web": "rimraf dist/web",
|
||||
"clean": "rimraf dist && rimraf build",
|
||||
"build:main": "cross-env NODE_ENV=production webpack --config build-config/main/webpack.config.prod.js --progress --hide-modules",
|
||||
"build:renderer": "cross-env NODE_ENV=production webpack --config build-config/renderer/webpack.config.prod.js --progress --hide-modules",
|
||||
"build:web": "npm run clean:web && cross-env NODE_ENV=production webpack --config build-config/web/webpack.config.prod.js --progress --hide-modules",
|
||||
"build": "npm run clean:electron && npm run build:main && npm run build:renderer",
|
||||
"build:renderer-lyric": "cross-env NODE_ENV=production webpack --config build-config/renderer-lyric/webpack.config.prod.js --progress --hide-modules",
|
||||
"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"
|
||||
},
|
||||
"browserslist": [
|
||||
"Chrome >= 76"
|
||||
"Electron 9.3.4"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
@@ -29,60 +69,75 @@
|
||||
"build": {
|
||||
"appId": "cn.toside.music.desktop",
|
||||
"directories": {
|
||||
"output": "build"
|
||||
"output": "./build"
|
||||
},
|
||||
"files": [
|
||||
"dist/electron/**/*"
|
||||
],
|
||||
"extraResources": [
|
||||
"./licenses"
|
||||
],
|
||||
"win": {
|
||||
"icon": "src/static/icons/lunch.ico",
|
||||
"icon": "./resources/icons/256x256.ico",
|
||||
"legalTrademarks": "lyswhut",
|
||||
"target": [
|
||||
{
|
||||
"arch": [
|
||||
"ia32",
|
||||
"x64"
|
||||
],
|
||||
"target": "nsis"
|
||||
}
|
||||
]
|
||||
"artifactName": "${productName} v${version} ${env.ARCH} ${env.TARGET}.${ext}"
|
||||
},
|
||||
"mac": {
|
||||
"icon": "./resources/icons/512x512.icns",
|
||||
"category": "public.app-category.music"
|
||||
},
|
||||
"linux": {
|
||||
"target": [
|
||||
{
|
||||
"target": "AppImage",
|
||||
"arch": [
|
||||
"x64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"arch": [
|
||||
"ia32",
|
||||
"x64"
|
||||
],
|
||||
"target": "deb"
|
||||
},
|
||||
{
|
||||
"arch": [
|
||||
"x64"
|
||||
],
|
||||
"target": "snap"
|
||||
}
|
||||
],
|
||||
"maintainer": "lyswhut <lyswuhut@qq.com>"
|
||||
"maintainer": "lyswhut <lyswhut@qq.com>",
|
||||
"artifactName": "${productName} v${version} ${env.ARCH}.${ext}",
|
||||
"icon": "./resources/icons",
|
||||
"category": "Utility;AudioVideo;Audio;Player;Music;",
|
||||
"desktop": {
|
||||
"Name[zh_CN]": "洛雪音乐助手"
|
||||
}
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"language": "2052",
|
||||
"allowToChangeInstallationDirectory": true,
|
||||
"differentialPackage": true,
|
||||
"license": "./license.rtf"
|
||||
"license": "./licenses/license.rtf",
|
||||
"shortcutName": "LX Music"
|
||||
},
|
||||
"dmg": {
|
||||
"window": {
|
||||
"width": 600,
|
||||
"height": 400
|
||||
},
|
||||
"contents": [
|
||||
{
|
||||
"x": 106,
|
||||
"y": 252,
|
||||
"name": "LX Music"
|
||||
},
|
||||
{
|
||||
"x": 490,
|
||||
"y": 252,
|
||||
"type": "link",
|
||||
"path": "/Applications"
|
||||
}
|
||||
],
|
||||
"title": "洛雪音乐助手 v${version}"
|
||||
},
|
||||
"appImage": {
|
||||
"license": "./licenses/license_zh.txt",
|
||||
"category": "Utility;AudioVideo;Audio;Player;Music;"
|
||||
},
|
||||
"publish": [
|
||||
{
|
||||
"provider": "github",
|
||||
"owner": "lyswhut",
|
||||
"repo": "lx-music-desktop"
|
||||
},
|
||||
{
|
||||
"package": "lx-music-desktop",
|
||||
"repo": "lx-music-desktop",
|
||||
"user": "lyswhut",
|
||||
"provider": "bintray"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -90,87 +145,97 @@
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/lyswhut/lx-music-desktop.git"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "lyswhut",
|
||||
"license": "Apache License 2.0",
|
||||
"keywords": [
|
||||
"music-player",
|
||||
"electron-app",
|
||||
"vuejs2"
|
||||
],
|
||||
"author": {
|
||||
"name": "lyswhut",
|
||||
"email": "lyswhut@qq.com"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/lyswhut/lx-music-desktop/issues"
|
||||
},
|
||||
"homepage": "https://github.com/lyswhut/lx-music-desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/polyfill": "^7.4.4",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"autoprefixer": "^9.6.1",
|
||||
"babel-eslint": "^10.0.2",
|
||||
"babel-loader": "^8.0.6",
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-modules-umd": "^7.12.1",
|
||||
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@babel/preset-env": "^7.12.10",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-minify-webpack-plugin": "^0.3.1",
|
||||
"babel-preset-minify": "^0.5.0",
|
||||
"cfonts": "^2.4.4",
|
||||
"chalk": "^2.4.2",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"cfonts": "^2.9.0",
|
||||
"chalk": "^4.1.0",
|
||||
"changelog-parser": "^2.8.0",
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"core-js": "^3.2.1",
|
||||
"cos-nodejs-sdk-v5": "^2.5.11",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^3.2.0",
|
||||
"del": "^3.0.0",
|
||||
"electron": "^6.0.2",
|
||||
"electron-builder": "^21.2.0",
|
||||
"electron-debug": "^3.0.1",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-config-standard": "^13.0.1",
|
||||
"copy-webpack-plugin": "^6.4.0",
|
||||
"core-js": "^3.8.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^4.3.0",
|
||||
"del": "^6.0.0",
|
||||
"electron": "^9.3.3",
|
||||
"electron-builder": "^22.9.1",
|
||||
"electron-debug": "^3.1.0",
|
||||
"electron-devtools-installer": "^3.1.1",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-formatter-friendly": "^7.0.0",
|
||||
"eslint-loader": "^2.2.1",
|
||||
"eslint-plugin-html": "^6.0.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-html": "^6.1.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"file-loader": "^4.2.0",
|
||||
"eslint-plugin-standard": "^4.1.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^5.0.0",
|
||||
"markdown-it": "^9.1.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"multispinner": "^0.2.1",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"pug": "^2.0.4",
|
||||
"html-webpack-plugin": "^4.5.0",
|
||||
"less": "^3.12.2",
|
||||
"less-loader": "^7.1.0",
|
||||
"markdown-it": "^12.0.3",
|
||||
"mini-css-extract-plugin": "^0.12.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.4",
|
||||
"postcss-loader": "^4.1.0",
|
||||
"postcss-pxtorem": "^5.1.1",
|
||||
"pug": "^3.0.0",
|
||||
"pug-loader": "^2.4.0",
|
||||
"pug-plain-loader": "^1.0.0",
|
||||
"raw-loader": "^3.1.0",
|
||||
"rimraf": "^3.0.0",
|
||||
"stylus": "^0.54.5",
|
||||
"stylus-loader": "^3.0.2",
|
||||
"terser-webpack-plugin": "^1.4.1",
|
||||
"url-loader": "^2.1.0",
|
||||
"vue-loader": "^15.7.1",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.39.2",
|
||||
"webpack-cli": "^3.3.6",
|
||||
"webpack-dev-server": "^3.8.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": "^4.3.1",
|
||||
"terser-webpack-plugin": "^4.2.3",
|
||||
"url-loader": "^4.1.1",
|
||||
"vue-loader": "^15.9.5",
|
||||
"vue-template-compiler": "^2.6.12",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
"webpack-merge": "^4.2.1"
|
||||
"webpack-merge": "^5.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"electron-log": "^3.0.7",
|
||||
"electron-store": "^4.0.0",
|
||||
"electron-updater": "^4.1.2",
|
||||
"crypto-js": "^4.0.0",
|
||||
"dnscache": "^1.0.2",
|
||||
"electron-log": "^4.3.0",
|
||||
"electron-store": "^6.0.1",
|
||||
"electron-updater": "^4.3.5",
|
||||
"iconv-lite": "^0.6.2",
|
||||
"image-size": "^0.9.3",
|
||||
"js-htmlencode": "^0.3.0",
|
||||
"lrc-file-parser": "^0.1.12",
|
||||
"node-downloader-helper": "^1.0.10",
|
||||
"request": "^2.88.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-electron": "^1.0.6",
|
||||
"vue-router": "^3.1.2",
|
||||
"vuex": "^3.1.1",
|
||||
"vuex-electron": "^1.0.3",
|
||||
"lrc-file-parser": "^1.0.5",
|
||||
"needle": "^2.5.2",
|
||||
"node-id3": "^0.1.19",
|
||||
"request": "^2.88.2",
|
||||
"vue": "^2.6.12",
|
||||
"vue-i18n": "^8.22.2",
|
||||
"vue-router": "^3.4.9",
|
||||
"vuex": "^3.6.0",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
const autoprefixer = require('autoprefixer')
|
||||
// const autoprefixer = require('autoprefixer')
|
||||
const pxtorem = require('postcss-pxtorem')
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
autoprefixer(),
|
||||
pxtorem({
|
||||
rootValue: 16,
|
||||
unitPrecision: 5,
|
||||
propList: [
|
||||
'font', 'font-size',
|
||||
'letter-spacing',
|
||||
'padding', 'margin',
|
||||
'padding-*', 'margin-*',
|
||||
'height', 'width',
|
||||
'*-height', '*-width',
|
||||
'flex', '::-webkit-scrollbar',
|
||||
'top', 'left', 'bottom', 'right',
|
||||
'border-radius',
|
||||
],
|
||||
selectorBlackList: ['html', 'ignore-to-rem'],
|
||||
replace: true,
|
||||
mediaQuery: false,
|
||||
minPixelValue: 0,
|
||||
exclude: [/node_modules/i],
|
||||
}),
|
||||
// autoprefixer(),
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
### 新增
|
||||
|
||||
- 新增音乐来源切换,可到设置页面-基本设置 look look !
|
||||
- 为搜索结果列表添加多选功能。
|
||||
P.S:暂时没想好多选后的操作按钮放哪...
|
||||
- 直接从歌单详情收藏的列表新增同步功能。注意:这将会覆盖本地的目标列表,歌曲将被替换成最新的在线列表
|
||||
|
||||
### 优化
|
||||
|
||||
- 重构与改进checkbox组件,使其支持不定选中状态
|
||||
- 完善上一个版本的http请求封装并切换部分请求到该方法上
|
||||
- 优化其他一些细节
|
||||
- 优化软件启动时恢复上一次播放的歌曲进度功能
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复MAC平台上下载歌曲封面嵌入无法显示的问题
|
||||
- 修复MAC平台首次运行软件最小化、关闭控制按钮默认在右边的问题
|
||||
- 修复酷狗源的某些歌曲没有专辑字段导致的列表加载失败问题
|
||||
- 修复某些酷狗源歌单链接无法打开的问题
|
||||
|
||||
@@ -7,16 +7,17 @@ const clearAssets = require('./utils/clearAssets')
|
||||
const updateVersionFile = require('./utils/updateChangeLog')
|
||||
// const copyFile = require('./utils/copyFile')
|
||||
// const githubRelease = require('./utils/githubRelease')
|
||||
const { parseArgv } = require('./utils')
|
||||
// const { parseArgv } = require('./utils')
|
||||
|
||||
const run = async() => {
|
||||
const params = parseArgv(process.argv.slice(2))
|
||||
const bak = await updateVersionFile(params.ver)
|
||||
// const params = parseArgv(process.argv.slice(2))
|
||||
// const bak = await updateVersionFile(params.ver)
|
||||
const bak = await updateVersionFile(process.argv.slice(2)[0])
|
||||
|
||||
try {
|
||||
console.log(chalk.blue('Clearing assets...'))
|
||||
await clearAssets()
|
||||
console.log(chalk.green('Assets clear complated...'))
|
||||
console.log(chalk.green('Assets clear completed...'))
|
||||
|
||||
// console.log(chalk.blue('Compileing assets...'))
|
||||
// await compileAssets()
|
||||
|
||||
@@ -25,7 +25,7 @@ const updateChangeLog = async(newVerNum, newChangeLog) => {
|
||||
let changeLog = fs.readFileSync(changelogPath, 'utf-8')
|
||||
const prevVer = await getPrevVer()
|
||||
const log = `## [${newVerNum}](${pkg.repository.url.replace(/^git\+(http.+)\.git$/, '$1')}/compare/v${prevVer}...v${newVerNum}) - ${formatTime()}\n\n${newChangeLog}`
|
||||
fs.writeFileSync(changelogPath, changeLog.replace(new RegExp(`(## [?0.1.1]?)`), log + '\n$1'), 'utf-8')
|
||||
fs.writeFileSync(changelogPath, changeLog.replace(new RegExp('(## [?0.1.1]?)'), log + '\n$1'), 'utf-8')
|
||||
}
|
||||
|
||||
const renderChangeLog = md => md_renderer(md)
|
||||
@@ -49,7 +49,7 @@ module.exports = async newVerNum => {
|
||||
|
||||
console.log(chalk.blue('new version: ') + chalk.green(newVerNum))
|
||||
|
||||
fs.writeFileSync(jp('../version.json'), JSON.stringify(version, null, 2) + '\n', 'utf-8')
|
||||
fs.writeFileSync(jp('../version.json'), JSON.stringify(version) + '\n', 'utf-8')
|
||||
|
||||
fs.writeFileSync(jp(pkgDir), JSON.stringify(pkg, null, 2) + '\n', 'utf-8')
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
BIN
resources/icons/512x512.icns
Normal file
BIN
resources/icons/512x512.icns
Normal file
Binary file not shown.
BIN
resources/icons/512x512.png
Normal file
BIN
resources/icons/512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
56
src/common/config.js
Normal file
56
src/common/config.js
Normal file
@@ -0,0 +1,56 @@
|
||||
module.exports = {
|
||||
windowSizeList: [
|
||||
{
|
||||
id: 0,
|
||||
name: 'smaller',
|
||||
width: 828,
|
||||
height: 530,
|
||||
fontSize: '14px',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
name: 'small',
|
||||
width: 920,
|
||||
height: 590,
|
||||
fontSize: '16px',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'medium',
|
||||
width: 1018,
|
||||
height: 650,
|
||||
fontSize: '16px',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'big',
|
||||
width: 1114,
|
||||
height: 708,
|
||||
fontSize: '17px',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'larger',
|
||||
width: 1202,
|
||||
height: 766,
|
||||
fontSize: '17px',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'oversized',
|
||||
width: 1382,
|
||||
height: 886,
|
||||
fontSize: '18px',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'huge',
|
||||
width: 1686,
|
||||
height: 1062,
|
||||
fontSize: '19px',
|
||||
},
|
||||
],
|
||||
navigationUrlWhiteList: [
|
||||
/^https:\/\/www\.xiami\.com/,
|
||||
],
|
||||
}
|
||||
89
src/common/defaultHotKey.js
Normal file
89
src/common/defaultHotKey.js
Normal file
@@ -0,0 +1,89 @@
|
||||
const { player: hotKeyPlayer, common: hotKeyCommon, desktop_lyric: hotKeyDesktopLyric } = require('./hotKey')
|
||||
|
||||
module.exports = {
|
||||
local: {
|
||||
enable: true,
|
||||
keys: {
|
||||
'mod+f5': {
|
||||
type: hotKeyPlayer.toggle_play.type,
|
||||
name: hotKeyPlayer.toggle_play.name,
|
||||
action: hotKeyPlayer.toggle_play.action,
|
||||
},
|
||||
'mod+arrowleft': {
|
||||
type: hotKeyPlayer.prev.type,
|
||||
name: hotKeyPlayer.prev.name,
|
||||
action: hotKeyPlayer.prev.action,
|
||||
},
|
||||
'mod+arrowright': {
|
||||
type: hotKeyPlayer.next.type,
|
||||
name: hotKeyPlayer.next.name,
|
||||
action: hotKeyPlayer.next.action,
|
||||
},
|
||||
f1: {
|
||||
type: hotKeyCommon.focusSearchInput.type,
|
||||
name: hotKeyCommon.focusSearchInput.name,
|
||||
action: hotKeyCommon.focusSearchInput.action,
|
||||
},
|
||||
},
|
||||
},
|
||||
global: {
|
||||
enable: false,
|
||||
keys: {
|
||||
MediaPlayPause: {
|
||||
type: hotKeyPlayer.toggle_play.type,
|
||||
name: null,
|
||||
action: hotKeyPlayer.toggle_play.action,
|
||||
},
|
||||
MediaPreviousTrack: {
|
||||
type: hotKeyPlayer.prev.type,
|
||||
name: null,
|
||||
action: hotKeyPlayer.prev.action,
|
||||
},
|
||||
MediaNextTrack: {
|
||||
type: hotKeyPlayer.next.type,
|
||||
name: null,
|
||||
action: hotKeyPlayer.next.action,
|
||||
},
|
||||
'mod+alt+f5': {
|
||||
type: hotKeyPlayer.toggle_play.type,
|
||||
name: hotKeyPlayer.toggle_play.name,
|
||||
action: hotKeyPlayer.toggle_play.action,
|
||||
},
|
||||
'mod+alt+arrowleft': {
|
||||
type: hotKeyPlayer.prev.type,
|
||||
name: hotKeyPlayer.prev.name,
|
||||
action: hotKeyPlayer.prev.action,
|
||||
},
|
||||
'mod+alt+arrowright': {
|
||||
type: hotKeyPlayer.next.type,
|
||||
name: hotKeyPlayer.next.name,
|
||||
action: hotKeyPlayer.next.action,
|
||||
},
|
||||
'mod+alt+arrowup': {
|
||||
type: hotKeyPlayer.volume_up.type,
|
||||
name: hotKeyPlayer.volume_up.name,
|
||||
action: hotKeyPlayer.volume_up.action,
|
||||
},
|
||||
'mod+alt+arrowdown': {
|
||||
type: hotKeyPlayer.volume_down.type,
|
||||
name: hotKeyPlayer.volume_down.name,
|
||||
action: hotKeyPlayer.volume_down.action,
|
||||
},
|
||||
'mod+alt+0': {
|
||||
type: hotKeyDesktopLyric.toggle_visible.type,
|
||||
name: hotKeyDesktopLyric.toggle_visible.name,
|
||||
action: hotKeyDesktopLyric.toggle_visible.action,
|
||||
},
|
||||
'mod+alt+-': {
|
||||
type: hotKeyDesktopLyric.toggle_lock.type,
|
||||
name: hotKeyDesktopLyric.toggle_lock.name,
|
||||
action: hotKeyDesktopLyric.toggle_lock.action,
|
||||
},
|
||||
'mod+alt+=': {
|
||||
type: hotKeyDesktopLyric.toggle_always_top.type,
|
||||
name: hotKeyDesktopLyric.toggle_always_top.name,
|
||||
action: hotKeyDesktopLyric.toggle_always_top.action,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
106
src/common/defaultSetting.js
Normal file
106
src/common/defaultSetting.js
Normal file
@@ -0,0 +1,106 @@
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
|
||||
const defaultSetting = {
|
||||
version: '1.0.38',
|
||||
player: {
|
||||
togglePlayMethod: 'listLoop',
|
||||
highQuality: false,
|
||||
isShowTaskProgess: true,
|
||||
volume: 1,
|
||||
isMute: false,
|
||||
mediaDeviceId: 'default',
|
||||
isMediaDeviceRemovedStopPlay: false,
|
||||
isShowLyricTransition: true,
|
||||
},
|
||||
desktopLyric: {
|
||||
enable: false,
|
||||
isLock: false,
|
||||
isAlwaysOnTop: false,
|
||||
width: 380,
|
||||
height: 420,
|
||||
x: null,
|
||||
y: null,
|
||||
theme: 0,
|
||||
isLockScreen: true,
|
||||
style: {
|
||||
fontSize: 120,
|
||||
opacity: 95,
|
||||
isZoomActiveLrc: true,
|
||||
},
|
||||
},
|
||||
list: {
|
||||
isShowAlbumName: true,
|
||||
isShowSource: true,
|
||||
prevSelectListId: 'default',
|
||||
isSaveScrollLocation: true,
|
||||
},
|
||||
download: {
|
||||
enable: false,
|
||||
savePath: path.join(os.homedir(), 'Desktop'),
|
||||
fileName: '歌名 - 歌手',
|
||||
maxDownloadNum: 3,
|
||||
isDownloadLrc: false,
|
||||
isEmbedPic: true,
|
||||
isEmbedLyric: false,
|
||||
},
|
||||
leaderboard: {
|
||||
source: 'kw',
|
||||
tabId: 'kw__16',
|
||||
},
|
||||
songList: {
|
||||
source: 'kg',
|
||||
sortId: '5',
|
||||
tagInfo: {
|
||||
name: '默认',
|
||||
id: null,
|
||||
},
|
||||
},
|
||||
odc: {
|
||||
isAutoClearSearchInput: false,
|
||||
isAutoClearSearchList: false,
|
||||
},
|
||||
search: {
|
||||
searchSource: 'all',
|
||||
tempSearchSource: 'kw',
|
||||
isShowHotSearch: false,
|
||||
isShowHistorySearch: false,
|
||||
isFocusSearchBox: false,
|
||||
},
|
||||
network: {
|
||||
proxy: {
|
||||
enable: false,
|
||||
host: '',
|
||||
port: '',
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
},
|
||||
tray: {
|
||||
isShow: false,
|
||||
isToTray: false,
|
||||
themeId: 0,
|
||||
},
|
||||
windowSizeId: 2,
|
||||
themeId: 0,
|
||||
langId: null,
|
||||
sourceId: 'kw',
|
||||
apiSource: 'temp',
|
||||
sourceNameType: 'alias',
|
||||
isShowAnimation: true,
|
||||
randomAnimate: true,
|
||||
ignoreVersion: null,
|
||||
isAgreePact: false,
|
||||
controlBtnPosition: process.platform === 'darwin' ? 'left' : 'right',
|
||||
}
|
||||
|
||||
const overwriteSetting = {
|
||||
|
||||
}
|
||||
|
||||
// 使用新年皮肤
|
||||
if (new Date().getMonth() < 2) defaultSetting.themeId = 9
|
||||
|
||||
|
||||
exports.defaultSetting = defaultSetting
|
||||
exports.overwriteSetting = overwriteSetting
|
||||
12
src/common/error.js
Normal file
12
src/common/error.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const { log } = require('./utils')
|
||||
|
||||
process.on('uncaughtException', function(err) {
|
||||
console.error('An uncaught error occurred!')
|
||||
console.error(err)
|
||||
log.error(err)
|
||||
})
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.error('Unhandled Rejection at: Promise ', p)
|
||||
console.error(' reason: ', reason)
|
||||
log.error(reason)
|
||||
})
|
||||
83
src/common/hotKey.js
Normal file
83
src/common/hotKey.js
Normal file
@@ -0,0 +1,83 @@
|
||||
const names = require('@main/events/_name')
|
||||
const hotKey = {
|
||||
common: {
|
||||
min: {
|
||||
name: 'min',
|
||||
action: 'min',
|
||||
},
|
||||
min_toggle: {
|
||||
name: 'toggle_min',
|
||||
action: 'toggle_min',
|
||||
},
|
||||
hide_toggle: {
|
||||
name: 'toggle_hide',
|
||||
action: 'toggle_hide',
|
||||
},
|
||||
close: {
|
||||
name: 'toggle_close',
|
||||
action: 'toggle_close',
|
||||
},
|
||||
focusSearchInput: {
|
||||
name: 'focus_search_input',
|
||||
action: 'focus_search_input',
|
||||
},
|
||||
},
|
||||
player: {
|
||||
toggle_play: {
|
||||
name: 'toggle_play',
|
||||
action: 'toggle_play',
|
||||
},
|
||||
next: {
|
||||
name: 'next',
|
||||
action: 'next',
|
||||
},
|
||||
prev: {
|
||||
name: 'prev',
|
||||
action: 'prev',
|
||||
},
|
||||
volume_up: {
|
||||
name: 'volume_up',
|
||||
action: 'volume_up',
|
||||
},
|
||||
volume_down: {
|
||||
name: 'volume_down',
|
||||
action: 'volume_down',
|
||||
},
|
||||
volume_mute: {
|
||||
name: 'volume_mute',
|
||||
action: 'volume_mute',
|
||||
},
|
||||
},
|
||||
desktop_lyric: {
|
||||
toggle_visible: {
|
||||
name: 'toggle_visible',
|
||||
action: 'toggle_visible',
|
||||
},
|
||||
toggle_lock: {
|
||||
name: 'toggle_lock',
|
||||
action: 'toggle_lock',
|
||||
},
|
||||
toggle_always_top: {
|
||||
name: 'toggle_always_top',
|
||||
action: 'toggle_always_top',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const keyName = {
|
||||
player: names.mainWindow.name,
|
||||
desktop_lyric: names.winLyric.name,
|
||||
}
|
||||
|
||||
for (const type of Object.keys(hotKey)) {
|
||||
let item = hotKey[type]
|
||||
for (const key of Object.keys(item)) {
|
||||
item[key].action = `${type}_${item[key].action}`
|
||||
item[key].name = `${type}_${item[key].name}`
|
||||
item[key].type = keyName[type]
|
||||
}
|
||||
}
|
||||
|
||||
exports.common = hotKey.common
|
||||
exports.player = hotKey.player
|
||||
exports.desktop_lyric = hotKey.desktop_lyric
|
||||
@@ -1,19 +0,0 @@
|
||||
const { ipcMain, ipcRenderer } = require('electron')
|
||||
|
||||
|
||||
export const mainSend = (name, params) => {
|
||||
ipcMain.send(name, params)
|
||||
}
|
||||
|
||||
export const mainOn = (name, callback) => {
|
||||
ipcMain.on(name, callback)
|
||||
}
|
||||
|
||||
|
||||
export const rendererSend = (name, params) => {
|
||||
ipcRenderer.send(name, params)
|
||||
}
|
||||
|
||||
export const rendererOn = (name, callback) => {
|
||||
ipcRenderer.on(name, callback)
|
||||
}
|
||||
37
src/common/ipc.js
Normal file
37
src/common/ipc.js
Normal file
@@ -0,0 +1,37 @@
|
||||
const { ipcMain, ipcRenderer } = require('electron')
|
||||
const names = require('./ipcNames')
|
||||
|
||||
|
||||
exports.mainOn = (event, callback) => {
|
||||
ipcMain.on(event, callback)
|
||||
}
|
||||
exports.mainOnce = (event, callback) => {
|
||||
ipcMain.once(event, callback)
|
||||
}
|
||||
|
||||
exports.mainHandle = (name, callback) => {
|
||||
ipcMain.handle(name, callback)
|
||||
}
|
||||
exports.mainHandleOnce = (name, callback) => {
|
||||
ipcMain.handleOnce(name, callback)
|
||||
}
|
||||
|
||||
exports.mainSend = (window, name, params) => {
|
||||
window.webContents.send(name, params)
|
||||
}
|
||||
|
||||
exports.rendererSend = (name, params) => {
|
||||
ipcRenderer.send(name, params)
|
||||
}
|
||||
exports.rendererSendSync = (name, params) => ipcRenderer.sendSync(name, params)
|
||||
|
||||
exports.rendererInvoke = (name, params) => ipcRenderer.invoke(name, params)
|
||||
|
||||
exports.rendererOn = (name, callback) => {
|
||||
ipcRenderer.on(name, callback)
|
||||
}
|
||||
exports.rendererOnce = (name, callback) => {
|
||||
ipcRenderer.once(name, callback)
|
||||
}
|
||||
|
||||
exports.NAMES = names
|
||||
79
src/common/ipcNames.js
Normal file
79
src/common/ipcNames.js
Normal file
@@ -0,0 +1,79 @@
|
||||
const names = {
|
||||
mainWindow: {
|
||||
focus: 'focus',
|
||||
close: 'close',
|
||||
min: 'min',
|
||||
max: 'max',
|
||||
set_app_name: 'set_app_name',
|
||||
clear_cache: 'clear_cache',
|
||||
get_cache_size: 'get_cache_size',
|
||||
get_env_params: 'get_env_params',
|
||||
|
||||
set_music_meta: 'set_music_meta',
|
||||
progress: 'progress',
|
||||
change_tray: 'change_tray',
|
||||
quit_update: 'quit_update',
|
||||
update_available: 'update_available',
|
||||
update_error: 'update_error',
|
||||
update_progress: 'update_progress',
|
||||
update_downloaded: 'update_downloaded',
|
||||
update_not_available: 'update_not_available',
|
||||
set_ignore_mouse_events: 'set_ignore_mouse_events',
|
||||
set_app_setting: 'set_app_setting',
|
||||
set_window_size: 'set_window_size',
|
||||
show_save_dialog: 'show_save_dialog',
|
||||
|
||||
handle_request: 'handle_request',
|
||||
cancel_request: 'cancel_request',
|
||||
|
||||
handle_xm_verify_open: 'handle_xm_verify_open',
|
||||
handle_xm_verify_close: 'handle_xm_verify_close',
|
||||
select_dir: 'select_dir',
|
||||
|
||||
restart_window: 'restart_window',
|
||||
|
||||
handle_kw_decode_lyric: 'handle_kw_decode_lyric',
|
||||
get_lyric_info: 'get_lyric_info',
|
||||
set_lyric_info: 'set_lyric_info',
|
||||
set_config: 'set_config',
|
||||
set_hot_key_config: 'set_hot_key_config',
|
||||
key_down: 'key_down',
|
||||
quit: 'quit',
|
||||
min_toggle: 'min_toggle',
|
||||
hide_toggle: 'hide_toggle',
|
||||
get_data_path: 'get_data_path',
|
||||
show_dialog: 'show_dialog',
|
||||
|
||||
get_setting: 'get_setting',
|
||||
get_playlist: 'get_playlist',
|
||||
save_playlist: 'save_playlist',
|
||||
get_data: 'get_data',
|
||||
save_data: 'save_data',
|
||||
get_hot_key: 'get_hot_key',
|
||||
},
|
||||
winLyric: {
|
||||
close: 'close',
|
||||
set_lyric_info: 'set_lyric_info',
|
||||
get_lyric_info: 'get_lyric_info',
|
||||
set_lyric_config: 'set_lyric_config',
|
||||
get_lyric_config: 'get_lyric_config',
|
||||
set_win_bounds: 'set_win_bounds',
|
||||
key_down: 'key_down',
|
||||
},
|
||||
hotKey: {
|
||||
enable: 'enable',
|
||||
status: 'status',
|
||||
set_config: 'set_config',
|
||||
},
|
||||
}
|
||||
|
||||
for (const item of Object.keys(names)) {
|
||||
let name = names[item]
|
||||
for (const key of Object.keys(name)) {
|
||||
name[key] = `${item}_${name[key]}`
|
||||
}
|
||||
}
|
||||
|
||||
exports.mainWindow = names.mainWindow
|
||||
exports.winLyric = names.winLyric
|
||||
exports.hotKey = names.hotKey
|
||||
228
src/common/utils.js
Normal file
228
src/common/utils.js
Normal file
@@ -0,0 +1,228 @@
|
||||
const log = require('electron-log')
|
||||
const Store = require('electron-store')
|
||||
const { defaultSetting, overwriteSetting } = require('./defaultSetting')
|
||||
const apiSource = require('../renderer/utils/music/api-source-info')
|
||||
const defaultHotKey = require('./defaultHotKey')
|
||||
const { dialog, app } = require('electron')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
exports.isLinux = process.platform == 'linux'
|
||||
exports.isWin = process.platform == 'win32'
|
||||
exports.isMac = process.platform == 'darwin'
|
||||
|
||||
|
||||
/**
|
||||
* 生成节流函数
|
||||
* @param {*} fn
|
||||
* @param {*} delay
|
||||
*/
|
||||
exports.throttle = (fn, delay = 100) => {
|
||||
let timer = null
|
||||
let _args = null
|
||||
return function(...args) {
|
||||
_args = args
|
||||
if (timer) return
|
||||
timer = setTimeout(() => {
|
||||
timer = null
|
||||
fn.apply(this, _args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成防抖函数
|
||||
* @param {*} fn
|
||||
* @param {*} delay
|
||||
*/
|
||||
exports.debounce = (fn, delay = 100) => {
|
||||
let timer = null
|
||||
let _args = null
|
||||
return function(...args) {
|
||||
_args = args
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
timer = null
|
||||
fn.apply(this, _args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.log = log
|
||||
|
||||
// https://stackoverflow.com/a/53387532
|
||||
exports.compareVer = (currentVer, targetVer) => {
|
||||
// treat non-numerical characters as lower version
|
||||
// replacing them with a negative number based on charcode of each character
|
||||
const fix = s => `.${s.toLowerCase().charCodeAt(0) - 2147483647}.`
|
||||
|
||||
currentVer = ('' + currentVer).replace(/[^0-9.]/g, fix).split('.')
|
||||
targetVer = ('' + targetVer).replace(/[^0-9.]/g, fix).split('.')
|
||||
let c = Math.max(currentVer.length, targetVer.length)
|
||||
for (let i = 0; i < c; i++) {
|
||||
// convert to integer the most efficient way
|
||||
currentVer[i] = ~~currentVer[i]
|
||||
targetVer[i] = ~~targetVer[i]
|
||||
if (currentVer[i] > targetVer[i]) return 1
|
||||
else if (currentVer[i] < targetVer[i]) return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
exports.isObject = item => item && typeof item === 'object' && !Array.isArray(item)
|
||||
|
||||
/**
|
||||
* 对象深度合并
|
||||
* @param {} target 要合并源对象
|
||||
* @param {} source 要合并目标对象
|
||||
*/
|
||||
exports.objectDeepMerge = (target, source, mergedObj) => {
|
||||
if (!mergedObj) {
|
||||
mergedObj = new Set()
|
||||
mergedObj.add(target)
|
||||
}
|
||||
let base = {}
|
||||
Object.keys(source).forEach(item => {
|
||||
if (exports.isObject(source[item])) {
|
||||
if (mergedObj.has(source[item])) return
|
||||
if (!exports.isObject(target[item])) target[item] = {}
|
||||
mergedObj.add(source[item])
|
||||
exports.objectDeepMerge(target[item], source[item], mergedObj)
|
||||
return
|
||||
}
|
||||
base[item] = source[item]
|
||||
})
|
||||
Object.assign(target, base)
|
||||
}
|
||||
|
||||
exports.mergeSetting = (setting, version) => {
|
||||
let defaultSettingCopy = JSON.parse(JSON.stringify(defaultSetting))
|
||||
let overwriteSettingCopy = JSON.parse(JSON.stringify(overwriteSetting))
|
||||
const defaultVersion = defaultSettingCopy.version
|
||||
if (!version) {
|
||||
if (setting) {
|
||||
version = setting.version
|
||||
delete setting.version
|
||||
}
|
||||
}
|
||||
|
||||
if (!setting) {
|
||||
setting = defaultSettingCopy
|
||||
} else if (exports.compareVer(version, defaultVersion) < 0) {
|
||||
exports.objectDeepMerge(defaultSettingCopy, setting)
|
||||
exports.objectDeepMerge(defaultSettingCopy, overwriteSettingCopy)
|
||||
setting = defaultSettingCopy
|
||||
}
|
||||
|
||||
if (!apiSource.some(api => api.id === setting.apiSource && !api.disabled)) {
|
||||
let api = apiSource.find(api => !api.disabled)
|
||||
if (api) setting.apiSource = api.id
|
||||
}
|
||||
|
||||
return { setting, version: defaultVersion }
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化设置
|
||||
* @param {*} setting
|
||||
*/
|
||||
exports.initSetting = () => {
|
||||
let electronStore_list
|
||||
try {
|
||||
electronStore_list = new Store({
|
||||
name: 'playList',
|
||||
clearInvalidConfig: false,
|
||||
})
|
||||
} catch (error) {
|
||||
log.error(error)
|
||||
const backPath = path.join(app.getPath('userData'), 'playList.json.bak')
|
||||
fs.copyFileSync(path.join(app.getPath('userData'), 'playList.json'), backPath)
|
||||
dialog.showMessageBoxSync({
|
||||
type: 'error',
|
||||
message: 'Playlist data loading error',
|
||||
detail: `We have helped you back up the old list file to ${backPath}\nYou can try to repair and restore it manually\n\nError detail: ${error.message}`,
|
||||
})
|
||||
electronStore_list = new Store({
|
||||
name: 'playList',
|
||||
})
|
||||
}
|
||||
const electronStore_config = new Store({
|
||||
name: 'config',
|
||||
})
|
||||
let setting = electronStore_config.get('setting')
|
||||
if (setting) {
|
||||
let version = electronStore_config.get('version')
|
||||
if (!version) { // 迁移配置
|
||||
version = electronStore_config.get('setting.version')
|
||||
electronStore_config.set('version', version)
|
||||
electronStore_config.delete('setting.version')
|
||||
const list = electronStore_config.get('list')
|
||||
if (list) {
|
||||
if (list.defaultList) electronStore_list.set('defaultList', list.defaultList)
|
||||
if (list.loveList) electronStore_list.set('loveList', list.loveList)
|
||||
electronStore_config.delete('list')
|
||||
}
|
||||
const downloadList = electronStore_config.get('download')
|
||||
if (downloadList) {
|
||||
if (downloadList.list) electronStore_list.set('downloadList', downloadList.list)
|
||||
electronStore_config.delete('download')
|
||||
}
|
||||
}
|
||||
|
||||
// 迁移列表滚动位置设置 ~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
|
||||
}
|
||||
}
|
||||
|
||||
const { version: settingVersion, setting: newSetting } = exports.mergeSetting(setting, electronStore_config.get('version'))
|
||||
|
||||
// 重置 ^0.18.2 排行榜ID
|
||||
if (!newSetting.leaderboard.tabId.includes('__')) newSetting.leaderboard.tabId = 'kw__16'
|
||||
|
||||
// newSetting.controlBtnPosition = 'right'
|
||||
electronStore_config.set('version', settingVersion)
|
||||
electronStore_config.set('setting', newSetting)
|
||||
return { version: settingVersion, setting: newSetting }
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化快捷键设置
|
||||
*/
|
||||
exports.initHotKey = () => {
|
||||
const electronStore_hotKey = new Store({
|
||||
name: 'hotKey',
|
||||
})
|
||||
|
||||
let localConfig = electronStore_hotKey.get('local')
|
||||
if (!localConfig) {
|
||||
localConfig = defaultHotKey.local
|
||||
electronStore_hotKey.set('local', localConfig)
|
||||
}
|
||||
|
||||
let globalConfig = electronStore_hotKey.get('global')
|
||||
|
||||
// 移除v1.0.1及之前设置的全局声音媒体快捷键接管
|
||||
if (globalConfig && globalConfig.keys.VolumeUp) {
|
||||
delete globalConfig.keys.VolumeUp
|
||||
delete globalConfig.keys.VolumeDown
|
||||
delete globalConfig.keys.VolumeMute
|
||||
electronStore_hotKey.set('global', globalConfig)
|
||||
}
|
||||
|
||||
if (!globalConfig) {
|
||||
globalConfig = defaultHotKey.global
|
||||
electronStore_hotKey.set('global', globalConfig)
|
||||
}
|
||||
|
||||
return {
|
||||
global: globalConfig,
|
||||
local: localConfig,
|
||||
}
|
||||
}
|
||||
17
src/main/env/cmdParams.js
vendored
Normal file
17
src/main/env/cmdParams.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
const parseEnv = () => {
|
||||
const params = {}
|
||||
const rx = /^-\w+/
|
||||
for (let param of process.argv) {
|
||||
if (!rx.test(param)) continue
|
||||
param = param.substring(1)
|
||||
let index = param.indexOf('=')
|
||||
if (index < 0) {
|
||||
params[param] = true
|
||||
} else {
|
||||
params[param.substring(0, index)] = param.substring(index + 1)
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
global.envParams.cmdParams = parseEnv()
|
||||
4
src/main/env/index.js
vendored
Normal file
4
src/main/env/index.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
global.envParams = {}
|
||||
|
||||
require('./cmdParams')
|
||||
require('./screen')
|
||||
11
src/main/env/screen.js
vendored
Normal file
11
src/main/env/screen.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
const { app, screen } = require('electron')
|
||||
|
||||
const initScreenParams = () => {
|
||||
global.envParams.workAreaSize = screen.getPrimaryDisplay().workAreaSize
|
||||
}
|
||||
|
||||
|
||||
app.on('ready', () => {
|
||||
screen.on('display-metrics-changed', initScreenParams)
|
||||
initScreenParams()
|
||||
})
|
||||
34
src/main/event.js
Normal file
34
src/main/event.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const { common: COMMON_EVENT_NAME, mainWindow: MAIN_WINDOW_EVENT_NAME } = require('./events/_name')
|
||||
const { mainSend, NAMES: { mainWindow: ipcMainWindowNames } } = require('./../common/ipc')
|
||||
const { getAppHotKeyConfig } = require('./utils')
|
||||
|
||||
global.lx_event.common.on(COMMON_EVENT_NAME.config, name => {
|
||||
if (MAIN_WINDOW_EVENT_NAME.name === name) return
|
||||
if (global.modules.mainWindow) mainSend(global.modules.mainWindow, ipcMainWindowNames.set_config, global.appSetting)
|
||||
})
|
||||
|
||||
global.lx_event.common.on(COMMON_EVENT_NAME.initHotKey, () => {
|
||||
global.appHotKey.config = getAppHotKeyConfig()
|
||||
})
|
||||
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_EVENT_NAME.quit, () => {
|
||||
global.isTrafficLightClose = false
|
||||
global.isQuitting = true
|
||||
global.modules.mainWindow.close()
|
||||
})
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_EVENT_NAME.toggle_minimize, () => {
|
||||
if (global.modules.mainWindow.isMinimized()) {
|
||||
if (!global.modules.mainWindow.isVisible()) {
|
||||
global.modules.mainWindow.show()
|
||||
}
|
||||
global.modules.mainWindow.restore()
|
||||
global.modules.mainWindow.focus()
|
||||
} else {
|
||||
global.modules.mainWindow.minimize()
|
||||
}
|
||||
})
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_EVENT_NAME.toggle_hide, () => {
|
||||
global.modules.mainWindow.isVisible()
|
||||
? global.modules.mainWindow.hide()
|
||||
: global.modules.mainWindow.show()
|
||||
})
|
||||
18
src/main/events/Common.js
Normal file
18
src/main/events/Common.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { EventEmitter } = require('events')
|
||||
const { common: COMMON_EVENT_NAME } = require('./_name')
|
||||
const { updateSetting } = require('../utils')
|
||||
|
||||
class Common extends EventEmitter {
|
||||
initSetting() {
|
||||
this.emit(COMMON_EVENT_NAME.initConfig)
|
||||
this.emit(COMMON_EVENT_NAME.config, null)
|
||||
}
|
||||
|
||||
setAppConfig(config, name) {
|
||||
if (config) updateSetting(config)
|
||||
this.emit(COMMON_EVENT_NAME.config, name)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Common
|
||||
|
||||
21
src/main/events/HotKey.js
Normal file
21
src/main/events/HotKey.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const { EventEmitter } = require('events')
|
||||
const { hotKey: HOT_KEY_EVENT_NAME } = require('./_name')
|
||||
const { saveAppHotKeyConfig } = require('../utils')
|
||||
|
||||
class HotKey extends EventEmitter {
|
||||
init() {
|
||||
this.emit(HOT_KEY_EVENT_NAME.init)
|
||||
}
|
||||
|
||||
saveConfig(config, source) {
|
||||
if (config) saveAppHotKeyConfig(config)
|
||||
this.emit(HOT_KEY_EVENT_NAME.config, config, source)
|
||||
}
|
||||
|
||||
keyDown(info) {
|
||||
this.emit(HOT_KEY_EVENT_NAME.keyDown, info)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HotKey
|
||||
|
||||
34
src/main/events/MainWindow.js
Normal file
34
src/main/events/MainWindow.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const { EventEmitter } = require('events')
|
||||
const { mainWindow: MAIN_WINDOW_EVENT_NAME } = require('./_name')
|
||||
|
||||
class MainWindow extends EventEmitter {
|
||||
setLyricInfo(info) {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.setLyricInfo, info)
|
||||
}
|
||||
|
||||
quit() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.quit)
|
||||
}
|
||||
|
||||
toggleMinimize() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.toggle_minimize)
|
||||
}
|
||||
|
||||
toggleHide() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.toggle_hide)
|
||||
}
|
||||
|
||||
readyToShow() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.ready_to_show)
|
||||
}
|
||||
|
||||
show() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.show)
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.emit(MAIN_WINDOW_EVENT_NAME.hide)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MainWindow
|
||||
14
src/main/events/Tray.js
Normal file
14
src/main/events/Tray.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { EventEmitter } = require('events')
|
||||
const { tray: TRAY_EVENT_NAME } = require('./_name')
|
||||
|
||||
class Tray extends EventEmitter {
|
||||
create() {
|
||||
this.emit(TRAY_EVENT_NAME.create)
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.emit(TRAY_EVENT_NAME.destroy)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Tray
|
||||
15
src/main/events/WinLyric.js
Normal file
15
src/main/events/WinLyric.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const { EventEmitter } = require('events')
|
||||
const { winLyric: WIN_LYRIC_EVENT_NAME } = require('./_name')
|
||||
// const { updateSetting } = require('../utils')
|
||||
|
||||
class WinLyric extends EventEmitter {
|
||||
create() {
|
||||
this.emit(WIN_LYRIC_EVENT_NAME.create)
|
||||
}
|
||||
|
||||
close() {
|
||||
this.emit(WIN_LYRIC_EVENT_NAME.close)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WinLyric
|
||||
35
src/main/events/_name.js
Normal file
35
src/main/events/_name.js
Normal file
@@ -0,0 +1,35 @@
|
||||
exports.common = {
|
||||
initConfig: 'initConfig',
|
||||
config: 'config',
|
||||
}
|
||||
|
||||
exports.mainWindow = {
|
||||
name: 'mainWindow',
|
||||
setLyricInfo: 'setLyricInfo',
|
||||
destroy: 'destroy',
|
||||
quit: 'quit',
|
||||
toggle_minimize: 'toggle_minimize',
|
||||
toggle_hide: 'toggle_hide',
|
||||
ready_to_show: 'ready_to_show',
|
||||
show: 'show',
|
||||
hide: 'hide',
|
||||
}
|
||||
|
||||
exports.tray = {
|
||||
name: 'tray',
|
||||
create: 'create',
|
||||
destroy: 'destroy',
|
||||
}
|
||||
|
||||
exports.winLyric = {
|
||||
name: 'winLyric',
|
||||
create: 'create',
|
||||
close: 'close',
|
||||
}
|
||||
|
||||
exports.hotKey = {
|
||||
name: 'hotKey',
|
||||
init: 'init',
|
||||
config: 'config',
|
||||
keyDown: 'keyDown',
|
||||
}
|
||||
@@ -1,4 +1,13 @@
|
||||
global.lx_event = {}
|
||||
|
||||
require('./request')
|
||||
require('./appName')
|
||||
const Common = require('./Common')
|
||||
const MainWindow = require('./MainWindow')
|
||||
const Tray = require('./Tray')
|
||||
const WinLyric = require('./WinLyric')
|
||||
const HotKey = require('./HotKey')
|
||||
|
||||
if (!global.lx_event.common) global.lx_event.common = new Common()
|
||||
if (!global.lx_event.mainWindow) global.lx_event.mainWindow = new MainWindow()
|
||||
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()
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
|
||||
module.exports = win => {
|
||||
mainOn('progress', (event, params) => {
|
||||
// console.log(params)
|
||||
win.setProgressBar(params.status, {
|
||||
mode: params.mode || 'normal',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { dialog } = require('electron')
|
||||
|
||||
module.exports = win => {
|
||||
mainOn('selectPath', (event, params) => {
|
||||
let path = dialog.showOpenDialog(win, params.options)
|
||||
if (path === undefined) return
|
||||
event.sender.send(params.eventName, path)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
|
||||
module.exports = win => {
|
||||
mainOn('min', event => {
|
||||
if (win) {
|
||||
win.minimize()
|
||||
}
|
||||
})
|
||||
// mainOn('max', event => {
|
||||
// if (win) {
|
||||
// win.maximize()
|
||||
// }
|
||||
// })
|
||||
mainOn('close', event => {
|
||||
if (win) {
|
||||
win.close()
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,43 +1,107 @@
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
// 单例应用程序
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
app.quit()
|
||||
return
|
||||
}
|
||||
if (!global.modules) global.modules = {}
|
||||
app.on('second-instance', (event, argv, cwd) => {
|
||||
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 {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
const isDev = global.isDev = process.env.NODE_ENV !== 'production'
|
||||
require('./env')
|
||||
const { navigationUrlWhiteList } = require('../common/config')
|
||||
const { getWindowSizeInfo } = require('./utils')
|
||||
const { isMac, isLinux, initSetting, initHotKey } = require('../common/utils')
|
||||
|
||||
|
||||
// https://github.com/electron/electron/issues/22691
|
||||
app.commandLine.appendSwitch('wm-window-animations-disabled')
|
||||
|
||||
// https://github.com/electron/electron/issues/18397
|
||||
// 开发模式下为true时 多次引入native模块会导致渲染进程卡死
|
||||
// https://github.com/electron/electron/issues/22791
|
||||
app.allowRendererProcessReuse = !isDev
|
||||
|
||||
|
||||
app.on('web-contents-created', (event, contents) => {
|
||||
contents.on('will-navigate', (event, navigationUrl) => {
|
||||
if (isDev) return console.log('navigation to url:', navigationUrl)
|
||||
if (!navigationUrlWhiteList.some(url => url.test(navigationUrl))) return event.preventDefault()
|
||||
console.log('navigation to url:', navigationUrl)
|
||||
})
|
||||
contents.on('new-window', async(event, navigationUrl) => {
|
||||
event.preventDefault()
|
||||
if (/^devtools/.test(navigationUrl)) return
|
||||
console.log(navigationUrl)
|
||||
await shell.openExternal(navigationUrl)
|
||||
})
|
||||
contents.on('will-attach-webview', (event, webPreferences, params) => {
|
||||
// Strip away preload scripts if unused or verify their location is legitimate
|
||||
delete webPreferences.preload
|
||||
delete webPreferences.preloadURL
|
||||
|
||||
// Disable Node.js integration
|
||||
webPreferences.nodeIntegration = false
|
||||
|
||||
// Verify URL being loaded
|
||||
if (!navigationUrlWhiteList.some(url => url.test(params.src))) {
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
require('../common/error')
|
||||
require('./events')
|
||||
const progressBar = require('./events/progressBar')
|
||||
const trafficLight = require('./events/trafficLight')
|
||||
require('./event')
|
||||
require('./rendererEvents')
|
||||
const winEvent = require('./rendererEvents/winEvent')
|
||||
const autoUpdate = require('./utils/autoUpdate')
|
||||
|
||||
const isDev = process.env.NODE_ENV !== 'production'
|
||||
|
||||
/**
|
||||
* Set `__static` path to static files in production
|
||||
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
|
||||
*/
|
||||
|
||||
let mainWindow
|
||||
let winURL
|
||||
|
||||
if (isDev) {
|
||||
global.__static = path.join(__dirname, '../static')
|
||||
winURL = `http://localhost:9080`
|
||||
// eslint-disable-next-line no-undef
|
||||
global.__static = __static
|
||||
winURL = 'http://localhost:9080'
|
||||
} else {
|
||||
global.__static = path.join(__dirname, '/static')
|
||||
winURL = `file://${__dirname}/index.html`
|
||||
winURL = `file://${path.join(__dirname, 'index.html')}`
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
/**
|
||||
* Initial window options
|
||||
*/
|
||||
mainWindow = new BrowserWindow({
|
||||
height: 590,
|
||||
global.modules.mainWindow = new BrowserWindow({
|
||||
height: windowSizeInfo.height,
|
||||
useContentSize: true,
|
||||
width: 920,
|
||||
width: windowSizeInfo.width,
|
||||
frame: false,
|
||||
transparent: true,
|
||||
icon: path.join(global.__static, 'icons/lunch.ico'),
|
||||
transparent: !global.envParams.nt,
|
||||
enableRemoteModule: false,
|
||||
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
fullscreenable: false,
|
||||
show: false,
|
||||
webPreferences: {
|
||||
// contextIsolation: true,
|
||||
webSecurity: !isDev,
|
||||
@@ -45,30 +109,53 @@ function createWindow() {
|
||||
},
|
||||
})
|
||||
|
||||
mainWindow.loadURL(winURL)
|
||||
global.modules.mainWindow.loadURL(winURL)
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null
|
||||
})
|
||||
winEvent(global.modules.mainWindow)
|
||||
// global.modules.mainWindow.webContents.openDevTools()
|
||||
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
trafficLight(mainWindow)
|
||||
progressBar(mainWindow)
|
||||
if (!isDev) autoUpdate(mainWindow)
|
||||
if (!isDev) autoUpdate()
|
||||
}
|
||||
|
||||
app.once('ready', createWindow)
|
||||
global.appHotKey = {
|
||||
enable: true,
|
||||
config: {},
|
||||
state: null,
|
||||
}
|
||||
|
||||
function init() {
|
||||
const info = initSetting()
|
||||
global.appSetting = info.setting
|
||||
global.appSettingVersion = info.version
|
||||
global.appHotKey.config = initHotKey()
|
||||
global.lx_event.common.initSetting()
|
||||
global.lx_event.hotKey.init()
|
||||
createWindow()
|
||||
}
|
||||
|
||||
// https://github.com/electron/electron/issues/16809
|
||||
app.on('ready', isLinux ? () => setTimeout(init, 300) : init)
|
||||
|
||||
app.on('activate', () => {
|
||||
if (global.modules.mainWindow) {
|
||||
if (global.modules.mainWindow.isMinimized()) {
|
||||
global.modules.mainWindow.restore()
|
||||
} else if (global.modules.mainWindow.isVisible()) {
|
||||
global.modules.mainWindow.focus()
|
||||
} else {
|
||||
global.modules.mainWindow.show()
|
||||
}
|
||||
} else if (global.modules.mainWindow === null) {
|
||||
init()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
if (isMac) {
|
||||
global.lx_event.tray.destroy()
|
||||
} else {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', () => {
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
require('./modules')
|
||||
|
||||
48
src/main/modules/appMenu.js
Normal file
48
src/main/modules/appMenu.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const { app, Menu } = require('electron')
|
||||
const { isMac } = require('../../common/utils')
|
||||
|
||||
if (isMac) {
|
||||
const template = [
|
||||
{
|
||||
label: app.getName(),
|
||||
submenu: [
|
||||
{ label: '关于洛雪音乐', role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ label: '隐藏', role: 'hide' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: '退出',
|
||||
accelerator: 'Command+Q',
|
||||
click() {
|
||||
global.isQuitting = true
|
||||
app.quit()
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '窗口',
|
||||
role: 'window',
|
||||
submenu: [
|
||||
{ label: '最小化', role: 'minimize', accelerator: 'Command+W' },
|
||||
{ label: '关闭', role: 'close' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
submenu: [
|
||||
{ label: '撤销', accelerator: 'Command+Z', role: 'undo' },
|
||||
{ label: '恢复', accelerator: 'Shift+Command+Z', role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ label: '剪切', accelerator: 'Command+X', role: 'cut' },
|
||||
{ label: '复制', accelerator: 'Command+C', role: 'copy' },
|
||||
{ label: '粘贴', accelerator: 'Command+V', role: 'paste' },
|
||||
{ label: '选择全部', accelerator: 'Command+A', role: 'selectAll' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template))
|
||||
} else {
|
||||
Menu.setApplicationMenu(null)
|
||||
}
|
||||
12
src/main/modules/hotKey/index.js
Normal file
12
src/main/modules/hotKey/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const { app } = require('electron')
|
||||
const { init, unRegisterHotkeyAll } = require('./utils')
|
||||
const { hotKey: HOT_KEY_EVENT_NAME } = require('../../events/_name')
|
||||
|
||||
global.appHotKey.state = {}
|
||||
|
||||
app.on('will-quit', unRegisterHotkeyAll)
|
||||
|
||||
global.lx_event.hotKey.on(HOT_KEY_EVENT_NAME.init, init)
|
||||
|
||||
|
||||
require('./rendererEvent')
|
||||
28
src/main/modules/hotKey/rendererEvent.js
Normal file
28
src/main/modules/hotKey/rendererEvent.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const {
|
||||
mainHandle,
|
||||
NAMES: {
|
||||
hotKey: ipcHotKeyNames,
|
||||
},
|
||||
} = require('../../../common/ipc')
|
||||
const { init, registerHotkey, unRegisterHotkey, unRegisterHotkeyAll } = require('./utils')
|
||||
|
||||
mainHandle(ipcHotKeyNames.set_config, async(event, { action, data, source }) => {
|
||||
switch (action) {
|
||||
case 'config':
|
||||
global.lx_event.hotKey.saveConfig(data, source)
|
||||
return true
|
||||
case 'enable':
|
||||
data ? init(true) : unRegisterHotkeyAll()
|
||||
return true
|
||||
case 'register':
|
||||
return registerHotkey(data)
|
||||
case 'unregister':
|
||||
return unRegisterHotkey(data)
|
||||
}
|
||||
})
|
||||
|
||||
mainHandle(ipcHotKeyNames.status, async() => global.appHotKey.state)
|
||||
|
||||
mainHandle(ipcHotKeyNames.enable, async(event, flag) => {
|
||||
flag ? init() : unRegisterHotkeyAll()
|
||||
})
|
||||
67
src/main/modules/hotKey/utils.js
Normal file
67
src/main/modules/hotKey/utils.js
Normal file
@@ -0,0 +1,67 @@
|
||||
const { globalShortcut } = require('electron')
|
||||
const { log } = require('../../../common/utils')
|
||||
|
||||
const handleKeyDown = key => {
|
||||
if (!global.appHotKey.enable) return
|
||||
global.lx_event.hotKey.keyDown({ type: 'global', key })
|
||||
}
|
||||
|
||||
const transformedKeyRxp = /(^|\+)[a-z]/g
|
||||
|
||||
const transformedKey = key => {
|
||||
if (key.includes('arrow')) key = key.replace(/arrow/g, '')
|
||||
return key.replace('mod', 'CommandOrControl').replace(transformedKeyRxp, l => l.toUpperCase())
|
||||
}
|
||||
exports.registerHotkey = ({ key, info }) => {
|
||||
if (global.appHotKey.state[key] && global.appHotKey.state[key].status) return true
|
||||
let transKey = transformedKey(key)
|
||||
// console.log('Register key:', transKey)
|
||||
if (!global.appHotKey.state[key]) {
|
||||
global.appHotKey.state[key] = {
|
||||
status: false,
|
||||
info: null,
|
||||
}
|
||||
}
|
||||
global.appHotKey.state[key].info = info
|
||||
let status = global.appHotKey.state[key].status = globalShortcut.isRegistered(transKey)
|
||||
? false
|
||||
: globalShortcut.register(transKey, () => {
|
||||
handleKeyDown(key)
|
||||
})
|
||||
return status
|
||||
}
|
||||
|
||||
exports.unRegisterHotkey = key => {
|
||||
let transKey = transformedKey(key)
|
||||
// console.log('Unregister key:', transKey)
|
||||
globalShortcut.unregister(transKey)
|
||||
delete global.appHotKey.state[key]
|
||||
}
|
||||
|
||||
exports.unRegisterHotkeyAll = () => {
|
||||
global.appHotKey.state = {}
|
||||
globalShortcut.unregisterAll()
|
||||
}
|
||||
|
||||
exports.handleKeyDown = handleKeyDown
|
||||
exports.transformedKey = transformedKey
|
||||
|
||||
const handleRegisterHotkey = data => {
|
||||
let ret = exports.registerHotkey(data)
|
||||
if (!ret) log.info('Register hot key failed:', data.key)
|
||||
}
|
||||
|
||||
|
||||
exports.init = (isForce = false) => {
|
||||
exports.unRegisterHotkeyAll()
|
||||
if (!isForce && !global.appHotKey.config.global.enable) return
|
||||
global.appHotKey.state = {}
|
||||
// console.log(global.appHotKey.config.global.keys)
|
||||
for (const key of Object.keys(global.appHotKey.config.global.keys)) {
|
||||
try {
|
||||
handleRegisterHotkey({ key, info: global.appHotKey.config.global.keys[key] })
|
||||
} catch (err) {
|
||||
log.info(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/main/modules/index.js
Normal file
4
src/main/modules/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
require('./appMenu')
|
||||
require('./winLyric')
|
||||
require('./tray')
|
||||
require('./hotKey')
|
||||
138
src/main/modules/tray.js
Normal file
138
src/main/modules/tray.js
Normal file
@@ -0,0 +1,138 @@
|
||||
const { app, Tray, Menu } = 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
|
||||
let themeId = null
|
||||
const themeList = [
|
||||
{
|
||||
id: 0,
|
||||
fileName: 'tray0Template',
|
||||
isNative: true,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
fileName: 'tray1Template',
|
||||
isNative: false,
|
||||
},
|
||||
]
|
||||
global.lx_event.common.on(COMMON_EVENT_NAME.config, sourceName => {
|
||||
if (sourceName === TRAY_EVENT_NAME.name) return
|
||||
if (themeId !== global.appSetting.tray.themeId) {
|
||||
themeId = global.appSetting.tray.themeId
|
||||
setTrayImage(themeId)
|
||||
}
|
||||
if (isEnableTray !== global.appSetting.tray.isShow) {
|
||||
isEnableTray = global.appSetting.tray.isShow
|
||||
global.appSetting.tray.isShow ? createTray() : destroyTray()
|
||||
}
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.ready_to_show, () => {
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.show, () => {
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_NAME.hide, () => {
|
||||
createMenu(global.modules.tray)
|
||||
})
|
||||
|
||||
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')
|
||||
|
||||
// 托盘
|
||||
global.modules.tray = new Tray(iconPath)
|
||||
|
||||
global.modules.tray.setToolTip('洛雪音乐助手')
|
||||
createMenu(global.modules.tray)
|
||||
global.modules.tray.setIgnoreDoubleClickEvents(true)
|
||||
global.modules.tray.on('click', () => {
|
||||
const mainWindow = global.modules.mainWindow
|
||||
if (!mainWindow) return
|
||||
mainWindow.isVisible()
|
||||
? mainWindow.focus()
|
||||
: mainWindow.show()
|
||||
})
|
||||
}
|
||||
|
||||
const destroyTray = () => {
|
||||
if (!global.modules.tray) return
|
||||
global.modules.tray.destroy()
|
||||
global.modules.tray = null
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
global.modules.mainWindow.restore()
|
||||
global.modules.mainWindow.focus()
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.enable ? {
|
||||
label: '关闭桌面歌词',
|
||||
click() {
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: { enable: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
} : {
|
||||
label: '开启桌面歌词',
|
||||
click() {
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: { enable: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.isLock ? {
|
||||
label: '解锁桌面歌词',
|
||||
click() {
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: { isLock: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
} : {
|
||||
label: '锁定桌面歌词',
|
||||
click() {
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: { isLock: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push(global.appSetting.desktopLyric.isAlwaysOnTop ? {
|
||||
label: '取消置顶',
|
||||
click() {
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: { isAlwaysOnTop: false } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
} : {
|
||||
label: '置顶歌词',
|
||||
click() {
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: { isAlwaysOnTop: true } }, TRAY_EVENT_NAME.name)
|
||||
},
|
||||
})
|
||||
menu.push({
|
||||
label: '退出',
|
||||
click() {
|
||||
global.isQuitting = true
|
||||
app.quit()
|
||||
},
|
||||
})
|
||||
const contextMenu = Menu.buildFromTemplate(menu)
|
||||
tray.setContextMenu(contextMenu)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
80
src/main/modules/winLyric/event.js
Normal file
80
src/main/modules/winLyric/event.js
Normal file
@@ -0,0 +1,80 @@
|
||||
const { common: COMMON_EVENT_NAME, winLyric: WIN_LYRIC_EVENT_NAME, hotKey: HOT_KEY_EVENT_NAME, mainWindow: MAIN_WINDOW_EVENT_NAME } = require('../../events/_name')
|
||||
const { mainSend, NAMES: { winLyric: ipcWinLyricNames } } = require('../../../common/ipc')
|
||||
const { desktop_lyric } = require('../../../common/hotKey')
|
||||
const { getLyricWindowBounds } = require('./utils')
|
||||
|
||||
let isLock = null
|
||||
let isEnable = null
|
||||
let isAlwaysOnTop = null
|
||||
let isLockScreen = null
|
||||
const setLrcConfig = () => {
|
||||
let desktopLyric = global.appSetting.desktopLyric
|
||||
if (global.modules.lyricWindow) {
|
||||
mainSend(global.modules.lyricWindow, ipcWinLyricNames.set_lyric_config, {
|
||||
config: desktopLyric,
|
||||
languageId: global.appSetting.langId,
|
||||
isShowLyricTransition: global.appSetting.player.isShowLyricTransition,
|
||||
})
|
||||
if (isLock != desktopLyric.isLock) {
|
||||
isLock = desktopLyric.isLock
|
||||
if (desktopLyric.isLock) {
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(true, { forward: false })
|
||||
} else {
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(false)
|
||||
}
|
||||
}
|
||||
if (isAlwaysOnTop != desktopLyric.isAlwaysOnTop) {
|
||||
isAlwaysOnTop = desktopLyric.isAlwaysOnTop
|
||||
global.modules.lyricWindow.setAlwaysOnTop(desktopLyric.isAlwaysOnTop, 'screen-saver')
|
||||
}
|
||||
if (isLockScreen != desktopLyric.isLockScreen) {
|
||||
isLockScreen = desktopLyric.isLockScreen
|
||||
if (desktopLyric.isLockScreen) {
|
||||
global.modules.lyricWindow.setBounds(getLyricWindowBounds(global.modules.lyricWindow.getBounds(), {
|
||||
x: null,
|
||||
y: null,
|
||||
w: desktopLyric.width,
|
||||
h: desktopLyric.height,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isEnable != desktopLyric.enable) {
|
||||
isEnable = desktopLyric.enable
|
||||
if (desktopLyric.enable) {
|
||||
global.lx_event.winLyric.create()
|
||||
} else {
|
||||
global.lx_event.winLyric.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
global.lx_event.common.on(COMMON_EVENT_NAME.config, name => {
|
||||
if (WIN_LYRIC_EVENT_NAME.name === name) return
|
||||
setLrcConfig()
|
||||
})
|
||||
|
||||
global.lx_event.mainWindow.on(MAIN_WINDOW_EVENT_NAME.setLyricInfo, info => {
|
||||
if (!global.modules.lyricWindow) return
|
||||
mainSend(global.modules.lyricWindow, ipcWinLyricNames.set_lyric_info, info)
|
||||
})
|
||||
|
||||
global.lx_event.hotKey.on(HOT_KEY_EVENT_NAME.keyDown, ({ type, key }) => {
|
||||
let info = global.appHotKey.config.global.keys[key]
|
||||
if (!info || info.type != WIN_LYRIC_EVENT_NAME.name) return
|
||||
let desktopLyricSetting = JSON.parse(JSON.stringify(global.appSetting.desktopLyric))
|
||||
let settingKey
|
||||
switch (info.action) {
|
||||
case desktop_lyric.toggle_visible.action:
|
||||
settingKey = 'enable'
|
||||
break
|
||||
case desktop_lyric.toggle_lock.action:
|
||||
settingKey = 'isLock'
|
||||
break
|
||||
case desktop_lyric.toggle_always_top.action:
|
||||
settingKey = 'isAlwaysOnTop'
|
||||
break
|
||||
}
|
||||
desktopLyricSetting[settingKey] = !desktopLyricSetting[settingKey]
|
||||
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: desktopLyricSetting }, null)
|
||||
})
|
||||
127
src/main/modules/winLyric/index.js
Normal file
127
src/main/modules/winLyric/index.js
Normal file
@@ -0,0 +1,127 @@
|
||||
const path = require('path')
|
||||
const { BrowserWindow } = require('electron')
|
||||
const { winLyric: WIN_LYRIC_EVENT_NAME } = require('../../events/_name')
|
||||
const { debounce } = require('../../../common/utils')
|
||||
const { getLyricWindowBounds } = require('./utils')
|
||||
|
||||
require('./event')
|
||||
require('./rendererEvent')
|
||||
|
||||
global.lx_event.winLyric.on(WIN_LYRIC_EVENT_NAME.create, () => {
|
||||
createWindow()
|
||||
})
|
||||
global.lx_event.winLyric.on(WIN_LYRIC_EVENT_NAME.close, () => {
|
||||
closeWindow()
|
||||
})
|
||||
|
||||
let winURL = global.isDev ? 'http://localhost:9081/lyric.html' : `file://${path.join(__dirname, 'lyric.html')}`
|
||||
|
||||
const setLyricsConfig = debounce(config => {
|
||||
// if (x != null) bounds.x = x
|
||||
// if (y != null) bounds.y = y
|
||||
// if (width != null) bounds.width = width
|
||||
// if (height != null) bounds.height = height
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: config }, WIN_LYRIC_EVENT_NAME.name)
|
||||
}, 500)
|
||||
|
||||
const winEvent = lyricWindow => {
|
||||
// let bounds
|
||||
// lyricWindow.on('close', event => {
|
||||
// if (global.isQuitting || !global.appSetting.tray.isToTray || (!isWin && !global.isTrafficLightClose)) {
|
||||
// lyricWindow.setProgressBar(-1)
|
||||
// return
|
||||
// }
|
||||
|
||||
// if (global.isTrafficLightClose) global.isTrafficLightClose = false
|
||||
// event.preventDefault()
|
||||
// lyricWindow.hide()
|
||||
// })
|
||||
|
||||
lyricWindow.on('closed', () => {
|
||||
lyricWindow = global.modules.lyricWindow = null
|
||||
})
|
||||
|
||||
|
||||
lyricWindow.on('move', event => {
|
||||
// bounds = lyricWindow.getBounds()
|
||||
// console.log(bounds)
|
||||
setLyricsConfig(lyricWindow.getBounds())
|
||||
})
|
||||
|
||||
lyricWindow.on('resize', event => {
|
||||
// bounds = lyricWindow.getBounds()
|
||||
// console.log(bounds)
|
||||
setLyricsConfig(lyricWindow.getBounds())
|
||||
})
|
||||
|
||||
// lyricWindow.on('restore', () => {
|
||||
// lyricWindow.webContents.send('restore')
|
||||
// })
|
||||
// lyricWindow.on('focus', () => {
|
||||
// lyricWindow.webContents.send('focus')
|
||||
// })
|
||||
|
||||
lyricWindow.once('ready-to-show', () => {
|
||||
lyricWindow.show()
|
||||
if (global.appSetting.desktopLyric.isLock) {
|
||||
global.modules.lyricWindow.setIgnoreMouseEvents(true, { forward: false })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const createWindow = () => {
|
||||
if (global.modules.lyricWindow) return
|
||||
if (!global.appSetting.desktopLyric.enable) return
|
||||
// const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
let { x, y, width, height, isAlwaysOnTop } = global.appSetting.desktopLyric
|
||||
let { width: screenWidth, height: screenHeight } = global.envParams.workAreaSize
|
||||
if (x == null) {
|
||||
x = screenWidth - width
|
||||
y = screenHeight - height
|
||||
}
|
||||
if (global.appSetting.desktopLyric.isLockScreen) {
|
||||
let bounds = getLyricWindowBounds({ x, y, width, height }, { x: null, y: null, w: width, h: height })
|
||||
x = bounds.x
|
||||
y = bounds.y
|
||||
width = bounds.width
|
||||
height = bounds.height
|
||||
}
|
||||
/**
|
||||
* Initial window options
|
||||
*/
|
||||
global.modules.lyricWindow = new BrowserWindow({
|
||||
height,
|
||||
width,
|
||||
x,
|
||||
y,
|
||||
minWidth: 380,
|
||||
minHeight: 80,
|
||||
useContentSize: true,
|
||||
frame: false,
|
||||
transparent: true,
|
||||
enableRemoteModule: false,
|
||||
// icon: path.join(global.__static, isWin ? 'icons/256x256.ico' : 'icons/512x512.png'),
|
||||
resizable: false,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
fullscreenable: false,
|
||||
show: false,
|
||||
alwaysOnTop: isAlwaysOnTop,
|
||||
skipTaskbar: true,
|
||||
webPreferences: {
|
||||
// contextIsolation: true,
|
||||
webSecurity: !global.isDev,
|
||||
nodeIntegration: true,
|
||||
},
|
||||
})
|
||||
|
||||
global.modules.lyricWindow.loadURL(winURL)
|
||||
|
||||
winEvent(global.modules.lyricWindow)
|
||||
// mainWindow.webContents.openDevTools()
|
||||
}
|
||||
|
||||
const closeWindow = () => {
|
||||
if (!global.modules.lyricWindow) return
|
||||
global.modules.lyricWindow.close()
|
||||
}
|
||||
32
src/main/modules/winLyric/rendererEvent.js
Normal file
32
src/main/modules/winLyric/rendererEvent.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const {
|
||||
mainOn,
|
||||
mainHandle,
|
||||
mainSend,
|
||||
NAMES: {
|
||||
mainWindow: ipcMainWindowNames,
|
||||
winLyric: ipcWinLyricNames,
|
||||
},
|
||||
} = require('../../../common/ipc')
|
||||
const { winLyric: WIN_LYRIC_EVENT_NAME } = require('../../events/_name')
|
||||
const { getLyricWindowBounds } = require('./utils')
|
||||
|
||||
mainOn(ipcWinLyricNames.get_lyric_info, (event, action) => {
|
||||
if (!global.modules.mainWindow) return
|
||||
mainSend(global.modules.mainWindow, ipcMainWindowNames.get_lyric_info, {
|
||||
name: ipcWinLyricNames.set_lyric_info,
|
||||
modal: 'lyricWindow',
|
||||
action,
|
||||
})
|
||||
})
|
||||
|
||||
mainOn(ipcWinLyricNames.set_lyric_config, (event, config) => {
|
||||
global.lx_event.common.setAppConfig({ desktopLyric: config }, WIN_LYRIC_EVENT_NAME.name)
|
||||
})
|
||||
|
||||
mainHandle(ipcWinLyricNames.get_lyric_config, async() => {
|
||||
return { config: global.appSetting.desktopLyric, languageId: global.appSetting.langId, isShowLyricTransition: global.appSetting.player.isShowLyricTransition }
|
||||
})
|
||||
|
||||
mainOn(ipcWinLyricNames.set_win_bounds, (event, options) => {
|
||||
global.modules.lyricWindow.setBounds(getLyricWindowBounds(global.modules.lyricWindow.getBounds(), options))
|
||||
})
|
||||
68
src/main/modules/winLyric/utils.js
Normal file
68
src/main/modules/winLyric/utils.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// 设置窗口位置、大小
|
||||
let winX
|
||||
let winY
|
||||
let wasW
|
||||
let wasH
|
||||
let offset = 8
|
||||
let minWidth = 380
|
||||
let minHeight = 80
|
||||
exports.getLyricWindowBounds = (bounds, { x = 0, y = 0, w = 0, h = 0 }) => {
|
||||
if (w < minWidth) w = minWidth
|
||||
if (h < minHeight) h = minHeight
|
||||
|
||||
if (global.appSetting.desktopLyric.isLockScreen) {
|
||||
wasW = global.envParams.workAreaSize.width + offset
|
||||
wasH = global.envParams.workAreaSize.height + offset
|
||||
if (w > wasW + offset) w = wasW + offset
|
||||
if (h > wasH + offset) h = wasH + offset
|
||||
if (x == null) {
|
||||
if (bounds.x > wasW - w) {
|
||||
x = wasW - w - bounds.x
|
||||
} else if (bounds.x < -offset) {
|
||||
x = bounds.x + offset
|
||||
} else {
|
||||
x = 0
|
||||
}
|
||||
if (bounds.y > wasH - h) {
|
||||
y = wasH - h - bounds.y
|
||||
} else if (bounds.y < -offset) {
|
||||
y = bounds.y + offset
|
||||
} else {
|
||||
y = 0
|
||||
}
|
||||
}
|
||||
winX = bounds.x + x
|
||||
winY = bounds.y + y
|
||||
|
||||
if (x != 0) {
|
||||
if (winX < -offset) {
|
||||
winX = -offset
|
||||
} else if (winX + w > wasW) {
|
||||
winX = wasW - w
|
||||
}
|
||||
}
|
||||
if (y != 0) {
|
||||
if (winY < -offset) {
|
||||
winY = -offset
|
||||
} else if (winY + h > wasH) {
|
||||
winY = wasH - h
|
||||
}
|
||||
}
|
||||
|
||||
x = winX
|
||||
y = winY
|
||||
|
||||
if (x + w > wasW) w = wasW - x
|
||||
if (y + h > wasH) h = wasH - y
|
||||
} else {
|
||||
y += bounds.y
|
||||
x += bounds.x
|
||||
}
|
||||
|
||||
bounds.width = w
|
||||
bounds.height = h
|
||||
bounds.x = x
|
||||
bounds.y = y
|
||||
// console.log('util bounds', bounds)
|
||||
return bounds
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { app } = require('electron')
|
||||
const { name: defaultName } = require('../../../package.json')
|
||||
|
||||
|
||||
mainOn('appName', (event, params) => {
|
||||
mainOn(ipcMainWindowNames.set_app_name, (event, params) => {
|
||||
if (params == null) {
|
||||
app.setName(defaultName)
|
||||
} else {
|
||||
9
src/main/rendererEvents/appSetting.js
Normal file
9
src/main/rendererEvents/appSetting.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const { mainWindow: MAIN_WINDOW_EVENT_NAME } = require('../events/_name')
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
|
||||
|
||||
mainOn(ipcMainWindowNames.set_app_setting, (event, config) => {
|
||||
if (!config) return
|
||||
global.lx_event.common.setAppConfig(config, MAIN_WINDOW_EVENT_NAME.name)
|
||||
})
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_setting, async() => ({ setting: global.appSetting, version: global.appSettingVersion }))
|
||||
11
src/main/rendererEvents/cache.js
Normal file
11
src/main/rendererEvents/cache.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
mainHandle(ipcMainWindowNames.clear_cache, async(event, options) => {
|
||||
if (!global.modules.mainWindow) throw new Error('mainWindow is undefined')
|
||||
return global.modules.mainWindow.webContents.session.clearCache()
|
||||
})
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_cache_size, async(event, options) => {
|
||||
if (!global.modules.mainWindow) throw new Error('mainWindow is undefined')
|
||||
return global.modules.mainWindow.webContents.session.getCacheSize()
|
||||
})
|
||||
12
src/main/rendererEvents/data.js
Normal file
12
src/main/rendererEvents/data.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const Store = require('electron-store')
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
|
||||
|
||||
|
||||
const electronStore_data = new Store({
|
||||
name: 'data',
|
||||
})
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_data, async(event, path) => electronStore_data.get(path))
|
||||
|
||||
|
||||
mainOn(ipcMainWindowNames.save_data, (event, { path, data }) => electronStore_data.set(path, data))
|
||||
5
src/main/rendererEvents/getDataPath.js
Normal file
5
src/main/rendererEvents/getDataPath.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { app } = require('electron')
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_data_path, async() => app.getPath('userData'))
|
||||
|
||||
6
src/main/rendererEvents/getEnvParams.js
Normal file
6
src/main/rendererEvents/getEnvParams.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_env_params, async(event, options) => {
|
||||
return global.envParams.cmdParams
|
||||
})
|
||||
|
||||
41
src/main/rendererEvents/hotKey.js
Normal file
41
src/main/rendererEvents/hotKey.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const Store = require('electron-store')
|
||||
const { mainSend, NAMES: { mainWindow: ipcMainWindowNames }, mainOn, mainHandle } = require('../../common/ipc')
|
||||
const { mainWindow: MAIN_WINDOW_EVENT_NAME, hotKey: HOT_KEY_EVENT_NAME } = require('../events/_name')
|
||||
|
||||
const electronStore_hotKey = new Store({
|
||||
name: 'hotKey',
|
||||
})
|
||||
// const { registerHotkey, unRegisterHotkey } = require('../modules/hotKey/utils')
|
||||
|
||||
// mainHandle(ipcMainWindowNames.set_hot_key_config, async(event, { action, data }) => {
|
||||
// switch (action) {
|
||||
// case 'config':
|
||||
// global.lx_event.hotKey.saveConfig(data.data, MAIN_WINDOW_EVENT_NAME.source)
|
||||
// return
|
||||
// case 'register':
|
||||
// return registerHotkey(data)
|
||||
// case 'unregister':
|
||||
// return unRegisterHotkey(data)
|
||||
// }
|
||||
// })
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_hot_key, async() => ({
|
||||
local: electronStore_hotKey.get('local'),
|
||||
global: electronStore_hotKey.get('global'),
|
||||
}))
|
||||
|
||||
mainOn(ipcMainWindowNames.quit, () => global.lx_event.mainWindow.quit())
|
||||
mainOn(ipcMainWindowNames.min_toggle, () => global.lx_event.mainWindow.toggleMinimize())
|
||||
mainOn(ipcMainWindowNames.hide_toggle, () => global.lx_event.mainWindow.toggleHide())
|
||||
|
||||
|
||||
global.lx_event.hotKey.on(HOT_KEY_EVENT_NAME.config, (config, source) => {
|
||||
if (!global.modules.mainWindow || source === MAIN_WINDOW_EVENT_NAME.name) return
|
||||
mainSend(global.modules.mainWindow, ipcMainWindowNames.set_hot_key_config, { config, source })
|
||||
})
|
||||
|
||||
global.lx_event.hotKey.on(HOT_KEY_EVENT_NAME.keyDown, ({ type, key }) => {
|
||||
let info = global.appHotKey.config.global.keys[key]
|
||||
if (!info || info.type != MAIN_WINDOW_EVENT_NAME.name) return
|
||||
mainSend(global.modules.mainWindow, ipcMainWindowNames.key_down, { type, key })
|
||||
})
|
||||
23
src/main/rendererEvents/index.js
Normal file
23
src/main/rendererEvents/index.js
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
// require('./request')
|
||||
// require('./appName')
|
||||
require('./progressBar')
|
||||
require('./trafficLight')
|
||||
require('./musicMeta')
|
||||
require('./selectDir')
|
||||
require('./setWindowSize')
|
||||
require('./showSaveDialog')
|
||||
require('./cache')
|
||||
require('./setIgnoreMouseEvent')
|
||||
require('./getEnvParams')
|
||||
require('./appSetting')
|
||||
require('./setLyricInfo')
|
||||
require('./hotKey')
|
||||
require('./getDataPath')
|
||||
require('./showDialog')
|
||||
require('./playList')
|
||||
require('./data')
|
||||
|
||||
require('./xm_verify')
|
||||
|
||||
require('./kw_decodeLyric')
|
||||
45
src/main/rendererEvents/kw_decodeLyric.js
Normal file
45
src/main/rendererEvents/kw_decodeLyric.js
Normal file
@@ -0,0 +1,45 @@
|
||||
const { inflate } = require('zlib')
|
||||
const iconv = require('iconv-lite')
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
const handleInflate = data => new Promise((resolve, reject) => {
|
||||
inflate(data, (err, result) => {
|
||||
if (err) return reject(err)
|
||||
resolve(result)
|
||||
})
|
||||
})
|
||||
|
||||
const buf_key = Buffer.from('yeelion')
|
||||
const buf_key_len = buf_key.length
|
||||
|
||||
const decodeLyric = async(buf, isGetLyricx) => {
|
||||
// const info = buf.slice(0, index).toString()
|
||||
// if (!info.startsWith('tp=content')) return null
|
||||
// const isLyric = info.includes('\r\nlrcx=0\r\n')
|
||||
if (buf.toString('utf8', 0, 10) != 'tp=content') return ''
|
||||
// const index = buf.indexOf('\r\n\r\n') + 4
|
||||
const lrcData = await handleInflate(buf.slice(buf.indexOf('\r\n\r\n') + 4))
|
||||
|
||||
if (!isGetLyricx) return iconv.decode(lrcData, 'gb18030')
|
||||
|
||||
const buf_str = Buffer.from(lrcData.toString(), 'base64')
|
||||
const buf_str_len = buf_str.length
|
||||
const output = new Uint16Array(buf_str_len)
|
||||
let i = 0
|
||||
while (i < buf_str_len) {
|
||||
let j = 0
|
||||
while (j < buf_key_len && i < buf_str_len) {
|
||||
output[i] = buf_str[i] ^ buf_key[j]
|
||||
i++
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
return iconv.decode(Buffer.from(output), 'gb18030')
|
||||
}
|
||||
|
||||
mainHandle(ipcMainWindowNames.handle_kw_decode_lyric, async(event, { lrcBase64, isGetLyricx }) => {
|
||||
if (!global.modules.mainWindow) throw new Error('mainWindow is undefined')
|
||||
const lrc = await decodeLyric(Buffer.from(lrcBase64, 'base64'), isGetLyricx)
|
||||
return Buffer.from(lrc).toString('base64')
|
||||
})
|
||||
6
src/main/rendererEvents/musicMeta.js
Normal file
6
src/main/rendererEvents/musicMeta.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { setMeta } = require('../utils/musicMeta')
|
||||
|
||||
mainOn(ipcMainWindowNames.set_music_meta, (event, { filePath, meta }) => {
|
||||
setMeta(filePath, meta)
|
||||
})
|
||||
23
src/main/rendererEvents/playList.js
Normal file
23
src/main/rendererEvents/playList.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const Store = require('electron-store')
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames }, mainHandle } = require('../../common/ipc')
|
||||
|
||||
|
||||
let electronStore_list
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_playlist, async(event, isIgnoredError = false) => {
|
||||
if (!electronStore_list) {
|
||||
electronStore_list = new Store({
|
||||
name: 'playList',
|
||||
clearInvalidConfig: !isIgnoredError,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
defaultList: electronStore_list.get('defaultList'),
|
||||
loveList: electronStore_list.get('loveList'),
|
||||
userList: electronStore_list.get('userList'),
|
||||
downloadList: electronStore_list.get('downloadList'),
|
||||
}
|
||||
})
|
||||
|
||||
mainOn(ipcMainWindowNames.save_playlist, (event, { type, data }) => electronStore_list && electronStore_list.set(type, data))
|
||||
10
src/main/rendererEvents/progressBar.js
Normal file
10
src/main/rendererEvents/progressBar.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
|
||||
mainOn(ipcMainWindowNames.progress, (event, params) => {
|
||||
// console.log(params)
|
||||
global.modules.mainWindow && global.modules.mainWindow.setProgressBar(params.status, {
|
||||
mode: params.mode || 'normal',
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
const request = require('request')
|
||||
|
||||
const { mainOn } = require('../../common/icp')
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
const tasks = []
|
||||
|
||||
mainOn('request', (event, options) => {
|
||||
mainOn(ipcMainWindowNames.handle_request, (event, options) => {
|
||||
// console.log(args)
|
||||
if (!options) return
|
||||
let index = fatchData(options, (err, resp) => {
|
||||
let index = fetchData(options, (err, resp) => {
|
||||
tasks[index] = null
|
||||
if (err) {
|
||||
console.log(err)
|
||||
@@ -19,7 +19,7 @@ mainOn('request', (event, options) => {
|
||||
event.returnValue = index
|
||||
})
|
||||
|
||||
mainOn('cancelRequest', (event, index) => {
|
||||
mainOn(ipcMainWindowNames.cancel_request, (event, index) => {
|
||||
if (index == null) return
|
||||
let r = tasks[index]
|
||||
if (r == null) return
|
||||
@@ -27,7 +27,7 @@ mainOn('cancelRequest', (event, index) => {
|
||||
tasks[index] = null
|
||||
})
|
||||
|
||||
const fatchData = (options, callback) => pushTask(tasks, request(options.url, {
|
||||
const fetchData = (options, callback) => pushTask(tasks, request(options.url, {
|
||||
method: options.method,
|
||||
headers: options.headers,
|
||||
Origin: options.origin,
|
||||
13
src/main/rendererEvents/restartWindow.js
Normal file
13
src/main/rendererEvents/restartWindow.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
|
||||
mainOn(ipcMainWindowNames.restart_window, (event, name) => {
|
||||
console.log(name)
|
||||
switch (name) {
|
||||
case 'main':
|
||||
default:
|
||||
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
8
src/main/rendererEvents/selectDir.js
Normal file
8
src/main/rendererEvents/selectDir.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { dialog } = require('electron')
|
||||
|
||||
mainHandle(ipcMainWindowNames.select_dir, async(event, options) => {
|
||||
if (!global.modules.mainWindow) throw new Error('mainWindow is undefined')
|
||||
return dialog.showOpenDialog(global.modules.mainWindow, options)
|
||||
})
|
||||
|
||||
8
src/main/rendererEvents/setIgnoreMouseEvent.js
Normal file
8
src/main/rendererEvents/setIgnoreMouseEvent.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
mainOn(ipcMainWindowNames.set_ignore_mouse_events, (event, isIgnored) => {
|
||||
if (!global.modules.mainWindow) return
|
||||
isIgnored
|
||||
? global.modules.mainWindow.setIgnoreMouseEvents(true, { forward: true })
|
||||
: global.modules.mainWindow.setIgnoreMouseEvents(false)
|
||||
})
|
||||
10
src/main/rendererEvents/setLyricInfo.js
Normal file
10
src/main/rendererEvents/setLyricInfo.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const { mainOn, mainSend, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
|
||||
mainOn(ipcMainWindowNames.set_lyric_info, (event, info) => {
|
||||
if (info.info == null) {
|
||||
global.lx_event.mainWindow.setLyricInfo(info)
|
||||
return
|
||||
}
|
||||
mainSend(global.modules[info.info.modal], info.info.name, info)
|
||||
})
|
||||
7
src/main/rendererEvents/setWindowSize.js
Normal file
7
src/main/rendererEvents/setWindowSize.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
mainOn(ipcMainWindowNames.set_window_size, (event, options) => {
|
||||
if (!global.modules.mainWindow) return
|
||||
global.modules.mainWindow.setBounds(options)
|
||||
})
|
||||
|
||||
12
src/main/rendererEvents/showDialog.js
Normal file
12
src/main/rendererEvents/showDialog.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { dialog } = require('electron')
|
||||
|
||||
|
||||
mainHandle(ipcMainWindowNames.show_dialog, async(event, { type, message, detail }) => {
|
||||
if (!global.modules.mainWindow) throw new Error('mainWindow is undefined')
|
||||
dialog.showMessageBoxSync(global.modules.mainWindow, {
|
||||
type,
|
||||
message,
|
||||
detail,
|
||||
})
|
||||
})
|
||||
8
src/main/rendererEvents/showSaveDialog.js
Normal file
8
src/main/rendererEvents/showSaveDialog.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { dialog } = require('electron')
|
||||
|
||||
mainHandle(ipcMainWindowNames.show_save_dialog, async(event, options) => {
|
||||
if (!global.modules.mainWindow) throw new Error('mainWindow is undefined')
|
||||
return dialog.showSaveDialog(global.modules.mainWindow, options)
|
||||
})
|
||||
|
||||
18
src/main/rendererEvents/trafficLight.js
Normal file
18
src/main/rendererEvents/trafficLight.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { app } = require('electron')
|
||||
const { mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
mainOn(ipcMainWindowNames.min, event => {
|
||||
if (global.modules.mainWindow) {
|
||||
global.modules.mainWindow.minimize()
|
||||
}
|
||||
})
|
||||
mainOn(ipcMainWindowNames.max, event => {
|
||||
if (global.modules.mainWindow) {
|
||||
global.modules.mainWindow.maximize()
|
||||
}
|
||||
})
|
||||
mainOn(ipcMainWindowNames.close, (event, isForce) => {
|
||||
if (isForce) return app.exit(0)
|
||||
global.isTrafficLightClose = true
|
||||
if (global.modules.mainWindow) global.modules.mainWindow.close()
|
||||
})
|
||||
41
src/main/rendererEvents/winEvent.js
Normal file
41
src/main/rendererEvents/winEvent.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const { isWin } = require('../../common/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)) {
|
||||
mainWindow.setProgressBar(-1)
|
||||
global.lx_event.winLyric.close()
|
||||
return
|
||||
}
|
||||
|
||||
if (global.isTrafficLightClose) global.isTrafficLightClose = false
|
||||
event.preventDefault()
|
||||
mainWindow.hide()
|
||||
})
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = global.modules.mainWindow = null
|
||||
})
|
||||
|
||||
// mainWindow.on('restore', () => {
|
||||
// mainWindow.webContents.send('restore')
|
||||
// })
|
||||
mainWindow.on('focus', () => {
|
||||
mainSend(mainWindow, ipcMainWindowNames.focus)
|
||||
})
|
||||
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
mainWindow.show()
|
||||
global.lx_event.mainWindow.readyToShow()
|
||||
})
|
||||
|
||||
mainWindow.on('show', () => {
|
||||
global.lx_event.mainWindow.show()
|
||||
})
|
||||
mainWindow.on('hide', () => {
|
||||
global.lx_event.mainWindow.hide()
|
||||
})
|
||||
}
|
||||
4
src/main/rendererEvents/xm_verify/index.js
Normal file
4
src/main/rendererEvents/xm_verify/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const { isMac } = require('../../../common/utils')
|
||||
|
||||
// mac下的 BrowserView 无法拖动验证栏,改用 BrowserWindow
|
||||
require(isMac ? './xm_verify_win' : './xm_verify_view')
|
||||
4
src/main/rendererEvents/xm_verify/xm_verify.js
Normal file
4
src/main/rendererEvents/xm_verify/xm_verify.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const { isMac } = require('../../../common/utils')
|
||||
|
||||
// mac下的 BrowserView 无法拖动验证栏,改用 BrowserWindow
|
||||
require(isMac ? './xm_verify_win' : './xm_verify_view')
|
||||
66
src/main/rendererEvents/xm_verify/xm_verify_view.js
Normal file
66
src/main/rendererEvents/xm_verify/xm_verify_view.js
Normal file
@@ -0,0 +1,66 @@
|
||||
const { BrowserView } = require('electron')
|
||||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../../common/ipc')
|
||||
const { getWindowSizeInfo } = require('../../utils')
|
||||
|
||||
let view
|
||||
let isActioned = false
|
||||
let rejectFn
|
||||
|
||||
const closeView = async() => {
|
||||
if (!view) return
|
||||
// await view.webContents.session.clearCache()
|
||||
if (global.modules.mainWindow) global.modules.mainWindow.removeBrowserView(view)
|
||||
await view.webContents.session.clearStorageData()
|
||||
view.destroy()
|
||||
view = null
|
||||
}
|
||||
|
||||
mainHandle(ipcMainWindowNames.handle_xm_verify_open, (event, url) => new Promise((resolve, reject) => {
|
||||
if (!global.modules.mainWindow) return reject(new Error('mainWindow is undefined'))
|
||||
if (view) {
|
||||
global.modules.mainWindow.removeBrowserView(view)
|
||||
view.destroy()
|
||||
}
|
||||
|
||||
rejectFn = reject
|
||||
|
||||
isActioned = false
|
||||
|
||||
view = new BrowserView({
|
||||
webPreferences: {
|
||||
enableRemoteModule: false,
|
||||
disableHtmlFullscreenWindowResize: true,
|
||||
},
|
||||
})
|
||||
view.webContents.on('did-finish-load', () => {
|
||||
if (/punish\?/.test(view.webContents.getURL())) return
|
||||
let ses = view.webContents.session
|
||||
ses.cookies.get({ name: 'x5sec' })
|
||||
.then(async([x5sec]) => {
|
||||
isActioned = true
|
||||
await closeView()
|
||||
if (!x5sec) return reject(new Error('get x5sec failed'))
|
||||
resolve(x5sec.value)
|
||||
}).catch(async err => {
|
||||
isActioned = true
|
||||
await closeView()
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
|
||||
global.modules.mainWindow.setBrowserView(view)
|
||||
const windowSizeInfo = getWindowSizeInfo(global.appSetting)
|
||||
view.setBounds({ x: (windowSizeInfo.width - 380) / 2, y: ((windowSizeInfo.height - 320 + 52) / 2), width: 380, height: 320 })
|
||||
view.webContents.loadURL(url, {
|
||||
httpReferrer: 'https://www.xiami.com/',
|
||||
})
|
||||
// view.webContents.openDevTools()
|
||||
}))
|
||||
|
||||
mainHandle(ipcMainWindowNames.handle_xm_verify_close, async() => {
|
||||
await closeView()
|
||||
if (!rejectFn) return
|
||||
if (!isActioned) rejectFn(new Error('canceled verify'))
|
||||
rejectFn = null
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user